]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Change lookup/search code that it returns the match from the last repodata
authorMichael Schroeder <mls@suse.de>
Mon, 10 Sep 2018 09:38:19 +0000 (11:38 +0200)
committerMichael Schroeder <mls@suse.de>
Mon, 10 Sep 2018 09:38:19 +0000 (11:38 +0200)
This is the first part of fixing a longstanding bug. This fixes
the lookup cases and the case where a keyname is provided in the
search/iterator.

We do this by adding a repo_lookup_repodata function that returns the
last repodata that has the specified keyname.

There is also a repo_lookup_repodata_opt function that may return
a repodata that does not contain the keyname instead of NULL. This
is a bit faster if you need to do a lookup anyway.

We also now have a repo_lookup_filelist_repodata that contains all
the logic to deal with filtered filelists.

src/repo.c
src/repo.h
src/repodata.c

index 7d67bee94a9e4e409f4257f24523df83d7c59a9f..7e31d78574136af03ae67bff3de4590188d79a65 100644 (file)
@@ -742,7 +742,7 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
   KeyValue kv;
   Pool *pool = repo->pool;
   Repodata *data;
-  int i, j, flags;
+  int i, flags;
   Solvable *s;
 
   kv.parent = 0;
@@ -759,8 +759,7 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
       return;
     }
   else if (p < 0)
-    /* The callback only supports solvables, so we can't iterate over the
-       extra things.  */
+    /* The callback only supports solvables, so we can't iterate over the extra things.  */
     return;
   flags = md->flags;
   if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
@@ -856,41 +855,21 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
        }
     }
 
+  if (keyname)
+    {
+      if (keyname == SOLVABLE_FILELIST)
+       data = repo_lookup_filelist_repodata(repo, p, &md->matcher);
+      else
+        data = repo_lookup_repodata_opt(repo, p, keyname);
+      if (data)
+        repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
+      return;
+    }
+
   FOR_REPODATAS(repo, i, data)
     {
       if (p < data->start || p >= data->end)
        continue;
-      if (keyname && !repodata_precheck_keyname(data, keyname))
-       continue;
-      if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST))
-       {
-         /* do not search filelist extensions */
-         if (data->state != REPODATA_AVAILABLE)
-           continue;
-         for (j = 1; j < data->nkeys; j++)
-           if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-             break;
-         if (j == data->nkeys)
-           continue;
-       }
-      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, keyname, md->flags, repo_matchvalue, md);
       if (md->stop > SEARCH_NEXT_KEY)
        break;
@@ -916,13 +895,113 @@ repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*ca
     datamatcher_free(&md.matcher);
 }
 
