From 5bb97e51a00ec15f1cb6bd6b5f3b4befd0263e1d Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Tue, 29 Jan 2008 16:14:03 +0000 Subject: [PATCH] - add key filtering to repo_write - change repo_write so that it combines all available data - integrate attr_store into repodata - write storage parameter with every key, bump solv revision to 5 - don't create system rules for atoms - change repo_susetags to use repodata interface --- src/CMakeLists.txt | 6 +- src/dirpool.c | 27 +- src/dirpool.h | 2 +- src/pool.c | 36 +- src/pool.h | 8 +- src/poolid.c | 19 +- src/poolid.h | 1 + src/pooltypes.h | 1 + src/repo.c | 671 ++++++++++++-------------- src/repo.h | 98 ++-- src/repo_solv.c | 461 ++++++++++++++---- src/repodata.c | 1157 ++++++++++++++++++++++++++++++++++++++++++++ src/repodata.h | 123 +++++ src/solver.c | 99 +++- src/strpool.c | 45 +- src/strpool.h | 8 +- src/util.h | 29 ++ tools/CMakeLists.txt | 13 +- tools/content2solv.c | 2 +- tools/dumpsolv.c | 81 +++- tools/helix2solv.c | 2 +- tools/mergesolv.c | 2 +- tools/patchxml2solv.c | 2 +- tools/repo_susetags.c | 131 ++++- tools/repo_write.c | 1281 ++++++++++++++++++++++++++++++++++++++----------- tools/repo_write.h | 2 +- tools/rpmdb2solv.c | 2 +- tools/rpmmd2solv.c | 2 +- tools/susetags2solv.c | 46 +- 29 files changed, 3437 insertions(+), 920 deletions(-) create mode 100644 src/repodata.c create mode 100644 src/repodata.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0122505..b1536eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,10 @@ -SET(libsatsolver_SRCS attr_store.c bitmap.c poolarch.c poolvendor.c poolid.c strpool.c -solver.c repo_solv.c evr.c pool.c queue.c repo.c util.c policy.c) +SET(libsatsolver_SRCS bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c +solver.c repo_solv.c evr.c pool.c queue.c repo.c repodata.c util.c policy.c) ADD_LIBRARY(satsolver STATIC ${libsatsolver_SRCS}) -SET(libsatsolver_HEADERS attr_store.h bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h poolid.h pooltypes.h queue.h solvable.h solver.h repo.h repo_solv.h util.h strpool.h) +SET(libsatsolver_HEADERS bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h poolid.h pooltypes.h queue.h solvable.h solver.h repo.h repodata.h repo_solv.h util.h strpool.h dirpool.h) SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -Wall -fPIC" ) diff --git a/src/dirpool.c b/src/dirpool.c index 22874e8..e843b2a 100644 --- a/src/dirpool.c +++ b/src/dirpool.c @@ -31,8 +31,9 @@ dirpool_make_dirtraverse(Dirpool *dp) Id parent, i, *dirtraverse; if (!dp->ndirs) return; - dp->dirs = sat_realloc2(dp->dirs, (dp->ndirs + DIR_BLOCK) &~ DIR_BLOCK, sizeof(Id)); - dirtraverse = sat_calloc((dp->ndirs + DIR_BLOCK) &~ DIR_BLOCK, sizeof(Id)); + dp->dirs = sat_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK); + dirtraverse = sat_extend_resize(0, dp->ndirs, sizeof(Id), DIR_BLOCK); + memset(dirtraverse, 0, dp->ndirs * sizeof(Id)); for (parent = 0, i = 0; i < dp->ndirs; i++) { if (dp->dirs[i] > 0) @@ -45,14 +46,14 @@ dirpool_make_dirtraverse(Dirpool *dp) } Id -dirpool_add_dir(Dirpool *dp, Id parent, Id comp) +dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create) { Id did, d, ds, *dirtraverse; if (!dp->ndirs) { - dp->dirs = sat_malloc2(DIR_BLOCK, sizeof(Id)); dp->ndirs = 2; + dp->dirs = sat_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK); dp->dirs[0] = 0; dp->dirs[1] = 1; /* "" */ } @@ -76,27 +77,25 @@ dirpool_add_dir(Dirpool *dp, Id parent, Id comp) if (ds) ds = dp->dirtraverse[ds]; } + if (!create) + return 0; /* a new one, find last parent */ for (did = dp->ndirs - 1; did > 0; did--) if (dp->dirs[did] <= 0) break; if (dp->dirs[did] != -parent) { - if ((dp->ndirs & DIR_BLOCK) == 0) - { - dp->dirs = sat_realloc2(dp->dirs, dp->ndirs + DIR_BLOCK, sizeof(Id)); - dp->dirtraverse = sat_realloc2(dp->dirtraverse, dp->ndirs + DIR_BLOCK, sizeof(Id)); - } + /* make room for parent entry */ + dp->dirs = sat_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK); + dp->dirtraverse = sat_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK); /* new parent block, link in */ dp->dirs[dp->ndirs] = -parent; dp->dirtraverse[dp->ndirs] = dp->dirtraverse[parent]; dp->dirtraverse[parent] = ++dp->ndirs; } - if ((dp->ndirs & DIR_BLOCK) == 0) - { - dp->dirs = sat_realloc2(dp->dirs, dp->ndirs + DIR_BLOCK, sizeof(Id)); - dp->dirtraverse = sat_realloc2(dp->dirtraverse, dp->ndirs + DIR_BLOCK, sizeof(Id)); - } + /* make room for new entry */ + dp->dirs = sat_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK); + dp->dirtraverse = sat_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK); dp->dirs[dp->ndirs] = comp; dp->dirtraverse[dp->ndirs] = 0; return dp->ndirs++; diff --git a/src/dirpool.h b/src/dirpool.h index 86b9e80..fb441d7 100644 --- a/src/dirpool.h +++ b/src/dirpool.h @@ -21,7 +21,7 @@ typedef struct _Dirpool { void dirpool_create(Dirpool *dp); void dirpool_make_dirtraverse(Dirpool *dp); -Id dirpool_add_dir(Dirpool *dp, Id parent, Id comp); +Id dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create); static inline Id dirpool_parent(Dirpool *dp, Id did) { diff --git a/src/pool.c b/src/pool.c index aff39bb..192e71c 100644 --- a/src/pool.c +++ b/src/pool.c @@ -76,19 +76,22 @@ pool_create(void) stringpool_init (&pool->ss, initpool_data); - // pre-alloc space for a RelDep - pool->rels = (Reldep *)sat_calloc(1 + REL_BLOCK, sizeof(Reldep)); + /* alloc space for ReDep 0 */ + pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK); pool->nrels = 1; + memset(pool->rels, 0, sizeof(Reldep)); - // pre-alloc space for a Solvable - pool->solvables = (Solvable *)sat_calloc(SOLVABLE_BLOCK + 1, sizeof(Solvable)); + /* alloc space for Solvable 0 and system solvable */ + pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK); pool->nsolvables = 2; - queue_init(&pool->vendormap); + memset(pool->solvables, 0, 2 * sizeof(Solvable)); s = pool->solvables + SYSTEMSOLVABLE; s->name = SYSTEM_SYSTEM; s->arch = ARCH_NOARCH; s->evr = ID_EMPTY; + queue_init(&pool->vendormap); + pool->debugmask = SAT_DEBUG_RESULT; /* FIXME */ return pool; } @@ -117,8 +120,7 @@ pool_free(Pool *pool) Id pool_add_solvable(Pool *pool) { - if ((pool->nsolvables & SOLVABLE_BLOCK) == 0) - pool->solvables = sat_realloc2(pool->solvables, pool->nsolvables + (SOLVABLE_BLOCK + 1), sizeof(Solvable)); + pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK); memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable)); return pool->nsolvables++; } @@ -129,8 +131,7 @@ pool_add_solvable_block(Pool *pool, int count) Id nsolvables = pool->nsolvables; if (!count) return nsolvables; - if (((nsolvables - 1) | SOLVABLE_BLOCK) != ((nsolvables + count - 1) | SOLVABLE_BLOCK)) - pool->solvables = sat_realloc2(pool->solvables, (nsolvables + count + SOLVABLE_BLOCK) & ~SOLVABLE_BLOCK, sizeof(Solvable)); + pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK); memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count); pool->nsolvables += count; return nsolvables; @@ -305,8 +306,10 @@ pool_createwhatprovides(Pool *pool) pool_freeidhashes(pool); /* XXX: should not be here! */ pool_freewhatprovides(pool); num = pool->ss.nstrings; - pool->whatprovides = whatprovides = sat_calloc((num + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK, sizeof(Offset)); - pool->whatprovides_rel = sat_calloc((pool->nrels + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK, sizeof(Offset)); + pool->whatprovides = whatprovides = sat_extend_resize(0, num, sizeof(Offset), WHATPROVIDES_BLOCK); + memset(whatprovides, 0, num * sizeof(Offset)); + pool->whatprovides_rel = sat_extend_resize(0, pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK); + memset(pool->whatprovides_rel, 0, pool->nrels * sizeof(Offset)); /* count providers for each name */ for (i = 1; i < pool->nsolvables; i++) @@ -593,7 +596,7 @@ pool_debug(Pool *pool, int type, const char *format, ...) va_list args; char buf[1024]; - if ((type & SAT_FATAL) == 0) + if ((type & (SAT_FATAL|SAT_ERROR)) == 0) { if ((pool->debugmask & type) == 0) return; @@ -691,8 +694,7 @@ pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct sea s = id2str(pool, dep); if (*s != '/') continue; - if ((sf->nfiles & SEARCHFILES_BLOCK) == 0) - sf->files = sat_realloc2(sf->files, sf->nfiles + (SEARCHFILES_BLOCK + 1), sizeof(const char *)); + sf->files = sat_extend(sf->files, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); sf->files[sf->nfiles++] = strdup(s); } } @@ -756,8 +758,7 @@ pool_addfileprovides(Pool *pool, Repo *installed) for (i = 0; i < sf.nfiles; i++) POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", sf.files[i]); #endif - if ((sf.nfiles & SEARCHFILES_BLOCK) == 0) - sf.files = sat_realloc2(sf.files, sf.nfiles + (SEARCHFILES_BLOCK + 1), sizeof(const char *)); + sf.files = sat_extend(sf.files, sf.nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); sf.files[sf.nfiles++] = 0; #if 0 pool_search(0, SOLVABLE_FILELIST, (const char *)sf.files, SEARCH_STRING|SEARCH_MULTIPLE, addfileprovides_cb, 0); @@ -770,8 +771,7 @@ pool_addfileprovides(Pool *pool, Repo *installed) for (i = 0; i < isf.nfiles; i++) POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", isf.files[i]); #endif - if ((isf.nfiles & SEARCHFILES_BLOCK) == 0) - isf.files = sat_realloc2(isf.files, isf.nfiles + (SEARCHFILES_BLOCK + 1), sizeof(const char *)); + isf.files = sat_extend(isf.files, isf.nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); isf.files[isf.nfiles++] = 0; #if 0 repo_search(installed, 0, SOLVABLE_FILELIST, (const char *)isf.files, SEARCH_STRING|SEARCH_MULTIPLE, addfileprovides_cb, 0); diff --git a/src/pool.h b/src/pool.h index e62a9ff..c2969fe 100644 --- a/src/pool.h +++ b/src/pool.h @@ -153,9 +153,13 @@ struct _Pool { #define TYPE_IDVALUEARRAY 13 #define TYPE_DIR 14 -#define TYPE_DIRVALUEVALUEARRAY 15 +#define TYPE_DIRNUMNUMARRAY 15 +#define TYPE_DIRSTRARRAY 16 -#define TYPE_ATTR_TYPE_MAX TYPE_DIRVALUEVALUEARRAY +#define TYPE_CONSTANT 17 +#define TYPE_NUM 18 + +#define TYPE_ATTR_TYPE_MAX 18 //----------------------------------------------- diff --git a/src/poolid.c b/src/poolid.c index 8a06437..6911367 100644 --- a/src/poolid.c +++ b/src/poolid.c @@ -38,6 +38,20 @@ str2id(Pool *pool, const char *str, int create) } Id +strn2id(Pool *pool, const char *str, unsigned int len, int create) +{ + int oldnstrings = pool->ss.nstrings; + Id id = stringpool_strn2id (&pool->ss, str, len, create); + if (create && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0) + { + /* grow whatprovides array */ + pool->whatprovides = sat_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset)); + memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset)); + } + return id; +} + +Id rel2id(Pool *pool, Id name, Id evr, int flags, int create) { Hashval h; @@ -86,8 +100,7 @@ rel2id(Pool *pool, Id name, Id evr, int flags, int create) id = pool->nrels++; /* extend rel space if needed */ - if ((id & REL_BLOCK) == 0) - pool->rels = sat_realloc(pool->rels, ((pool->nrels + REL_BLOCK) & ~REL_BLOCK) * sizeof(Reldep)); + pool->rels = sat_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK); hashtbl[h] = id; ran = pool->rels + id; ran->name = name; @@ -247,7 +260,7 @@ pool_shrink_strings(Pool *pool) void pool_shrink_rels(Pool *pool) { - pool->rels = (Reldep *)sat_realloc(pool->rels, ((pool->nrels + REL_BLOCK) & ~REL_BLOCK) * sizeof(Reldep)); + pool->rels = sat_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK); } // reset all hash tables diff --git a/src/poolid.h b/src/poolid.h index 7ea597c..ff3b45d 100644 --- a/src/poolid.h +++ b/src/poolid.h @@ -26,6 +26,7 @@ typedef struct _Reldep { } Reldep; extern Id str2id(Pool *pool, const char *, int); +extern Id strn2id(Pool *pool, const char *, unsigned int, int); extern Id rel2id(Pool *pool, Id, Id, int, int); extern const char *id2str(Pool *pool, Id); extern const char *dep2str(Pool *pool, Id); diff --git a/src/pooltypes.h b/src/pooltypes.h index 0622a31..9681f9d 100644 --- a/src/pooltypes.h +++ b/src/pooltypes.h @@ -19,6 +19,7 @@ #define SOLV_VERSION_2 2 #define SOLV_VERSION_3 3 #define SOLV_VERSION_4 4 +#define SOLV_VERSION_5 5 #define SOLV_FLAG_PACKEDSIZES 1 #define SOLV_FLAG_VERTICAL 2 diff --git a/src/repo.c b/src/repo.c index bc8546d..954b0e0 100644 --- a/src/repo.c +++ b/src/repo.c @@ -12,15 +12,22 @@ * */ +#define _GNU_SOURCE +#include +#include + #include #include -#include + + #include "repo.h" #include "pool.h" #include "poolid_private.h" #include "util.h" +#if 0 #include "attr_store_p.h" +#endif #define IDARRAY_BLOCK 4095 @@ -74,17 +81,16 @@ repo_addid(Repo *repo, Offset olddeps, Id id) if (!idarray) /* alloc idarray if not done yet */ { - idarray = sat_malloc2(1 + IDARRAY_BLOCK, sizeof(Id)); - idarray[0] = 0; idarraysize = 1; + idarray = sat_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK); + idarray[0] = 0; repo->lastoff = 0; } if (!olddeps) /* no deps yet */ { olddeps = idarraysize; - if ((idarraysize & IDARRAY_BLOCK) == 0) - idarray = sat_realloc2(idarray, idarraysize + 1 + IDARRAY_BLOCK, sizeof(Id)); + idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); } else if (olddeps == repo->lastoff) /* extend at end */ idarraysize--; @@ -94,19 +100,14 @@ repo_addid(Repo *repo, Offset olddeps, Id id) olddeps = idarraysize; for (; idarray[i]; i++) { - if ((idarraysize & IDARRAY_BLOCK) == 0) - idarray = sat_realloc2(idarray, idarraysize + 1 + IDARRAY_BLOCK, sizeof(Id)); + idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); idarray[idarraysize++] = idarray[i]; } - if ((idarraysize & IDARRAY_BLOCK) == 0) - idarray = sat_realloc2(idarray, idarraysize + 1 + IDARRAY_BLOCK, sizeof(Id)); + idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); } idarray[idarraysize++] = id; /* insert Id into array */ - - if ((idarraysize & IDARRAY_BLOCK) == 0) /* realloc if at block boundary */ - idarray = sat_realloc2(idarray, idarraysize + 1 + IDARRAY_BLOCK, sizeof(Id)); - + idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); idarray[idarraysize++] = 0; /* ensure NULL termination */ repo->idarraydata = idarray; @@ -215,7 +216,7 @@ repo_reserve_ids(Repo *repo, Offset olddeps, int num) if (!repo->idarraysize) /* ensure buffer space */ { repo->idarraysize = 1; - repo->idarraydata = sat_malloc2((1 + num + IDARRAY_BLOCK) & ~IDARRAY_BLOCK, sizeof(Id)); + repo->idarraydata = sat_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK); repo->idarraydata[0] = 0; repo->lastoff = 1; return 1; @@ -235,10 +236,7 @@ repo_reserve_ids(Repo *repo, Offset olddeps, int num) ; count = idend - idstart - 1 + num; /* new size */ - /* realloc if crossing block boundary */ - if (((repo->idarraysize - 1) | IDARRAY_BLOCK) != ((repo->idarraysize + count - 1) | IDARRAY_BLOCK)) - repo->idarraydata = sat_realloc2(repo->idarraydata, (repo->idarraysize + count + IDARRAY_BLOCK) & ~IDARRAY_BLOCK, sizeof(Id)); - + repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK); /* move old deps to end */ olddeps = repo->lastoff = repo->idarraysize; memcpy(repo->idarraydata + olddeps, idstart, count - num); @@ -250,9 +248,8 @@ repo_reserve_ids(Repo *repo, Offset olddeps, int num) if (olddeps) /* appending */ repo->idarraysize--; - /* realloc if crossing block boundary */ - if (((repo->idarraysize - 1) | IDARRAY_BLOCK) != ((repo->idarraysize + num - 1) | IDARRAY_BLOCK)) - repo->idarraydata = sat_realloc2(repo->idarraydata, (repo->idarraysize + num + IDARRAY_BLOCK) & ~IDARRAY_BLOCK, sizeof(Id)); + /* make room*/ + repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK); /* appending or new */ repo->lastoff = olddeps ? olddeps : repo->idarraysize; @@ -457,413 +454,272 @@ repo_fix_legacy(Repo *repo, Offset provides, Offset supplements) return supplements; } -static unsigned char * -data_read_id(unsigned char *dp, Id *idp) -{ - Id x = 0; - unsigned char c; - for (;;) - { - c = *dp++; - if (!(c & 0x80)) - { - *idp = (x << 7) ^ c; - return dp; - } - x = (x << 7) ^ c ^ 128; - } -} - -static unsigned char * -data_skip(unsigned char *dp, int type) -{ - switch (type) - { - case TYPE_VOID: - return dp; - case TYPE_ID: - case TYPE_DIR: - while ((*dp & 0x80) != 0) - dp++; - return dp; - case TYPE_IDARRAY: - case TYPE_REL_IDARRAY: - case TYPE_IDVALUEARRAY: - case TYPE_DIRVALUEVALUEARRAY: - while ((*dp & 0xc0) != 0) - dp++; - return dp; - default: - fprintf(stderr, "unknown type in data_skip\n"); - exit(1); - } -} - -static unsigned char * -forward_to_key(Repodata *data, Id key, Id schema, unsigned char *dp) -{ - Id k, *keyp; - - keyp = data->schemadata + schema; - while ((k = *keyp++) != 0) - { - if (k == key) - return dp; - if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET) - { - /* skip that offset */ - dp = data_skip(dp, TYPE_ID); - continue; - } - if (data->keys[k].storage != KEY_STORAGE_INCORE) - continue; - dp = data_skip(dp, data->keys[k].type); - } - return 0; -} - -static unsigned char * -load_page_range(Repodata *data, unsigned int pstart, unsigned int pend) -{ - /* add smart paging here */ - return 0; -} - -static unsigned char * -get_data(Repodata *data, Repokey *key, unsigned char **dpp) -{ - Id off; - unsigned char *dp = *dpp; - int i, max; - unsigned int pstart, pend, poff, plen; - - if (!dp) - return 0; - if (key->storage == KEY_STORAGE_INCORE) - { - *dpp = data_skip(dp, key->type); - return dp; - } - if (key->storage != KEY_STORAGE_VERTICAL_OFFSET) - return 0; - if (!data->fp) - return 0; - dp = data_read_id(dp, &off); - *dpp = dp; - if (key->type == TYPE_VOID) - return 0; - max = key->size - off; - if (max <= 0) - return 0; - /* we now have the offset, go into vertical */ - for (i = key - data->keys - 1; i > 0; i--) - if (data->keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET) - off += data->keys[i].size; - pstart = off / BLOB_PAGESIZE; - pend = pstart; - poff = off % BLOB_PAGESIZE; - plen = BLOB_PAGESIZE - poff; - for (;;) - { - if (plen > max) - plen = max; - dp = load_page_range(data, pstart, pend) + poff; - if (!dp) - return 0; - switch (key->type) - { - case TYPE_STR: - if (memchr(dp, 0, plen)) - return dp; - break; - case TYPE_ID: - for (i = 0; i < plen; i++) - if ((dp[i] & 0x80) == 0) - return dp; - break; - case TYPE_IDARRAY: - case TYPE_REL_IDARRAY: - case TYPE_IDVALUEARRAY: - case TYPE_DIRVALUEVALUEARRAY: - for (i = 0; i < plen; i++) - if ((dp[i] & 0xc0) == 0) - return dp; - break; - } - if (plen == max) - return 0; - pend++; - plen += BLOB_PAGESIZE; - } -} - - -const char * -repodata_lookup_str(Repodata *data, Id entry, Id key) -{ - Id schema; - Id id, k, *kp, *keyp; - unsigned char *dp; - - if (data->entryschemau8) - schema = data->entryschemau8[entry]; - else - schema = data->entryschema[entry]; - keyp = data->schemadata + schema; - /* make sure the schema of this solvable contains the key */ - for (kp = keyp; (k = *kp++) != 0; ) - if (k == key) - break; - if (k == 0) - return 0; - dp = forward_to_key(data, key, schema, data->incoredata + data->incoreoffset[entry]); - dp = get_data(data, data->keys + key, &dp); - if (!dp) - return 0; - if (data->keys[key].type == TYPE_STR) - return (const char *)dp; - /* id type, must either use global or local string strore*/ - dp = data_read_id(dp, &id); -#if 0 - /* not yet working */ - return data->ss.stringspace + data->ss.strings[id]; -#else - return id2str(data->repo->pool, id); -#endif -} - -#define SEARCH_NEXT_KEY 1 -#define SEARCH_NEXT_SOLVABLE 2 -#define SEACH_STOP 3 - struct matchdata { Pool *pool; - const char *matchstr; + const char *match; int flags; #if 0 regex_t regex; #endif int stop; - int (*callback)(void *data, Solvable *s, Id key, const char *str); + int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv); void *callback_data; }; -static void -domatch(Id p, Id key, struct matchdata *md, const char *str) +int +repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) { - /* fill match code here */ - md->stop = md->callback(md->callback_data, md->pool->solvables + p, key, str); -} + struct matchdata *md = cbdata; + int flags = md->flags; -static void -repodata_search(Repodata *data, Id entry, Id key, struct matchdata *md) -{ - Id schema; - Id id, k, *kp, *keyp; - unsigned char *dp, *ddp; - int onekey = 0; - - if (data->entryschemau8) - schema = data->entryschemau8[entry]; - else - schema = data->entryschema[entry]; - keyp = data->schemadata + schema; - dp = data->incoredata + data->incoreoffset[entry]; - if (key) + if ((flags & SEARCH_STRINGMASK) != 0) { - /* search in a specific key */ - for (kp = keyp; (k = *kp++) != 0; ) - if (k == key) + switch (key->type) + { + case TYPE_ID: + case TYPE_IDARRAY: + if (data->localpool) + kv->str = stringpool_id2str(&data->spool, kv->id); + else + kv->str = id2str(data->repo->pool, kv->id); break; - if (k == 0) - return; - dp = forward_to_key(data, key, schema, dp); - if (!dp) - return; - keyp = kp - 1; - onekey = 1; - } - md->stop = 0; - while ((key = *keyp++) != 0) - { - ddp = get_data(data, data->keys + key, &dp); - while (ddp) + case TYPE_STR: + break; + default: + return 0; + } + switch ((flags & SEARCH_STRINGMASK)) { - switch (data->keys[key].type) - { - case TYPE_STR: - domatch(data->start + entry, data->keys[key].name, md, (const char *)ddp); - ddp = 0; - break; - case TYPE_ID: - data_read_id(ddp, &id); - /* domatch */ - ddp = 0; - break; - case TYPE_IDARRAY: - ddp = data_read_id(ddp, &id); - if ((id & 0x40) == 0) - ddp = 0; - id = (id & 0x3f) | ((id >> 1) & ~0x3f); - /* domatch */ - while (md->stop == SEARCH_NEXT_KEY && ddp) - ddp = data_read_id(ddp, &id); - break; - default: - ddp = 0; - } + case SEARCH_SUBSTRING: + if (flags & SEARCH_NOCASE) + { + if (!strcasestr(kv->str, md->match)) + return 0; + } + else + { + if (!strstr(kv->str, md->match)) + return 0; + } + break; + case SEARCH_STRING: + if (flags & SEARCH_NOCASE) + { + if (strcasecmp(md->match, kv->str)) + return 0; + } + else + { + if (strcmp(md->match, kv->str)) + return 0; + } + break; + case SEARCH_GLOB: + if (fnmatch(md->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0)) + return 0; + break; +#if 0 + case SEARCH_REGEX: + if (regexec(&md->regexp, kv->str, 0, NULL, 0)) + return 0; +#endif + default: + return 0; } - if (onekey || md->stop > SEARCH_NEXT_KEY) - return; } + md->stop = md->callback(md->callback_data, s, data, key, kv); + return md->stop; } + +static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = { + { SOLVABLE_NAME, TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_ARCH, TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_EVR, TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_VENDOR, TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_PROVIDES, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_OBSOLETES, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_CONFLICTS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_REQUIRES, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_RECOMMENDS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_SUGGESTS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_SUPPLEMENTS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_ENHANCES, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { SOLVABLE_FRESHENS, TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, + { RPM_RPMDBID, TYPE_U32, 0, KEY_STORAGE_SOLVABLE }, +}; + static void -domatch_idarray(Id p, Id key, struct matchdata *md, Id *ida) +domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida) { + KeyValue kv; for (; *ida && !md->stop; ida++) - domatch(p, key, md, id2str(md->pool, *ida)); + { + kv.id = *ida; + kv.eof = ida[1] ? 0 : 1; + repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv); + } } static void -repo_search_md(Repo *repo, Id p, Id key, struct matchdata *md) +repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md) { + KeyValue kv; Pool *pool = repo->pool; Repodata *data; Solvable *s; - int i; + int i, j, flags; md->stop = 0; if (!p) { -#if 0 - switch(key) - { - case 0: - case SOLVABLE_NAME: - case SOLVABLE_ARCH: - case SOLVABLE_EVR: - case SOLVABLE_VENDOR: - case SOLVABLE_PROVIDES: - case SOLVABLE_OBSOLETES: - case SOLVABLE_CONFLICTS: - case SOLVABLE_REQUIRES: - case SOLVABLE_RECOMMENDS: - case SOLVABLE_SUPPLEMENTS: - case SOLVABLE_SUGGESTS: - case SOLVABLE_ENHANCES: - case SOLVABLE_FRESHENS: - break; - default: - for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) - repodata_search(data, -1, key, md); - return; - } -#endif for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++) { if (s->repo == repo) - repo_search_md(repo, p, key, md); + repo_search_md(repo, p, keyname, md); if (md->stop > SEARCH_NEXT_SOLVABLE) break; } return; } s = pool->solvables + p; - switch(key) + flags = md->flags; + if (!(flags & SEARCH_NO_STORAGE_SOLVABLE)) { - case 0: - case SOLVABLE_NAME: - if (s->name) - domatch(p, SOLVABLE_NAME, md, id2str(pool, s->name)); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_ARCH: - if (s->arch) - domatch(p, SOLVABLE_ARCH, md, id2str(pool, s->arch)); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_EVR: - if (s->evr) - domatch(p, SOLVABLE_EVR, md, id2str(pool, s->evr)); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_VENDOR: - if (s->vendor) - domatch(p, SOLVABLE_VENDOR, md, id2str(pool, s->vendor)); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_PROVIDES: - if (s->provides) - domatch_idarray(p, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_OBSOLETES: - if (s->obsoletes) - domatch_idarray(p, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_CONFLICTS: - if (s->obsoletes) - domatch_idarray(p, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_REQUIRES: - if (s->requires) - domatch_idarray(p, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_RECOMMENDS: - if (s->recommends) - domatch_idarray(p, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_SUPPLEMENTS: - if (s->supplements) - domatch_idarray(p, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_SUGGESTS: - if (s->suggests) - domatch_idarray(p, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_ENHANCES: - if (s->enhances) - domatch_idarray(p, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - case SOLVABLE_FRESHENS: - if (s->freshens) - domatch_idarray(p, SOLVABLE_FRESHENS, md, repo->idarraydata + s->freshens); - if (key || md->stop > SEARCH_NEXT_KEY) - return; - default: - break; + switch(keyname) + { + case 0: + case SOLVABLE_NAME: + if (s->name) + { + kv.id = s->name; + repo_matchvalue(md, s, 0, solvablekeys + 0, &kv); + } + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_ARCH: + if (s->arch) + { + kv.id = s->arch; + repo_matchvalue(md, s, 0, solvablekeys + 1, &kv); + } + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_EVR: + if (s->evr) + { + kv.id = s->evr; + repo_matchvalue(md, s, 0, solvablekeys + 2, &kv); + } + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_VENDOR: + if (s->vendor) + { + kv.id = s->vendor; + repo_matchvalue(md, s, 0, solvablekeys + 3, &kv); + } + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_PROVIDES: + if (s->provides) + domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_OBSOLETES: + if (s->obsoletes) + domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_CONFLICTS: + if (s->conflicts) + domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_REQUIRES: + if (s->requires) + domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_RECOMMENDS: + if (s->recommends) + domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_SUPPLEMENTS: + if (s->supplements) + domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_SUGGESTS: + if (s->suggests) + domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_ENHANCES: + if (s->enhances) + domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case SOLVABLE_FRESHENS: + if (s->freshens) + domatch_idarray(s, SOLVABLE_FRESHENS, md, repo->idarraydata + s->freshens); + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + case RPM_RPMDBID: + if (repo->rpmdbid) + { + kv.num = repo->rpmdbid[p - repo->start]; + repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv); + } + if (keyname || md->stop > SEARCH_NEXT_KEY) + return; + break; + default: + break; + } } for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) { if (p < data->start || p >= data->end) continue; - repodata_search(data, p - data->start, key, md); + if (data->state == REPODATA_STUB) + { + if (keyname) + { + for (j = 1; j < data->nkeys; j++) + if (keyname == data->keys[j].name) + break; + if (j == data->nkeys) + continue; + } + /* load it */ + if (data->loadcallback) + data->loadcallback(data); + else + data->state = REPODATA_ERROR; + } + if (data->state == REPODATA_ERROR) + continue; + repodata_search(data, p - data->start, keyname, repo_matchvalue, md); if (md->stop > SEARCH_NEXT_KEY) break; } } void -repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *data, Solvable *s, Id key, const char *str), void *callback_data) +repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) { struct matchdata md; memset(&md, 0, sizeof(md)); md.pool = repo->pool; - md.matchstr = match; + md.match = match; md.flags = flags; md.callback = callback; - md.callback_data = callback_data; + md.callback_data = cbdata; repo_search_md(repo, p, key, &md); } @@ -900,7 +756,91 @@ repo_lookup_str(Solvable *s, Id key) return 0; } +Repodata * +repo_add_repodata(Repo *repo) +{ + Repodata *data; + repo->nrepodata++; + repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data)); + data = repo->repodata + repo->nrepodata - 1; + memset(data, 0, sizeof (*data)); + data->repo = repo; + data->start = repo->start; + data->end = repo->end; + data->localpool = 0; + data->keys = sat_calloc(1, sizeof(Repokey)); + data->nkeys = 1; + data->schemata = sat_calloc(1, sizeof(Id)); + data->schemadata = sat_calloc(1, sizeof(Id)); + data->nschemata = 1; + data->schemadatalen = 1; + data->entryschemau8 = sat_calloc(data->end - data->start, 1); + data->incoreoffset = sat_calloc(data->end - data->start, sizeof(Id)); + return data; +} + +static Repodata *findrepodata(Repo *repo, Id p, Id keyname) +{ + int i; + Repodata *data; + + /* FIXME: enter nice code here */ + for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) + if (p >= data->start && p < data->end) + return data; + for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) + if (p == data->end) + break; + if (i < repo->nrepodata) + { + repodata_extend(data, p); + return data; + } + return repo_add_repodata(repo); +} + +void +repo_set_id(Repo *repo, Id p, Id keyname, Id id) +{ + Repodata *data = findrepodata(repo, p, keyname); + repodata_set_id(data, p - data->start, keyname, id); +} + +void +repo_set_num(Repo *repo, Id p, Id keyname, Id num) +{ + Repodata *data = findrepodata(repo, p, keyname); + repodata_set_num(data, p - data->start, keyname, num); +} + +void +repo_set_str(Repo *repo, Id p, Id keyname, const char *str) +{ + Repodata *data = findrepodata(repo, p, keyname); + repodata_set_str(data, p - data->start, keyname, str); +} + +void +repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str) +{ + Repodata *data = findrepodata(repo, p, keyname); + repodata_set_poolstr(data, p - data->start, keyname, str); +} + +void +repo_internalize(Repo *repo) +{ + int i; + Repodata *data; + + for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) + if (data->attrs) + repodata_internalize(data); +} + + +#if 0 static int key_cmp (const void *pa, const void *pb) @@ -948,5 +888,6 @@ repo_add_attrstore (Repo *repo, Attrstore *s, const char *location) if (location) data->location = strdup(location); } +#endif // EOF diff --git a/src/repo.h b/src/repo.h index 980eb0d..34b100e 100644 --- a/src/repo.h +++ b/src/repo.h @@ -15,7 +15,10 @@ #include "pooltypes.h" #include "pool.h" +#if 0 #include "attr_store.h" +#endif +#include "repodata.h" typedef struct _Repokey { Id name; @@ -29,57 +32,6 @@ typedef struct _Repokey { #define KEY_STORAGE_INCORE 2 #define KEY_STORAGE_VERTICAL_OFFSET 3 -struct _Repo; - -typedef struct _Repodata { - struct _Repo *repo; /* back pointer to repo */ - - int start; /* start of solvables this repodata is valid for */ - int end; /* last solvable + 1 of this repodata */ - - FILE *fp; /* file pointer of solv file */ - int error; /* corrupt solv file */ - - /* Keys provided by this attribute store, sorted by name value. - The same keys may be provided by multiple attribute stores, but - then only for different solvables. I.e. the relation - (solvable,name) -> store - has to be injective. */ - - Repokey *keys; /* keys, first entry is always zero */ - unsigned int nkeys; /* length of keys array */ - - Id *schemata; /* schema -> offset into schemadata */ - unsigned int nschemata; /* number of schemata */ - - Id *schemadata; /* schema storage */ - - unsigned char *entryschemau8; /* schema for entry */ - Id *entryschema; /* schema for entry */ - - unsigned char *incoredata; /* in-core data (flat_attrs) */ - unsigned int incoredatalen; /* data len (attr_next_free) */ - unsigned int incoredatafree; /* free data len */ - - Id *incoreoffset; /* offset for all entries (ent2attr) */ - - Id verticaloffset; /* file offset of verticals */ - - Id *dirs; /* directory list */ - int ndirs; /* its size */ - - /* The attribute store itself. */ - Attrstore *s; - /* A filename where to find this attribute store, or where to store - it. May be "", in which case we can't load it on demand or store - into it. It may also be NULL for at most one of the repodata per - repo, in which case these are the embedded attributes. */ - - const char *location; - /* The SHA1 checksum of the file. */ - unsigned char checksum[20]; -} Repodata; - typedef struct _Repo { const char *name; @@ -95,12 +47,10 @@ typedef struct _Repo { int idarraysize; Offset lastoff; - Id *rpmdbid; + Id *rpmdbid; /* hmm, go to repodata? */ - /* The attribute stores we know about. */ - Repodata *repodata; - /* Number of attribute stores.. */ - unsigned nrepodata; + Repodata *repodata; /* our stores for non-solvable related data */ + unsigned nrepodata; /* number of our stores.. */ } Repo; extern Repo *repo_create(Pool *pool, const char *name); @@ -112,7 +62,9 @@ extern Offset repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker); extern Offset repo_reserve_ids(Repo *repo, Offset olddeps, int num); extern Offset repo_fix_legacy(Repo *repo, Offset provides, Offset supplements); +#if 0 extern void repo_add_attrstore (Repo *repo, Attrstore *s, const char *location); +#endif static inline const char *repo_name(const Repo *repo) { @@ -183,4 +135,38 @@ static inline void repo_free_solvable_block(Repo *repo, Id start, int count, int for (p = (r)->start, s = (r)->pool->solvables + p; p < (r)->end; p++, s++) \ if (s->repo == (r)) + +/* search callback values */ + +#define SEARCH_NEXT_KEY 1 +#define SEARCH_NEXT_SOLVABLE 2 +#define SEACH_STOP 3 + +typedef struct _KeyValue { + Id id; + const char *str; + int num; + int num2; + int eof; +} KeyValue; + +/* search flags */ +#define SEARCH_STRINGMASK 15 +#define SEARCH_STRING 1 +#define SEARCH_SUBSTRING 2 +#define SEARCH_GLOB 3 +#define SEARCH_REGEX 4 + +#define SEARCH_NOCASE (1<<8) +#define SEARCH_NO_STORAGE_SOLVABLE (1<<9) + +Repodata *repo_add_repodata(Repo *repo); +void repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata); + +void repo_set_id(Repo *repo, Id p, Id keyname, Id id); +void repo_set_num(Repo *repo, Id p, Id keyname, Id num); +void repo_set_str(Repo *repo, Id p, Id keyname, const char *str); +void repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str); +void repo_internalize(Repo *repo); + #endif /* SATSOLVER_REPO_H */ diff --git a/src/repo_solv.c b/src/repo_solv.c index a341d34..c1852c5 100644 --- a/src/repo_solv.c +++ b/src/repo_solv.c @@ -25,7 +25,9 @@ #include "repo_solv.h" #include "util.h" +#if 0 #include "attr_store_p.h" +#endif #define INTERESTED_START SOLVABLE_NAME #define INTERESTED_END SOLVABLE_FRESHENS @@ -253,29 +255,50 @@ skip_item (Repodata *data, unsigned type, unsigned numid, unsigned numrel) switch (type) { case TYPE_VOID: + case TYPE_CONSTANT: break; case TYPE_ID: read_id(data, numid + numrel); /* just check Id */ break; case TYPE_DIR: - read_id(data, numid + data->ndirs); /* just check Id */ + read_id(data, numid + data->dirpool.ndirs); /* just check Id */ + break; + case TYPE_NUM: + read_id(data, 0); break; case TYPE_U32: read_u32(data); break; case TYPE_ATTR_STRING: case TYPE_STR: - while(read_u8(data) != 0) + while (read_u8(data) != 0) ; break; case TYPE_IDARRAY: - case TYPE_IDVALUEARRAY: - case TYPE_DIRVALUEVALUEARRAY: case TYPE_REL_IDARRAY: case TYPE_ATTR_INTLIST: while ((read_u8(data) & 0xc0) != 0) ; break; + case TYPE_DIRNUMNUMARRAY: + for (;;) + { + read_id(data, numid + data->dirpool.ndirs); /* just check Id */ + read_id(data, 0); + if (!(read_id(data, 0) & 0x40)) + break; + } + break; + case TYPE_DIRSTRARRAY: + for (;;) + { + Id id = read_id(data, 0); + while (read_u8(data) != 0) + ; + if (!(id & 0x40)) + break; + } + break; case TYPE_COUNT_NAMED: { unsigned count = read_id(data, 0); @@ -320,6 +343,8 @@ key_cmp (const void *pa, const void *pb) return a->name - b->name; } +static void repodata_load_solv(Repodata *data); + static void parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned numid, unsigned numrel, Repo *repo) { @@ -330,8 +355,10 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata + 1, sizeof (*data)); data = repo->repodata + repo->nrepodata++; - data->repo = repo; memset(data, 0, sizeof(*data)); + data->repo = repo; + data->state = REPODATA_STUB; + data->loadcallback = repodata_load_solv; while ((key = *keyp++) != 0) { @@ -349,6 +376,7 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned n = ide - ida - 1; if (n & 1) { + pool_debug (mypool, SAT_ERROR, "invalid attribute data\n"); data->error = SOLV_ERROR_CORRUPT; return; } @@ -359,8 +387,8 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned { if (*ide >= numid) { - data->error = SOLV_ERROR_CORRUPT; pool_debug (mypool, SAT_ERROR, "invalid attribute data\n"); + data->error = SOLV_ERROR_CORRUPT; return; } data->keys[i].name = idmap ? idmap[*ide++] : *ide++; @@ -381,7 +409,9 @@ parse_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned unsigned len = sizeof (buf); char *filename = buf; read_str(maindata, &filename, &len); +#if 0 data->location = strdup(filename); +#endif if (filename != buf) free(filename); } @@ -469,15 +499,18 @@ incore_add_u8(Repodata *data, unsigned int x) data->incoredatalen++; } + + // ---------------------------------------------- + /* * read repo from .solv file * and add it to pool */ -int -repo_add_solv(Repo *repo, FILE *fp) +static int +repo_add_solv_parent(Repo *repo, FILE *fp, Repodata *parent) { Pool *pool = repo->pool; int i, l; @@ -508,6 +541,9 @@ repo_add_solv(Repo *repo, FILE *fp) Repokey *keys; Id *schemadata, *schemadatap, *schemadataend; Id *schemata, key; + int have_xdata; + + struct _Stringpool *spool; Repodata data; @@ -529,6 +565,7 @@ repo_add_solv(Repo *repo, FILE *fp) case SOLV_VERSION_2: case SOLV_VERSION_3: case SOLV_VERSION_4: + case SOLV_VERSION_5: break; default: pool_debug(pool, SAT_ERROR, "unsupported SOLV version\n"); @@ -549,6 +586,9 @@ repo_add_solv(Repo *repo, FILE *fp) numinfo = read_u32(&data); solvflags = read_u32(&data); + if (solvversion < SOLV_VERSION_5) + numschemata++; + if (numdir && numdir < 2) { pool_debug(pool, SAT_ERROR, "bad number of dirs\n"); @@ -560,6 +600,25 @@ repo_add_solv(Repo *repo, FILE *fp) return SOLV_ERROR_UNSUPPORTED; } + if (parent) + { + if (numrel) + { + pool_debug(pool, SAT_ERROR, "relations are forbidden in a store\n"); + return SOLV_ERROR_CORRUPT; + } + if (numsolv) + { + pool_debug(pool, SAT_ERROR, "solvables are forbidden in a store\n"); + return SOLV_ERROR_CORRUPT; + } + if (numinfo) + { + pool_debug(pool, SAT_ERROR, "info blocks are forbidden in a store\n"); + return SOLV_ERROR_CORRUPT; + } + } + /******* Part 1: string IDs *****************************************/ sizeid = read_u32(&data); /* size of string+Id space */ @@ -574,16 +633,27 @@ repo_add_solv(Repo *repo, FILE *fp) * alloc buffers */ + if (!parent) + spool = &pool->ss; + else + { + spool = &data.spool; + spool->stringspace = sat_malloc(7); + strcpy(spool->stringspace, ""); + spool->sstrings = 7; + spool->nstrings = 0; + } + /* alloc string buffer */ - pool->ss.stringspace = sat_realloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1); + spool->stringspace = sat_realloc(spool->stringspace, spool->sstrings + sizeid + 1); /* alloc string offsets (Id -> Offset into string space) */ - pool->ss.strings = sat_realloc2(pool->ss.strings, pool->ss.nstrings + numid, sizeof(Offset)); + spool->strings = sat_realloc2(spool->strings, spool->nstrings + numid, sizeof(Offset)); - strsp = pool->ss.stringspace; - str = pool->ss.strings; /* array of offsets into strsp, indexed by Id */ + strsp = spool->stringspace; + str = spool->strings; /* array of offsets into strsp, indexed by Id */ /* point to _BEHIND_ already allocated string/Id space */ - strsp += pool->ss.sstrings; + strsp += spool->sstrings; /* @@ -603,7 +673,7 @@ repo_add_solv(Repo *repo, FILE *fp) unsigned int pfsize = read_u32(&data); char *prefix = sat_malloc(pfsize); char *pp = prefix; - char *old_str = ""; + char *old_str = 0; char *dest = strsp; if (fread(prefix, pfsize, 1, fp) != 1) { @@ -627,87 +697,113 @@ repo_add_solv(Repo *repo, FILE *fp) strsp[sizeid] = 0; /* make string space \0 terminated */ sp = strsp; + /* make sure first entry is "" for a store */ + if (parent) + { + /* no shared pool, thus no idmap and no unification */ + idmap = 0; + sp += 7; + if (*sp) + { + pool_debug(pool, SAT_ERROR, "store strings don't start with ''\n"); + return SOLV_ERROR_CORRUPT; + } + str[0] = 0; + for (i = 1; i < spool->nstrings; i++) + { + if (sp >= strsp + sizeid) + { + pool_debug(pool, SAT_ERROR, "not enough strings\n"); + return SOLV_ERROR_OVERFLOW; + } + str[i] = sp - strsp; + sp += strlen(sp) + 1; + } + } + else + { - /* alloc id map for name and rel Ids. this maps ids in the solv files - * to the ids in our pool */ - idmap = sat_calloc(numid + numrel, sizeof(Id)); + /* alloc id map for name and rel Ids. this maps ids in the solv files + * to the ids in our pool */ + idmap = sat_calloc(numid + numrel, sizeof(Id)); - /* - * build hashes for all read strings - * - */ - - hashmask = mkmask(pool->ss.nstrings + numid); + /* + * build hashes for all read strings + * + */ + + hashmask = mkmask(spool->nstrings + numid); #if 0 - POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid); - POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1); + POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid); + POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1); #endif - /* - * create hashtable with strings already in pool - */ - - hashtbl = sat_calloc(hashmask + 1, sizeof(Id)); - for (i = 1; i < pool->ss.nstrings; i++) /* leave out our dummy zero id */ - { - h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask; - hh = HASHCHAIN_START; - while (hashtbl[h]) - h = HASHCHAIN_NEXT(h, hh, hashmask); - hashtbl[h] = i; - } + /* + * create hashtable with strings already in pool + */ - /* - * run over string space, calculate offsets - * - * build id map (maps solv Id -> pool Id) - */ - - for (i = 1; i < numid; i++) - { - if (sp >= strsp + sizeid) - { - sat_free(hashtbl); - sat_free(idmap); - pool_debug(pool, SAT_ERROR, "not enough strings\n"); - return SOLV_ERROR_OVERFLOW; - } - if (!*sp) /* empty string */ + hashtbl = sat_calloc(hashmask + 1, sizeof(Id)); + for (i = 1; i < spool->nstrings; i++) /* leave out our dummy zero id */ { - idmap[i] = ID_EMPTY; - sp++; - continue; + h = strhash(spool->stringspace + spool->strings[i]) & hashmask; + hh = HASHCHAIN_START; + while (hashtbl[h]) + h = HASHCHAIN_NEXT(h, hh, hashmask); + hashtbl[h] = i; } - /* find hash slot */ - h = strhash(sp) & hashmask; - hh = HASHCHAIN_START; - for (;;) + /* + * run over string space, calculate offsets + * + * build id map (maps solv Id -> pool Id) + */ + + for (i = 1; i < numid; i++) { - id = hashtbl[h]; - if (id == 0) - break; - if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp)) - break; /* existing string */ - h = HASHCHAIN_NEXT(h, hh, hashmask); - } + if (sp >= strsp + sizeid) + { + sat_free(hashtbl); + sat_free(idmap); + pool_debug(pool, SAT_ERROR, "not enough strings\n"); + return SOLV_ERROR_OVERFLOW; + } + if (!*sp) /* empty string */ + { + idmap[i] = ID_EMPTY; + sp++; + continue; + } - /* length == offset to next string */ - l = strlen(sp) + 1; - if (id == ID_NULL) /* end of hash chain -> new string */ - { - id = pool->ss.nstrings++; - hashtbl[h] = id; - str[id] = pool->ss.sstrings; /* save Offset */ - if (sp != pool->ss.stringspace + pool->ss.sstrings) /* not at end-of-buffer */ - memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l); /* append to pool buffer */ - pool->ss.sstrings += l; + /* find hash slot */ + h = strhash(sp) & hashmask; + hh = HASHCHAIN_START; + for (;;) + { + id = hashtbl[h]; + if (id == 0) + break; + if (!strcmp(spool->stringspace + spool->strings[id], sp)) + break; /* existing string */ + h = HASHCHAIN_NEXT(h, hh, hashmask); + } + + /* length == offset to next string */ + l = strlen(sp) + 1; + if (id == ID_NULL) /* end of hash chain -> new string */ + { + id = spool->nstrings++; + hashtbl[h] = id; + str[id] = spool->sstrings; /* save Offset */ + if (sp != spool->stringspace + spool->sstrings) /* not at end-of-buffer */ + memmove(spool->stringspace + spool->sstrings, sp, l); /* append to pool buffer */ + spool->sstrings += l; + } + idmap[i] = id; /* repo relative -> pool relative */ + sp += l; /* next string */ } - idmap[i] = id; /* repo relative -> pool relative */ - sp += l; /* next string */ + sat_free(hashtbl); } - sat_free(hashtbl); pool_shrink_strings(pool); /* vacuum */ @@ -783,18 +879,19 @@ repo_add_solv(Repo *repo, FILE *fp) /******* Part 3: Dirs ***********************************************/ if (numdir) { - data.dirs = sat_calloc(numdir, sizeof(Id)); - data.ndirs = numdir; - /* dir 0: no directory - * dir 1: / - */ + data.dirpool.dirs = sat_malloc2(numdir, sizeof(Id)); + data.dirpool.ndirs = numdir; + data.dirpool.dirs[0] = 0; /* dir 0: virtual root */ + data.dirpool.dirs[1] = 1; /* dir 1: / */ for (i = 2; i < numdir; i++) { id = read_id(&data, i + numid); - if (i > numid) - data.dirs[i] = -(id - numid); + if (id >= numid) + data.dirpool.dirs[i] = -(id - numid); + else if (idmap) + data.dirpool.dirs[i] = idmap[id]; else - data.dirs[i] = idmap[id]; + data.dirpool.dirs[i] = id; } } @@ -810,9 +907,26 @@ repo_add_solv(Repo *repo, FILE *fp) keys[i].name = id; keys[i].type = read_id(&data, 0); keys[i].size = read_id(&data, 0); + if (solvversion >= SOLV_VERSION_5) + { + keys[i].storage = read_id(&data, 0); + continue; + } keys[i].storage = KEY_STORAGE_DROPPED; + if (parent) + { + keys[i].storage = KEY_STORAGE_INCORE; + continue; + } switch (keys[i].type) { + case TYPE_VOID: + case TYPE_CONSTANT: + case TYPE_STR: + case TYPE_NUM: + case TYPE_DIRNUMNUMARRAY: + keys[i].storage = KEY_STORAGE_INCORE; + break; case TYPE_ID: switch(id) { @@ -834,9 +948,6 @@ repo_add_solv(Repo *repo, FILE *fp) else keys[i].storage = KEY_STORAGE_INCORE; break; - case TYPE_STR: - keys[i].storage = KEY_STORAGE_INCORE; - break; case TYPE_U32: if (id == RPM_RPMDBID) keys[i].storage = KEY_STORAGE_SOLVABLE; @@ -848,17 +959,22 @@ repo_add_solv(Repo *repo, FILE *fp) } } + have_xdata = parent ? 1 : 0; + for (i = 1; i < numkeys; i++) + if (keys[i].storage == KEY_STORAGE_INCORE || keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET) + have_xdata = 1; + data.keys = keys; data.nkeys = numkeys; /******* Part 5: Schemata ********************************************/ id = read_id(&data, 0); - schemadata = sat_calloc(id, sizeof(Id)); - schemadatap = schemadata; - schemadataend = schemadata + id; + schemadata = sat_calloc(id + 1, sizeof(Id)); + schemadatap = schemadata + 1; + schemadataend = schemadatap + id; schemata = sat_calloc(numschemata, sizeof(Id)); - for (i = 0; i < numschemata; i++) + for (i = 1; i < numschemata; i++) { schemata[i] = schemadatap - schemadata; schemadatap = read_idarray(&data, numid, 0, schemadatap, schemadataend, 0); @@ -866,6 +982,8 @@ repo_add_solv(Repo *repo, FILE *fp) data.schemata = schemata; data.nschemata = numschemata; data.schemadata = schemadata; + data.schemadatalen = schemadataend - data.schemadata; + /******* Part 6: Info ***********************************************/ for (i = 0; i < numinfo; i++) @@ -873,7 +991,11 @@ repo_add_solv(Repo *repo, FILE *fp) /* for now we're just interested in data that starts with * the repodata_external id */ - Id *keyp = schemadata + schemata[read_id(&data, numschemata)]; + Id *keyp; + id = read_id(&data, numschemata); + if (solvversion < SOLV_VERSION_5) + id++; + keyp = schemadata + schemata[id]; key = *keyp; if (keys[key].name == REPODATA_EXTERNAL && keys[key].type == TYPE_VOID) { @@ -884,6 +1006,7 @@ repo_add_solv(Repo *repo, FILE *fp) skip_schema(&data, keyp, keys, numid, numrel); } + /******* Part 7: packed sizes (optional) ****************************/ char *exists = 0; if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0) @@ -893,6 +1016,7 @@ repo_add_solv(Repo *repo, FILE *fp) exists[i] = read_id(&data, 0) != 0; } + /******* Part 8: item data *******************************************/ /* calculate idarray size */ @@ -921,24 +1045,63 @@ repo_add_solv(Repo *repo, FILE *fp) } /* read solvables */ - s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv)); - - /* store start and end of our id block */ - data.start = s - pool->solvables; - data.end = data.start + numsolv; + if (numsolv) + { + s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv)); + /* store start and end of our id block */ + data.start = s - pool->solvables; + data.end = data.start + numsolv; + } + else + s = 0; + if (have_xdata) + { + if (numschemata < 255) + data.entryschemau8 = sat_calloc(numsolv, 1); + else + data.entryschema = sat_calloc(numsolv, sizeof(Id)); + data.incoreoffset = sat_calloc(numsolv, sizeof(Id)); + } for (i = 0; i < numsolv; i++, s++) { + Id *keyp; if (data.error) break; if (exists && !exists[i]) continue; - Id *keyp = schemadata + schemata[read_id(&data, numschemata)]; + id = read_id(&data, numschemata); + if (solvversion < SOLV_VERSION_5) + id++; + if (have_xdata) + { + if (data.entryschemau8) + data.entryschemau8[i] = id; + else + data.entryschema[i] = id; + data.incoreoffset[i] = data.incoredatalen; + } + keyp = schemadata + schemata[id]; while ((key = *keyp++) != 0) { id = keys[key].name; +#if 0 +fprintf(stderr, "solv %d name %d type %d class %d\n", i, id, keys[key].type, keys[key].storage); +#endif + if (keys[key].storage == KEY_STORAGE_VERTICAL_OFFSET) + { + /* copy offset/length into incore */ + did = read_id(&data, 0); + incore_add_id(&data, did); + did = read_id(&data, 0); + incore_add_id(&data, did); + continue; + } switch (keys[key].type) { + case TYPE_VOID: + case TYPE_CONSTANT: + break; case TYPE_ID: did = read_id(&data, numid + numrel); if (idmap) @@ -957,6 +1120,14 @@ repo_add_solv(Repo *repo, FILE *fp) POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did)); #endif break; + case TYPE_NUM: + did = read_id(&data, 0); + if (keys[key].storage == KEY_STORAGE_INCORE) + incore_add_id(&data, did); +#if 0 + POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %d\n", id2str(pool, id), did); +#endif + break; case TYPE_U32: h = read_u32(&data); #if 0 @@ -1073,6 +1244,27 @@ repo_add_solv(Repo *repo, FILE *fp) add_attr_from_file (embedded_store, i, id, keys[key].type, idmap, numid, &data, keys[key].size); break; #endif + case TYPE_DIRNUMNUMARRAY: + for (;;) + { + Id num, num2; + did = read_id(&data, numdir); + num = read_id(&data, 0); + num2 = read_id(&data, 0); + if (keys[key].storage == KEY_STORAGE_INCORE) + { +#if 0 + POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %d %d %d\n", id2str(pool, id), did, num, num2); +#endif + incore_add_id(&data, did); + incore_add_id(&data, num); + incore_add_id(&data, num2); + } + if (!(num2 & 0x40)) + break; + } + break; + default: skip_item(&data, keys[key].type, numid, numrel); } @@ -1102,8 +1294,20 @@ repo_add_solv(Repo *repo, FILE *fp) break; if (i < numkeys && !data.error) { + Id fileoffset = 0; + unsigned int pagesize; + /* we have vertical data, make it available */ - data.verticaloffset = ftell(fp); + data.verticaloffset = sat_calloc(numkeys, sizeof(Id)); + for (i = 1; i < numkeys; i++) + if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET) + { + data.verticaloffset[i] = fileoffset; + fileoffset += keys[i].size; + } + data.lastverticaloffset = fileoffset; + pagesize = read_u32(&data); + repodata_read_or_setup_pages(&data, pagesize, fileoffset); } else { @@ -1111,7 +1315,15 @@ repo_add_solv(Repo *repo, FILE *fp) data.fp = 0; } - if (data.incoredatalen || data.fp) + if (parent) + { + /* we're a store */ + sat_free(parent->schemata); + sat_free(parent->schemadata); + sat_free(parent->keys); + *parent = data; + } + else if (data.incoredatalen || data.fp) { /* we got some data, make it available */ repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata + 1, sizeof(data)); @@ -1120,7 +1332,10 @@ repo_add_solv(Repo *repo, FILE *fp) else { /* discard data */ - sat_free(data.dirs); + sat_free(data.dirpool.dirs); + sat_free(data.entryschemau8); + sat_free(data.entryschema); + sat_free(data.incoreoffset); sat_free(schemata); sat_free(schemadata); sat_free(keys); @@ -1142,4 +1357,38 @@ repo_add_solv(Repo *repo, FILE *fp) return data.error; } +int +repo_add_solv(Repo *repo, FILE *fp) +{ + return repo_add_solv_parent(repo, fp, 0); +} + +static void +repodata_load_solv(Repodata *data) +{ + FILE *fp; +#if 0 + Pool *pool = data->repo->pool; + if (!pool->loadcallback) + { + data->state = REPODATA_ERROR; + return; + } + fp = pool->loadcallback(pool->loadcallback_data, pool, data); +#else + fp = 0; +#endif + + if (!fp) + { + data->state = REPODATA_ERROR; + return; + } + if (repo_add_solv_parent(data->repo, fp, data)) + data->state = REPODATA_ERROR; + else + data->state = REPODATA_AVAILABLE; +} + + // EOF diff --git a/src/repodata.c b/src/repodata.c new file mode 100644 index 0000000..8d99429 --- /dev/null +++ b/src/repodata.c @@ -0,0 +1,1157 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * repodata.c + * + * Manage data coming from one repository + * + */ + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include + +#include "repo.h" +#include "pool.h" +#include "poolid_private.h" +#include "util.h" + +#include "fastlz.c" + +unsigned char * +data_read_id(unsigned char *dp, Id *idp) +{ + Id x = 0; + unsigned char c; + for (;;) + { + c = *dp++; + if (!(c & 0x80)) + { + *idp = (x << 7) ^ c; + return dp; + } + x = (x << 7) ^ c ^ 128; + } +} + +static unsigned char * +data_read_ideof(unsigned char *dp, Id *idp, int *eof) +{ + Id x = 0; + unsigned char c; + for (;;) + { + c = *dp++; + if (!(c & 0x80)) + { + if (c & 0x40) + { + c ^= 0x40; + *eof = 0; + } + else + *eof = 1; + *idp = (x << 6) ^ c; + return dp; + } + x = (x << 7) ^ c ^ 128; + } +} + +static unsigned char * +data_skip(unsigned char *dp, int type) +{ + unsigned char x; + switch (type) + { + case TYPE_VOID: + case TYPE_CONSTANT: + return dp; + case TYPE_ID: + case TYPE_NUM: + case TYPE_DIR: + while ((*dp & 0x80) != 0) + dp++; + return dp + 1; + case TYPE_IDARRAY: + while ((*dp & 0xc0) != 0) + dp++; + return dp + 1; + case TYPE_STR: + while ((*dp) != 0) + dp++; + return dp + 1; + case TYPE_DIRSTRARRAY: + for (;;) + { + while ((*dp & 0x80) != 0) + dp++; + x = *dp++; + while ((*dp) != 0) + dp++; + dp++; + if (!(x & 0x40)) + return dp; + } + case TYPE_DIRNUMNUMARRAY: + for (;;) + { + while ((*dp & 0x80) != 0) + dp++; + dp++; + while ((*dp & 0x80) != 0) + dp++; + dp++; + while ((*dp & 0x80) != 0) + dp++; + if (!(*dp & 0x40)) + return dp + 1; + dp++; + } + default: + fprintf(stderr, "unknown type in data_skip\n"); + exit(1); + } +} + +static unsigned char * +data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key) +{ + if (!dp) + return 0; + kv->eof = 1; + switch (key->type) + { + case TYPE_VOID: + return dp; + case TYPE_CONSTANT: + kv->num = key->size; + return dp; + case TYPE_STR: + kv->str = (const char *)dp; + return dp + strlen(kv->str) + 1; + case TYPE_ID: + return data_read_id(dp, &kv->id); + case TYPE_NUM: + return data_read_id(dp, &kv->num); + case TYPE_IDARRAY: + return data_read_ideof(dp, &kv->id, &kv->eof); + case TYPE_DIR: + return data_read_id(dp, &kv->id); + case TYPE_DIRSTRARRAY: + dp = data_read_ideof(dp, &kv->id, &kv->eof); + kv->str = (const char *)dp; + return dp + strlen(kv->str) + 1; + case TYPE_DIRNUMNUMARRAY: + dp = data_read_id(dp, &kv->id); + dp = data_read_id(dp, &kv->num); + return data_read_ideof(dp, &kv->num2, &kv->eof); + default: + return 0; + } +} + +static unsigned char * +forward_to_key(Repodata *data, Id key, Id schemaid, unsigned char *dp) +{ + Id k, *keyp; + + keyp = data->schemadata + data->schemata[schemaid]; + while ((k = *keyp++) != 0) + { + if (k == key) + return dp; + if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET) + { + dp = data_skip(dp, TYPE_ID); /* skip that offset */ + dp = data_skip(dp, TYPE_ID); /* skip that length */ + continue; + } + if (data->keys[k].storage != KEY_STORAGE_INCORE) + continue; + dp = data_skip(dp, data->keys[k].type); + } + return 0; +} + +#define BLOB_PAGEBITS 15 +#define BLOB_PAGESIZE (1 << BLOB_PAGEBITS) + +static unsigned char * +load_page_range(Repodata *data, unsigned int pstart, unsigned int pend) +{ +/* Make sure all pages from PSTART to PEND (inclusive) are loaded, + and are consecutive. Return a pointer to the mapping of PSTART. */ + unsigned char buf[BLOB_PAGESIZE]; + unsigned int i; + + /* Quick check in case all pages are there already and consecutive. */ + for (i = pstart; i <= pend; i++) + if (data->pages[i].mapped_at == -1 + || (i > pstart + && data->pages[i].mapped_at + != data->pages[i-1].mapped_at + BLOB_PAGESIZE)) + break; + if (i > pend) + return data->blob_store + data->pages[pstart].mapped_at; + + /* Ensure that we can map the numbers of pages we need at all. */ + if (pend - pstart + 1 > data->ncanmap) + { + unsigned int oldcan = data->ncanmap; + data->ncanmap = pend - pstart + 1; + if (data->ncanmap < 4) + data->ncanmap = 4; + data->mapped = sat_realloc2(data->mapped, data->ncanmap, sizeof(data->mapped[0])); + memset (data->mapped + oldcan, 0, (data->ncanmap - oldcan) * sizeof (data->mapped[0])); + data->blob_store = sat_realloc2(data->blob_store, data->ncanmap, BLOB_PAGESIZE); +#ifdef DEBUG_PAGING + fprintf (stderr, "PAGE: can map %d pages\n", data->ncanmap); +#endif + } + + /* Now search for "cheap" space in our store. Space is cheap if it's either + free (very cheap) or contains pages we search for anyway. */ + + /* Setup cost array. */ + unsigned int cost[data->ncanmap]; + for (i = 0; i < data->ncanmap; i++) + { + unsigned int pnum = data->mapped[i]; + if (pnum == 0) + cost[i] = 0; + else + { + pnum--; + Attrblobpage *p = data->pages + pnum; + assert (p->mapped_at != -1); + if (pnum >= pstart && pnum <= pend) + cost[i] = 1; + else + cost[i] = 3; + } + } + + /* And search for cheapest space. */ + unsigned int best_cost = -1; + unsigned int best = 0; + unsigned int same_cost = 0; + for (i = 0; i + pend - pstart < data->ncanmap; i++) + { + unsigned int c = cost[i]; + unsigned int j; + for (j = 0; j < pend - pstart + 1; j++) + c += cost[i+j]; + if (c < best_cost) + best_cost = c, best = i; + else if (c == best_cost) + same_cost++; + /* A null cost won't become better. */ + if (c == 0) + break; + } + /* If all places have the same cost we would thrash on slot 0. Avoid + this by doing a round-robin strategy in this case. */ + if (same_cost == data->ncanmap - pend + pstart - 1) + best = data->rr_counter++ % (data->ncanmap - pend + pstart); + + /* So we want to map our pages from [best] to [best+pend-pstart]. + Use a very simple strategy, which doesn't make the best use of + our resources, but works. Throw away all pages in that range + (even ours) then copy around ours (in case they were outside the + range) or read them in. */ + for (i = best; i < best + pend - pstart + 1; i++) + { + unsigned int pnum = data->mapped[i]; + if (pnum-- + /* If this page is exactly at the right place already, + no need to evict it. */ + && pnum != pstart + i - best) + { + /* Evict this page. */ +#ifdef DEBUG_PAGING + fprintf (stderr, "PAGE: evict page %d from %d\n", pnum, i); +#endif + cost[i] = 0; + data->mapped[i] = 0; + data->pages[pnum].mapped_at = -1; + } + } + + /* Everything is free now. Read in the pages we want. */ + for (i = pstart; i <= pend; i++) + { + Attrblobpage *p = data->pages + i; + unsigned int pnum = i - pstart + best; + void *dest = data->blob_store + pnum * BLOB_PAGESIZE; + if (p->mapped_at != -1) + { + if (p->mapped_at != pnum * BLOB_PAGESIZE) + { +#ifdef DEBUG_PAGING + fprintf (stderr, "PAGECOPY: %d to %d\n", i, pnum); +#endif + /* Still mapped somewhere else, so just copy it from there. */ + memcpy (dest, data->blob_store + p->mapped_at, BLOB_PAGESIZE); + data->mapped[p->mapped_at / BLOB_PAGESIZE] = 0; + } + } + else + { + unsigned int in_len = p->file_size; + unsigned int compressed = in_len & 1; + in_len >>= 1; +#ifdef DEBUG_PAGING + fprintf (stderr, "PAGEIN: %d to %d", i, pnum); +#endif + /* Not mapped, so read in this page. */ + if (fseek(data->fp, p->file_offset, SEEK_SET) < 0) + { + perror ("mapping fseek"); + exit (1); + } + if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1) + { + perror ("mapping fread"); + exit (1); + } + if (compressed) + { + unsigned int out_len; + out_len = unchecked_decompress_buf(buf, in_len, + dest, BLOB_PAGESIZE); + if (out_len != BLOB_PAGESIZE + && i < data->num_pages - 1) + { + fprintf (stderr, "can't decompress\n"); + exit (1); + } +#ifdef DEBUG_PAGING + fprintf (stderr, " (expand %d to %d)", in_len, out_len); +#endif + } +#ifdef DEBUG_PAGING + fprintf (stderr, "\n"); +#endif + } + p->mapped_at = pnum * BLOB_PAGESIZE; + data->mapped[pnum] = i + 1; + } + return data->blob_store + best * BLOB_PAGESIZE; +} + +static unsigned char * +make_vertical_available(Repodata *data, Repokey *key, Id off, Id len) +{ + unsigned char *dp; + if (key->type == TYPE_VOID) + return 0; + if (off >= data->lastverticaloffset) + { + off -= data->lastverticaloffset; + if (off + len > data->vincorelen) + return 0; + return data->vincore + off; + } + if (!data->fp) + return 0; + if (off + len > key->size) + return 0; + /* we now have the offset, go into vertical */ + off += data->verticaloffset[key - data->keys]; + dp = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE); + if (dp) + dp += off % BLOB_PAGESIZE; + return dp; +} + +static inline unsigned char * +get_data(Repodata *data, Repokey *key, unsigned char **dpp) +{ + unsigned char *dp = *dpp; + + if (!dp) + return 0; + if (key->storage == KEY_STORAGE_INCORE) + { + /* hmm, this is a bit expensive */ + *dpp = data_skip(dp, key->type); + return dp; + } + else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET) + { + Id off, len; + dp = data_read_id(dp, &off); + dp = data_read_id(dp, &len); + *dpp = dp; + return make_vertical_available(data, key, off, len); + } + return 0; +} + + +const char * +repodata_lookup_str(Repodata *data, Id entry, Id keyid) +{ + Id schema; + Repokey *key; + Id id, *keyp; + unsigned char *dp; + + if (data->entryschemau8) + schema = data->entryschemau8[entry]; + else + schema = data->entryschema[entry]; + /* make sure the schema of this solvable contains the key */ + for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++) + if (!*keyp) + return 0; + dp = forward_to_key(data, keyid, schema, data->incoredata + data->incoreoffset[entry]); + key = data->keys + keyid; + dp = get_data(data, key, &dp); + if (!dp) + return 0; + if (key->type == TYPE_STR) + return (const char *)dp; + if (key->type != TYPE_ID) + return 0; + /* id type, must either use global or local string strore*/ + dp = data_read_id(dp, &id); + if (data->localpool) + return data->spool.stringspace + data->spool.strings[id]; + return id2str(data->repo->pool, id); +} + +void +repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) +{ + Id schema; + Repokey *key; + Id k, keyid, *kp, *keyp; + unsigned char *dp, *ddp; + int onekey = 0; + int stop; + KeyValue kv; + + if (data->entryschemau8) + schema = data->entryschemau8[entry]; + else + schema = data->entryschema[entry]; + keyp = data->schemadata + data->schemata[schema]; + dp = data->incoredata + data->incoreoffset[entry]; + if (keyname) + { + /* search in a specific key */ + for (kp = keyp; (k = *kp++) != 0; ) + if (data->keys[k].name == keyname) + break; + if (k == 0) + return; + dp = forward_to_key(data, k, schema, dp); + if (!dp) + return; + keyp = kp - 1; + onekey = 1; + } + while ((keyid = *keyp++) != 0) + { + stop = 0; + key = data->keys + keyid; + ddp = get_data(data, key, &dp); + do + { + ddp = data_fetch(ddp, &kv, key); + if (ddp) + stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv); + } + while (!kv.eof && !stop); + if (onekey || stop > SEARCH_NEXT_KEY) + return; + } +} + + +/* extend repodata so that it includes solvables p */ +void +repodata_extend(Repodata *data, Id p) +{ + if (data->start == data->end) + data->start = data->end = p; + if (p >= data->end) + { + int old = data->end - data->start; + int new = p - data->end + 1; + if (data->entryschemau8) + { + data->entryschemau8 = sat_realloc(data->entryschemau8, old + new); + memset(data->entryschemau8 + old, 0, new); + } + if (data->entryschema) + { + data->entryschema = sat_realloc2(data->entryschema, old + new, sizeof(Id)); + memset(data->entryschema + old, 0, new * sizeof(Id)); + } + if (data->attrs) + { + data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *)); + memset(data->attrs + old, 0, new * sizeof(Id *)); + } + data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id)); + memset(data->incoreoffset + old, 0, new * sizeof(Id)); + data->end = p + 1; + } + if (p < data->start) + { + int old = data->end - data->start; + int new = data->start - p; + if (data->entryschemau8) + { + data->entryschemau8 = sat_realloc(data->entryschemau8, old + new); + memmove(data->entryschemau8 + new, data->entryschemau8, old); + memset(data->entryschemau8, 0, new); + } + if (data->entryschema) + { + data->entryschema = sat_realloc2(data->entryschema, old + new, sizeof(Id)); + memmove(data->entryschema + new, data->entryschema, old * sizeof(Id)); + memset(data->entryschema, 0, new * sizeof(Id)); + } + if (data->attrs) + { + data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *)); + memmove(data->attrs + new, data->attrs, old * sizeof(Id *)); + memset(data->attrs, 0, new * sizeof(Id *)); + } + data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id)); + memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id)); + memset(data->incoreoffset, 0, new * sizeof(Id)); + data->start = p; + } +} + +void +repodata_set(Repodata *data, Id entry, Repokey *key, Id val) +{ + Id keyid, *pp; + int i; + + /* find key in keys */ + for (keyid = 1; keyid < data->nkeys; keyid++) + if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type) + { + if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size) + continue; + break; + } + if (keyid == data->nkeys) + { + /* allocate new key */ + data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey)); + data->keys[data->nkeys++] = *key; + if (data->verticaloffset) + { + data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id)); + data->verticaloffset[data->nkeys - 1] = 0; + } + } + key = data->keys + keyid; + if (!data->attrs) + data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *)); + i = 0; + if (data->attrs[entry]) + { + for (pp = data->attrs[entry]; *pp; pp += 2) + if (*pp == keyid) + break; + if (*pp) + { + pp[1] = val; + return; + } + i = pp - data->attrs[entry]; + } + data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id)); + pp = data->attrs[entry] + i; + *pp++ = keyid; + *pp++ = val; + *pp = 0; +} + +void +repodata_set_id(Repodata *data, Id entry, Id keyname, Id id) +{ + Repokey key; + key.name = keyname; + key.type = TYPE_ID; + key.size = 0; + key.storage = KEY_STORAGE_INCORE; + repodata_set(data, entry, &key, id); +} + +void +repodata_set_num(Repodata *data, Id entry, Id keyname, Id num) +{ + Repokey key; + key.name = keyname; + key.type = TYPE_NUM; + key.size = 0; + key.storage = KEY_STORAGE_INCORE; + repodata_set(data, entry, &key, num); +} + +void +repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str) +{ + Repokey key; + Id id; + if (data->localpool) + id = stringpool_str2id(&data->spool, str, 1); + else + id = str2id(data->repo->pool, str, 1); + key.name = keyname; + key.type = TYPE_ID; + key.size = 0; + key.storage = KEY_STORAGE_INCORE; + repodata_set(data, entry, &key, id); +} + +void +repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant) +{ + Repokey key; + key.name = keyname; + key.type = TYPE_CONSTANT; + key.size = constant; + key.storage = KEY_STORAGE_INCORE; + repodata_set(data, entry, &key, 0); +} + +void +repodata_set_void(Repodata *data, Id entry, Id keyname) +{ + Repokey key; + key.name = keyname; + key.type = TYPE_VOID; + key.size = 0; + key.storage = KEY_STORAGE_INCORE; + repodata_set(data, entry, &key, 0); +} + +void +repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str) +{ + Repokey key; + int l; + + l = strlen(str) + 1; + key.name = keyname; + key.type = TYPE_STR; + key.size = 0; + key.storage = KEY_STORAGE_INCORE; + data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l); + memcpy(data->attrdata + data->attrdatalen, str, l); + repodata_set(data, entry, &key, data->attrdatalen); + data->attrdatalen += l; +} + +void +repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2) +{ + Id *ida, *pp; + Repokey key; + +#if 0 +fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen); +#endif + if (data->attrs[entry]) + { + for (pp = data->attrs[entry]; *pp; pp += 2) + if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY) + break; + if (*pp) + { + int oldsize = 0; + for (ida = data->attriddata + pp[1]; *ida; ida += 3) + oldsize += 3; + if (ida + 1 == data->attriddata + data->attriddatalen) + { + /* this was the last entry, just append it */ + data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id)); + data->attriddatalen--; /* overwrite terminating 0 */ + } + else + { + /* too bad. move to back. */ + data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id)); + memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id)); + pp[1] = data->attriddatalen; + data->attriddatalen += oldsize; + } + data->attriddata[data->attriddatalen++] = dir; + data->attriddata[data->attriddatalen++] = num; + data->attriddata[data->attriddatalen++] = num2; + data->attriddata[data->attriddatalen++] = 0; + return; + } + } + key.name = keyname; + key.type = TYPE_DIRNUMNUMARRAY; + key.size = 0; + key.storage = KEY_STORAGE_INCORE; + data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id)); + repodata_set(data, entry, &key, data->attriddatalen); + data->attriddata[data->attriddatalen++] = dir; + data->attriddata[data->attriddatalen++] = num; + data->attriddata[data->attriddatalen++] = num2; + data->attriddata[data->attriddatalen++] = 0; +} + +/*********************************/ + +/* unify with repo_write! */ + +#define EXTDATA_BLOCK 1023 +#define SCHEMATA_BLOCK 31 +#define SCHEMATADATA_BLOCK 255 + +struct extdata { + unsigned char *buf; + int len; +}; + +static void +data_addid(struct extdata *xd, Id x) +{ + unsigned char *dp; + xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK); + dp = xd->buf + xd->len; + + if (x >= (1 << 14)) + { + if (x >= (1 << 28)) + *dp++ = (x >> 28) | 128; + if (x >= (1 << 21)) + *dp++ = (x >> 21) | 128; + *dp++ = (x >> 14) | 128; + } + if (x >= (1 << 7)) + *dp++ = (x >> 7) | 128; + *dp++ = x & 127; + xd->len = dp - xd->buf; +} + +static void +data_addideof(struct extdata *xd, Id x, int eof) +{ + if (x >= 64) + x = (x & 63) | ((x & ~63) << 1); + data_addid(xd, (eof ? x: x | 64)); +} + +static void +data_addblob(struct extdata *xd, unsigned char *blob, int len) +{ + xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK); + memcpy(xd->buf + xd->len, blob, len); + xd->len += len; +} + +/*********************************/ + +static void +addschema_prepare(Repodata *data, Id *schematacache) +{ + int h, len, i; + Id *sp; + + memset(schematacache, 0, 256 * sizeof(Id)); + for (i = 0; i < data->nschemata; i++) + { + for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++) + h = h * 7 + *sp++; + h &= 255; + schematacache[h] = i + 1; + } + data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK); + data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK); +} + +static Id +addschema(Repodata *data, Id *schema, Id *schematacache) +{ + int h, len; + Id *sp, cid; + + for (sp = schema, len = 0, h = 0; *sp; len++) + h = h * 7 + *sp++; + h &= 255; + len++; + + cid = schematacache[h]; + if (cid) + { + cid--; + if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id))) + return cid; + /* cache conflict */ + for (cid = 0; cid < data->nschemata; cid++) + if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id))) + return cid; + } + /* a new one. make room. */ + data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK); + data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK); + /* add schema */ + memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id)); + data->schemata[data->nschemata] = data->schemadatalen; + data->schemadatalen += len; + schematacache[h] = data->nschemata + 1; +#if 0 +fprintf(stderr, "addschema: new schema\n"); +#endif + return data->nschemata++; +} + + +void +repodata_internalize(Repodata *data) +{ + int i; + Repokey *key; + Id id, entry, nentry, *ida; + Id schematacache[256]; + Id schemaid, *schema, *sp, oldschema, *keyp, *seen; + unsigned char *dp, *ndp; + int newschema, oldcount; + struct extdata newincore; + struct extdata newvincore; + + if (!data->attrs) + return; + + newvincore.buf = data->vincore; + newvincore.len = data->vincorelen; + + schema = sat_malloc2(data->nkeys, sizeof(Id)); + seen = sat_malloc2(data->nkeys, sizeof(Id)); + + nentry = data->end - data->start; + addschema_prepare(data, schematacache); + memset(&newincore, 0, sizeof(newincore)); + for (entry = 0; entry < nentry; entry++) + { + memset(seen, 0, data->nkeys * sizeof(Id)); + sp = schema; + if (data->entryschemau8) + oldschema = data->entryschemau8[entry]; + else + oldschema = data->entryschema[entry]; +#if 0 +fprintf(stderr, "oldschema %d\n", oldschema); +fprintf(stderr, "schemata %d\n", data->schemata[oldschema]); +fprintf(stderr, "schemadata %p\n", data->schemadata); +#endif + /* seen: -1: old data 0: skipped >0: id + 1 */ + newschema = 0; + oldcount = 0; + for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++) + { + if (seen[*keyp]) + { + newschema = 1; + continue; + } + seen[*keyp] = -1; + *sp++ = *keyp; + oldcount++; + } + for (keyp = data->attrs[entry]; *keyp; keyp += 2) + { + if (!seen[*keyp]) + { + newschema = 1; + *sp++ = *keyp; + } + seen[*keyp] = keyp[1] + 1; + } + *sp++ = 0; + if (newschema) + { + schemaid = addschema(data, schema, schematacache); + if (schemaid > 255 && data->entryschemau8) + { + data->entryschema = sat_malloc2(nentry, sizeof(Id)); + for (i = 0; i < nentry; i++) + data->entryschema[i] = data->entryschemau8[i]; + data->entryschemau8 = sat_free(data->entryschemau8); + } + if (data->entryschemau8) + data->entryschemau8[entry] = schemaid; + else + data->entryschema[entry] = schemaid; + } + else + schemaid = oldschema; + + + /* now create data blob */ + dp = data->incoredata + data->incoreoffset[entry]; + data->incoreoffset[entry] = newincore.len; + for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++) + { + key = data->keys + *keyp; + ndp = dp; + if (oldcount) + { + if (key->storage == KEY_STORAGE_VERTICAL_OFFSET) + { + ndp = data_skip(dp, TYPE_ID); + ndp = data_skip(dp, TYPE_ID); + } + else if (key->storage == KEY_STORAGE_INCORE) + ndp = data_skip(dp, key->type); + oldcount--; + } + if (seen[*keyp] == -1) + { + if (dp != ndp) + data_addblob(&newincore, dp, ndp - dp); + seen[*keyp] = 0; + } + else if (seen[*keyp]) + { + struct extdata *xd; + unsigned int oldvincorelen = 0; + + xd = &newincore; + if (key->storage == KEY_STORAGE_VERTICAL_OFFSET) + { + xd = &newvincore; + oldvincorelen = xd->len; + } + id = seen[*keyp] - 1; + switch (key->type) + { + case TYPE_VOID: + case TYPE_CONSTANT: + break; + case TYPE_STR: + data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1); + break; + case TYPE_ID: + case TYPE_NUM: + case TYPE_DIR: + data_addid(xd, id); + break; + case TYPE_DIRNUMNUMARRAY: + ida = data->attriddata + id; + for (ida = data->attriddata + id; *ida; ida += 3) + { + data_addid(xd, ida[0]); + data_addid(xd, ida[1]); + data_addideof(xd, ida[2], ida[3] ? 0 : 1); + } + break; + default: + fprintf(stderr, "don't know how to handle type %d\n", key->type); + exit(1); + } + if (key->storage == KEY_STORAGE_VERTICAL_OFFSET) + { + /* put offset/len in incore */ + data_addid(&newincore, data->lastverticaloffset + oldvincorelen); + oldvincorelen = xd->len - oldvincorelen; + data_addid(&newincore, oldvincorelen); + } + } + dp = ndp; + } + } + data->incoredata = newincore.buf; + data->incoredatalen = newincore.len; + data->incoredatafree = 0; + + data->vincore = newvincore.buf; + data->vincorelen = newvincore.len; + + data->attrs = sat_free(data->attrs); + data->attrdata = sat_free(data->attrdata); + data->attrdatalen = 0; +} + +Id +repodata_str2dir(Repodata *data, const char *dir, int create) +{ + Id id, parent; + const char *dire; + + parent = 0; + while (*dir == '/' && dir[1] == '/') + dir++; + while (*dir) + { + dire = strchrnul(dir, '/'); + if (data->localpool) + id = stringpool_strn2id(&data->spool, dir, dire - dir, create); + else + id = strn2id(data->repo->pool, dir, dire - dir, create); + if (!id) + return 0; + parent = dirpool_add_dir(&data->dirpool, parent, id, create); + if (!parent) + return 0; + if (!*dire) + break; + dir = dire + 1; + while (*dir == '/') + dir++; + } + return parent; +} + +unsigned int +repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max) +{ + return compress_buf(page, len, cpage, max); +} + +/* Try to either setup on-demand paging (using FP as backing + file), or in case that doesn't work (FP not seekable) slurps in + all pages and deactivates paging. */ + +#define SOLV_ERROR_EOF 3 + +static inline unsigned int +read_u32(FILE *fp) +{ + int c, i; + unsigned int x = 0; + + for (i = 0; i < 4; i++) + { + c = getc(fp); + if (c == EOF) + return 0; + x = (x << 8) | c; + } + return x; +} + +void +repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz) +{ + FILE *fp = data->fp; + unsigned int npages; + unsigned int i; + unsigned int can_seek; + long cur_file_ofs; + unsigned char buf[BLOB_PAGESIZE]; + if (pagesz != BLOB_PAGESIZE) + { + /* We could handle this by slurping in everything. */ + fprintf (stderr, "non matching page size\n"); + exit (1); + } + can_seek = 1; + if ((cur_file_ofs = ftell(fp)) < 0) + can_seek = 0; + clearerr (fp); +#ifdef DEBUG_PAGING + fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT "); +#endif + npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE; + + data->num_pages = npages; + data->pages = sat_malloc2(npages, sizeof(data->pages[0])); + + /* If we can't seek on our input we have to slurp in everything. */ + if (!can_seek) + data->blob_store = sat_malloc(npages * BLOB_PAGESIZE); + for (i = 0; i < npages; i++) + { + unsigned int in_len = read_u32(fp); + unsigned int compressed = in_len & 1; + Attrblobpage *p = data->pages + i; + in_len >>= 1; +#ifdef DEBUG_PAGING + fprintf (stderr, "page %d: len %d (%scompressed)\n", + i, in_len, compressed ? "" : "not "); +#endif + if (can_seek) + { + cur_file_ofs += 4; + p->mapped_at = -1; + p->file_offset = cur_file_ofs; + p->file_size = in_len * 2 + compressed; + if (fseek(fp, in_len, SEEK_CUR) < 0) + { + perror ("fseek"); + fprintf (stderr, "can't seek after we thought we can\n"); + /* We can't fall back to non-seeking behaviour as we already + read over some data pages without storing them away. */ + exit (1); + } + cur_file_ofs += in_len; + } + else + { + unsigned int out_len; + void *dest = data->blob_store + i * BLOB_PAGESIZE; + p->mapped_at = i * BLOB_PAGESIZE; + p->file_offset = 0; + p->file_size = 0; + /* We can't seek, so suck everything in. */ + if (fread(compressed ? buf : dest, in_len, 1, fp) != 1) + { + perror ("fread"); + exit (1); + } + if (compressed) + { + out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE); + if (out_len != BLOB_PAGESIZE + && i < npages - 1) + { + fprintf (stderr, "can't decompress\n"); + exit (1); + } + } + } + } + + if (can_seek) + { + /* If we are here we were able to seek to all page + positions, so activate paging by copying FP into our structure. + We dup() the file, so that our callers can fclose() it and we + still have it open. But this means that we share file positions + with the input filedesc. So in case our caller reads it after us, + and calls back into us we might change the file position unexpectedly + to him. */ + int fd = dup (fileno (fp)); + if (fd < 0) + { + /* Jeez! What a bloody system, we can't dup() anymore. */ + perror ("dup"); + exit (1); + } + /* XXX we don't close this yet anywhere. */ + data->fp = fdopen (fd, "r"); + if (!data->fp) + { + /* My God! What happened now? */ + perror ("fdopen"); + exit (1); + } + } +} diff --git a/src/repodata.h b/src/repodata.h new file mode 100644 index 0000000..16f2e4c --- /dev/null +++ b/src/repodata.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * repodata.h + * + */ + +#ifndef SATSOLVER_REPODATA_H +#define SATSOLVER_REPODATA_H + +#include "pooltypes.h" +#include "pool.h" +#include "dirpool.h" + +struct _Repo; +struct _Repokey; +struct _KeyValue; + +typedef struct _Attrblobpage +{ + /* mapped_at == -1 --> not loaded, otherwise offset into + store->blob_store. The size of the mapping is BLOB_PAGESIZE + except for the last page. */ + unsigned int mapped_at; + long file_offset; + /* file_size == 0 means the page is not backed by some file storage. + Otherwise it is L*2+(compressed ? 1 : 0), with L being the data + length. */ + long file_size; +} Attrblobpage; + +typedef struct _Repodata { + struct _Repo *repo; /* back pointer to repo */ + + int state; /* available, stub or error */ + + void (*loadcallback)(struct _Repodata *); + + int start; /* start of solvables this repodata is valid for */ + int end; /* last solvable + 1 of this repodata */ + + FILE *fp; /* file pointer of solv file */ + int error; /* corrupt solv file */ + + struct _Repokey *keys; /* keys, first entry is always zero */ + unsigned int nkeys; /* length of keys array */ + + Id *schemata; /* schema -> offset into schemadata */ + unsigned int nschemata; /* number of schemata */ + + Id *schemadata; /* schema storage */ + unsigned int schemadatalen; /* schema storage size */ + + unsigned char *entryschemau8; /* schema for entry */ + Id *entryschema; /* schema for entry */ + + Stringpool spool; /* local string pool */ + int localpool; /* is local string pool used */ + + Dirpool dirpool; /* local dir pool */ + + unsigned char *incoredata; /* in-core data (flat_attrs) */ + unsigned int incoredatalen; /* data len (attr_next_free) */ + unsigned int incoredatafree; /* free data len */ + + Id *incoreoffset; /* offset for all entries (ent2attr) */ + + Id *verticaloffset; /* offset for all verticals, nkeys elements */ + Id lastverticaloffset; /* end of verticals */ + + unsigned char *blob_store; + + Attrblobpage *pages; + unsigned int num_pages; + + /* mapped[i] is zero if nothing is mapped at logical page I, + otherwise it contains the pagenumber plus one (of the mapped page). */ + unsigned int *mapped; + unsigned int nmapped, ncanmap; + unsigned int rr_counter; + + unsigned char *vincore; + unsigned int vincorelen; + + Id **attrs; /* un-internalized attributes */ + unsigned char *attrdata; /* their string data space */ + unsigned int attrdatalen; + Id *attriddata; /* their id space */ + unsigned int attriddatalen; + +} Repodata; + +#define REPODATA_AVAILABLE 0 +#define REPODATA_STUB 1 +#define REPODATA_ERROR 2 +#define REPODATA_STORE 3 + +void repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata); +const char *repodata_lookup_str(Repodata *data, Id entry, Id keyid); + +void repodata_extend(Repodata *data, Id p); + +void repodata_set_id(Repodata *data, Id entry, Id keyname, Id id); +void repodata_set_num(Repodata *data, Id entry, Id keyname, Id num); +void repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str); +void repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant); +void repodata_set_void(Repodata *data, Id entry, Id keyname); +void repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str); +void repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2); + +void repodata_internalize(Repodata *data); + +Id repodata_str2dir(Repodata *data, const char *dir, int create); + +unsigned int repodata_compress_page(unsigned char *, unsigned int, unsigned char *, unsigned int); +void repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz); + +#endif /* SATSOLVER_REPODATA_H */ diff --git a/src/solver.c b/src/solver.c index 11c325a..114fc15 100644 --- a/src/solver.c +++ b/src/solver.c @@ -294,7 +294,7 @@ unifyrules(Solver *solv) /* adapt rule buffer */ solv->nrules = j; - solv->rules = (Rule *)sat_realloc(solv->rules, ((solv->nrules + RULES_BLOCK) & ~RULES_BLOCK) * sizeof(Rule)); + solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK); IF_POOLDEBUG (SAT_DEBUG_STATS) { int binr = 0; @@ -461,12 +461,8 @@ addrule(Solver *solv, Id p, Id d) * allocate new rule */ - /* check and extend rule buffer */ - if ((solv->nrules & RULES_BLOCK) == 0) - { - solv->rules = (Rule *)sat_realloc(solv->rules, (solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule)); - } - + /* extend rule buffer */ + solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK); r = solv->rules + solv->nrules++; /* point to rule space */ r->p = p; @@ -921,6 +917,46 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx) } } +#if 0 +static void +addpatchatomrequires(Solver *solv, Solvable *s, Id *dp, Queue *q, Map *m) +{ + Pool *pool = solv->pool; + Id fre, *frep, p, *pp, ndp; + Solvable *ps; + Queue fq; + Id qbuf[64]; + int i, used = 0; + + queue_init_buffer(&fq, qbuf, sizeof(qbuf)/sizeof(*qbuf)); + queue_push(&fq, -(s - pool->solvables)); + for (; *dp; dp++) + queue_push(&fq, *dp); + ndp = pool_queuetowhatprovides(pool, &fq); + frep = s->repo->idarraydata + s->freshens; + while ((fre = *frep++) != 0) + { + FOR_PROVIDES(p, pp, fre) + { + ps = pool->solvables + p; + addrule(solv, -p, ndp); + used = 1; + if (!MAPTST(m, p)) + queue_push(q, p); + } + } + if (used) + { + for (i = 1; i < fq.count; i++) + { + p = fq.elements[i]; + if (!MAPTST(m, p)) + queue_push(q, p); + } + } + queue_free(&fq); +} +#endif /* * add (install) rules for solvable @@ -937,6 +973,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m) Id qbuf[64]; int i; int dontfix; + int patchatom; Id req, *reqp; Id con, *conp; Id obs, *obsp; @@ -979,6 +1016,14 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m) addrule(solv, -n, 0); /* uninstallable */ } + patchatom = 0; + if (s->freshens && !s->supplements) + { + const char *name = id2str(pool, s->name); + if (name[0] == 'a' && !strncmp(name, "atom:", 5)) + patchatom = 1; + } + /*----------------------------------------- * check requires of s */ @@ -996,6 +1041,13 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (*dp == SYSTEMSOLVABLE) /* always installed */ continue; +#if 0 + if (patchatom) + { + addpatchatomrequires(solv, s, dp, &q, m); + continue; + } +#endif if (dontfix) { /* the strategy here is to not insist on dependencies @@ -2005,9 +2057,9 @@ solver_create(Pool *pool, Repo *installed) solv->recommends_index = 0; solv->decisionmap = (Id *)sat_calloc(pool->nsolvables, sizeof(Id)); - solv->rules = (Rule *)sat_malloc((solv->nrules + (RULES_BLOCK + 1)) * sizeof(Rule)); - memset(solv->rules, 0, sizeof(Rule)); solv->nrules = 1; + solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK); + memset(solv->rules, 0, sizeof(Rule)); return solv; } @@ -2701,7 +2753,7 @@ solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, I */ Id * -create_obsoletesmap(Solver *solv) +create_decisions_obsoletesmap(Solver *solv) { Pool *pool = solv->pool; Repo *installed = solv->installed; @@ -2774,7 +2826,7 @@ printdecisions(Solver *solv) { Pool *pool = solv->pool; Repo *installed = solv->installed; - Id p, *obsoletesmap = create_obsoletesmap( solv ); + Id p, *obsoletesmap = create_decisions_obsoletesmap( solv ); int i; Solvable *s; @@ -3270,7 +3322,9 @@ printsolutions(Solver *solv, Queue *job) } -/* for each installed solvable find which packages with *different* names +/* create reverse obsoletes map for installed solvables + * + * for each installed solvable find which packages with *different* names * obsolete the solvable. * this index is used in policy_findupdatepackages if noupdateprovide is set. */ @@ -3286,7 +3340,6 @@ create_obsolete_index(Solver *solv) if (!installed || !installed->nsolvables) return; - /* create reverse obsoletes map for installed solvables */ solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id)); for (i = 1; i < pool->nsolvables; i++) { @@ -3582,10 +3635,22 @@ solver_solve(Solver *solv, Queue *job) { /* loop over all installed solvables */ /* we create all update rules, but disable some later on depending on the job */ for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++) - if (s->repo == installed) - addupdaterule(solv, s, 0); /* allowall = 0 */ - else - addupdaterule(solv, 0, 0); /* create dummy rule; allowall = 0 */ + { + /* no system rules for patch atoms */ + if (s->freshens && !s->supplements) + { + const char *name = id2str(pool, s->name); + if (name[0] == 'a' && !strncmp(name, "atom:", 5)) + { + addrule(solv, 0, 0); + continue; + } + } + if (s->repo == installed) + addupdaterule(solv, s, 0); /* allowall = 0 */ + else + addrule(solv, 0, 0); /* create dummy rule */ + } /* consistency check: we added a rule for _every_ system solvable */ assert(solv->nrules - solv->systemrules == installed->end - installed->start); } diff --git a/src/strpool.c b/src/strpool.c index 8bf73e5..4d09139 100644 --- a/src/strpool.c +++ b/src/strpool.c @@ -13,17 +13,19 @@ #define STRINGSPACE_BLOCK 65535 void -stringpool_init (Stringpool *ss, const char *strs[]) +stringpool_init(Stringpool *ss, const char *strs[]) { unsigned totalsize = 0; unsigned count; + + memset(ss, 0, sizeof(*ss)); // count number and total size of predefined strings for (count = 0; strs[count]; count++) totalsize += strlen(strs[count]) + 1; // alloc appropriate space - ss->stringspace = sat_malloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); - ss->strings = sat_malloc2((count + STRING_BLOCK) & ~STRING_BLOCK, sizeof(Offset)); + ss->stringspace = sat_extend_resize(0, totalsize, 1, STRINGSPACE_BLOCK); + ss->strings = sat_extend_resize(0, count, sizeof(Offset), STRING_BLOCK); // now copy predefined strings into allocated space ss->sstrings = 0; @@ -36,6 +38,29 @@ stringpool_init (Stringpool *ss, const char *strs[]) ss->nstrings = count; } +void +stringpool_init_empty(Stringpool *ss) +{ + const char *emptystrs[] = { + "", + "", + 0, + }; + stringpool_init(ss, emptystrs); +} + +void +stringpool_clone(Stringpool *ss, Stringpool *from) +{ + memset(ss, 0, sizeof(*ss)); + ss->strings = sat_extend_resize(0, from->nstrings, sizeof(Offset), STRING_BLOCK); + memcpy(ss->strings, from->strings, from->nstrings * sizeof(Offset)); + ss->stringspace = sat_extend_resize(0, from->sstrings, 1, STRINGSPACE_BLOCK); + memcpy(ss->stringspace, from->stringspace, from->sstrings); + ss->nstrings = from->nstrings; + ss->sstrings = from->sstrings; +} + Id stringpool_strn2id (Stringpool *ss, const char *str, unsigned len, int create) { @@ -96,17 +121,13 @@ stringpool_strn2id (Stringpool *ss, const char *str, unsigned len, int create) id = ss->nstrings++; hashtbl[h] = id; - // - if ((id & STRING_BLOCK) == 0) - ss->strings = sat_realloc2(ss->strings, (ss->nstrings + STRING_BLOCK) & ~STRING_BLOCK, sizeof(Hashval)); + ss->strings = sat_extend(ss->strings, id, 1, sizeof(Offset), STRING_BLOCK); // 'pointer' into stringspace is Offset of next free pos: sstrings ss->strings[id] = ss->sstrings; space_needed = len + 1; - - // resize string buffer if needed - if (((ss->sstrings + space_needed - 1) | STRINGSPACE_BLOCK) != ((ss->sstrings - 1) | STRINGSPACE_BLOCK)) - ss->stringspace = sat_realloc(ss->stringspace, (ss->sstrings + space_needed + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); + // make room in string buffer + ss->stringspace = sat_extend(ss->stringspace, ss->sstrings, space_needed, 1, STRINGSPACE_BLOCK); // copy new string into buffer memcpy(ss->stringspace + ss->sstrings, str, space_needed - 1); // add the sentinel, we can't rely on it being in the source string (in @@ -128,6 +149,6 @@ stringpool_str2id (Stringpool *ss, const char *str, int create) void stringpool_shrink (Stringpool *ss) { - ss->stringspace = (char *)sat_realloc(ss->stringspace, (ss->sstrings + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); - ss->strings = (Offset *)sat_realloc2(ss->strings, (ss->nstrings + STRING_BLOCK) & ~STRING_BLOCK, sizeof(Offset)); + ss->stringspace = sat_extend_resize(ss->stringspace, ss->sstrings, 1, STRINGSPACE_BLOCK); + ss->strings = sat_extend_resize(ss->strings, ss->nstrings, sizeof(Offset), STRING_BLOCK); } diff --git a/src/strpool.h b/src/strpool.h index c8429b9..dcab2ae 100644 --- a/src/strpool.h +++ b/src/strpool.h @@ -24,11 +24,15 @@ struct _Stringpool Hashmask stringhashmask; // modulo value for hash table (size of table - 1) }; -void stringpool_init (Stringpool *ss, const char *strs[]); +void stringpool_init(Stringpool *ss, const char *strs[]); +void stringpool_init_empty(Stringpool *ss); +void stringpool_clone(Stringpool *ss, Stringpool *from); + Id stringpool_str2id (Stringpool *ss, const char *str, int create); -Id stringpool_strn2id (Stringpool *ss, const char *str, unsigned len, int create); +Id stringpool_strn2id (Stringpool *ss, const char *str, unsigned int len, int create); void stringpool_shrink (Stringpool *ss); + static inline const char * stringpool_id2str (Stringpool *ss, Id id) { diff --git a/src/util.h b/src/util.h index e38aa12..7c196e7 100644 --- a/src/util.h +++ b/src/util.h @@ -20,4 +20,33 @@ extern void *sat_realloc(void *, size_t); extern void *sat_realloc2(void *, size_t, size_t); extern void *sat_free(void *); +static inline void *sat_extend(void *buf, size_t len, size_t nmemb, size_t size, size_t block) +{ + if (nmemb == 1) + { + if ((len & block) == 0) + buf = sat_realloc2(buf, len + (1 + block), size); + } + else + { + if (((len - 1) | block) != ((len + nmemb - 1) | block)) + buf = sat_realloc2(buf, (len + (nmemb + block)) & ~block, size); + } + return buf; +} + +static inline void *sat_extend_resize(void *buf, size_t len, size_t size, size_t block) +{ + if (len) + buf = sat_realloc2(buf, (len + block) & ~block, size); + return buf; +} + +static inline void *sat_extend_cleanup(void *buf, size_t len, size_t size) +{ + if (len) + buf = sat_realloc2(buf, len, size); + return buf; +} + #endif /* SATSOLVER_UTIL_H */ diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 0ed361c..e854a72 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -43,14 +43,14 @@ SET(mergesolv_REPOS mergesolv.c repo_write.c) ADD_EXECUTABLE( mergesolv ${mergesolv_REPOS} ) TARGET_LINK_LIBRARIES( mergesolv satsolver) -SET(dumpattr_REPOS dumpattr.c) -ADD_EXECUTABLE( dumpattr ${dumpattr_REPOS} ) -TARGET_LINK_LIBRARIES( dumpattr satsolver) +#SET(dumpattr_REPOS dumpattr.c) +#ADD_EXECUTABLE( dumpattr ${dumpattr_REPOS} ) +#TARGET_LINK_LIBRARIES( dumpattr satsolver) -ADD_EXECUTABLE( addstore addstore.c repo_write.c ) -TARGET_LINK_LIBRARIES( addstore satsolver ) +#ADD_EXECUTABLE( addstore addstore.c repo_write.c ) +#TARGET_LINK_LIBRARIES( addstore satsolver ) -install(TARGETS dumpattr +install(TARGETS mergesolv dumpsolv patchxml2solv @@ -58,7 +58,6 @@ install(TARGETS dumpattr helix2solv rpmmd2solv rpmdb2solv - addstore content2solv DESTINATION ${BIN_INSTALL_DIR} ) diff --git a/tools/content2solv.c b/tools/content2solv.c index 30a6350..5c5af58 100644 --- a/tools/content2solv.c +++ b/tools/content2solv.c @@ -23,7 +23,7 @@ main(int argc, char **argv) Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); repo_add_content(repo, stdin); - repo_write(repo, stdout); + repo_write(repo, stdout, 0, 0); pool_free(pool); return 0; } diff --git a/tools/dumpsolv.c b/tools/dumpsolv.c index 06083d9..bcdeb35 100644 --- a/tools/dumpsolv.c +++ b/tools/dumpsolv.c @@ -12,6 +12,7 @@ #include "pool.h" #include "repo_solv.h" +#if 0 #include "attr_store.h" #include "attr_store_p.h" @@ -104,6 +105,7 @@ dump_repodata (Repo *repo) } printf("\n"); } +#endif static void printids(Repo *repo, char *kind, Offset ido) @@ -118,6 +120,75 @@ printids(Repo *repo, char *kind, Offset ido) printf(" %s\n", dep2str(pool, id)); } +static void +printdir(Repodata *data, Id dir) +{ + Id comp; + Id parent = dirpool_parent(&data->dirpool, dir); + if (parent) + { + printdir(data, parent); + putchar('/'); + } + comp = dirpool_compid(&data->dirpool, dir); + if (data->localpool) + printf("%s", stringpool_id2str(&data->spool, comp)); + else + printf("%s", id2str(data->repo->pool, comp)); +} + +int +dump_repoattrs_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) +{ + const char *keyname; + + keyname = id2str(data->repo->pool, key->name); + switch(key->type) + { + case TYPE_ID: + if (data->localpool) + kv->str = stringpool_id2str(&data->spool, kv->id); + else + kv->str = id2str(data->repo->pool, kv->id); + printf("%s: %s\n", keyname, kv->str); + break; + case TYPE_STR: + printf("%s: %s\n", keyname, kv->str); + break; + case TYPE_VOID: + printf("%s\n", keyname); + break; + case TYPE_NUM: + case TYPE_CONSTANT: + printf("%s: %d\n", keyname, kv->num); + break; + case TYPE_DIRNUMNUMARRAY: + printf("%s: ", keyname); + printdir(data, kv->id); + printf(" %d %d\n", kv->num, kv->num2); + break; + default: + printf("%s: ?\n", keyname); + break; + } + return 0; +} + +void +dump_repoattrs(Repo *repo, Id p) +{ + int i; + Repodata *data; + for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) + { + if (data->state == REPODATA_STUB || data->state == REPODATA_ERROR) + continue; + if (p < data->start || p >= data->end) + continue; + repodata_search(data, p - data->start, 0, dump_repoattrs_cb, 0); + } +} + int main(int argc, char **argv) { Repo *repo; @@ -134,9 +205,14 @@ int main(int argc, char **argv) } } pool = pool_create(); + pool_setdebuglevel(pool, 1); + repo = repo_create(pool, argc != 1 ? argv[1] : ""); - repo_add_solv(repo, stdin); + if (repo_add_solv(repo, stdin)) + printf("could not read repository\n"); +#if 0 dump_repodata (repo); +#endif printf("repo contains %d solvables\n", repo->nsolvables); for (i = repo->start, n = 1; i < repo->end; i++) { @@ -158,7 +234,10 @@ int main(int argc, char **argv) printids(repo, "supplements", s->supplements); printids(repo, "enhances", s->enhances); printids(repo, "freshens", s->freshens); +#if 0 dump_attrs (repo, n - 1); +#endif + dump_repoattrs(repo, i); n++; } pool_free(pool); diff --git a/tools/helix2solv.c b/tools/helix2solv.c index a179952..9c3a618 100644 --- a/tools/helix2solv.c +++ b/tools/helix2solv.c @@ -31,7 +31,7 @@ main(int argc, char **argv) Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); repo_add_helix(repo, stdin); - repo_write(repo, stdout); + repo_write(repo, stdout, 0, 0); pool_free(pool); exit(0); } diff --git a/tools/mergesolv.c b/tools/mergesolv.c index de176ea..44d3ddd 100644 --- a/tools/mergesolv.c +++ b/tools/mergesolv.c @@ -103,7 +103,7 @@ main(int argc, char **argv) pool->repos[0]->idarraydata = new_id; pool->repos[0]->idarraysize = new_id_size; - repo_write(pool->repos[0], stdout); + repo_write(pool->repos[0], stdout, 0, 0); pool_free(pool); return 0; diff --git a/tools/patchxml2solv.c b/tools/patchxml2solv.c index 6555af4..30a359d 100644 --- a/tools/patchxml2solv.c +++ b/tools/patchxml2solv.c @@ -23,7 +23,7 @@ main(int argc, char **argv) Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); repo_add_patchxml(repo, stdin); - repo_write(repo, stdout); + repo_write(repo, stdout, 0, 0); pool_free(pool); exit(0); } diff --git a/tools/repo_susetags.c b/tools/repo_susetags.c index a2bc1fa..d5e54fc 100644 --- a/tools/repo_susetags.c +++ b/tools/repo_susetags.c @@ -14,7 +14,9 @@ #include "pool.h" #include "repo.h" +#if 0 #include "attr_store.h" +#endif #include "repo_susetags.h" static int @@ -40,6 +42,7 @@ split(char *l, char **sp, int m) struct parsedata { char *kind; Repo *repo; + Repodata *data; char *tmp; int tmpl; char **sources; @@ -140,7 +143,9 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id ma return repo_addid_dep(pd->repo, olddeps, id, marker); } +#if 0 Attrstore *attr; +#endif static Id id_authors; static Id id_description; static Id id_diskusage; @@ -162,7 +167,7 @@ static Id id_summary; static Id id_time; static void -add_location (char *line, Solvable *s, unsigned entry) +add_location(struct parsedata *pd, char *line, Solvable *s, unsigned entry) { Pool *pool = s->repo->pool; char *sp[3]; @@ -182,9 +187,15 @@ add_location (char *line, Solvable *s, unsigned entry) { /* medianr filename dir don't optimize this one */ +#if 0 add_attr_special_int (attr, entry, id_medianr, atoi (sp[0])); add_attr_localids_id (attr, entry, id_mediadir, str2localid (attr, sp[2], 1)); add_attr_string (attr, entry, id_mediafile, sp[1]); +#else + repodata_set_constant(pd->data, entry, id_medianr, atoi(sp[0])); + repodata_set_poolstr(pd->data, entry, id_mediadir, sp[2]); + repodata_set_str(pd->data, entry, id_mediafile, sp[1]); +#endif return; } else @@ -213,19 +224,30 @@ add_location (char *line, Solvable *s, unsigned entry) break; if (*n2 || strcmp (n1, ".rpm")) goto nontrivial; +#if 0 add_attr_special_int (attr, entry, id_medianr, medianr); add_attr_void (attr, entry, id_mediafile); +#else + repodata_set_constant(pd->data, entry, id_medianr, medianr); + repodata_set_void(pd->data, entry, id_mediafile); +#endif return; nontrivial: +#if 0 add_attr_special_int (attr, entry, id_medianr, medianr); add_attr_string (attr, entry, id_mediafile, sp[1]); +#else + repodata_set_constant(pd->data, entry, id_medianr, medianr); + repodata_set_str(pd->data, entry, id_mediafile, sp[1]); +#endif return; } } +#if 0 static void -add_source (char *line, struct parsedata *pd, Solvable *s, unsigned entry, int first) +add_source(struct parsedata *pd, char *line, Solvable *s, unsigned entry, int first) { Repo *repo = s->repo; Pool *pool = repo->pool; @@ -245,7 +267,9 @@ add_source (char *line, struct parsedata *pd, Solvable *s, unsigned entry, int f (src or nosrc), code only that fact. */ if (s->name == name && s->evr == evr && (arch == ARCH_SRC || arch == ARCH_NOSRC)) - add_attr_void (attr, entry, arch == ARCH_SRC ? id_source : id_nosource); + { + add_attr_void (attr, entry, arch == ARCH_SRC ? id_source : id_nosource); + } else if (first) { if (entry >= pd->nsources) @@ -296,6 +320,7 @@ add_source (char *line, struct parsedata *pd, Solvable *s, unsigned entry, int f } } } +#endif static void add_dirline (struct parsedata *pd, char *line) @@ -303,18 +328,18 @@ add_dirline (struct parsedata *pd, char *line) char *sp[6]; if (split (line, sp, 6) != 5) return; - if (!(pd->ndirs & 31)) - { - if (pd->dirs) - pd->dirs = realloc (pd->dirs, (pd->ndirs + 32) * sizeof (pd->dirs[0])); - else - pd->dirs = malloc ((pd->ndirs + 32) * sizeof (pd->dirs[0])); - } + pd->dirs = sat_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31); long filesz = strtol (sp[1], 0, 0); filesz += strtol (sp[2], 0, 0); long filenum = strtol (sp[3], 0, 0); filenum += strtol (sp[4], 0, 0); - unsigned dirid = dir_lookup (attr, sp[0], 1); + /* hack: we know that there's room for a / */ + if (*sp[0] != '/') + *--sp[0] = '/'; + unsigned dirid = repodata_str2dir(pd->data, sp[0], 1); +#if 0 +fprintf(stderr, "%s -> %d\n", sp[0], dirid); +#endif pd->dirs[pd->ndirs][0] = dirid; pd->dirs[pd->ndirs][1] = filesz; pd->dirs[pd->ndirs][2] = filenum; @@ -333,6 +358,7 @@ static void commit_diskusage (struct parsedata *pd, unsigned entry) { unsigned i; + Dirpool *dp = &pd->data->dirpool; /* Now sort in dirid order. This ensures that parents come before their children. */ if (pd->ndirs > 1) @@ -343,9 +369,9 @@ commit_diskusage (struct parsedata *pd, unsigned entry) the array moving to the start, hence seeing leafs before parents. */ for (i = pd->ndirs; i--;) { - unsigned p = dir_parent (attr, pd->dirs[i][0]); + unsigned p = dirpool_parent(dp, pd->dirs[i][0]); unsigned j = i; - for (; p; p = dir_parent (attr, p)) + for (; p; p = dirpool_parent(dp, p)) { for (; j--;) if (pd->dirs[j][0] == p) @@ -382,13 +408,17 @@ commit_diskusage (struct parsedata *pd, unsigned entry) for (i = 0; i < pd->ndirs; i++) if (pd->dirs[i][1] || pd->dirs[i][2]) { + repodata_add_dirnumnum(pd->data, entry, id_diskusage, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]); +#if 0 add_attr_intlist_int (attr, entry, id_diskusage, pd->dirs[i][0]); add_attr_intlist_int (attr, entry, id_diskusage, pd->dirs[i][1]); add_attr_intlist_int (attr, entry, id_diskusage, pd->dirs[i][2]); +#endif } pd->ndirs = 0; } + /* Unfortunately "a"[0] is no constant expression in the C languages, so we need to pass the four characters individually :-/ */ #define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \ @@ -416,10 +446,15 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) int last_found_pack = 0; char *sp[5]; struct parsedata pd; + Repodata *data = 0; +#if 1 if (with_attr) { +#if 0 attr = new_store(pool); +#endif + data = repo_add_repodata(repo); id_authors = str2id (pool, "authors", 1); id_description = str2id (pool, "description", 1); id_diskusage = str2id (pool, "diskusage", 1); @@ -440,12 +475,14 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) id_summary = str2id (pool, "summary", 1); id_time = str2id (pool, "time", 1); } +#endif memset(&pd, 0, sizeof(pd)); line = malloc(1024); aline = 1024; pd.repo = repo; + pd.data = data; linep = line; s = 0; @@ -538,6 +575,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) pd.kind = "pattern"; s = pool_id2solvable(pool, repo_add_solvable(repo)); last_found_pack = (s - pool->solvables) - repo->start; + if (data) + repodata_extend(data, s - pool->solvables); if (split(line + 5, sp, 5) != 4) { fprintf(stderr, "Bad line: %s\n", line); @@ -558,7 +597,6 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) { if (s && pd.ndirs) commit_diskusage (&pd, last_found_pack); - Id name, evr, arch; int n, nn; pd.kind = 0; @@ -654,52 +692,99 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) switch (tag) { case CTAG('=', 'G', 'r', 'p'): + repodata_set_poolstr(data, last_found_pack, id_group, line + 6); +#if 0 add_attr_localids_id (attr, last_found_pack, id_group, str2localid (attr, line + 6, 1)); +#endif continue; case CTAG('=', 'L', 'i', 'c'): + repodata_set_poolstr(data, last_found_pack, id_license, line + 6); +#if 0 add_attr_localids_id (attr, last_found_pack, id_license, str2localid (attr, line + 6, 1)); +#endif continue; case CTAG('=', 'L', 'o', 'c'): - add_location (line + 6, s, last_found_pack); + add_location(&pd, line + 6, s, last_found_pack); continue; +#if 0 case CTAG('=', 'S', 'r', 'c'): - add_source (line + 6, &pd, s, last_found_pack, 1); + add_source(&pd, line + 6, s, last_found_pack, 1); continue; +#endif case CTAG('=', 'S', 'i', 'z'): if (split (line + 6, sp, 3) == 2) { + repodata_set_num(data, last_found_pack, id_downloadsize, (atoi(sp[0]) + 1023) / 1024); + repodata_set_num(data, last_found_pack, id_installsize, (atoi(sp[1]) + 1023) / 1024); +#if 0 add_attr_int (attr, last_found_pack, id_downloadsize, (atoi (sp[0]) + 1023) / 1024); add_attr_int (attr, last_found_pack, id_installsize, (atoi (sp[1]) + 1023) / 1024); +#endif } continue; case CTAG('=', 'T', 'i', 'm'): { unsigned int t = atoi (line + 6); if (t) - add_attr_int (attr, last_found_pack, id_time, t); + { +#if 0 + add_attr_int (attr, last_found_pack, id_time, t); +#else + repodata_set_num(data, last_found_pack, id_time, t); +#endif + } } continue; case CTAG('=', 'K', 'w', 'd'): +#if 0 add_attr_localids_id (attr, last_found_pack, id_keywords, str2localid (attr, line + 6, 1)); +#else + repodata_set_poolstr(data, last_found_pack, id_keywords, line + 6); +#endif continue; case CTAG('=', 'A', 'u', 't'): +#if 0 add_attr_blob (attr, last_found_pack, id_authors, line + 6, strlen (line + 6) + 1); +#else + repodata_set_str(data, last_found_pack, id_authors, line + 6); +#endif continue; case CTAG('=', 'S', 'u', 'm'): +#if 0 add_attr_string (attr, last_found_pack, id_summary, line + 6); +#else + repodata_set_str(data, last_found_pack, id_summary, line + 6); +#endif continue; case CTAG('=', 'D', 'e', 's'): +#if 0 add_attr_blob (attr, last_found_pack, id_description, line + 6, strlen (line + 6) + 1); +#else + repodata_set_str(data, last_found_pack, id_description, line + 6); +#endif continue; case CTAG('=', 'E', 'u', 'l'): +#if 0 add_attr_blob (attr, last_found_pack, id_eula, line + 6, strlen (line + 6) + 1); +#else + repodata_set_str(data, last_found_pack, id_eula, line + 6); +#endif continue; case CTAG('=', 'I', 'n', 's'): +#if 0 add_attr_blob (attr, last_found_pack, id_messageins, line + 6, strlen (line + 6) + 1); +#else + repodata_set_str(data, last_found_pack, id_messageins, line + 6); +#endif continue; case CTAG('=', 'D', 'e', 'l'): +#if 0 add_attr_blob (attr, last_found_pack, id_messagedel, line + 6, strlen (line + 6) + 1); +#else + repodata_set_str(data, last_found_pack, id_messagedel, line + 6); +#endif continue; +#if 0 case CTAG('=', 'S', 'h', 'r'): if (last_found_pack >= pd.nshare) { @@ -714,6 +799,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) } pd.share_with[last_found_pack] = strdup (line + 6); continue; +#endif case CTAG('=', 'D', 'i', 'r'): add_dirline (&pd, line + 6); continue; @@ -727,16 +813,18 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); if (s) s->supplements = repo_fix_legacy(repo, s->provides, s->supplements); + if (s && pd.ndirs) - commit_diskusage (&pd, last_found_pack); + commit_diskusage(&pd, last_found_pack); +#if 0 if (pd.sources) { int i, last_found; for (i = 0; i < pd.nsources; i++) if (pd.sources[i]) { - add_source (pd.sources[i], &pd, pool->solvables + repo->start + i, i, 0); + add_source(&pd, pd.sources[i], pool->solvables + repo->start + i, i, 0); free (pd.sources[i]); } free (pd.sources); @@ -776,6 +864,11 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr) } free (pd.share_with); } +#endif + + if (data) + repodata_internalize(data); + if (pd.tmp) free(pd.tmp); free(line); diff --git a/tools/repo_write.c b/tools/repo_write.c index 4895aa8..78a56ab 100644 --- a/tools/repo_write.c +++ b/tools/repo_write.c @@ -27,8 +27,6 @@ #include "util.h" #include "repo_write.h" -/* #define IGNORE_NEED_FREQUENCY */ - /*------------------------------------------------------------------*/ /* Id map optimizations */ @@ -38,7 +36,7 @@ typedef struct needid { } NeedId; -#define RELOFF(id) (pool->ss.nstrings + GETRELID(id)) +#define RELOFF(id) (needid[0].map + GETRELID(id)) /* * increment need Id @@ -49,15 +47,30 @@ typedef struct needid { * */ -static int -incneedid(Pool *pool, Id *idarray, NeedId *needid) +static void +incneedid(Pool *pool, Id id, NeedId *needid) { - if (!idarray) - return 0; + while (ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + needid[RELOFF(id)].need++; + if (ISRELDEP(rd->evr)) + incneedid(pool, rd->evr, needid); + else + needid[rd->evr].need++; + id = rd->name; + } + needid[id].need++; +} +static int +incneedidarray(Pool *pool, Id *idarray, NeedId *needid) +{ Id id; int n = 0; + if (!idarray) + return 0; while ((id = *idarray++) != 0) { n++; @@ -66,12 +79,7 @@ incneedid(Pool *pool, Id *idarray, NeedId *needid) Reldep *rd = GETRELDEP(pool, id); needid[RELOFF(id)].need++; if (ISRELDEP(rd->evr)) - { - Id ida[2]; - ida[0] = rd->evr; - ida[1] = 0; - incneedid(pool, ida, needid); - } + incneedid(pool, rd->evr, needid); else needid[rd->evr].need++; id = rd->name; @@ -99,34 +107,24 @@ needid_cmp_need(const void *ap, const void *bp) } static Pool *cmp_pool; + static int needid_cmp_need_s(const void *ap, const void *bp) { const NeedId *a = ap; const NeedId *b = bp; - if (a == b) - return 0; -#ifdef IGNORE_NEED_FREQUENCY - if (a->need == 0) - return 1; - else if (b->need == 0) - return -1; -#else int r; r = b->need - a->need; if (r) return r; -#endif - char *as = cmp_pool->ss.stringspace + cmp_pool->ss.strings[a->map]; - char *bs = cmp_pool->ss.stringspace + cmp_pool->ss.strings[b->map]; - size_t alen = strlen (as); - size_t blen = strlen (bs); - return memcmp (as, bs, alen < blen ? alen + 1 : blen + 1); + const char *as = cmp_pool->ss.stringspace + cmp_pool->ss.strings[a->map]; + const char *bs = cmp_pool->ss.stringspace + cmp_pool->ss.strings[b->map]; + return strcmp(as, bs); } /*------------------------------------------------------------------*/ -/* output routines */ +/* output helper routines */ /* * unsigned 32-bit @@ -160,6 +158,19 @@ write_u8(FILE *fp, unsigned int x) } } +/* + * data blob + */ + +static void +write_blob(FILE *fp, void *data, int len) +{ + if (fwrite(data, len, 1, fp) != 1) + { + perror("write error"); + exit(1); + } +} /* * Id @@ -185,16 +196,17 @@ write_id(FILE *fp, Id x) } } +#if 0 static void write_str(FILE *fp, const char *str) { - if (fputs (str, fp) == EOF - || putc (0, fp) == EOF) + if (fputs (str, fp) == EOF || putc (0, fp) == EOF) { perror("write error"); exit(1); } } +#endif /* * Array of Ids @@ -239,50 +251,52 @@ static void write_idarray_sort(FILE *fp, Pool *pool, NeedId *needid, Id *ids) { int len, i; + Id lids[64], *sids; + if (!ids) return; if (!*ids) { - write_u8 (fp, 0); + write_u8(fp, 0); return; } - /* If we ever share idarrays we can't do this in-place. */ - for (len = 0; ids[len]; len++) + for (len = 0; len < 64 && ids[len]; len++) { Id id = ids[len]; if (needid) - ids[len] = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + lids[len] = id; + } + if (ids[len]) + { + for (i = len + 1; ids[i]; i++) + ; + sids = sat_malloc2(i, sizeof(Id)); + memcpy(sids, lids, 64 * sizeof(Id)); + for (; ids[len]; len++) + { + Id id = ids[len]; + if (needid) + id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + sids[len] = id; + } } + else + sids = lids; /* That bloody solvable:prereqmarker needs to stay in position :-( */ Id prereq = SOLVABLE_PREREQMARKER; if (needid) prereq = needid[prereq].need; for (i = 0; i < len; i++) - if (ids[i] == prereq) + if (sids[i] == prereq) break; if (i > 1) - qsort (ids, i, sizeof (Id), cmp_ids); + qsort(sids, i, sizeof (Id), cmp_ids); if ((len - i) > 2) - qsort (ids + i + 1, len - i - 1, sizeof (Id), cmp_ids); + qsort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids); - Id old = 0; - for (i = 0; i < len; i++) - /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker, - hence all real differences are offsetted by 1. Otherwise we would - have to handle negative differences, which would cost code space for - the encoding of the sign. We loose the exact mapping of prereq here, - but we know the result, so we can recover from that in the reader. */ - if (ids[i] == prereq) - old = ids[i] = 0; - else - { - ids[i] -= old; - old = ids[i] + old; - /* XXX If difference is zero we have multiple equal elements, - we might want to skip writing them out. */ - ids[i]++; - } + Id id, old = 0; /* The differencing above produces many runs of ones and twos. I tried fairly elaborate schemes to RLE those, but they give only very mediocre @@ -292,15 +306,35 @@ write_idarray_sort(FILE *fp, Pool *pool, NeedId *needid, Id *ids) invest some complexity into sharing idarrays, than RLEing. */ for (i = 0; i < len - 1; i++) { - Id id = ids[i]; + id = sids[i]; + /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker, + hence all real differences are offsetted by 1. Otherwise we would + have to handle negative differences, which would cost code space for + the encoding of the sign. We loose the exact mapping of prereq here, + but we know the result, so we can recover from that in the reader. */ + if (id == prereq) + id = old = 0; + else + { + id = id - old + 1; + old = sids[i]; + } + /* XXX If difference is zero we have multiple equal elements, + we might want to skip writing them out. */ if (id >= 64) id = (id & 63) | ((id & ~63) << 1); write_id(fp, id | 64); } - old = ids[i]; - if (old >= 64) - old = (old & 63) | ((old & ~63) << 1); - write_id(fp, old); + id = sids[i]; + if (id == prereq) + id = 0; + else + id = id - old + 1; + if (id >= 64) + id = (id & 63) | ((id & ~63) << 1); + write_id(fp, id); + if (sids != lids) + sat_free(sids); } static inline void @@ -314,171 +348,785 @@ write_id_value(FILE *fp, Id id, Id value, int eof) write_id(fp, value | (eof ? 0 : 64)); } -struct schemata { - int nschemata; - Id *schemadata, *schemadatap; - int schemadatafree; - Id lastschema[256]; - Id lastschemakey[256]; +struct extdata { + unsigned char *buf; + int len; +}; + +struct cbdata { + Repo *repo; + + Stringpool *ownspool; + Dirpool *owndirpool; + + Repokey *mykeys; + int nmykeys; + + Id *keymap; + int nkeymap; + Id *keymapstart; + + NeedId *needid; + + Id *schema; /* schema construction space */ + Id *sp; /* pointer in above */ + + Id *myschemata; + int nmyschemata; + + Id *myschemadata; + int myschemadatalen; + + Id schematacache[256]; + + Id *solvschemata; + Id *incorelen; + + struct extdata *extdata; + + Id *dirused; + Id *dirmap; + + Id vstart; }; +#define NEEDED_BLOCK 1023 +#define SCHEMATA_BLOCK 31 +#define SCHEMATADATA_BLOCK 255 +#define EXTDATA_BLOCK 1023 + +void +data_addid(struct extdata *xd, Id x) +{ + unsigned char *dp; + xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK); + dp = xd->buf + xd->len; + + if (x >= (1 << 14)) + { + if (x >= (1 << 28)) + *dp++ = (x >> 28) | 128; + if (x >= (1 << 21)) + *dp++ = (x >> 21) | 128; + *dp++ = (x >> 14) | 128; + } + if (x >= (1 << 7)) + *dp++ = (x >> 7) | 128; + *dp++ = x & 127; + xd->len = dp - xd->buf; +} + +void +data_addideof(struct extdata *xd, Id x, int eof) +{ + if (x >= 64) + x = (x & 63) | ((x & ~63) << 1); + data_addid(xd, (eof ? x: x | 64)); +} + +void +data_addblob(struct extdata *xd, unsigned char *blob, int len) +{ + xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK); + memcpy(xd->buf + xd->len, blob, len); + xd->len += len; +} + static Id -addschema(struct schemata *schemata, Id *schema) +addschema(struct cbdata *cbdata, Id *schema) { int h, len; - Id *sp, schemaid; + Id *sp, cid; for (sp = schema, len = 0, h = 0; *sp; len++) h = h * 7 + *sp++; h &= 255; len++; - if (schemata->lastschema[h] && !memcmp(schemata->schemadata + schemata->lastschema[h], schema, len * sizeof(Id))) - return schemata->lastschemakey[h]; - schemaid = 0; - for (sp = schemata->schemadata + 1; sp < schemata->schemadatap; ) + cid = cbdata->schematacache[h]; + if (cid) { - if (!memcmp(sp, schemata->schemadatap, len * sizeof(Id))) - return schemaid; - while (*sp++) - ; - schemaid++; + if (!memcmp(cbdata->myschemadata + cbdata->myschemata[cid], schema, len * sizeof(Id))) + return cid; + /* cache conflict */ + for (cid = 1; cid < cbdata->nmyschemata; cid++) + if (!memcmp(cbdata->myschemadata + cbdata->myschemata[cid], schema, len * sizeof(Id))) + return cid; + } + /* a new one. make room. */ + cbdata->myschemadata = sat_extend(cbdata->myschemadata, cbdata->myschemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK); + cbdata->myschemata = sat_extend(cbdata->myschemata, cbdata->nmyschemata, 1, sizeof(Id), SCHEMATA_BLOCK); + if (!cbdata->nmyschemata) + { + cbdata->myschemata[0] = 0; + cbdata->myschemadata[0] = 0; + cbdata->nmyschemata = 1; + cbdata->myschemadatalen = 1; + } + /* add schema */ + memcpy(cbdata->myschemadata + cbdata->myschemadatalen, schema, len * sizeof(Id)); + cbdata->myschemata[cbdata->nmyschemata] = cbdata->myschemadatalen; + cbdata->myschemadatalen += len; + cbdata->schematacache[h] = cbdata->nmyschemata; + return cbdata->nmyschemata++; +} + +static Id +putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id) +{ + const char *str = stringpool_id2str(ss, id); + id = stringpool_str2id(cbdata->ownspool, str, 1); + if (id >= cbdata->needid[0].map) + { + int oldoff = cbdata->needid[0].map; + int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK; + int nrels = cbdata->repo->pool->nrels; + fprintf(stderr, "growing needid...\n"); + cbdata->needid = sat_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId)); + if (nrels) + memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId)); + memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId)); + cbdata->needid[0].map = newoff; } + return id; +} + +Id +putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir) +{ + Id compid, parent; + + parent = dirpool_parent(dp, dir); + if (parent) + parent = putinowndirpool(cbdata, data, dp, parent); + compid = dp->dirs[dir]; + if (cbdata->ownspool && compid > 1) + compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid); + return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1); +} + +static inline void +setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir) +{ + if (cbdata->dirused[dir]) + return; + cbdata->dirused[dir] = 1; + while ((dir = dirpool_parent(dp, dir)) != 0) + { + if (cbdata->dirused[dir] == 2) + return; + if (cbdata->dirused[dir]) + { + cbdata->dirused[dir] = 2; + return; + } + cbdata->dirused[dir] = 2; + } + cbdata->dirused[0] = 2; +} + +int +repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) +{ + struct cbdata *cbdata = vcbdata; + Repo *repo = s ? s->repo : 0; + Id id; + int rm; - /* a new one */ - if (len > schemata->schemadatafree) +#if 0 + fprintf(stderr, "solvable %d (%s): key %d %d\n", s ? s - s->repo->pool->solvables : 0, s ? id2str(s->repo->pool, s->name) : "", key->name, key->type); +#endif + rm = cbdata->keymap[cbdata->keymapstart[data->repo->repodata - data] + (key - data->keys)]; + if (!rm) + return SEARCH_NEXT_KEY; /* we do not want this one */ + if (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm) + *cbdata->sp++ = rm; + switch(key->type) { - int l = schemata->schemadatap - schemata->schemadata; - schemata->schemadata = sat_realloc(schemata->schemadata, (schemata->schemadatap - schemata->schemadata + len + 256) * sizeof(Id)); - schemata->schemadatafree = len + 256; - schemata->schemadatap = schemata->schemadata + l; - if (l == 0) + case TYPE_ID: + case TYPE_IDARRAY: + id = kv->id; + if (!ISRELDEP(id) && cbdata->ownspool && id > 1) + id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id); + incneedid(repo->pool, id, cbdata->needid); + break; + case TYPE_DIR: + case TYPE_DIRNUMNUMARRAY: + id = kv->id; + if (cbdata->owndirpool) + putinowndirpool(cbdata, data, &data->dirpool, id); + else + setdirused(cbdata, &data->dirpool, id); + break; + default: + break; + } + return 0; +} + +int +repo_write_cb_sizes(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) +{ + struct cbdata *cbdata = vcbdata; + int rm; + Id id; + unsigned int u32; + unsigned char v[4]; + struct extdata *xd; + + rm = cbdata->keymap[cbdata->keymapstart[data->repo->repodata - data] + (key - data->keys)]; + if (!rm) + return 0; /* we do not want this one */ + + if (cbdata->mykeys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET) + { + xd = cbdata->extdata + rm; /* vertical buffer */ + if (!cbdata->vstart) + cbdata->vstart = xd->len; + } + else + xd = cbdata->extdata + 0; /* incore buffer */ + switch(key->type) + { + case TYPE_VOID: + case TYPE_CONSTANT: + break; + case TYPE_ID: + id = kv->id; + if (!ISRELDEP(id) && cbdata->ownspool && id > 1) + id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id); + id = cbdata->needid[id].need; + data_addid(xd, id); + break; + case TYPE_IDARRAY: + id = kv->id; + if (cbdata->ownspool && id > 1) + id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id); + id = cbdata->needid[id].need; + data_addideof(xd, id, kv->eof); + break; + case TYPE_STR: + data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1); + break; + case TYPE_U32: + u32 = kv->num; + v[0] = u32 >> 24; + v[1] = u32 >> 16; + v[2] = u32 >> 8; + v[3] = u32; + data_addblob(xd, v, 4); + break; + case TYPE_DIR: + id = kv->id; + id = cbdata->dirused[id]; + data_addid(xd, id); + break; + case TYPE_NUM: + data_addid(xd, kv->num); + break; + case TYPE_DIRNUMNUMARRAY: + id = kv->id; + id = cbdata->dirused[id]; + data_addid(xd, id); + data_addid(xd, kv->num); + data_addideof(xd, kv->num2, kv->eof); + break; + case TYPE_DIRSTRARRAY: + id = kv->id; + id = cbdata->dirused[id]; + data_addideof(xd, id, kv->eof); + data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1); + break; + default: + fprintf(stderr, "unknown type for %d: %d\n", key->name, key->type); + exit(1); + } + if (cbdata->mykeys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof) + { + data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */ + data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */ + cbdata->vstart = 0; + } + return 0; +} + +static int +traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used) +{ + Id sib, child; + Id parent, lastn; + + parent = n; + /* special case for '/', which has to come first */ + if (parent == 1) + dirmap[n++] = 1; + for (sib = dir; sib; sib = dirpool_sibling(dp, sib)) + { + if (used && !used[sib]) + continue; + if (sib == 1 && parent == 1) + continue; /* already did that one above */ + dirmap[n++] = sib; + } + lastn = n; + for (; parent < lastn; parent++) + { + sib = dirmap[parent]; + if (used && used[sib] != 2) + continue; + child = dirpool_child(dp, sib); + if (child) { - /* leave first one free so that our lastschema test works */ - *schemata->schemadatap++ = 0; - schemata->schemadatafree--; + dirmap[n++] = -parent; + n = traverse_dirs(dp, dirmap, n, child, used); } } - if (schemaid != schemata->nschemata) - abort(); - schemata->lastschema[h] = schemata->schemadatap - schemata->schemadata; - schemata->lastschemakey[h] = schemaid; - memcpy(schemata->schemadatap, schema, len * sizeof(Id)); - schemata->schemadatafree -= len; - schemata->schemadatap += len; - schemata->nschemata++; - return schemaid; + return n; } +#define BLOB_PAGEBITS 15 +#define BLOB_PAGESIZE (1 << BLOB_PAGEBITS) + +static void +write_compressed_page(FILE *fp, unsigned char *page, int len) +{ + int clen; + unsigned char cpage[BLOB_PAGESIZE]; + + clen = repodata_compress_page(page, len, cpage, len - 1); + if (!clen) + { + write_u32(fp, len * 2); + write_blob(fp, page, len); + } + else + { + write_u32(fp, clen * 2 + 1); + write_blob(fp, cpage, clen); + } +} /* * Repo */ void -repo_write(Repo *repo, FILE *fp) +repo_write(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata) { Pool *pool = repo->pool; - int i, n; + int i, j, k, n; Solvable *s; NeedId *needid; - int nstrings, nrels, nkeys; + int nstrings, nrels; unsigned int sizeid; unsigned int solv_flags; Reldep *ran; Id *idarraydata; - int idsizes[ID_NUM_INTERNAL]; - int id2key[ID_NUM_INTERNAL]; - int nsolvables; + Id id, *sp; - Id schema[ID_NUM_INTERNAL], *sp; - struct schemata schemata; - Id *solvschema; /* schema of our solvables */ - Id repodataschema, repodataschema_internal; + Id *dirmap; + int ndirmap; + Id *keyused; + int ext0len; + unsigned char *repodataused; + + struct cbdata cbdata; + int needrels; + Repokey *key; + int poolusage, dirpoolusage, idused, dirused; + int reloff; + unsigned char *incoredata; - nsolvables = 0; - idarraydata = repo->idarraydata; + Repodata *data; + Stringpool ownspool, *spool; + Dirpool owndirpool, *dirpool; + + memset(&cbdata, 0, sizeof(cbdata)); + + /* go through all repodata and find the keys we need */ + /* also unify keys */ + /* creates: mykeys - key array, still has global pool ids */ + /* keymapstart - maps repo number to keymap offset */ + /* keymap - maps repo key to my key, 0 -> not used */ - needid = sat_calloc(pool->ss.nstrings + pool->nrels, sizeof(*needid)); - memset(idsizes, 0, sizeof(idsizes)); + /* start with all KEY_STORAGE_SOLVABLE ids */ - repodataschema = repodataschema_internal = 0; + n = ID_NUM_INTERNAL; for (i = 0; i < repo->nrepodata; i++) + n += repo->repodata[i].nkeys; + cbdata.mykeys = sat_calloc(n, sizeof(Repokey)); + cbdata.keymap = sat_calloc(n, sizeof(Id)); + cbdata.keymapstart = sat_calloc(repo->nrepodata, sizeof(Id)); + repodataused = sat_calloc(repo->nrepodata, 1); + + cbdata.nmykeys = 1; + needrels = 0; + poolusage = 0; + for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++) { - int j; - idsizes[REPODATA_EXTERNAL] = 1; - idsizes[REPODATA_KEYS]++; - if (repo->repodata[i].location) + key = cbdata.mykeys + i; + key->name = i; + if (i < SOLVABLE_PROVIDES) + key->type = TYPE_ID; + else if (i < RPM_RPMDBID) + key->type = TYPE_REL_IDARRAY; + else + key->type = TYPE_U32; + key->size = 0; + key->storage = KEY_STORAGE_SOLVABLE; + if (keyfilter) { - repodataschema = 1; /* mark that we need it */ - idsizes[REPODATA_LOCATION] = 1; + key->storage = keyfilter(repo, key, kfdata); + if (key->storage == KEY_STORAGE_DROPPED) + continue; + key->storage = KEY_STORAGE_SOLVABLE; + } + poolusage = 1; + if (key->type == TYPE_IDARRAY || key->type == TYPE_REL_IDARRAY) + needrels = 1; + cbdata.keymap[i] = i; + } + cbdata.nmykeys = i; + + dirpoolusage = 0; + + spool = 0; + dirpool = 0; + n = ID_NUM_INTERNAL; + for (i = 0; i < repo->nrepodata; i++) + { + data = repo->repodata + i; + cbdata.keymapstart[i] = n; + cbdata.keymap[n++] = 0; /* key 0 */ + idused = 0; + dirused = 0; + for (j = 1; j < data->nkeys; j++) + { + key = data->keys + j; + /* see if we already had this one, should use hash for fast miss */ + for (k = 0; k < cbdata.nmykeys; k++) + { + if (key->name == cbdata.mykeys[k].name && key->type == cbdata.mykeys[k].type) + { + if (key->type == TYPE_CONSTANT && key->size != cbdata.mykeys[k].size) + continue; + break; + } + } + if (k < cbdata.nmykeys) + { + cbdata.keymap[n++] = 0; + continue; + } + cbdata.mykeys[cbdata.nmykeys] = *key; + key = cbdata.mykeys + cbdata.nmykeys; + key->storage = KEY_STORAGE_INCORE; + if (key->type != TYPE_CONSTANT) + key->size = 0; + if (keyfilter) + { + key->storage = keyfilter(repo, key, kfdata); + if (key->storage == KEY_STORAGE_DROPPED) + { + cbdata.keymap[n++] = 0; + continue; + } + } + /* load repodata if not already loaded */ + if (data->state == REPODATA_STUB) + { + if (data->loadcallback) + data->loadcallback(data); + else + data->state = REPODATA_ERROR; + if (data->state != REPODATA_ERROR) + { + /* redo this repodata! */ + j = 0; + n = cbdata.keymapstart[i] + 1; + continue; + } + } + if (data->state == REPODATA_ERROR) + { + /* too bad! */ + cbdata.keymap[n++] = 0; + continue; + } + cbdata.keymap[n++] = cbdata.nmykeys++; + repodataused[i] = 1; + if (key->type != TYPE_STR && key->type != TYPE_U32) + idused = 1; + if (key->type == TYPE_DIR || key->type == TYPE_DIRNUMNUMARRAY) + dirused = 1; + } + if (idused) + { + if (data->localpool) + { + if (poolusage) + poolusage = 3; /* need local pool */ + else + { + poolusage = 2; + spool = &data->spool; + } + } + else + { + if (poolusage == 0) + poolusage = 1; + else if (poolusage != 1) + poolusage = 3; /* need local pool */ + } + } + if (dirused) + { + if (dirpoolusage) + dirpoolusage = 3; /* need local dirpool */ + else + { + dirpoolusage = 2; + dirpool = &data->dirpool; + } + } + } + cbdata.nkeymap = n; + + /* 0: no pool needed at all */ + /* 1: use global pool */ + /* 2: use repodata local pool */ + /* 3: need own pool */ + if (poolusage == 3) + { + spool = &ownspool; + if (needrels) + { + /* hack: reuse global pool so we don't have to map rel ids */ + stringpool_clone(spool, &repo->pool->ss); } else - repodataschema_internal = 1; /* mark that we need it */ - for (j = 0; j < repo->repodata[i].nkeys; j++) - needid[repo->repodata[i].keys[j].name].need++; - idsizes[REPODATA_KEYS] += 2 * repo->repodata[i].nkeys; + stringpool_init_empty(spool); + cbdata.ownspool = spool; + } + else if (poolusage == 0 || poolusage == 1) + { + poolusage = 1; + spool = &repo->pool->ss; } - idsizes[SOLVABLE_NAME] = 1; - idsizes[SOLVABLE_ARCH] = 1; - idsizes[SOLVABLE_EVR] = 1; - if (repo->rpmdbid) - idsizes[RPM_RPMDBID] = 1; - for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++) + if (dirpoolusage == 3) + { + dirpool = &owndirpool; + dirpool_create(dirpool); + cbdata.owndirpool = dirpool; + } + else if (dirpool) + cbdata.dirused = sat_calloc(dirpool->ndirs, sizeof(Id)); + + +/********************************************************************/ +#if 0 +fprintf(stderr, "poolusage: %d\n", poolusage); +fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage); +fprintf(stderr, "nmykeys: %d\n", cbdata.nmykeys); +for (i = 1; i < cbdata.nmykeys; i++) + fprintf(stderr, " %2d: %d %d\n", i, cbdata.mykeys[i].name, cbdata.mykeys[i].type); +#endif + +/********************************************************************/ + + /* set needed count of all strings and rels, + * find which keys are used in the solvables + * put all strings in own spool + */ + + reloff = spool->nstrings; + if (poolusage == 3) + reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK; + + needid = calloc(reloff + pool->nrels, sizeof(*needid)); + needid[0].map = reloff; + + cbdata.needid = needid; + cbdata.schema = sat_calloc(cbdata.nmykeys, sizeof(Id)); + cbdata.sp = cbdata.schema; + cbdata.solvschemata = sat_calloc(repo->nsolvables, sizeof(Id)); + + idarraydata = repo->idarraydata; + + for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) { if (s->repo != repo) continue; - nsolvables++; - needid[s->name].need++; - needid[s->arch].need++; - needid[s->evr].need++; - if (s->vendor) + + /* set schema info, keep in sync with further down */ + sp = cbdata.schema; + if (cbdata.keymap[SOLVABLE_NAME]) + { + *sp++ = SOLVABLE_NAME; + needid[s->name].need++; + } + if (cbdata.keymap[SOLVABLE_ARCH]) + { + *sp++ = SOLVABLE_ARCH; + needid[s->arch].need++; + } + if (cbdata.keymap[SOLVABLE_EVR]) + { + *sp++ = SOLVABLE_EVR; + needid[s->arch].need++; + } + if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR]) + { + *sp++ = SOLVABLE_VENDOR; + needid[s->vendor].need++; + } + if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES]) + { + *sp++ = SOLVABLE_PROVIDES; + cbdata.mykeys[SOLVABLE_PROVIDES].size += incneedidarray(pool, idarraydata + s->provides, needid); + } + if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES]) + { + *sp++ = SOLVABLE_OBSOLETES; + cbdata.mykeys[SOLVABLE_OBSOLETES].size += incneedidarray(pool, idarraydata + s->obsoletes, needid); + } + if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS]) + { + *sp++ = SOLVABLE_CONFLICTS; + cbdata.mykeys[SOLVABLE_CONFLICTS].size += incneedidarray(pool, idarraydata + s->conflicts, needid); + } + if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES]) + { + *sp++ = SOLVABLE_REQUIRES; + cbdata.mykeys[SOLVABLE_REQUIRES].size += incneedidarray(pool, idarraydata + s->requires, needid); + } + if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS]) + { + *sp++ = SOLVABLE_RECOMMENDS; + cbdata.mykeys[SOLVABLE_RECOMMENDS].size += incneedidarray(pool, idarraydata + s->recommends, needid); + } + if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS]) + { + *sp++ = SOLVABLE_SUGGESTS; + cbdata.mykeys[SOLVABLE_SUGGESTS].size += incneedidarray(pool, idarraydata + s->suggests, needid); + } + if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS]) + { + *sp++ = SOLVABLE_SUPPLEMENTS; + cbdata.mykeys[SOLVABLE_SUPPLEMENTS].size += incneedidarray(pool, idarraydata + s->supplements, needid); + } + if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES]) + { + *sp++ = SOLVABLE_ENHANCES; + cbdata.mykeys[SOLVABLE_ENHANCES].size += incneedidarray(pool, idarraydata + s->enhances, needid); + } + if (s->freshens && cbdata.keymap[SOLVABLE_FRESHENS]) + { + *sp++ = SOLVABLE_FRESHENS; + cbdata.mykeys[SOLVABLE_FRESHENS].size += incneedidarray(pool, idarraydata + s->freshens, needid); + } + if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID]) + { + *sp++ = RPM_RPMDBID; + cbdata.mykeys[RPM_RPMDBID].size++; + } + cbdata.sp = sp; + + for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++) + { + if (!repodataused[j]) + continue; + if (i < data->start || i >= data->end) + continue; + repodata_search(data, i - data->start, 0, repo_write_cb_needed, &cbdata); + needid = cbdata.needid; + } + *cbdata.sp = 0; + cbdata.solvschemata[n] = addschema(&cbdata, cbdata.schema); + n++; + } + + reloff = needid[0].map; + + +/********************************************************************/ + + /* remove unused keys, also increment needid for key names */ + keyused = sat_calloc(cbdata.nmykeys, sizeof(Id)); + for (i = 0; i < cbdata.myschemadatalen; i++) + keyused[cbdata.myschemadata[i]] = 1; + keyused[0] = 0; + for (n = i = 1; i < cbdata.nmykeys; i++) + { + if (!keyused[i]) + continue; + keyused[i] = n; + if (i != n) + cbdata.mykeys[n] = cbdata.mykeys[i]; + needid[cbdata.mykeys[n].name].need++; + n++; + } + cbdata.nmykeys = n; + for (i = 0; i < cbdata.myschemadatalen; i++) + cbdata.myschemadata[i] = keyused[cbdata.myschemadata[i]]; + for (i = 0; i < cbdata.nkeymap; i++) + cbdata.keymap[i] = keyused[cbdata.keymap[i]]; + keyused = sat_free(keyused); + +/********************************************************************/ + + /* increment need id for used dir components */ + if (cbdata.dirused && !cbdata.dirused[0]) + { + /* no dirs used at all */ +fprintf(stderr, "no dirs used!\n"); + sat_free(cbdata.dirused); + dirpool = 0; + } + if (dirpool) + { + for (i = 1; i < dirpool->ndirs; i++) { - needid[s->vendor].need++; - idsizes[SOLVABLE_VENDOR] = 1; +#if 0 +if (cbdata.dirused) + fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused[i]); +#endif + id = dirpool->dirs[i]; + if (id <= 0) + continue; + if (cbdata.dirused && !cbdata.dirused[i]) + continue; + needid[id].need++; } - if (s->provides) - idsizes[SOLVABLE_PROVIDES] += incneedid(pool, idarraydata + s->provides, needid); - if (s->requires) - idsizes[SOLVABLE_REQUIRES] += incneedid(pool, idarraydata + s->requires, needid); - if (s->conflicts) - idsizes[SOLVABLE_CONFLICTS] += incneedid(pool, idarraydata + s->conflicts, needid); - if (s->obsoletes) - idsizes[SOLVABLE_OBSOLETES] += incneedid(pool, idarraydata + s->obsoletes, needid); - if (s->recommends) - idsizes[SOLVABLE_RECOMMENDS] += incneedid(pool, idarraydata + s->recommends, needid); - if (s->suggests) - idsizes[SOLVABLE_SUGGESTS] += incneedid(pool, idarraydata + s->suggests, needid); - if (s->supplements) - idsizes[SOLVABLE_SUPPLEMENTS] += incneedid(pool, idarraydata + s->supplements, needid); - if (s->enhances) - idsizes[SOLVABLE_ENHANCES] += incneedid(pool, idarraydata + s->enhances, needid); - if (s->freshens) - idsizes[SOLVABLE_FRESHENS] += incneedid(pool, idarraydata + s->freshens, needid); - } - if (nsolvables != repo->nsolvables) - abort(); - - for (i = SOLVABLE_NAME; i < ID_NUM_INTERNAL; i++) - { - if (idsizes[i]) - needid[i].need++; } +/********************************************************************/ + + /* + * create mapping table, new keys are sorted by needid[].need + * + * needid[key].need : old key -> new key + * needid[key].map : new key -> old key + */ + + /* zero out id 0 and rel 0 just in case */ + needid[0].need = 0; - needid[pool->ss.nstrings].need = 0; - for (i = 0; i < pool->ss.nstrings + pool->nrels; i++) + needid[reloff].need = 0; + + for (i = 1; i < reloff + pool->nrels; i++) needid[i].map = i; cmp_pool = pool; - qsort(needid + 1, pool->ss.nstrings - 1, sizeof(*needid), needid_cmp_need_s); - qsort(needid + pool->ss.nstrings, pool->nrels, sizeof(*needid), needid_cmp_need); + qsort(needid + 1, reloff - 1, sizeof(*needid), needid_cmp_need_s); + qsort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need); sizeid = 0; - for (i = 1; i < pool->ss.nstrings; i++) + for (i = 1; i < reloff; i++) { if (!needid[i].need) break; @@ -487,103 +1135,93 @@ repo_write(Repo *repo, FILE *fp) } nstrings = i; - for (i = 0; i < nstrings; i++) + for (i = 1; i < nstrings; i++) needid[needid[i].map].need = i; for (i = 0; i < pool->nrels; i++) { - if (!needid[pool->ss.nstrings + i].need) + if (!needid[reloff + i].need) break; else - needid[pool->ss.nstrings + i].need = 0; + needid[reloff + i].need = 0; } nrels = i; for (i = 0; i < nrels; i++) + needid[needid[reloff + i].map].need = nstrings + i; + + +/********************************************************************/ + + /* create dir map */ + ndirmap = 0; + dirmap = 0; + if (dirpool) { - needid[needid[pool->ss.nstrings + i].map].need = nstrings + i; + if (cbdata.dirused && !cbdata.dirused[1]) + cbdata.dirused[1] = 1; /* always want / entry */ + dirmap = sat_calloc(dirpool->ndirs, sizeof(Id)); + dirpool_make_dirtraverse(dirpool); + dirmap[0] = 0; + ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused); + if (!cbdata.dirused) + cbdata.dirused = sat_malloc2(dirpool->ndirs, sizeof(Id)); + memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id)); + for (i = 1; i < ndirmap; i++) + { + if (dirmap[i] <= 0) + continue; + cbdata.dirused[dirmap[i]] = i; + dirmap[i] = needid[dirpool->dirs[dirmap[i]]].need; + } } - /* find the keys we need */ - nkeys = 1; - memset(id2key, 0, sizeof(id2key)); - for (i = SOLVABLE_NAME; i < ID_NUM_INTERNAL; i++) - if (idsizes[i]) - id2key[i] = nkeys++; - - /* find the schemata we need */ - memset(&schemata, 0, sizeof(schemata)); - solvschema = sat_calloc(repo->nsolvables, sizeof(Id)); +/********************************************************************/ + cbdata.extdata = sat_calloc(cbdata.nmykeys, sizeof(struct extdata)); + cbdata.incorelen = sat_calloc(repo->nsolvables, sizeof(Id)); + /* calculate incore/vertical data and sizes */ + ext0len = 0; - for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) + for (i = 1; i < cbdata.nmykeys; i++) + if (cbdata.mykeys[i].storage != KEY_STORAGE_SOLVABLE) + break; + if (i < cbdata.nmykeys) { - if (s->repo != repo) - continue; - sp = schema; - *sp++ = SOLVABLE_NAME; - *sp++ = SOLVABLE_ARCH; - *sp++ = SOLVABLE_EVR; - if (s->vendor) - *sp++ = SOLVABLE_VENDOR; - if (s->provides) - *sp++ = SOLVABLE_PROVIDES; - if (s->obsoletes) - *sp++ = SOLVABLE_OBSOLETES; - if (s->conflicts) - *sp++ = SOLVABLE_CONFLICTS; - if (s->requires) - *sp++ = SOLVABLE_REQUIRES; - if (s->recommends) - *sp++ = SOLVABLE_RECOMMENDS; - if (s->suggests) - *sp++ = SOLVABLE_SUGGESTS; - if (s->supplements) - *sp++ = SOLVABLE_SUPPLEMENTS; - if (s->enhances) - *sp++ = SOLVABLE_ENHANCES; - if (s->freshens) - *sp++ = SOLVABLE_FRESHENS; - if (repo->rpmdbid) - *sp++ = RPM_RPMDBID; - *sp = 0; - solvschema[n++] = addschema(&schemata, schema); - } - - if (repodataschema) - { - /* add us a schema for our repodata */ - sp = schema; - *sp++ = REPODATA_EXTERNAL; - *sp++ = REPODATA_KEYS; - *sp++ = REPODATA_LOCATION; - *sp = 0; - repodataschema = addschema(&schemata, schema); - } - if (repodataschema_internal) - { - sp = schema; - *sp++ = REPODATA_EXTERNAL; - *sp++ = REPODATA_KEYS; - *sp = 0; - repodataschema_internal = addschema(&schemata, schema); - } - - /* convert all schemas to local keys */ - if (schemata.nschemata) - for (sp = schemata.schemadata; sp < schemata.schemadatap; sp++) - *sp = id2key[*sp]; + /* we need incore/vertical data */ + for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) + { + if (s->repo != repo) + continue; + for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++) + { + if (!repodataused[j]) + continue; + if (i < data->start || i >= data->end) + continue; + repodata_search(data, i - data->start, 0, repo_write_cb_sizes, &cbdata); + } + cbdata.incorelen[n] = cbdata.extdata[0].len - ext0len; + ext0len = cbdata.extdata[0].len; + n++; + } + } + +/********************************************************************/ + + /* write header */ /* write file header */ write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V'); - write_u32(fp, SOLV_VERSION_3); + write_u32(fp, SOLV_VERSION_5); /* write counts */ write_u32(fp, nstrings); write_u32(fp, nrels); - write_u32(fp, nsolvables); - write_u32(fp, nkeys); - write_u32(fp, schemata.nschemata); - write_u32(fp, repo->nrepodata); /* info blocks. */ + write_u32(fp, ndirmap); + write_u32(fp, repo->nsolvables); + write_u32(fp, cbdata.nmykeys); + write_u32(fp, cbdata.nmyschemata); + write_u32(fp, 0); /* info blocks. */ solv_flags = 0; solv_flags |= SOLV_FLAG_PREFIX_POOL; #if 0 @@ -597,12 +1235,12 @@ repo_write(Repo *repo, FILE *fp) that this actually is an expansion we can't easily reuse the stringspace for this. The max expansion per string is 1 byte, so it will fit into sizeid+nstrings bytes. */ - char *prefix = sat_malloc (sizeid + nstrings); + char *prefix = sat_malloc(sizeid + nstrings); char *pp = prefix; char *old_str = ""; for (i = 1; i < nstrings; i++) { - char *str = pool->ss.stringspace + pool->ss.strings[needid[i].map]; + char *str = spool->stringspace + spool->strings[needid[i].map]; int same; size_t len; for (same = 0; same < 255; same++) @@ -625,58 +1263,55 @@ repo_write(Repo *repo, FILE *fp) perror("write error"); exit(1); } - sat_free (prefix); + sat_free(prefix); /* * write RelDeps */ for (i = 0; i < nrels; i++) { - ran = pool->rels + (needid[pool->ss.nstrings + i].map - pool->ss.nstrings); + ran = pool->rels + (needid[reloff + i].map - pool->ss.nstrings); write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need); write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need); write_u8(fp, ran->flags); } /* + * write dirs (skip both root and / entry) + */ + for (i = 2; i < ndirmap; i++) + { + if (dirmap[i] > 0) + write_id(fp, dirmap[i]); + else + write_id(fp, nstrings - dirmap[i]); + } + + /* * write keys */ - for (i = SOLVABLE_NAME; i < ID_NUM_INTERNAL; i++) + for (i = 1; i < cbdata.nmykeys; i++) { - if (!idsizes[i]) - continue; - write_id(fp, needid[i].need); - if (i >= SOLVABLE_PROVIDES && i <= SOLVABLE_FRESHENS) - write_id(fp, TYPE_REL_IDARRAY); - else if (i == RPM_RPMDBID) - write_id(fp, TYPE_U32); - else if (i == REPODATA_EXTERNAL) - write_id(fp, TYPE_VOID); - else if (i == REPODATA_KEYS) - write_id(fp, TYPE_IDVALUEARRAY); - else if (i == REPODATA_LOCATION) - write_id(fp, TYPE_STR); + write_id(fp, needid[cbdata.mykeys[i].name].need); + write_id(fp, cbdata.mykeys[i].type); + if (cbdata.mykeys[i].storage != KEY_STORAGE_VERTICAL_OFFSET) + write_id(fp, cbdata.mykeys[i].size); else - write_id(fp, TYPE_ID); - write_id(fp, idsizes[i]); + write_id(fp, cbdata.extdata[i].len); + write_id(fp, cbdata.mykeys[i].storage); } /* * write schemata */ - if (schemata.nschemata) + write_id(fp, cbdata.myschemadatalen); + if (cbdata.nmyschemata) { - write_id(fp, schemata.schemadatap - schemata.schemadata - 1); - for (sp = schemata.schemadata + 1; sp < schemata.schemadatap; ) - { - write_idarray(fp, pool, 0, sp); - while (*sp++) - ; - } + for (i = 1; i < cbdata.nmyschemata; i++) + write_idarray(fp, pool, 0, cbdata.myschemadata + cbdata.myschemata[i]); } - else - write_id(fp, 0); +#if 0 /* * write info block */ @@ -697,46 +1332,120 @@ repo_write(Repo *repo, FILE *fp) if (repo->repodata[i].location) write_str(fp, repo->repodata[i].location); } +#endif + + +/********************************************************************/ + /* * write Solvables */ + incoredata = cbdata.extdata[0].buf; for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) { if (s->repo != repo) continue; /* keep in sync with schema generation! */ - write_id(fp, solvschema[n++]); - write_id(fp, needid[s->name].need); - write_id(fp, needid[s->arch].need); - write_id(fp, needid[s->evr].need); - if (s->vendor) + write_id(fp, cbdata.solvschemata[n]); +#if 0 +{ + Id *sp; + fprintf(stderr, "write solvable %d (%s): \n", n, id2str(pool, s->name)); + sp = cbdata.myschemadata + cbdata.myschemata[cbdata.solvschemata[n]]; + for (; *sp; sp++) + fprintf(stderr, " (%d,%d)", cbdata.mykeys[*sp].name, cbdata.mykeys[*sp].type); + fprintf(stderr, "\n"); +} +#endif + if (cbdata.keymap[SOLVABLE_NAME]); + write_id(fp, needid[s->name].need); + if (cbdata.keymap[SOLVABLE_ARCH]); + write_id(fp, needid[s->arch].need); + if (cbdata.keymap[SOLVABLE_EVR]); + write_id(fp, needid[s->evr].need); + if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR]) write_id(fp, needid[s->vendor].need); - if (s->provides) + if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES]) write_idarray_sort(fp, pool, needid, idarraydata + s->provides); - if (s->obsoletes) + if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES]) write_idarray_sort(fp, pool, needid, idarraydata + s->obsoletes); - if (s->conflicts) + if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS]) write_idarray_sort(fp, pool, needid, idarraydata + s->conflicts); - if (s->requires) + if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES]) write_idarray_sort(fp, pool, needid, idarraydata + s->requires); - if (s->recommends) + if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS]) write_idarray_sort(fp, pool, needid, idarraydata + s->recommends); - if (s->suggests) + if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS]) write_idarray_sort(fp, pool, needid, idarraydata + s->suggests); - if (s->supplements) + if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS]) write_idarray_sort(fp, pool, needid, idarraydata + s->supplements); - if (s->enhances) + if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES]) write_idarray_sort(fp, pool, needid, idarraydata + s->enhances); - if (s->freshens) + if (s->freshens && cbdata.keymap[SOLVABLE_FRESHENS]) write_idarray_sort(fp, pool, needid, idarraydata + s->freshens); - if (repo->rpmdbid) + if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID]) write_u32(fp, repo->rpmdbid[i - repo->start]); + if (cbdata.incorelen[n]) + { + write_blob(fp, incoredata, cbdata.incorelen[n]); + incoredata += cbdata.incorelen[n]; + } + n++; } + sat_free(cbdata.extdata[0].buf); + + /* write vertical data */ + for (i = 1; i < cbdata.nmykeys; i++) + if (cbdata.extdata[i].len) + break; + if (i < cbdata.nmykeys) + { + unsigned char *dp, vpage[BLOB_PAGESIZE]; + int l, ll, lpage = 0; + + write_u32(fp, BLOB_PAGESIZE); + for (i = 1; i < cbdata.nmykeys; i++) + { + if (!cbdata.extdata[i].len) + continue; + l = cbdata.extdata[i].len; + dp = cbdata.extdata[i].buf; + while (l) + { + ll = BLOB_PAGESIZE - lpage; + if (l < ll) + ll = l; + memcpy(vpage + lpage, dp, ll); + dp += ll; + lpage += ll; + l -= ll; + if (lpage == BLOB_PAGESIZE) + { + write_compressed_page(fp, vpage, lpage); + lpage = 0; + } + } + } + if (lpage) + write_compressed_page(fp, vpage, lpage); + } + +#if 0 + /* write vertical_offset entries */ + write_u32(fp, 0); /* no paging */ + for (i = 1; i < cbdata.nmykeys; i++) + if (cbdata.extdata[i].len) + write_blob(fp, cbdata.extdata[i].buf, cbdata.extdata[i].len); +#endif + + for (i = 1; i < cbdata.nmykeys; i++) + sat_free(cbdata.extdata[i].buf); sat_free(needid); - sat_free(solvschema); - sat_free(schemata.schemadata); + sat_free(cbdata.solvschemata); + sat_free(cbdata.myschemadata); + sat_free(cbdata.myschemata); } // EOF diff --git a/tools/repo_write.h b/tools/repo_write.h index 145a09a..eb3b7e7 100644 --- a/tools/repo_write.h +++ b/tools/repo_write.h @@ -18,6 +18,6 @@ #include "pool.h" #include "repo.h" -extern void repo_write(Repo *repo, FILE *fp); +void repo_write(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata); #endif diff --git a/tools/rpmdb2solv.c b/tools/rpmdb2solv.c index 8050c73..ba23da6 100644 --- a/tools/rpmdb2solv.c +++ b/tools/rpmdb2solv.c @@ -54,7 +54,7 @@ main(int argc, char **argv) ref = 0; } - repo_write(repo, stdout); + repo_write(repo, stdout, 0, 0); pool_free(pool); exit(0); diff --git a/tools/rpmmd2solv.c b/tools/rpmmd2solv.c index f494106..b035ac6 100644 --- a/tools/rpmmd2solv.c +++ b/tools/rpmmd2solv.c @@ -23,7 +23,7 @@ main(int argc, char **argv) Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); repo_add_rpmmd(repo, stdin); - repo_write(repo, stdout); + repo_write(repo, stdout, 0, 0); pool_free(pool); exit(0); } diff --git a/tools/susetags2solv.c b/tools/susetags2solv.c index 09e7b51..234a57d 100644 --- a/tools/susetags2solv.c +++ b/tools/susetags2solv.c @@ -16,9 +16,50 @@ #include "repo.h" #include "repo_susetags.h" #include "repo_write.h" +#if 0 #include "attr_store.h" extern Attrstore *attr; +#endif + +static char *verticals[] = { + "authors", + "description", + "messagedel", + "messageins", + "eula", + "diskusage", + 0 +}; + +static unsigned char *filter; +static int nfilter; + +static void +create_filter(Pool *pool) +{ + char **s; + Id id; + for (s = verticals; *s; s++) + { + id = str2id(pool, *s, 1); + if (id >= nfilter) + { + filter = sat_realloc(filter, id + 16); + memset(filter + nfilter, 0, id + 16 - nfilter); + nfilter = id + 16; + } + filter[id] = 1; + } +} + +static int +keyfilter(Repo *data, Repokey *key, void *kfdata) +{ + if (key->name < nfilter && filter[key->name]) + return KEY_STORAGE_VERTICAL_OFFSET; + return KEY_STORAGE_INCORE; +} int main(int argc, char **argv) @@ -41,13 +82,16 @@ main(int argc, char **argv) Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); repo_add_susetags(repo, stdin, 0, with_attr); - repo_write(repo, stdout); + create_filter(pool); + repo_write(repo, stdout, keyfilter, 0); +#if 0 if (with_attr && attr) { FILE *fp = fopen ("test.attr", "w"); write_attr_store (fp, attr); fclose (fp); } +#endif pool_free(pool); exit(0); } -- 2.7.4