Gitlab Community Edition Instance

Commit f1f5d2cd authored by mhellka's avatar mhellka
Browse files

Make NioPool cache size configurable; Fixed some metrics

parent 808f5d98
......@@ -53,6 +53,8 @@ import de.gwdg.cdstar.ta.UserTransaction;
@Plugin
public class NioPool implements StoragePool {
private static final String PROP_CACHE_SIZE = "cacheSize";
private static final String PROP_PATH = "path";
static final String EXT_BLOB = ".bin";
static final String EXT_REVISION = ".json";
static final String FILENAME_NEXT = "HEAD_NEXT";
......@@ -62,21 +64,21 @@ public class NioPool implements StoragePool {
public static final int SHARD_DEPTH = 2;
private static JsonFormat objectLoader = new JsonFormat();
private int cacheSize = 1024;
// Running transactions
ConcurrentHashMap<String, NioSession> scopes = new ConcurrentHashMap<>();
final Path basePath;
private final FileSharder pathSharder;
NioRecoveryHandler recoveryHandler;
LoadingCache<Path, JsonIndex> indexCache;
private final PoolStats stats;
final NioRecoveryHandler recoveryHandler;
private LoadingCache<Path, JsonIndex> indexCache;
public NioPool(Config cfg) throws IOException, ConfigException {
// TODO: Make more than just the path configurable
this(Paths.get(cfg.get("path")));
this(Paths.get(cfg.get(PROP_PATH)));
cfg.setDefault(PROP_CACHE_SIZE, Integer.toString(cacheSize));
setCacheSize(cfg.getInt(PROP_CACHE_SIZE));
}
public NioPool(Path base) throws IOException {
......@@ -85,15 +87,21 @@ public class NioPool implements StoragePool {
recoveryHandler = new NioRecoveryHandler(this);
if (!Files.isDirectory(base))
Files.createDirectories(basePath);
rebuildCache();
}
indexCache = Caffeine.newBuilder()
// TODO: Make this configurable
.maximumSize(1024)
// Allow GC to shrink the heap during idle hours.
.expireAfterAccess(60, TimeUnit.SECONDS)
.build(this::loadFromDisk);
public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
rebuildCache();
}
stats = new PoolStats();
private void rebuildCache() {
indexCache = Caffeine.newBuilder()
// TODO: Make this configurable
.maximumSize(cacheSize)
// Allow GC to shrink the heap during idle hours.
.expireAfterAccess(60, TimeUnit.SECONDS)
.build(this::loadFromDisk);
}
@Override
......@@ -157,7 +165,7 @@ public class NioPool implements StoragePool {
void write(JsonIndex obj) throws IOException {
try (final OutputStream stream = Files.newOutputStream(getObjectFile(obj.id, obj.rev),
StandardOpenOption.CREATE_NEW);
OutputStream buffered = new BufferedOutputStream(stream)) {
OutputStream buffered = new BufferedOutputStream(stream)) {
objectLoader.write(buffered, obj);
}
}
......@@ -295,6 +303,7 @@ public class NioPool implements StoragePool {
/**
* Create the object directory, if it does not exist already.
*
* @param id Object ID
* @return true on success, false otherwise
*/
......@@ -316,11 +325,9 @@ public class NioPool implements StoragePool {
/**
* Lock an object globally for writing (reading allowed).
*
* @param id
* The object ID
* @param nextRevision
* The target revision, or null if the lock is not actually
* creating a new revision.
* @param id The object ID
* @param nextRevision The target revision, or null if the lock is not actually
* creating a new revision.
*/
SymlinkLock lockObject(String id, String nextRevision) throws IOException {
return new SymlinkLock(getHEAD(id), getObjectFile(id, nextRevision),
......@@ -342,48 +349,52 @@ public class NioPool implements StoragePool {
return false;
}
/**
* Return a snapshot of the current pool statistics
*/
public PoolStats getStats() {
return stats;
return new PoolStats();
}
public class PoolStats {
public CacheStats getCacheStats() {
return indexCache.stats();
}
FileStore getFileStore() throws IOException {
Path target = basePath;
while (Files.isSymbolicLink(target))
target = Files.readSymbolicLink(target);
return Files.getFileStore(target);
}
public long getDiskTotal() {
private final CacheStats cacheStats;
private long fsFree = -1;
private long fsTotal = -1;
private final long cacheSize;
public PoolStats() {
cacheStats = indexCache.stats();
cacheSize = indexCache.estimatedSize();
try {
return getFileStore().getTotalSpace();
Path target = basePath;
while (Files.isSymbolicLink(target))
target = Files.readSymbolicLink(target);
final FileStore fileStore = Files.getFileStore(target);
fsFree = fileStore.getUsableSpace();
fsTotal = fileStore.getTotalSpace();
} catch (final IOException e) {
return -1;
log.warn("Unable to read file system statistics", e);
}
}
public long getDiskFree() {
try {
return getFileStore().getUsableSpace();
} catch (final IOException e) {
return -1;
}
public long diskTotal() {
return fsTotal;
}
public long diskFree() {
return fsFree;
}
public long cacheSize() {
return indexCache.estimatedSize();
return cacheSize;
}
public long cacheHitCount() {
return indexCache.stats().hitCount();
return cacheStats.hitCount();
}
public long cacheMissCount() {
return indexCache.stats().missCount();
return cacheStats.missCount();
}
}
......
......@@ -27,7 +27,6 @@ import de.gwdg.cdstar.config.MapConfig;
import de.gwdg.cdstar.pool.PoolError;
import de.gwdg.cdstar.pool.StoragePool;
import de.gwdg.cdstar.pool.nio.NioPool;
import de.gwdg.cdstar.pool.nio.NioPool.PoolStats;
import de.gwdg.cdstar.runtime.Config;
import de.gwdg.cdstar.runtime.ConfigException;
import de.gwdg.cdstar.runtime.RuntimeContext;
......@@ -116,7 +115,7 @@ public class VaultRegistry implements RuntimeListener {
vaultConfigs.forEach((name, vc) -> {
try {
vc.close();
} catch (Exception e) {
} catch (final Exception e) {
log.warn("Failed to properly close vault: {}", vc.getName(), e);
}
});
......@@ -130,15 +129,15 @@ public class VaultRegistry implements RuntimeListener {
if (vaultConfigs.containsKey(vaultName))
throw new IllegalStateException("Vault loaded twice: " + vaultName);
Config properties = ConfigLoader.fromFile(getConfigPathFor(vaultName).toFile());
VaultConfigImpl vci = new VaultConfigImpl(vaultName, properties);
final Config properties = ConfigLoader.fromFile(getConfigPathFor(vaultName).toFile());
final VaultConfigImpl vci = new VaultConfigImpl(vaultName, properties);
vaultConfigs.put(vci.getName(), vci);
return vci;
}
private synchronized void saveVault(String vaultName, Config properties, boolean reload) throws IOException {
Path confFile = getConfigPathFor(vaultName);
VaultConfigImpl old = vaultConfigs.remove(vaultName);
final Path confFile = getConfigPathFor(vaultName);
final VaultConfigImpl old = vaultConfigs.remove(vaultName);
if (!reload && (old != null || Files.exists(confFile)))
throw new IllegalStateException("Vault exists: " + vaultName);
......@@ -156,7 +155,7 @@ public class VaultRegistry implements RuntimeListener {
if (old != null)
old.close();
VaultConfigImpl vci = new VaultConfigImpl(vaultName, properties);
final VaultConfigImpl vci = new VaultConfigImpl(vaultName, properties);
vaultConfigs.put(vaultName, vci);
runtime.lookupAll(VaultConfigListener.class).forEach(l -> l.vaultConfigChanged(vaultConfigs.get(vaultName)));
......@@ -181,8 +180,8 @@ public class VaultRegistry implements RuntimeListener {
}
public StoragePool getPoolFor(VaultConfig vault) {
VaultConfigImpl vci = (VaultConfigImpl) vault;
StoragePool pool = vci.pool;
final VaultConfigImpl vci = (VaultConfigImpl) vault;
final StoragePool pool = vci.pool;
if (pool == null)
return initPool(vci);
return pool;
......@@ -194,8 +193,8 @@ public class VaultRegistry implements RuntimeListener {
return vci.pool;
try {
Config scoped = vci.config.with("pool");
String poolClassName = scoped.get("class", NioPool.class.getName());
final Config scoped = vci.config.with("pool");
final String poolClassName = scoped.get("class", NioPool.class.getName());
// Resolve relative or missing pool data paths
scoped.set("path", dataPath.resolve(scoped.get("path", vci.getName())).toAbsolutePath().toString());
......@@ -217,21 +216,16 @@ public class VaultRegistry implements RuntimeListener {
private void addMetrics(VaultConfigImpl vci) {
if (vci.pool instanceof NioPool) {
runtime.lookup(MetricRegistry.class).ifPresent(mr -> {
String name = "pool." + vci.getName();
NioPool pool = (NioPool) vci.pool;
PoolStats poolStats = pool.getStats();
mr.gauge(name + ".cache.hit", () -> () -> poolStats.cacheHitCount());
mr.gauge(name + ".cache.miss", () -> () -> poolStats.cacheMissCount());
mr.gauge(name + ".cache.size", () -> () -> poolStats.cacheSize());
mr.gauge(name + ".disk.total", () -> () -> poolStats.getDiskTotal());
mr.gauge(name + ".disk.free", () -> () -> poolStats.getDiskFree());
final String name = "pool." + vci.getName();
final NioPool pool = (NioPool) vci.pool;
mr.gauge(name + ".cache.hit", () -> () -> pool.getStats().cacheHitCount());
mr.gauge(name + ".cache.miss", () -> () -> pool.getStats().cacheMissCount());
mr.gauge(name + ".cache.size", () -> () -> pool.getStats().cacheSize());
mr.gauge(name + ".disk.total", () -> () -> pool.getStats().diskTotal());
mr.gauge(name + ".disk.free", () -> () -> pool.getStats().diskFree());
});
}
}
private boolean isValidVaultName(String name) {
......@@ -249,7 +243,7 @@ public class VaultRegistry implements RuntimeListener {
public class VaultConfigImpl implements VaultConfig, Closeable {
private StoragePool pool;
private boolean isPublic;
private final boolean isPublic;
private final String name;
private final Config config;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment