/** * Destroy the DBM wrapper, optionally closing the underlying DB map. */ void dbmw_destroy(dbmw_t *dw, bool close_map) { dbmw_check(dw); if (common_stats) { s_debug("DBMW destroying \"%s\" with %s back-end " "(read cache hits = %.2f%% on %s request%s, " "write cache hits = %.2f%% on %s request%s)", dw->name, dbmw_map_type(dw) == DBMAP_SDBM ? "sdbm" : "map", dw->r_hits * 100.0 / MAX(1, dw->r_access), uint64_to_string(dw->r_access), plural(dw->r_access), dw->w_hits * 100.0 / MAX(1, dw->w_access), uint64_to_string2(dw->w_access), plural(dw->w_access)); } if (dbg_ds_debugging(dw->dbg, 1, DBG_DSF_DESTROY)) { dbg_ds_log(dw->dbg, dw, "%s: with %s back-end " "(read cache hits = %.2f%% on %s request%s, " "write cache hits = %.2f%% on %s request%s)", G_STRFUNC, dbmw_map_type(dw) == DBMAP_SDBM ? "sdbm" : "map", dw->r_hits * 100.0 / MAX(1, dw->r_access), uint64_to_string(dw->r_access), plural(dw->r_access), dw->w_hits * 100.0 / MAX(1, dw->w_access), uint64_to_string2(dw->w_access), plural(dw->w_access)); } /* * If we close the map and we're volatile, there's no need to flush * the cache as the data is going to be gone soon anyway. */ if (!close_map || !dw->is_volatile) { dbmw_sync(dw, DBMW_SYNC_CACHE); } dbmw_clear_cache(dw); hash_list_free(&dw->keys); map_destroy(dw->values); if (dw->mb) pmsg_free(dw->mb); bstr_free(&dw->bs); if (close_map) dbmap_destroy(dw->dm); WFREE_TYPE_NULL(dw->dbmap_dbg); dw->magic = 0; WFREE(dw); }
/** * Record debugging configuration. */ void dbmw_set_debugging(dbmw_t *dw, const dbg_config_t *dbg) { dbmw_check(dw); dw->dbg = dbg; if (dbg_ds_debugging(dw->dbg, 1, DBG_DSF_DEBUGGING)) { dbg_ds_log(dw->dbg, dw, "%s: attached with %s back-end " "(max cached = %zu, key=%zu bytes, value=%zu bytes, " "%zu max serialized)", G_STRFUNC, dbmw_map_type(dw) == DBMAP_SDBM ? "sdbm" : "map", dw->max_cached, dw->key_size, dw->value_size, dw->value_data_size); } /* * Patch in place for the DBMAP. */ WFREE_TYPE_NULL(dw->dbmap_dbg); dw->dbmap_dbg = WCOPY(dbg); dw->dbmap_dbg->o2str = NULL; dw->dbmap_dbg->type = "DBMAP"; dbmap_set_debugging(dw->dm, dw->dbmap_dbg); }
/** * Destroy the DBM wrapper, optionally closing the underlying DB map. */ void dbmw_destroy(dbmw_t *dw, gboolean close_map) { dbmw_check(dw); if (common_stats) g_debug("DBMW destroying \"%s\" with %s back-end " "(read cache hits = %.2f%% on %s request%s, " "write cache hits = %.2f%% on %s request%s)", dw->name, dbmw_map_type(dw) == DBMAP_SDBM ? "sdbm" : "map", dw->r_hits * 100.0 / MAX(1, dw->r_access), uint64_to_string(dw->r_access), 1 == dw->r_access ? "" : "s", dw->w_hits * 100.0 / MAX(1, dw->w_access), uint64_to_string2(dw->w_access), 1 == dw->w_access ? "" : "s"); /* * If we close the map and we're volatile, there's no need to flush * the cache as the data is going to be gone soon anyway. */ if (!close_map || !dw->is_volatile) { dbmw_sync(dw, DBMW_SYNC_CACHE); } dbmw_clear_cache(dw); hash_list_free(&dw->keys); map_destroy(dw->values); if (dw->mb) pmsg_free(dw->mb); bstr_free(&dw->bs); if (close_map) dbmap_destroy(dw->dm); dw->magic = 0; WFREE(dw); }
/** * Create a new DBM wrapper over already created DB map. * * If value_data_size is 0, the length for value_size is used. * * @param dm The database (already opened) * @param name Database name, for logs * @param value_size Maximum value size, in bytes (structure) * @param value_data_size Maximum value size, in bytes (serialized form) * @param pack Serialization routine for values * @param unpack Deserialization routine for values * @param valfree Free routine for value (or NULL if none needed) * @param cache_size Amount of items to cache (0 = no cache, 1 = default) * @param hash_func Key hash function * @param eq_func Key equality test function * * If serialization and deserialization routines are NULL pointers, data * will be stored and retrieved as-is. In that case, they must be both * NULL. */ dbmw_t * dbmw_create(dbmap_t *dm, const char *name, size_t value_size, size_t value_data_size, dbmw_serialize_t pack, dbmw_deserialize_t unpack, dbmw_free_t valfree, size_t cache_size, GHashFunc hash_func, GEqualFunc eq_func) { dbmw_t *dw; g_assert(pack == NULL || value_size); g_assert((pack != NULL) == (unpack != NULL)); g_assert(valfree == NULL || unpack != NULL); g_assert(dm); WALLOC0(dw); dw->magic = DBMW_MAGIC; dw->dm = dm; dw->name = name; dw->key_size = dbmap_key_size(dm); dw->key_len = dbmap_key_length(dm); dw->value_size = value_size; dw->value_data_size = 0 == value_data_size ? value_size : value_data_size; /* Make sure we do not violate the SDBM constraint */ g_assert(sdbm_is_storable(dw->key_size, dw->value_data_size)); /* * There must be a serialization routine if the serialized length is not * the same as the structure length. */ g_assert(dw->value_size == dw->value_data_size || pack != NULL); /* * For a small amount of items, a PATRICIA tree is more efficient * than a hash table although it uses more memory. */ if ( NULL == dw->key_len && dw->key_size * 8 <= PATRICIA_MAXBITS && cache_size <= DBMW_CACHE ) { dw->values = map_create_patricia(dw->key_size * 8); } else { dw->values = map_create_hash(hash_func, eq_func); } dw->keys = hash_list_new(hash_func, eq_func); dw->pack = pack; dw->unpack = unpack; dw->valfree = valfree; /* * If a serialization routine is provided, we'll also have a need for * deserialization. Allocate the message in/out streams. * * We're allocating one more byte than necessary to be able to check * whether serialization stays within the imposed boundaries. */ if (dw->pack) { dw->bs = bstr_create(); dw->mb = pmsg_new(PMSG_P_DATA, NULL, dw->value_data_size + 1); } /* * If cache_size is zero, we won't cache anything but the latest * value requested, in deserialized form. If modified, it will be * written back immediately. * * If cache_size is one, use the default (DBMW_CACHE). * * Any other value is used as-is. */ if (0 == cache_size) dw->max_cached = 1; /* No cache, only keep latest around */ else if (cache_size == 1) dw->max_cached = DBMW_CACHE; else dw->max_cached = cache_size; if (common_dbg) g_debug("DBMW created \"%s\" with %s back-end " "(max cached = %lu, key=%lu bytes, value=%lu bytes, " "%lu max serialized)", dw->name, dbmw_map_type(dw) == DBMAP_SDBM ? "sdbm" : "map", (gulong) dw->max_cached, (gulong) dw->key_size, (gulong) dw->value_size, (gulong) dw->value_data_size); return dw; }