int read_cache(void) { FILE *fr; LIST_MEMBER *pentry; char Line[LINESIZE + 1]; int result = 0; Line[LINESIZE] = '\0'; fr = fopen(cache_name, "r"); if (!fr) { l2l_dbg(1, "Open %s failed\n", cache_name); return 2; } cache.phead = cache.ptail = NULL; while (fgets(Line, LINESIZE, fr) != NULL) { pentry = cache_entry_create(Line); if (!pentry) { l2l_dbg(2, "** Create entry failed of: %s\n", Line); } else entry_insert(&cache, pentry); } fclose(fr); return result; }
struct stasis_message *stasis_cache_get(struct stasis_cache *cache, struct stasis_message_type *type, const char *id) { RAII_VAR(struct cache_entry *, search_entry, NULL, ao2_cleanup); RAII_VAR(struct cache_entry *, cached_entry, NULL, ao2_cleanup); ast_assert(cache->entries != NULL); search_entry = cache_entry_create(type, id, NULL); if (search_entry == NULL) { return NULL; } cached_entry = ao2_find(cache->entries, search_entry, OBJ_POINTER); if (cached_entry == NULL) { return NULL; } ast_assert(cached_entry->snapshot != NULL); ao2_ref(cached_entry->snapshot, +1); return cached_entry->snapshot; }
static struct stasis_message *cache_put(struct stasis_cache *cache, struct stasis_message_type *type, const char *id, struct stasis_message *new_snapshot) { RAII_VAR(struct cache_entry *, new_entry, NULL, ao2_cleanup); RAII_VAR(struct cache_entry *, cached_entry, NULL, ao2_cleanup); struct stasis_message *old_snapshot = NULL; ast_assert(cache->entries != NULL); ast_assert(new_snapshot == NULL || type == stasis_message_type(new_snapshot)); new_entry = cache_entry_create(type, id, new_snapshot); if (new_snapshot == NULL) { /* Remove entry from cache */ cached_entry = ao2_find(cache->entries, new_entry, OBJ_POINTER | OBJ_UNLINK); if (cached_entry) { old_snapshot = cached_entry->snapshot; cached_entry->snapshot = NULL; } } else { /* Insert/update cache */ SCOPED_AO2LOCK(lock, cache->entries); cached_entry = ao2_find(cache->entries, new_entry, OBJ_POINTER | OBJ_NOLOCK); if (cached_entry) { /* Update cache. Because objects are moving, no need to update refcounts. */ old_snapshot = cached_entry->snapshot; cached_entry->snapshot = new_entry->snapshot; new_entry->snapshot = NULL; } else { /* Insert into the cache */ ao2_link_flags(cache->entries, new_entry, OBJ_NOLOCK); } } return old_snapshot; }
int main (int argc, char *argv[]) { struct cache *cache; struct cache_entry *e1, *e2; json_object *o1; json_object *o2; wait_t *w; int count, i; plan (NO_PLAN); cache_destroy (NULL); cache_entry_destroy (NULL); diag ("cache_destroy and cache_entry_destroy accept NULL arg"); ok ((cache = cache_create ()) != NULL, "cache_create works"); ok (cache_count_entries (cache) == 0, "cache contains 0 entries"); cache_destroy (cache); /* Play with one entry. * N.B.: json ref is NOT incremented by create or get_json. */ o1 = Jnew (); Jadd_int (o1, "foo", 42); ok ((e1 = cache_entry_create (o1)) != NULL, "cache_entry_create works"); ok (cache_entry_get_valid (e1) == true, "cache entry initially valid"); ok (cache_entry_get_dirty (e1) == false, "cache entry initially not dirty"); cache_entry_set_dirty (e1, true); ok (cache_entry_get_dirty (e1) == true, "cache entry succcessfully set dirty"); ok ((o2 = cache_entry_get_json (e1)) != NULL, "json retrieved from cache entry"); ok (Jget_int (o2, "foo", &i) == true && i == 42, "expected json object found"); cache_entry_destroy (e1); /* destroys o1 */ /* Test cache entry waiters. * N.B. waiter is destroyed when run. */ count = 0; ok ((w = wait_create (wait_cb, &count)) != NULL, "wait_create works"); ok ((e1 = cache_entry_create (NULL)) != NULL, "cache_entry_create created empty object"); ok (cache_entry_get_valid (e1) == false, "cache entry invalid, adding waiter"); o1 = Jnew (); Jadd_int (o1, "foo", 42); cache_entry_wait_valid (e1, w); cache_entry_set_json (e1, o1); ok (cache_entry_get_valid (e1) == true, "cache entry set valid with one waiter"); ok (count == 1, "waiter callback ran"); count = 0; ok ((w = wait_create (wait_cb, &count)) != NULL, "wait_create works"); cache_entry_set_dirty (e1, true); ok (cache_entry_get_dirty (e1) == true, "cache entry set dirty, adding waiter"); cache_entry_wait_notdirty (e1, w); cache_entry_set_dirty (e1, false); ok (cache_entry_get_dirty (e1) == false, "cache entry set not dirty with one waiter"); ok (count == 1, "waiter callback ran"); cache_entry_destroy (e1); /* destroys o1 */ /* Put entry in cache and test lookup, expire */ ok ((cache = cache_create ()) != NULL, "cache_create works"); ok (cache_count_entries (cache) == 0, "cache contains 0 entries"); o1 = Jnew (); Jadd_int (o1, "foo", 42); ok ((e1 = cache_entry_create (o1)) != NULL, "cache_entry_create works"); cache_insert (cache, "xxx1", e1); ok (cache_count_entries (cache) == 1, "cache contains 1 entry after insert"); ok (cache_lookup (cache, "yyy1", 0) == NULL, "cache_lookup of wrong hash fails"); ok ((e2 = cache_lookup (cache, "xxx1", 42)) != NULL, "cache_lookup of correct hash works (last use=42)"); i = 0; ok ((o2 = cache_entry_get_json (e2)) != NULL && Jget_int (o2, "foo", &i) == true && i == 42, "expected json object found"); ok (cache_count_entries (cache) == 1, "cache contains 1 entry"); ok (cache_expire_entries (cache, 43, 1) == 0, "cache_expire_entries now=43 thresh=1 expired 0"); ok (cache_count_entries (cache) == 1, "cache contains 1 entry"); ok (cache_expire_entries (cache, 44, 1) == 1, "cache_expire_entries now=44 thresh=1 expired 1"); ok (cache_count_entries (cache) == 0, "cache contains 0 entries"); cache_destroy (cache); done_testing (); return (0); }
// store file buffer into local storage // if success == TRUE then "buf" successfuly stored on disc void cache_mng_store_file_buf (CacheMng *cmng, fuse_ino_t ino, size_t size, off_t off, unsigned char *buf, cache_mng_on_store_file_buf_cb on_store_file_buf_cb, void *ctx) { struct _CacheContext *context; struct _CacheEntry *entry; ssize_t res; int fd; char path[PATH_MAX]; guint64 old_length, new_length; guint64 range_size; time_t now; range_size = (guint64)(off + size); // limit the number of cache checks now = time (NULL); if (cmng->check_time < now && now - cmng->check_time >= 10) { // remove data until we have at least size bytes of max_size left while (cmng->max_size < cmng->size + size && g_queue_peek_tail (cmng->q_lru)) { entry = (struct _CacheEntry *) g_queue_peek_tail (cmng->q_lru); cache_mng_remove_file (cmng, entry->ino); } cmng->check_time = now; } context = cache_context_create (size, ctx); context->cb.store_cb = on_store_file_buf_cb; cache_mng_file_name (cmng, path, sizeof (path), ino); fd = open (path, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { LOG_err (CMNG_LOG, INO_H"Failed to create / open file for writing! Path: %s", INO_T (ino), path); if (context->cb.store_cb) context->cb.store_cb (FALSE, context->user_ctx); cache_context_destroy (context); return; } res = pwrite(fd, buf, size, off); close (fd); entry = g_hash_table_lookup (cmng->h_entries, GUINT_TO_POINTER (ino)); if (!entry) { entry = cache_entry_create (ino); g_queue_push_head (cmng->q_lru, entry); entry->ll_lru = g_queue_peek_head_link (cmng->q_lru); g_hash_table_insert (cmng->h_entries, GUINT_TO_POINTER (ino), entry); } old_length = range_length (entry->avail_range); range_add (entry->avail_range, off, range_size); new_length = range_length (entry->avail_range); if (new_length >= old_length) cmng->size += new_length - old_length; else { LOG_err (CMNG_LOG, INO_H"New length is less than the old length !: %"G_GUINT64_FORMAT" <= %"G_GUINT64_FORMAT, INO_T (ino), new_length, old_length); } // update modification time entry->modification_time = time (NULL); context->success = (res == (ssize_t) size); LOG_debug (CMNG_LOG, INO_H"Written [%"OFF_FMT":%zu] bytes, result: %s", INO_T (ino), off, size, context->success ? "OK" : "Failed"); context->ev = event_new (application_get_evbase (cmng->app), -1, 0, cache_write_cb, context); // fire this event at once event_active (context->ev, 0, 0); event_add (context->ev, NULL); }