package de.hub.emffrag.datastore; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.TreeMap; import de.hub.emffrag.EmfFragActivator; public class WriteCachingDataStore extends AbstractDelegatingDataStore { private final TreeMap<byte[], byte[]> cache = new TreeMap<byte[], byte[]>(InMemoryDataStore.byteComparator); private final IBulkInsertExtension bulkInsertExtension; private int bulkInsertSize = 1000; public void setBulkInsertSize(int bulkInsertSize) { this.bulkInsertSize = bulkInsertSize; } public WriteCachingDataStore(IBaseDataStore baseDataStore, IBulkInsertExtension bulkInsertExtension) { super(baseDataStore); this.bulkInsertExtension = bulkInsertExtension; if (EmfFragActivator.instance != null) { this.bulkInsertSize = EmfFragActivator.instance.bulkInsertSize; } } private void performBulkInsert() { bulkInsertExtension.bulkInsert(cache); cache.clear(); } @Override public InputStream openInputStream(byte[] key) { byte[] cachedValue = cache.get(key); if (cachedValue == null) { return super.openInputStream(key); } else { return new ByteArrayInputStream(cachedValue); } } @Override public OutputStream openOutputStream(final byte[] key) { return new ByteArrayOutputStream() { @Override public void close() throws IOException { super.close(); cache.put(key, toByteArray()); if (cache.size() > bulkInsertSize) { performBulkInsert(); } } }; } private byte[] computeFloorOrCeiling(byte[] cachedValue, byte[] dbValue, int compareValue) { if (cachedValue == null) { return dbValue; } else { if (dbValue == null) { return cachedValue; } else { if (cachedValue != null && InMemoryDataStore.byteComparator.compare(cachedValue, dbValue) == compareValue) { return cachedValue; } else { return dbValue; } } } } @Override public byte[] ceiling(byte[] key) { byte[] cacheCeiling = cache.ceilingKey(key); byte[] dbCeiling = super.ceiling(key); return computeFloorOrCeiling(cacheCeiling, dbCeiling, -1); } @Override public byte[] floor(byte[] key) { byte[] cacheFloor = cache.floorKey(key); byte[] dbFloor = super.floor(key); return computeFloorOrCeiling(cacheFloor, dbFloor, 1); } @Override public boolean check(byte[] key) { if (cache.get(key) != null) { return false; } else { return super.check(key); } } @Override public boolean checkAndCreate(byte[] key) { if (cache.get(key) != null) { return false; } else { if (super.checkAndCreate(key)) { cache.put(key, new byte[]{}); return true; } else { return false; } } } @Override public void delete(byte[] bytes) { cache.remove(bytes); super.delete(bytes); } @Override public void flush() { performBulkInsert(); super.flush(); } }