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+
432445static gboolean
433446checksum_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+
523640static inline gchar *
524641get_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