+Repodata *
+repo_lookup_repodata(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data;
+  int rdid;
+  Id type;
+
+  if (entry == SOLVID_POS)
+    {
+      Pool *pool = repo->pool;
+      return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
+    }
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {
+      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
+       continue;
+      if (!repodata_precheck_keyname(data, keyname))
+       continue;
+      if ((type = repodata_lookup_type(data, entry, keyname)) != 0)
+        return type == REPOKEY_TYPE_DELETED ? 0 : data;
+    }
+  return 0;
+}
+
+/* like repo_lookup_repodata, but may return a repodata that contains no match instead of NULL */
+Repodata *
+repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data, *found = 0;
+  int rdid;
+  Id type;
+
+  if (entry == SOLVID_POS)
+    {
+      Pool *pool = repo->pool;
+      return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
+    }
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {
+      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
+       continue;
+      if (!repodata_precheck_keyname(data, keyname))
+       continue;
+      if (found && (type = repodata_lookup_type(found, entry, keyname)) != 0)
+       return type == REPOKEY_TYPE_DELETED ? 0 : found;
+      found = data;
+    }
+  return found;
+}
+
+Repodata *
+repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher)
+{
+  Repodata *data;
+  int haveextension;
+  int rdid;
+  Id type;
+
+  if (entry <= 0 || !matcher || !matcher->match || ((matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
+      && (matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB))
+    return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);   /* cannot use filtered filelist */
+
+  haveextension = 0;
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {    
+      if (entry < data->start || entry >= data->end)
+       continue;
+      if (data->filelisttype == REPODATA_FILELIST_FILTERED)
+       {
+         if (data->state != REPODATA_AVAILABLE)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE || entry < data->start || entry >= data->end)
+               continue;
+           }
+         /* does this contain any data about the solvable we're looking for? */
+         if (!data->incoreoffset[entry - data->start])
+           continue;   /* no, ignore */
+         if (haveextension && repodata_filelistfilter_matches(data, matcher->match))
+           return data;
+         break;        /* fall back to normal code */
+       }
+      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+       continue;
+      if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+       {
+         haveextension++;
+         continue;
+       }
+      if ((type = repodata_lookup_type(data, entry, SOLVABLE_FILELIST)) != 0)
+       {
+         if (haveextension)
+           break;              /* need to look in extension */
+         return type == REPOKEY_TYPE_DELETED ? 0 : data;
+       }
+    }
+  /* cannot use filtered filelist */
+  return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);
+}
+
 const char *
 repo_lookup_str(Repo *repo, Id entry, Id keyname)
 {
   Pool *pool = repo->pool;
   Repodata *data;
-  int i;
-  const char *str;
 
   if (entry >= 0)
     {
@@ -938,30 +1017,15 @@ repo_lookup_str(Repo *repo, Id entry, Id keyname)
          return pool_id2str(pool, pool->solvables[entry].vendor);
        }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      str = repodata_lookup_str(data, entry, keyname);
-      if (str)
-       return str;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
-  return 0;
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  return data ? repodata_lookup_str(data, entry, keyname) : 0;
 }
 
 
 unsigned long long
 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
-  int i;
   unsigned long long value;
 
   if (entry >= 0)
@@ -973,28 +1037,14 @@ repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
          return notfound;
        }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, &value) ? value : notfound;
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      if (repodata_lookup_num(data, entry, keyname, &value))
-       return value;
-      if (repodata_lookup_type(data, entry, keyname))
-       return notfound;
-    }
-  return notfound;
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  return data && repodata_lookup_num(data, entry, keyname, &value) ? value : notfound;
 }
 
 Id
 repo_lookup_id(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
-  int i;
   Id id;
 
   if (entry >= 0)
@@ -1011,24 +1061,9 @@ repo_lookup_id(Repo *repo, Id entry, Id keyname)
          return repo->pool->solvables[entry].vendor;
        }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    {
-      Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
-      Id id = repodata_lookup_id(data, entry, keyname);
-      return data->localpool ? repodata_globalize_id(data, id, 1) : id;
-    }
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      id = repodata_lookup_id(data, entry, keyname);
-      if (id)
-       return data->localpool ? repodata_globalize_id(data, id, 1) : id;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (id = repodata_lookup_id(data, entry, keyname)) != 0)
+    return data->localpool ? repodata_globalize_id(data, id, 1) : id;
   return 0;
 }
 
@@ -1047,7 +1082,6 @@ lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
 int
 repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
   int i;
   if (entry >= 0)
@@ -1072,36 +1106,15 @@ repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
          return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
         }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && repodata_lookup_idarray(data, entry, keyname, q))
     {
-      Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
-      if (repodata_lookup_idarray(data, entry, keyname, q))
+      if (data->localpool)
        {
-         if (data->localpool)
-           {
-             for (i = 0; i < q->count; i++)
-               q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
-           }
-         return 1;
-       }
-    }
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      if (repodata_lookup_idarray(data, entry, keyname, q))
-       {
-         if (data->localpool)
-           {
-             for (i = 0; i < q->count; i++)
-               q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
-           }
-         return 1;
+         for (i = 0; i < q->count; i++)
+           q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
        }
-      if (repodata_lookup_type(data, entry, keyname))
-       break;
+      return 1;
     }
   queue_empty(q);
   return 0;
@@ -1145,25 +1158,10 @@ repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker)
 const unsigned char *
 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
   const unsigned char *chk;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, typep);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
-      if (chk)
-       return chk;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (chk = repodata_lookup_bin_checksum(data, entry, keyname, typep)) != 0)
+    return chk;
   *typep = 0;
   return 0;
 }
