#include "bluesky-private.h"
#define WRITEBACK_DELAY (20 * 1000000)
+#define CACHE_DROP_DELAY (20 * 1000000)
/* Filesystem caching and cache coherency. There are actually a couple of
* different tasks that are performed here:
bluesky_inode_start_sync(inode);
}
+/* Check whether memory usage may have dropped below critical thresholds for
+ * waking up waiting threads. */
+void flushd_check_wakeup(BlueSkyFS *fs)
+{
+ int dirty = g_atomic_int_get(&fs->cache_dirty);
+ dirty += g_atomic_int_get(&fs->cache_log_dirty);
+
+ if (dirty <= bluesky_watermark_high_dirty)
+ g_cond_broadcast(fs->flushd_cond);
+}
+
/* Try to flush dirty data to disk, either due to memory pressure or due to
* timeouts. */
static void flushd_dirty(BlueSkyFS *fs)
bluesky_inode_unref(inode);
g_mutex_lock(fs->lock);
+ flushd_check_wakeup(fs);
}
+ g_cond_broadcast(fs->flushd_cond);
+
g_mutex_unlock(fs->lock);
}
-/* Try to flush dirty data to the cloud. */
+/* Try to flush dirty data to the cloud.
+ * TODO: Rewrite this to work on cloud log items rather than inodes, so we can
+ * better track which logs are fully synchronized to the cloud and can be
+ * garbage collected if needed? */
static void flushd_cloud(BlueSkyFS *fs)
{
int64_t start_time = bluesky_get_current_time();
bluesky_file_drop_cached(inode);
}
-/* Drop clean data from the cache if needed due to memory pressure. */
+/* Drop clean data from the cache if needed. Clean data should generally be
+ * memory-mapped from log file or similar, so the kernel can drop this clean
+ * data from memory for us and hence memory management isn't too important.
+ * Mainly, we'll want to drop references to data that hasn't been accessed in a
+ * while so that it is possible to reclaim log segments on disk. */
static void flushd_clean(BlueSkyFS *fs)
{
g_mutex_lock(fs->lock);
inode_count = 1;
while (inode_count-- > 0) {
-#if 0
- if (g_atomic_int_get(&fs->cache_total) < bluesky_watermark_medium_total)
- break;
-#endif
-
BlueSkyInode *inode;
if (fs->accessed_list.prev == NULL)
break;
inode = fs->accessed_list.prev->data;
+ uint64_t elapsed = bluesky_get_current_time() - inode->access_time;
+ if (elapsed < CACHE_DROP_DELAY)
+ break;
+
if (bluesky_verbose) {
g_log("bluesky/flushd", G_LOG_LEVEL_DEBUG,
"Considering dropping cached data for inode %"PRIu64,
void bluesky_flushd_invoke_conditional(BlueSkyFS *fs)
{
- if (g_atomic_int_get(&fs->cache_dirty) < bluesky_watermark_high_dirty
- /*&& g_atomic_int_get(&fs->cache_total) < bluesky_watermark_high_total*/)
+ if (g_atomic_int_get(&fs->cache_dirty) < bluesky_watermark_medium_dirty)
return;
if (bluesky_verbose) {
}
bluesky_flushd_invoke(fs);
+
+ /* If the system is under heavy memory pressure, actually delay execution
+ * so the flush daemon can catch up. */
+ while (g_atomic_int_get(&fs->cache_dirty)
+ + g_atomic_int_get(&fs->cache_log_dirty)
+ > bluesky_watermark_high_dirty) {
+ g_log("bluesky/flushd", G_LOG_LEVEL_DEBUG,
+ "Waiting due to memory pressure, dirty=%d + %d",
+ g_atomic_int_get(&fs->cache_dirty),
+ g_atomic_int_get(&fs->cache_log_dirty));
+ g_mutex_lock(fs->lock);
+ g_cond_wait(fs->flushd_cond, fs->lock);
+ g_mutex_unlock(fs->lock);
+ }
}
/* Start a perpetually-running thread that flushes the cache occasionally. */