Check if a kind has at least one entity
This resolves an issue with metadata queries where a
recently-deleted kind can be listed.
@@ -336,8 +336,9 @@ class IndexIterator(object):
class KindIterator(object):
- def __init__(self, tr, project_dir, namespace):
+ def __init__(self, tr, tornado_fdb, project_dir, namespace):
self._tr = tr
+ self._tornado_fdb = tornado_fdb
self._project_dir = project_dir
self._namespace = namespace
self._done = False
@@ -351,13 +352,39 @@ class KindIterator(object):
ns_dir = self._project_dir.open(
self._tr, (KindIndex.DIR_NAME, self._namespace))
kinds = ns_dir.list(self._tr)
+ populated_kinds = [
+ kind for kind, populated in zip(
+ kinds, (yield [self._populated(ns_dir, kind) for kind in kinds]))
+ if populated]
+
results = [IndexEntry(self._project_dir.get_path()[-1], self._namespace,
(u'__kind__', kind), None, None)
- for kind in kinds]
+ for kind in populated_kinds]
self._done = True
raise gen.Return((results, False))
+ @gen.coroutine
+ def _populated(self, ns_dir, kind):
+ """ Checks if at least one entity exists for a given kind. """
+ kind_dir = ns_dir.open(self._tr, (kind,))
+ kind_index = KindIndex(kind_dir)
+ # TODO: Check if the presence of stat entities should mark a kind as being
+ # populated.
+ index_slice = kind_index.get_slice(())
+ # This query is reversed to increase the likelihood of getting an relevant
+ # (not marked for GC) entry.
+ iterator = IndexIterator(self._tr, self._tornado_fdb, kind_index,
+ index_slice, fetch_limit=1, reverse=True,
+ snapshot=True)
+ while True:
+ results, more_results = yield iterator.next_page()
+ if results:
+ raise gen.Return(True)
+
+ if not more_results:
+ raise gen.Return(False)
+
class MergeJoinIterator(object):
"""
@@ -1115,7 +1142,8 @@ class IndexManager(object):
if query.has_kind() and query.kind() == u'__kind__':
project_dir = yield self._directory_cache.get(tr, (project_id,))
- raise gen.Return(KindIterator(tr, project_dir, namespace))
+ raise gen.Return(KindIterator(tr, self._tornado_fdb, project_dir,
+ namespace))
index = yield self._get_perfect_index(tr, query)
reverse = get_scan_direction(query, index) == Query_Order.DESCENDING