@@ -1178,69 +1176,29 @@ repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
 int
 repo_lookup_void(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  Id type;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      type = repodata_lookup_type(data, entry, keyname);
-      if (type)
-       return type == REPOKEY_TYPE_VOID;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data)
+    return repodata_lookup_void(data, entry, keyname);
   return 0;
 }
 
 Id
 repo_lookup_type(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
   Id type;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_type(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      type = repodata_lookup_type(data, entry, keyname);
-      if (type)
-       return type == REPOKEY_TYPE_DELETED ? 0 : type;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (type = repodata_lookup_type(data, entry, keyname)) != 0 && type != REPOKEY_TYPE_DELETED)
+    return type;
   return 0;
 }
 
 const void *
 repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
   const void *bin;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_binary(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, lenp);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      bin = repodata_lookup_binary(data, entry, keyname, lenp);
-      if (bin)
-       return bin;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (bin = repodata_lookup_binary(data, entry, keyname, lenp)) != 0)
+    return bin;
   *lenp = 0;
   return 0;
 }
index bd9c58c74fbb8c4e6a68792cb6a8a09e8404c60d..7cd0690bd65ca2808fca7d4f5d10b5754f95b71e 100644 (file)
@@ -146,6 +146,11 @@ Repodata *repo_last_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);
 
+/* returns the last repodata that contains the key */
+Repodata *repo_lookup_repodata(Repo *repo, Id entry, Id keyname);
+Repodata *repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname);
+Repodata *repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher);
+
 /* returns the string value of the attribute, or NULL if not found */
 Id repo_lookup_type(Repo *repo, Id entry, Id keyname);
 const char *repo_lookup_str(Repo *repo, Id entry, Id keyname);
index 24e3f5a418ddedf1afcb4c22b266f40cca9162e2..421f914b9045bbe6e62eeb0f034b9934173a2a5f 100644 (file)
@@ -716,20 +716,7 @@ repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *v
 int
 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
 {
-  Id schema;
-  Id *keyp;
-  unsigned char *dp;
-
-  if (!maybe_load_repodata(data, keyname))
-    return 0;
-  dp = solvid2data(data, solvid, &schema);
-  if (!dp)
-    return 0;
-  /* can't use find_key_data as we need to test the type */
-  for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
-    if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
-      return 1;
-  return 0;
+  return repodata_lookup_type(data, solvid, keyname) == REPOKEY_TYPE_VOID ? 1 : 0;
 }
 
 const unsigned char *
@@ -762,9 +749,7 @@ repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
 
   queue_empty(q);
   dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  if (key->type != REPOKEY_TYPE_IDARRAY)
+  if (!dp || key->type != REPOKEY_TYPE_IDARRAY)
     return 0;
   for (;;)
     {
@@ -1452,88 +1437,21 @@ dataiterator_find_keyname(Dataiterator *di, Id keyname)
   return dp;
 }
 
