+ if (memcmp(&id, &id0, sizeof(BlueSkyCloudID)) == 0)
+ return NULL;
+
+ g_mutex_lock(fs->lock);
+ BlueSkyCloudLog *item;
+ item = g_hash_table_lookup(fs->locations, &id);
+ if (item == NULL) {
+ item = bluesky_cloudlog_new(fs, &id);
+ bluesky_cloudlog_stats_update(item, 1);
+ bluesky_cloudlog_insert_locked(item);
+ } else {
+ bluesky_cloudlog_ref(item);
+ }
+ g_mutex_unlock(fs->lock);
+ return item;
+}
+
+/* Work to fetch a cloudlog item in a background thread. The item will be
+ * locked while the fetch is in progress and unlocked when it completes. */
+static GThreadPool *fetch_pool;
+
+static void background_fetch_task(gpointer p, gpointer unused)
+{
+ BlueSkyCloudLog *item = (BlueSkyCloudLog *)p;
+
+ g_mutex_lock(item->lock);
+ g_mutex_unlock(item->lock);
+ bluesky_cloudlog_unref(item);
+}
+
+void bluesky_cloudlog_background_fetch(BlueSkyCloudLog *item)
+{
+ bluesky_cloudlog_ref(item);
+ g_thread_pool_push(fetch_pool, item, NULL);
+}
+
+/* Attempt to prefetch a cloud log item. This does not guarantee that it will
+ * be made available, but does make it more likely that a future call to
+ * bluesky_cloudlog_fetch will complete quickly. Item must be locked? */
+void bluesky_cloudlog_prefetch(BlueSkyCloudLog *item)
+{
+ if (item->data != NULL)
+ return;
+
+ /* When operating in a non log-structured mode, simply start a background
+ * fetch immediately when asked to prefetch. */
+ if (bluesky_options.disable_aggregation
+ || bluesky_options.disable_read_aggregation) {
+ bluesky_cloudlog_background_fetch(item);
+ return;
+ }
+
+ /* TODO: Some of the code here is duplicated with bluesky_log_map_object.
+ * Refactor to fix that. */
+ BlueSkyFS *fs = item->fs;
+ BlueSkyCacheFile *map = NULL;
+
+ /* First, check to see if the journal still contains a copy of the item and
+ * if so update the atime on the journal so it is likely to be kept around
+ * until we need it. */
+ if ((item->location_flags | item->pending_write) & CLOUDLOG_JOURNAL) {
+ map = bluesky_cachefile_lookup(fs, -1, item->log_seq, TRUE);
+ if (map != NULL) {
+ map->atime = bluesky_get_current_time();
+ bluesky_cachefile_unref(map);
+ g_mutex_unlock(map->lock);
+ return;
+ }
+ }
+
+ item->location_flags &= ~CLOUDLOG_JOURNAL;
+ if (!(item->location_flags & CLOUDLOG_CLOUD))
+ return;
+
+ map = bluesky_cachefile_lookup(fs,
+ item->location.directory,
+ item->location.sequence,
+ FALSE);
+ if (map == NULL)
+ return;