blob: 2705073de6ebafd73e1516e5e29f20fb39e43776 [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.je.evictor;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.dbi.DbConfigManager;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.dbi.MemoryBudget;
import com.sleepycat.je.utilint.TestHook;
/**
* The Arbiter determines whether eviction should occur, by consulting the
* memory budget.
*/
class Arbiter {
private final MemoryBudget.Totals memBudgetTotals;
/* Debugging and unit test support. */
private TestHook<Boolean> runnableHook;
/* je.evictor.evictBytes */
private final long evictBytesSetting;
Arbiter(EnvironmentImpl envImpl) {
DbConfigManager configManager = envImpl.getConfigManager();
evictBytesSetting = configManager.getLong(
EnvironmentParams.EVICTOR_EVICT_BYTES);
memBudgetTotals = envImpl.getMemoryBudget().getTotals();
}
/**
* Return true if the memory budget is overspent.
*/
boolean isOverBudget() {
return memBudgetTotals.getCacheUsage() >
memBudgetTotals.getMaxMemory();
}
/**
* Do a check on whether synchronous eviction is needed.
*
* Note that this method is intentionally not synchronized in order to
* minimize overhead when checking for critical eviction. This method is
* called from application threads for every cursor operation.
*/
boolean needCriticalEviction() {
final long over = memBudgetTotals.getCacheUsage() -
memBudgetTotals.getMaxMemory();
return (over > memBudgetTotals.getCriticalThreshold());
}
/**
* Do a check on whether the cache should still be subject to eviction.
*
* Note that this method is intentionally not synchronized in order to
* minimize overhead, because it's checked on every iteration of the
* evict batch loop.
*/
boolean stillNeedsEviction() {
return (memBudgetTotals.getCacheUsage() + evictBytesSetting) >
memBudgetTotals.getMaxMemory();
}
/**
* Return non zero number of bytes if eviction should happen. Caps the
* number of bytes a single thread will try to evict.
*/
long getEvictionPledge() {
long currentUsage = memBudgetTotals.getCacheUsage();
long maxMem = memBudgetTotals.getMaxMemory();
long overBudget = currentUsage - maxMem;
boolean doRun = (overBudget > 0);
long requiredEvictBytes = 0;
/* If running, figure out how much to evict. */
if (doRun) {
requiredEvictBytes = overBudget + evictBytesSetting;
/* Don't evict more than 50% of the cache. */
if (currentUsage - requiredEvictBytes < maxMem / 2) {
requiredEvictBytes = overBudget + (maxMem / 2);
}
}
/* Unit testing, force eviction. */
if (runnableHook != null) {
doRun = runnableHook.getHookValue();
if (doRun) {
requiredEvictBytes = maxMem;
} else {
requiredEvictBytes = 0;
}
}
return requiredEvictBytes;
}
/* For unit testing only. */
void setRunnableHook(TestHook<Boolean> hook) {
runnableHook = hook;
}
}