-static inline int
-is_filelist_extension(Repodata *data)
-{
-  int j;
-  if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
-    return 0;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name == SOLVABLE_FILELIST)
-      break;
-  if (j == data->nkeys)
-    return 0;
-  if (data->state != REPODATA_AVAILABLE)
-    return 1;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-      return 0;
-  return 1;
-}
-
-static int
-dataiterator_filelistcheck(Dataiterator *di)
-{
-  int j;
-  int needcomplete = 0;
-  Repodata *data = di->data;
-
-  if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
-    if (!di->matcher.match
-       || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
-           && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
-       || !repodata_filelistfilter_matches(data, di->matcher.match))
-      needcomplete = 1;
-  if (data->state != REPODATA_AVAILABLE)
-    return needcomplete ? 1 : 0;
-  if (!needcomplete)
-    {
-      /* we don't need the complete filelist, so ignore all stubs */
-      if (data->repo->nrepodata == 2)
-       return 1;
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-         return 1;
-      return 0;
-    }
-  else
-    {
-      /* we need the complete filelist. check if we habe a filtered filelist and there's
-       * a extension with the complete filelist later on */
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name == SOLVABLE_FILELIST)
-         break;
-      if (j == data->nkeys)
-       return 0;       /* does not have filelist */
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-         break;
-      if (j == data->nkeys)
-       return 1;       /* this is the externsion */
-      while (data - data->repo->repodata + 1 < data->repo->nrepodata)
-       {
-         data++;
-         if (is_filelist_extension(data))
-           return 0;
-       }
-      return 1;
-    }
-}
-
 int
 dataiterator_step(Dataiterator *di)
 {
   Id schema;
 
-  if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
-    unsigned int ddpoff = di->ddp - di->vert_ddp;
-    di->vert_off += ddpoff;
-    di->vert_len -= ddpoff;
-    di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
-    di->vert_storestate = di->data->storestate;
-    if (!di->ddp)
-      di->state = di_nextkey;
-  }
+  if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate)
+    {
+      unsigned int ddpoff = di->ddp - di->vert_ddp;
+      di->vert_off += ddpoff;
+      di->vert_len -= ddpoff;
+      di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
+      di->vert_storestate = di->data->storestate;
+      if (!di->ddp)
+       di->state = di_nextkey;
+    }
   for (;;)
     {
       switch (di->state)
@@ -1555,11 +1473,17 @@ dataiterator_step(Dataiterator *di)
              if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
                {
                  extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
-
                  di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
                  di->data = 0;
                  goto di_entersolvablekey;
                }
+             if (di->keyname)
+               {
+                 di->data = di->keyname == SOLVABLE_FILELIST ? repo_lookup_filelist_repodata(di->repo, di->solvid, &di->matcher) : repo_lookup_repodata_opt(di->repo, di->solvid, di->keyname);
+                 if (!di->data)
+                   goto di_nextsolvable;
+                 di->repodataid = di->data - di->repo->repodata;
+               }
            }
          /* FALLTHROUGH */
 
@@ -1570,8 +1494,6 @@ dataiterator_step(Dataiterator *di)
                goto di_nextsolvable;
              di->data = di->repo->repodata + di->repodataid;
            }
-         if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
-           goto di_nextrepodata;
          if (!maybe_load_repodata(di->data, di->keyname))
            goto di_nextrepodata;
          di->dp = solvid2data(di->data, di->solvid, &schema);
@@ -1631,10 +1553,7 @@ dataiterator_step(Dataiterator *di)
        case di_nextattr:
           di->kv.entry++;
          di->ddp = data_fetch(di->ddp, &di->kv, di->key);
-         if (di->kv.eof)
-           di->state = di_nextkey;
-         else
-           di->state = di_nextattr;
+         di->state = di->kv.eof ? di_nextkey : di_nextattr;
          break;
 
        case di_nextkey: di_nextkey:
@@ -1645,7 +1564,7 @@ dataiterator_step(Dataiterator *di)
          /* FALLTHROUGH */
 
        case di_nextrepodata: di_nextrepodata:
-         if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
+         if (!di->keyname && di->repodataid && ++di->repodataid < di->repo->nrepodata)
              goto di_enterrepodata;
          /* FALLTHROUGH */
 
@@ -1746,7 +1665,9 @@ dataiterator_step(Dataiterator *di)
         /* special solvable attr handling follows */
 
        case di_nextsolvablekey: di_nextsolvablekey:
-         if (di->keyname || di->key->name == RPM_RPMDBID)
+         if (di->keyname)
+           goto di_nextsolvable;
+         if (di->key->name == RPM_RPMDBID)     /* reached end of list? */
            goto di_enterrepodata;
          di->key++;
          /* FALLTHROUGH */
@@ -1781,6 +1702,7 @@ dataiterator_step(Dataiterator *di)
 
        }
 
+      /* we have a potential match */
       if (di->matcher.match)
        {
          const char *str;
@@ -1788,6 +1710,7 @@ dataiterator_step(Dataiterator *di)
          if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
            if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
              continue;
+         /* now stringify so that we can do the matching */
          if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
            {
              if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
@@ -1799,6 +1722,7 @@ dataiterator_step(Dataiterator *di)
        }
       else
        {
+         /* stringify filelist if requested */
          if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
            repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
        }