+
+/* Memory-map the given log object into memory (read-only) and return a pointer
+ * to it. */
+static int page_size = 0;
+
+BlueSkyRCStr *bluesky_log_map_object(BlueSkyLog *log,
+ int log_seq, int log_offset, int log_size)
+{
+ if (page_size == 0) {
+ page_size = getpagesize();
+ }
+
+ BlueSkyMmap *map;
+ g_mutex_lock(log->mmap_lock);
+ map = g_hash_table_lookup(log->mmap_cache, GINT_TO_POINTER(log_seq));
+
+ if (map == NULL) {
+ char logname[64];
+ g_snprintf(logname, sizeof(logname), "log-%08d", log_seq);
+ int fd = openat(log->dirfd, logname, O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, "Error opening logfile %s: %m\n", logname);
+ g_mutex_unlock(log->mmap_lock);
+ return NULL;
+ }
+
+ map = g_new0(BlueSkyMmap, 1);
+
+ off_t length = lseek(fd, 0, SEEK_END);
+ map->log_seq = log_seq;
+ map->addr = (const char *)mmap(NULL, length, PROT_READ, MAP_SHARED,
+ fd, 0);
+ map->len = length;
+ map->log = log;
+ g_atomic_int_set(&map->refcount, 0);
+
+ g_hash_table_insert(log->mmap_cache, GINT_TO_POINTER(log_seq), map);
+
+ close(fd);
+ }
+
+ g_mutex_unlock(log->mmap_lock);
+
+ return bluesky_string_new_from_mmap(map, log_offset, log_size);
+}
+
+void bluesky_mmap_unref(BlueSkyMmap *mmap)
+{
+ if (mmap == NULL)
+ return;
+
+ if (g_atomic_int_dec_and_test(&mmap->refcount)) {
+ /* There is a potential race condition here: the BlueSkyLog contains a
+ * hash table of currently-existing BlueSkyMmap objects, which does not
+ * hold a reference. Some other thread might grab a new reference to
+ * this object after reading it from the hash table. So, before
+ * destruction we need to grab the lock for the hash table, then check
+ * the reference count again. If it is still zero, we can proceed with
+ * object destruction. */
+ BlueSkyLog *log = mmap->log;
+ g_mutex_lock(log->mmap_lock);
+ if (g_atomic_int_get(&mmap->refcount) > 0) {
+ g_mutex_unlock(log->mmap_lock);
+ return;
+ }
+
+ g_hash_table_remove(log->mmap_cache, GINT_TO_POINTER(mmap->log_seq));
+ munmap((void *)mmap->addr, mmap->len);
+ g_free(mmap);
+ g_mutex_unlock(log->mmap_lock);
+ }
+}
+