Skip to content

Commit 3552c67

Browse files
committed
Use libsolv caches to speed things up
This can be specially helpful when doing multiple queries on the same repo metadata. Solves #65 Signed-off-by: Rafael Fonseca <r4f4rfs@gmail.com>
1 parent a638ad4 commit 3552c67

2 files changed

Lines changed: 159 additions & 3 deletions

File tree

fus.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,5 +770,12 @@ fus_depsolve (const char *arch,
770770
g_ptr_array_add (output, name);
771771
}
772772

773+
/* We need to free the repomd checksum we saved in repo->appdata */
774+
int id;
775+
Repo *r;
776+
FOR_REPOS(id, r)
777+
if (r->appdata)
778+
g_free (r->appdata);
779+
773780
return output;
774781
}

repo.c

Lines changed: 152 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <solv/repo_comps.h>
77
#include <solv/repo_repomdxml.h>
88
#include <solv/repo_rpmmd.h>
9+
#include <solv/repo_solv.h>
910
#include <solv/repo_write.h>
1011
#include <solv/solv_xfopen.h>
1112
#include <solv/testcase.h>
@@ -429,6 +430,18 @@ repomd_find (Repo *repo,
429430
return filename;
430431
}
431432

433+
/* Returns checksum as a hexadecimal string which we can use as filename */
434+
static gchar *
435+
chksum_string_for_filepath (GChecksumType type, const char *filepath)
436+
{
437+
gsize len = 0;
438+
g_autofree gchar *data = NULL;
439+
if (!g_file_get_contents (filepath, &data, &len, NULL))
440+
return NULL;
441+
442+
return g_compute_checksum_for_string (type, data, len);
443+
}
444+
432445
static gboolean
433446
checksum_matches (const char *filepath,
434447
const unsigned char *chksum,
@@ -520,6 +533,110 @@ download_repo_metadata (SoupSession *session,
520533
return fpath;
521534
}
522535

536+
static void
537+
switch_to_cached_repo (Repo *repo,
538+
Repodata *repodata,
539+
const char *repoext,
540+
const char *cachepath)
541+
{
542+
int i;
543+
FILE *fp;
544+
545+
if (!repoext && repodata)
546+
return;
547+
548+
for (i = repo->start; i < repo->end; i++)
549+
if (repo->pool->solvables[i].repo != repo)
550+
break;
551+
552+
if (i < repo->end)
553+
return; /* not a simple block */
554+
555+
fp = g_fopen (cachepath, "rb");
556+
if (!fp)
557+
return;
558+
559+
/* main repo */
560+
if (!repoext)
561+
{
562+
repo_empty (repo, 1);
563+
if (repo_add_solv (repo, fp, SOLV_ADD_NO_STUBS))
564+
{
565+
g_warning ("Could not add solvables from cache file");
566+
return;
567+
}
568+
}
569+
else
570+
{
571+
int flags = REPO_USE_LOADING | REPO_EXTEND_SOLVABLES | REPO_LOCALPOOL;
572+
/* make sure repodata contains complete repo */
573+
/* (this is how repodata_write saves it) */
574+
repodata_extend_block (repodata, repo->start, repo->end - repo->start);
575+
repodata->state = REPODATA_LOADING;
576+
repo_add_solv (repo, fp, flags);
577+
repodata->state = REPODATA_AVAILABLE; /* in case the load failed */
578+
}
579+
580+
fclose (fp);
581+
}
582+
583+
static gboolean
584+
write_repo_cache (Repo *repo,
585+
Repodata *repodata,
586+
const char *repoext,
587+
const gchar *cachename)
588+
{
589+
FILE *fp = g_fopen (cachename, "wb");
590+
if (!fp)
591+
{
592+
g_warning ("Could not open cache file %s: %s", cachename, g_strerror (errno));
593+
return FALSE;
594+
}
595+
596+
if (!repodata)
597+
repo_write (repo, fp); /* main repo */
598+
else
599+
repodata_write (repodata, fp);
600+
601+
if (fclose (fp))
602+
{
603+
g_warning ("Error when closing %s: %s", cachename, g_strerror (errno));
604+
g_unlink (cachename);
605+
return FALSE;
606+
}
607+
608+
/* Switch to just saved repo to activate paging and save memory */
609+
switch_to_cached_repo (repo, repodata, repoext, cachename);
610+
611+
return TRUE;
612+
}
613+
614+
static gboolean
615+
load_cached_repo (Repo *repo,
616+
const char *cachefn,
617+
const char *repoext)
618+
{
619+
int ret, flags = 0;
620+
621+
if (!g_file_test (cachefn, G_FILE_TEST_IS_REGULAR))
622+
{
623+
g_debug ("Cache %s for repo %s not found", cachefn, repo->name);
624+
return FALSE;
625+
}
626+
627+
FILE *fp = g_fopen (cachefn, "rb");
628+
if (!fp)
629+
return FALSE;
630+
631+
if (repoext)
632+
flags = REPO_USE_LOADING | REPO_EXTEND_SOLVABLES | REPO_LOCALPOOL;
633+
634+
ret = repo_add_solv (repo, fp, flags);
635+
fclose (fp);
636+
637+
return ret == 0;
638+
}
639+
523640
static inline gchar *
524641
get_repo_cachedir (const char *name)
525642
{
@@ -540,12 +657,21 @@ filelist_loadcb (Pool *pool,
540657
if (g_strcmp0 (type, "filelists") != 0)
541658
return 0;
542659

660+
g_autofree gchar *cachedir = get_repo_cachedir (repo->name);
661+
662+
/* repo ext cache name is $(CHECKSUM(REPOMD)).solvx */
663+
const char *cachefn = pool_tmpjoin (pool, cachedir, "/", repo->appdata);
664+
cachefn = pool_tmpappend (pool, cachefn, ".solvx", 0);
665+
if (load_cached_repo (repo, cachefn, type))
666+
{
667+
g_debug ("Using cached repo for \"%s\" filelists", repo->name);
668+
return 1;
669+
}
670+
543671
path = repodata_lookup_str (data, SOLVID_META, REPOSITORY_REPOMD_LOCATION);
544672
if (!path)
545673
return 0;
546674

547-
g_autofree gchar *cachedir = get_repo_cachedir (repo->name);
548-
549675
fname = download_repo_metadata (session, repo, type, path, cachedir);
550676
fp = solv_xfopen (fname, 0);
551677
if (!fp)
@@ -556,6 +682,9 @@ filelist_loadcb (Pool *pool,
556682
repo_add_rpmmd (repo, fp, NULL, REPO_USE_LOADING | REPO_LOCALPOOL | REPO_EXTEND_SOLVABLES);
557683
fclose (fp);
558684

685+
if (write_repo_cache (repo, data, type, cachefn))
686+
g_debug ("Wrote cache file %s for repo \"%s\"", cachefn, repo->name);
687+
559688
return 1;
560689
}
561690

@@ -591,6 +720,10 @@ create_repo (Pool *pool,
591720
if (!download_to_path (session, url, fname, error))
592721
return NULL;
593722

723+
gchar *mdchksum = chksum_string_for_filepath (G_CHECKSUM_SHA256, fname);
724+
if (!mdchksum)
725+
return NULL;
726+
594727
fp = solv_xfopen (fname, "r");
595728
if (!fp)
596729
{
@@ -602,6 +735,18 @@ create_repo (Pool *pool,
602735
}
603736

604737
Repo *repo = repo_create (pool, name);
738+
/* Save repomd checksum to the repo's appdata so we just calculate it once */
739+
repo->appdata = mdchksum;
740+
741+
/* repo main cache name is $(CHECKSUM(REPOMD)).solv */
742+
const char *cachefn = pool_tmpjoin (pool, cachedir, "/", mdchksum);
743+
cachefn = pool_tmpappend (pool, cachefn, ".solv", 0);
744+
if (load_cached_repo (repo, cachefn, NULL))
745+
{
746+
g_debug ("Using cached repo for \"%s\"", name);
747+
return repo;
748+
}
749+
605750
repo_add_repomdxml (repo, fp, 0);
606751
fclose (fp);
607752

@@ -637,7 +782,6 @@ create_repo (Pool *pool,
637782
repodata_add_idarray (data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRSTRARRAY);
638783
repodata_add_flexarray (data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
639784
repodata_internalize (data);
640-
repodata_create_stubs (repo_last_repodata (repo));
641785
}
642786

643787
pool_createwhatprovides (pool);
@@ -654,6 +798,11 @@ create_repo (Pool *pool,
654798

655799
pool_createwhatprovides (pool);
656800

801+
if (write_repo_cache (repo, NULL, NULL, cachefn))
802+
g_debug ("Wrote cache file %s for repo \"%s\" filelists", cachefn, repo->name);
803+
804+
repodata_create_stubs (repo_last_repodata (repo));
805+
657806
return repo;
658807
}
659808
#endif /* FUS_TESTING */

0 commit comments

Comments
 (0)