Exemple #1
0
/**
 * Turn LRU deferred writes on or off.
 * @return -1 on error with errno set, 0 if OK.
 */
int
setwdelay(DBM *db, bool on)
{
	struct lru_cache *cache = db->cache;

	if (NULL == cache)
		return init_cache(db, LRU_PAGES, on);

	sdbm_lru_check(cache);

	if (on == cache->write_deferred)
		return 0;

	/*
	 * Value is inverted.
	 */

	if (cache->write_deferred) {
		flush_dirtypag(db);
		cache->write_deferred = FALSE;
	} else {
		cache->write_deferred = TRUE;
	}

	return 0;
}
Exemple #2
0
/**
 * Mark current page as dirty.
 * If there are no deferred writes, the page is immediately flushed to disk.
 * If ``force'' is TRUE, we also ignore deferred writes and flush the page.
 * @return TRUE on success.
 */
bool
dirtypag(DBM *db, bool force)
{
	struct lru_cache *cache = db->cache;
	long n;

	sdbm_lru_check(cache);

	n = (db->pagbuf - cache->arena) / DBM_PBLKSIZ;

	g_assert(n >= 0 && n < cache->pages);
	g_assert(db->pagbno == cache->numpag[n]);

	if (cache->write_deferred && !force) {
		if (cache->dirty[n])
			cache->whits++;		/* Was already dirty -> write cache hit */
		else
			cache->wmisses++;
		cache->dirty[n] = TRUE;
		return TRUE;
	}

	/*
	 * Flush current page to the kernel.  If they are forcing the flush,
	 * make sure we ask the kernel to synchronize the data as well.
	 */

	if (flushpag(db, db->pagbuf, db->pagbno)) {
		cache->dirty[n] = FALSE;
		if G_UNLIKELY(force)
			fd_fdatasync(db->pagf);
		return TRUE;
	}
Exemple #3
0
/**
 * Flush all the dirty pages to disk.
 *
 * @return the amount of pages successfully flushed as a positive number
 * if everything was fine, 0 if there was nothing to flush, and -1 if there
 * were I/O errors (errno is set).
 */
ssize_t
flush_dirtypag(DBM *db)
{
	struct lru_cache *cache = db->cache;
	int n;
	ssize_t amount = 0;
	int saved_errno = 0;
	long pages;

	sdbm_lru_check(cache);

	pages = MIN(cache->pages, cache->next);

	for (n = 0; n < pages; n++) {
		if (cache->dirty[n]) {
			long num = cache->numpag[n];
			if (writebuf(db, num, n)) {
				amount++;
			} else {
				saved_errno = errno;
			}
		}
	}

	if (saved_errno != 0) {
		errno = saved_errno;
		return -1;
	}

	return amount;
}
Exemple #4
0
/**
 * Close (i.e. free) the LRU page cache.
 *
 * @attention
 * This does not attempt to flush any remaining dirty pages.
 */
void
lru_close(DBM *db)
{
	struct lru_cache *cache = db->cache;

	if (cache) {
		sdbm_lru_check(cache);

		if (common_stats)
			log_lrustats(db);

		free_cache(cache);
		cache->magic = 0;
		WFREE(cache);
	}

	db->cache = NULL;
}
Exemple #5
0
static void
log_lrustats(DBM *db)
{
	struct lru_cache *cache = db->cache;
	unsigned long raccesses = cache->rhits + cache->rmisses;
	unsigned long waccesses = cache->whits + cache->wmisses;

	sdbm_lru_check(cache);

	s_info("sdbm: \"%s\" LRU cache size = %ld page%s, %s writes, %s DB",
		sdbm_name(db), cache->pages, plural(cache->pages),
		cache->write_deferred ? "deferred" : "synchronous",
		db->is_volatile ? "volatile" : "persistent");
	s_info("sdbm: \"%s\" LRU read cache hits = %.2f%% on %lu request%s",
		sdbm_name(db), cache->rhits * 100.0 / MAX(raccesses, 1), raccesses,
		plural(raccesses));
	s_info("sdbm: \"%s\" LRU write cache hits = %.2f%% on %lu request%s",
		sdbm_name(db), cache->whits * 100.0 / MAX(waccesses, 1), waccesses,
		plural(waccesses));
}
Exemple #6
0
/**
 * Close the LRU page cache.
 */
void
lru_close(DBM *db)
{
	struct lru_cache *cache = db->cache;

	if (cache) {
		sdbm_lru_check(cache);

		if (!db->is_volatile && !(db->flags & DBM_BROKEN))
			flush_dirtypag(db);

		if (common_stats)
			log_lrustats(db);

		free_cache(cache);
		cache->magic = 0;
		WFREE(cache);
	}

	db->cache = NULL;
}
Exemple #7
0
/**
 * Set the page cache size.
 * @return 0 if OK, -1 on failure with errno set.
 */
int
setcache(DBM *db, long pages)
{
	struct lru_cache *cache = db->cache;
	bool wdelay;

	sdbm_lru_check(cache);

	if (pages <= 0) {
		errno = EINVAL;
		return -1;
	}

	if (NULL == cache)
		return init_cache(db, pages, FALSE);

	/*
	 * Easiest case: the size identical.
	 */

	if (pages == cache->pages)
		return 0;

	/*
	 * Cache size is changed.
	 *
	 * This means the arena will be reallocated, so we must invalidate the
	 * current db->pagbuf pointer, which lies within the old arena.  It is
	 * sufficient to reset db->pagbno, forcing a reload from the upper layers.
	 * Note than when the cache size is enlarged, the old page is still cached
	 * so reloading will be just a matter of recomputing db->pagbuf.  We could
	 * do so here, but cache size changes should only be infrequent.
	 *
	 * We also reset all the cache statistics, since a different cache size
	 * will imply a different set of hit/miss ratio.
	 */

	db->pagbno = -1;		/* Current page address will become invalid */
	db->pagbuf = NULL;

	if (common_stats) {
		s_info("sdbm: \"%s\" LRU cache size %s from %ld page%s to %ld",
			sdbm_name(db), pages > cache->pages ? "increased" : "decreased",
			cache->pages, plural(cache->pages), pages);
		log_lrustats(db);
	}

	cache->rhits = cache->rmisses = 0;
	cache->whits = cache->wmisses = 0;

	/*
	 * Straightforward: the size is increased.
	 */

	if (pages > cache->pages) {
		char *new_arena = vmm_alloc(pages * DBM_PBLKSIZ);
		if (NULL == new_arena)
			return -1;
		memmove(new_arena, cache->arena, cache->pages * DBM_PBLKSIZ);
		vmm_free(cache->arena, cache->pages * DBM_PBLKSIZ);
		cache->arena = new_arena;
		cache->dirty = wrealloc(cache->dirty, cache->pages, pages);
		cache->numpag = wrealloc(cache->numpag,
			cache->pages * sizeof(long), pages * sizeof(long));
		cache->pages = pages;
		return 0;
	}

	/*
	 * Difficult: the size is decreased.
	 *
	 * The current page buffer could point in a cache area that is going
	 * to disappear, and the internal data structures must forget about
	 * all the old indices that are greater than the new limit.
	 *
	 * We do not try to optimize anything here, as this call should happen
	 * only infrequently: we flush the current cache (in case there are
	 * deferred writes), destroy the LRU cache data structures, recreate a
	 * new one and invalidate the current DB page.
	 */

	wdelay = cache->write_deferred;
	flush_dirtypag(db);
	free_cache(cache);
	return setup_cache(cache, pages, wdelay);
}