/* 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. */
-void bluesky_cloudlog_prefetch(BlueSkyCloudLog *log)
+ * bluesky_cloudlog_fetch will complete quickly. Item must be locked? */
+void bluesky_cloudlog_prefetch(BlueSkyCloudLog *item)
{
- gchar *id = bluesky_cloudlog_id_to_string(log->id);
- g_print("Prefetch for %s\n", id);
- g_free(id);
+ if (item->data != NULL)
+ 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;
+
+ /* At this point, we have information about the log segment containing the
+ * item we need. If our item is already fetched, we have nothing to do
+ * except update the atime. If not, queue up a fetch of our object. */
+ const BlueSkyRangesetItem *rangeitem;
+ rangeitem = bluesky_rangeset_lookup(map->items,
+ item->location.offset);
+ if (rangeitem == NULL) {
+ if (map->prefetches == NULL)
+ map->prefetches = bluesky_rangeset_new();
+
+ gchar *id = bluesky_cloudlog_id_to_string(item->id);
+ g_print("Need to prefetch %s\n", id);
+ g_free(id);
+
+ bluesky_rangeset_insert(map->prefetches,
+ item->location.offset,
+ item->location.size, NULL);
+
+ uint64_t start, length;
+ bluesky_rangeset_get_extents(map->prefetches, &start, &length);
+ g_print("Range to prefetch: %"PRIu64" + %"PRIu64"\n", start, length);
+ }
+
+ bluesky_cachefile_unref(map);
+ g_mutex_unlock(map->lock);
}
/* Ensure that a cloud log item is loaded in memory, and if not read it in.
if (rangeitem == NULL) {
g_print("Item at offset 0x%zx not available, need to fetch.\n",
file_offset);
- if (range_request)
- cloudlog_partial_fetch_start(map, file_offset, file_size);
+ if (range_request) {
+ uint64_t start = 0, length = 0, end;
+ if (map->prefetches != NULL)
+ bluesky_rangeset_get_extents(map->prefetches,
+ &start, &length);
+ start = MIN(start, file_offset);
+ end = MAX(start + length, file_offset + file_size);
+ length = end - start;
+ cloudlog_partial_fetch_start(map, start, length);
+ if (map->prefetches != NULL) {
+ bluesky_rangeset_free(map->prefetches);
+ map->prefetches = NULL;
+ }
+ }
g_cond_wait(map->cond, map->lock);
} else if (rangeitem->start == file_offset
&& rangeitem->length == file_size) {
}
return item;
}
+
+/* Determine the full extent of a rangeset--the smallest offset covered and the
+ * length needed to extend to the end of the last item. */
+void bluesky_rangeset_get_extents(BlueSkyRangeset *rangeset,
+ uint64_t *start, uint64_t *length)
+{
+ GSequenceIter *i;
+ BlueSkyRangesetItem *item;
+
+ i = g_sequence_get_begin_iter(rangeset->seq);
+ if (g_sequence_iter_is_end(i)) {
+ *start = 0;
+ *length = 0;
+ return;
+ }
+
+ item = (BlueSkyRangesetItem *)g_sequence_get(i);
+ *start = item->start;
+
+ i = g_sequence_get_end_iter(rangeset->seq);
+ i = g_sequence_iter_prev(i);
+ item = (BlueSkyRangesetItem *)g_sequence_get(i);
+ *length = (item->start + item->length) - *start;
+}