- add key filtering to repo_write
authorMichael Schroeder <mls@suse.de>
Tue, 29 Jan 2008 16:14:03 +0000 (16:14 +0000)
committerMichael Schroeder <mls@suse.de>
Tue, 29 Jan 2008 16:14:03 +0000 (16:14 +0000)
- 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

29 files changed:
src/CMakeLists.txt
src/dirpool.c
src/dirpool.h
src/pool.c
src/pool.h
src/poolid.c
src/poolid.h
src/pooltypes.h
src/repo.c
src/repo.h
src/repo_solv.c
src/repodata.c [new file with mode: 0644]
src/repodata.h [new file with mode: 0644]
src/solver.c
src/strpool.c
src/strpool.h
src/util.h
tools/CMakeLists.txt
tools/content2solv.c
tools/dumpsolv.c
tools/helix2solv.c
tools/mergesolv.c
tools/patchxml2solv.c
tools/repo_susetags.c
tools/repo_write.c
tools/repo_write.h
tools/rpmdb2solv.c
tools/rpmmd2solv.c
tools/susetags2solv.c

index 0122505..b1536eb 100644 (file)
@@ -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" )
 
index 22874e8..e843b2a 100644 (file)
@@ -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++;
index 86b9e80..fb441d7 100644 (file)
@@ -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)
 {
index aff39bb..192e71c 100644 (file)
@@ -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);
index e62a9ff..c2969fe 100644 (file)
@@ -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
 
 //-----------------------------------------------
 
index 8a06437..6911367 100644 (file)
@@ -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
index 7ea597c..ff3b45d 100644 (file)
@@ -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);
index 0622a31..9681f9d 100644 (file)
@@ -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
index bc8546d..954b0e0 100644 (file)
  * 
  */
 
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+
+
 
 #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
index 980eb0d..34b100e 100644 (file)
 
 #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 */
index a341d34..c1852c5 100644 (file)
@@ -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, "<NULL>");
+      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 (file)
index 0000000..8d99429
--- /dev/null
@@ -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 <string.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+
+#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 (file)
index 0000000..16f2e4c
--- /dev/null
@@ -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 */
index 11c325a..114fc15 100644 (file)
@@ -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);
     }
index 8bf73e5..4d09139 100644 (file)
 #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[] = {
+    "<NULL>", 
+    "",
+    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);
 }
index c8429b9..dcab2ae 100644 (file)
@@ -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)
 {
index e38aa12..7c196e7 100644 (file)
@@ -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 */
index 0ed361c..e854a72 100644 (file)
@@ -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} )
 
index 30a6350..5c5af58 100644 (file)
@@ -23,7 +23,7 @@ main(int argc, char **argv)
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
   repo_add_content(repo, stdin);
-  repo_write(repo, stdout);
+  repo_write(repo, stdout, 0, 0);
   pool_free(pool);
   return 0;
 }
index 06083d9..bcdeb35 100644 (file)
@@ -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] : "<stdin>");
-  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);
index a179952..9c3a618 100644 (file)
@@ -31,7 +31,7 @@ main(int argc, char **argv)
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
   repo_add_helix(repo, stdin);
-  repo_write(repo, stdout);
+  repo_write(repo, stdout, 0, 0);
   pool_free(pool);
   exit(0);
 }
index de176ea..44d3ddd 100644 (file)
@@ -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;
index 6555af4..30a359d 100644 (file)
@@ -23,7 +23,7 @@ main(int argc, char **argv)
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
   repo_add_patchxml(repo, stdin);
-  repo_write(repo, stdout);
+  repo_write(repo, stdout, 0, 0);
   pool_free(pool);
   exit(0);
 }
index a2bc1fa..d5e54fc 100644 (file)
@@ -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);
index 4895aa8..78a56ab 100644 (file)
@@ -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
index 145a09a..eb3b7e7 100644 (file)
@@ -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
index 8050c73..ba23da6 100644 (file)
@@ -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);
index f494106..b035ac6 100644 (file)
@@ -23,7 +23,7 @@ main(int argc, char **argv)
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
   repo_add_rpmmd(repo, stdin);
-  repo_write(repo, stdout);
+  repo_write(repo, stdout, 0, 0);
   pool_free(pool);
   exit(0);
 }
index 09e7b51..234a57d 100644 (file)
 #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, "<stdin>");
   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);
 }