/** * Iterate over the DB, invoking the callback on each item along with the * supplied argument. */ void dbmw_foreach(dbmw_t *dw, dbmw_cb_t cb, gpointer arg) { struct foreach_ctx ctx; struct cache_foreach_ctx fctx; dbmw_check(dw); /* * Before iterating we flush the deleted keys we know about in the cache * and whose deletion was deferred, so that the underlying map will * not have to iterate on them. */ dbmw_sync(dw, DBMW_SYNC_CACHE | DBMW_DELETED_ONLY); /* * Some values may be present only in the cache. Hence we clear all * marks in the cache and each traversed value that happens to be * present in the cache will be marked as "traversed". * * We flushed deleted keys above, but that does not remove them from * the cache structure. We don't need to traverse these after iterating * on the map, so we make sure they are artifically set to "traversed". */ ctx.u.cb = cb; ctx.arg = arg; ctx.dw = dw; map_foreach(dw->values, cache_reset_before_traversal, NULL); dbmap_foreach(dw->dm, dbmw_foreach_trampoline, &ctx); /* * Continue traversal with all the cached entries that were not traversed * already because they do not exist in the underlying map. */ fctx.removing = FALSE; fctx.foreach = &ctx; fctx.u.cb = dbmw_foreach_trampoline; map_foreach(dw->values, cache_finish_traversal, &fctx); }
/** * Iterate over the DB, invoking the callback on each item along with the * supplied argument. */ void dbmw_foreach(dbmw_t *dw, dbmw_cb_t cb, void *arg) { struct foreach_ctx ctx; struct cache_foreach_ctx fctx; dbmw_check(dw); if (dbg_ds_debugging(dw->dbg, 1, DBG_DSF_ITERATOR)) { dbg_ds_log(dw->dbg, dw, "%s: starting with %s(%p)", G_STRFUNC, stacktrace_function_name(cb), arg); } /* * Before iterating we flush the deleted keys we know about in the cache * and whose deletion was deferred, so that the underlying map will * not have to iterate on them. */ dbmw_sync(dw, DBMW_SYNC_CACHE | DBMW_DELETED_ONLY); /* * Some values may be present only in the cache. Hence we clear all * marks in the cache and each traversed value that happens to be * present in the cache will be marked as "traversed". * * We flushed deleted keys above, but that does not remove them from * the cache structure. We don't need to traverse these after iterating * on the map, so we make sure they are artifically set to "traversed". */ ctx.u.cb = cb; ctx.arg = arg; ctx.dw = dw; map_foreach(dw->values, cache_reset_before_traversal, NULL); dbmap_foreach(dw->dm, dbmw_foreach_trampoline, &ctx); /* * Continue traversal with all the cached entries that were not traversed * already because they do not exist in the underlying map. * * We count these and remember how many there are so that we can determine * the correct overall item count after an iteration without having to * flush all the dirty values! */ ZERO(&fctx); fctx.foreach = &ctx; fctx.u.cb = dbmw_foreach_trampoline; map_foreach(dw->values, cache_finish_traversal, &fctx); dw->cached = fctx.cached; dw->count_needs_sync = FALSE; /* We just counted items the slow way! */ if (dbg_ds_debugging(dw->dbg, 1, DBG_DSF_ITERATOR)) { dbg_ds_log(dw->dbg, dw, "%s: done with %s(%p)" "has %zu unflushed entr%s in cache", G_STRFUNC, stacktrace_function_name(cb), arg, dw->cached, plural_y(dw->cached)); } }