static void *locked_read_add (struct tags_cache *c, const char *file, const int tags_sel, const int client_id, DBT *key, DBT *serialized_cache_rec) { int ret; struct file_tags *tags = NULL; assert (c->db != NULL); ret = c->db->get (c->db, NULL, key, serialized_cache_rec, 0); if (ret && ret != DB_NOTFOUND) logit ("Cache DB get error: %s", db_strerror (ret)); /* If this entry is already present in the cache, we have 3 options: * we must read different tags (TAGS_*) or the tags are outdated * or this is an immediate tags read (client_id == -1) */ if (ret == 0) { struct cache_record rec; if (cache_record_deserialize (&rec, serialized_cache_rec->data, serialized_cache_rec->size, 0)) { time_t curr_mtime = get_mtime (file); if (rec.mod_time != curr_mtime) { debug ("Tags in the cache are outdated"); tags_free (rec.tags); /* remove them and reread tags */ } else if ((rec.tags->filled & tags_sel) == tags_sel && client_id == -1) { debug ("Tags are in the cache."); return rec.tags; } else { debug ("Tags in the cache are not what we want"); tags = rec.tags; /* read additional tags */ } } } tags = read_missing_tags (file, tags, tags_sel); tags_cache_add (c, file, key, tags); return tags; }
/* Read the selected tags for this file and add it to the cache. * If client_id != -1, the server is notified using tags_response(). * If client_id == -1, copy of file_tags is returned. */ static struct file_tags *tags_cache_read_add (struct tags_cache *c, const int client_id, const char *file, int tags_sel) { struct file_tags *tags = NULL; DBT key; DBT serialized_cache_rec; DB_LOCK lock; int got_lock = 0; int ret; assert (c != NULL); assert (c->db != NULL); assert (file != NULL); debug ("Getting tags for %s", file); memset (&key, 0, sizeof(key)); memset (&serialized_cache_rec, 0, sizeof(serialized_cache_rec)); key.data = (void *)file; key.size = strlen(file); serialized_cache_rec.flags = DB_DBT_MALLOC; ret = c->db_env->lock_get (c->db_env, c->locker, 0, &key, DB_LOCK_WRITE, &lock); if (ret) { logit ("Can't get DB lock: %s", db_strerror(ret)); } else { got_lock = 1; ret = c->db->get (c->db, NULL, &key, &serialized_cache_rec, 0); if (ret && ret != DB_NOTFOUND) logit ("Cache DB get error: %s", db_strerror(ret)); } /* If this entry is already present in the cache, we have 3 options: * we must read different tags (TAGS_*) or the tags are outdated * or this is an immediate tags read (client_id == -1) */ if (ret == 0) { struct cache_record rec; if (cache_record_deserialize (&rec, serialized_cache_rec.data, serialized_cache_rec.size, 0)) { time_t curr_mtime = get_mtime (file); if (rec.mod_time != curr_mtime) { /* outdated tags - remove them and reread */ tags_free (rec.tags); debug ("Tags in the cache are outdated"); } else if ((rec.tags->filled & tags_sel) == tags_sel && client_id == -1) { debug ("Tags are in the cache."); tags = rec.tags; goto end; } else { tags = rec.tags; /* read tags in addition to already present tags */ debug ("Tags in the cache are not what we want."); } } } if (tags == NULL) tags = tags_new (); if (tags_sel & TAGS_TIME) { int time; /* Try to get it from the server's playlist first. */ time = audio_get_ftime (file); if (time != -1) { tags->time = time; tags->filled |= TAGS_TIME; tags_sel &= ~TAGS_TIME; } } tags = read_file_tags (file, tags, tags_sel); debug ("Adding/updating cache object"); tags_cache_add (c, file, tags); if (client_id != -1) { tags_response (client_id, file, tags); tags_free (tags); tags = NULL; } /* TODO: Remove the oldest items from the cache if we exceeded the maximum * cache size */ end: if (got_lock) { ret = c->db_env->lock_put (c->db_env, &lock); if (ret) logit ("Can't release DB lock: %s", db_strerror(ret)); } if (serialized_cache_rec.data) free (serialized_cache_rec.data); return tags; }