提交 5f5eb72d authored 作者: Thomas Mueller's avatar Thomas Mueller

MVStore: simpler API

上级 7cb0c93e
......@@ -847,7 +847,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* Forget those old versions that are no longer needed.
*/
void removeUnusedOldVersions() {
long oldest = store.getRetainOrStoreVersion();
long oldest = store.getOldestVersionToKeep();
if (oldest == -1) {
return;
}
......
......@@ -57,6 +57,10 @@ MVTableEngine:
TransactionStore:
MVStore:
- better document auto-commit (also when many unsaved pages)
advantages and disadvantages
- auto-commit when used in memory as well
- better document MVStore setters
- automated 'kill process' and 'power failure' test
- update checkstyle
- feature to auto-compact from time to time and on close
......@@ -124,7 +128,7 @@ MVStore:
- fix documentation (including examples)
- autocommit commits, stores, and compacts from time to time;
the background thread should wait at least 90% of the
configured write delay to store changes
configured write delay to store changes
- currently, uncommitted changes are stored if there are many transient changes,
and rolled back when opening - is this really needed?
- compact* should also store uncommitted changes (if there are any)
......@@ -177,8 +181,7 @@ public class MVStore {
/**
* The map of chunks.
*/
private final ConcurrentHashMap<Integer, Chunk> chunks =
new ConcurrentHashMap<Integer, Chunk>();
private final ConcurrentHashMap<Integer, Chunk> chunks = new ConcurrentHashMap<Integer, Chunk>();
/**
* The map of temporarily freed storage space caused by freed pages. The key
......@@ -189,12 +192,12 @@ public class MVStore {
new ConcurrentHashMap<Long, HashMap<Integer, Chunk>>();
/**
* The metadata map. Write access to this map needs to be synchronized on the store.
* The metadata map. Write access to this map needs to be synchronized on
* the store.
*/
private MVMap<String, String> meta;
private MVMapConcurrent<String, String> meta;
private final ConcurrentHashMap<Integer, MVMap<?, ?>> maps =
new ConcurrentHashMap<Integer, MVMap<?, ?>>();
private final ConcurrentHashMap<Integer, MVMap<?, ?>> maps = new ConcurrentHashMap<Integer, MVMap<?, ?>>();
private HashMap<String, String> storeHeader = New.hashMap();
......@@ -202,7 +205,7 @@ public class MVStore {
private int lastMapId;
private long retainVersion = -1;
private int versionsToKeep = 5;
/**
* Whether to compress new pages. Even if disabled, the store may contain
......@@ -222,14 +225,13 @@ public class MVStore {
private long lastStoredVersion;
/**
* The estimated number of unsaved pages
* (this number may not be completely accurate,
* because it may be changed concurrently, and
* because temporary pages are counted)
* The estimated number of unsaved pages (this number may not be completely
* accurate, because it may be changed concurrently, and because temporary
* pages are counted)
*/
private int unsavedPageCount;
private int unsavedPageCountMax;
private boolean storeNeeded;
private int autoCommitPageCount;
private boolean saveNeeded;
/**
* The time the store was created, in milliseconds since 1970.
......@@ -237,7 +239,7 @@ public class MVStore {
private long creationTime;
private int retentionTime;
private long lastStoreTime;
private long lastCommitTime;
/**
* The earliest chunk to retain, if any.
......@@ -248,15 +250,15 @@ public class MVStore {
* The version of the current store operation (if any).
*/
private volatile long currentStoreVersion = -1;
private Thread currentStoreThread;
private volatile boolean metaChanged;
/**
* The delay in milliseconds to automatically store changes.
* The delay in milliseconds to automatically commit and write changes.
*/
private int writeDelay;
private int autoCommitDelay;
/**
* Create and open the store.
......@@ -272,7 +274,8 @@ public class MVStore {
pageSplitSize = o == null ? 6 * 1024 : (Integer) o;
o = config.get("backgroundExceptionHandler");
this.backgroundExceptionHandler = (UncaughtExceptionHandler) o;
meta = new MVMap<String, String>(StringDataType.INSTANCE, StringDataType.INSTANCE);
meta = new MVMapConcurrent<String, String>(StringDataType.INSTANCE,
StringDataType.INSTANCE);
HashMap<String, String> c = New.hashMap();
c.put("id", "0");
c.put("createVersion", Long.toString(currentVersion));
......@@ -295,21 +298,21 @@ public class MVStore {
int averageMemory = Math.max(10, pageSplitSize / 2);
int segmentCount = 16;
int stackMoveDistance = maxMemoryBytes / averageMemory * 2 / 100;
cache = new CacheLongKeyLIRS<Page>(
maxMemoryBytes, averageMemory, segmentCount, stackMoveDistance);
cache = new CacheLongKeyLIRS<Page>(maxMemoryBytes, averageMemory,
segmentCount, stackMoveDistance);
}
o = config.get("writeBufferSize");
o = config.get("autoCommitBufferSize");
mb = o == null ? 4 : (Integer) o;
int writeBufferSize = mb * 1024 * 1024;
int autoCommitBufferSize = mb * 1024 * 1024;
int div = pageSplitSize;
unsavedPageCountMax = writeBufferSize / (div == 0 ? 1 : div);
autoCommitPageCount = autoCommitBufferSize / (div == 0 ? 1 : div);
char[] encryptionKey = (char[]) config.get("encryptionKey");
try {
fileStore.open(fileName, readOnly, encryptionKey);
if (fileStore.size() == 0) {
creationTime = 0;
creationTime = getTime();
lastStoreTime = creationTime;
lastCommitTime = creationTime;
storeHeader.put("H", "3");
storeHeader.put("blockSize", "" + BLOCK_SIZE);
storeHeader.put("format", "" + FORMAT_WRITE);
......@@ -348,14 +351,13 @@ public class MVStore {
Arrays.fill(encryptionKey, (char) 0);
}
}
lastStoreTime = getTime();
// setWriteDelay starts the thread, but only if
// the parameter is different than the current value
lastCommitTime = getTime();
o = config.get("writeDelay");
int writeDelay = o == null ? 1000 : (Integer) o;
setWriteDelay(writeDelay);
// setAutoCommitDelay starts the thread, but only if
// the parameter is different from the old value
o = config.get("autoCommitDelay");
int delay = o == null ? 1000 : (Integer) o;
setAutoCommitDelay(delay);
}
/**
......@@ -380,7 +382,8 @@ public class MVStore {
* @return the read-only map
*/
@SuppressWarnings("unchecked")
<T extends MVMap<?, ?>> T openMapVersion(long version, int mapId, MVMap<?, ?> template) {
<T extends MVMap<?, ?>> T openMapVersion(long version, int mapId,
MVMap<?, ?> template) {
MVMap<String, String> oldMeta = getMetaMap(version);
String r = oldMeta.get("root." + mapId);
long rootPos = DataUtils.parseLong(r, 0);
......@@ -468,7 +471,7 @@ public class MVStore {
* root.{mapId} = {root position}
* setting.storeVersion = {version}
* </pre>
*
*
* @return the metadata map
*/
public MVMap<String, String> getMetaMap() {
......@@ -512,7 +515,7 @@ public class MVStore {
metaChanged = true;
}
private void readMeta() {
private synchronized void readMeta() {
chunks.clear();
Chunk header = readChunkHeader(rootChunkStart);
if (header.start == Long.MAX_VALUE) {
......@@ -569,7 +572,8 @@ public class MVStore {
// we don't know which chunk is the newest
long newestChunk = -1;
// read the last block of the file, and then the two first blocks
ByteBuffer buffLastBlock = fileStore.readFully(fileStore.size() - BLOCK_SIZE, BLOCK_SIZE);
ByteBuffer buffLastBlock = fileStore.readFully(fileStore.size()
- BLOCK_SIZE, BLOCK_SIZE);
ByteBuffer buffFirst2Blocks = fileStore.readFully(0, BLOCK_SIZE * 2);
ByteBuffer buff = ByteBuffer.allocate(3 * BLOCK_SIZE);
buff.put(buffLastBlock);
......@@ -611,7 +615,8 @@ public class MVStore {
}
if (currentVersion < 0) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, "Store header is corrupt: {0}", fileStore);
DataUtils.ERROR_FILE_CORRUPT,
"Store header is corrupt: {0}", fileStore);
}
setWriteVersion(currentVersion);
lastStoredVersion = -1;
......@@ -647,10 +652,7 @@ public class MVStore {
}
/**
* Close the file and the store. If there are any uncommitted changes, they
* are written to disk first. All open maps are closed.
* <p>
* It is not allowed to concurrently call close and store.
* Close the file and the store. Unsaved changes are written to disk first.
*/
public void close() {
if (closed) {
......@@ -659,7 +661,7 @@ public class MVStore {
if (fileStore != null && !fileStore.isReadOnly()) {
stopBackgroundThread();
if (hasUnsavedChanges()) {
store();
commitAndSave();
}
}
closeStore(true);
......@@ -722,6 +724,11 @@ public class MVStore {
int chunkId = DataUtils.getPageChunkId(pos);
Chunk c = chunks.get(chunkId);
if (c == null) {
if (!Thread.holdsLock(this)) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_INTERNAL,
"Unsynchronized metadata read");
}
String s = meta.get("chunk." + chunkId);
if (s == null) {
throw DataUtils.newIllegalStateException(
......@@ -747,18 +754,22 @@ public class MVStore {
}
/**
* Commit the changes. This method marks the changes as committed and
* increments the version.
* Commit the changes.
* <p>
* Unless the write delay is set to 0, this method does not write to the
* file. Instead, data is written after the delay, manually by calling the
* store method, when the write buffer is full, or when closing the store.
* For in-memory stores, this method increments the version.
* <p>
* For persistent stores, it also writes changes to disk. It does nothing if
* there are no unsaved changes, and returns the old version. It is not
* necessary to call this method when auto-commit is enabled (the default
* setting), as in this case it is automatically called from time to time or
* when enough changes have accumulated. However, it may still be called to
* flush all changes to disk.
*
* @return the new version
*/
public long commit() {
if (fileStore != null) {
return store();
return commitAndSave();
}
long v = ++currentVersion;
setWriteVersion(v);
......@@ -774,13 +785,14 @@ public class MVStore {
*
* @return the new version (incremented if there were changes)
*/
public synchronized long store() {
private synchronized long commitAndSave() {
if (closed) {
return currentVersion;
}
if (fileStore == null) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_WRITING_FAILED, "This is an in-memory store");
DataUtils.ERROR_WRITING_FAILED,
"This is an in-memory store");
}
if (currentStoreVersion >= 0) {
// store is possibly called within store, if the meta map changed
......@@ -811,7 +823,7 @@ public class MVStore {
long version = ++currentVersion;
setWriteVersion(version);
long time = getTime();
lastStoreTime = time;
lastCommitTime = time;
retainChunk = null;
// the last chunk was not completely correct in the last store()
......@@ -903,14 +915,6 @@ public class MVStore {
}
boolean storeAtEndOfFile = filePos + length >= end;
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// ; int todo;
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
c.start = filePos;
c.length = chunkLength;
c.metaRootPos = metaRoot.getPos();
......@@ -944,8 +948,10 @@ public class MVStore {
}
metaRoot.writeEnd();
// some pages might have been changed in the meantime (in the newest version)
unsavedPageCount = Math.max(0, unsavedPageCount - currentUnsavedPageCount);
// some pages might have been changed in the meantime (in the newest
// version)
unsavedPageCount = Math.max(0, unsavedPageCount
- currentUnsavedPageCount);
metaChanged = false;
lastStoredVersion = storeVersion;
......@@ -1098,7 +1104,8 @@ public class MVStore {
long size = 2 * BLOCK_SIZE;
for (Chunk c : chunks.values()) {
long x = c.start + c.length;
size = Math.max(size, MathUtils.roundUpLong(x, BLOCK_SIZE) + BLOCK_SIZE);
size = Math.max(size, MathUtils.roundUpLong(x, BLOCK_SIZE)
+ BLOCK_SIZE);
}
return size;
}
......@@ -1109,8 +1116,6 @@ public class MVStore {
* @return if there are any changes
*/
public boolean hasUnsavedChanges() {
// TODO maybe private; rename to hasUncommittedChanges
checkOpen();
if (metaChanged) {
return true;
......@@ -1160,7 +1165,8 @@ public class MVStore {
chunks.remove(c.id);
markMetaChanged();
meta.remove("chunk." + c.id);
int length = MathUtils.roundUpInt(c.length, BLOCK_SIZE) + BLOCK_SIZE;
int length = MathUtils.roundUpInt(c.length, BLOCK_SIZE)
+ BLOCK_SIZE;
fileStore.free(c.start, length);
}
if (fileStore.getFillRate() == 100) {
......@@ -1175,7 +1181,8 @@ public class MVStore {
}
for (Chunk c : move) {
WriteBuffer buff = getWriteBuffer();
int length = MathUtils.roundUpInt(c.length, BLOCK_SIZE) + BLOCK_SIZE;
int length = MathUtils.roundUpInt(c.length, BLOCK_SIZE)
+ BLOCK_SIZE;
buff.limit(length);
ByteBuffer buff2 = fileStore.readFully(c.start, length);
buff.put(buff2);
......@@ -1200,7 +1207,7 @@ public class MVStore {
// update the metadata (store at the end of the file)
reuseSpace = false;
store();
commitAndSave();
sync();
......@@ -1213,7 +1220,8 @@ public class MVStore {
continue;
}
WriteBuffer buff = getWriteBuffer();
int length = MathUtils.roundUpInt(c.length, BLOCK_SIZE) + BLOCK_SIZE;
int length = MathUtils.roundUpInt(c.length, BLOCK_SIZE)
+ BLOCK_SIZE;
buff.limit(length);
ByteBuffer buff2 = fileStore.readFully(c.start, length);
buff.put(buff2);
......@@ -1235,7 +1243,7 @@ public class MVStore {
}
// update the metadata (within the file)
store();
commitAndSave();
sync();
shrinkFileIfPossible(0);
......@@ -1309,7 +1317,8 @@ public class MVStore {
Collections.sort(old, new Comparator<Chunk>() {
@Override
public int compare(Chunk o1, Chunk o2) {
return new Integer(o1.collectPriority).compareTo(o2.collectPriority);
return new Integer(o1.collectPriority)
.compareTo(o2.collectPriority);
}
});
......@@ -1341,7 +1350,7 @@ public class MVStore {
copyLive(c, old);
}
store();
commitAndSave();
return true;
}
......@@ -1413,7 +1422,8 @@ public class MVStore {
filePos += DataUtils.getPageOffset(pos);
if (filePos < 0) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, "Negative position {0}", filePos);
DataUtils.ERROR_FILE_CORRUPT,
"Negative position {0}", filePos);
}
p = Page.read(fileStore, map, pos, filePos, fileStore.size());
if (cache != null) {
......@@ -1460,11 +1470,13 @@ public class MVStore {
registerFreePage(version, c.id, DataUtils.getPageMaxLength(pos), 1);
}
private void registerFreePage(long version, int chunkId, long maxLengthLive, int pageCount) {
private void registerFreePage(long version, int chunkId,
long maxLengthLive, int pageCount) {
HashMap<Integer, Chunk> freed = freedPageSpace.get(version);
if (freed == null) {
freed = New.hashMap();
HashMap<Integer, Chunk> f2 = freedPageSpace.putIfAbsent(version, freed);
HashMap<Integer, Chunk> f2 = freedPageSpace.putIfAbsent(version,
freed);
if (f2 != null) {
freed = f2;
}
......@@ -1541,13 +1553,13 @@ public class MVStore {
}
/**
* Which version to retain in memory. If not set, all versions back to the
* last stored version are retained.
* How many versions to retain for in-memory stores. If not set, 5 versions
* are retained.
*
* @param retainVersion the oldest version to retain
* @param count the number of versions to keep
*/
public void setRetainVersion(long retainVersion) {
this.retainVersion = retainVersion;
public void setVersionsToKeep(int count) {
this.versionsToKeep = count;
}
/**
......@@ -1555,13 +1567,8 @@ public class MVStore {
*
* @return the version
*/
public long getRetainVersion() {
long v = retainVersion;
long storeVersion = currentStoreVersion;
if (storeVersion > -1) {
v = Math.min(v, storeVersion);
}
return v;
public long getVersionsToKeep() {
return versionsToKeep;
}
/**
......@@ -1570,8 +1577,11 @@ public class MVStore {
*
* @return the version
*/
long getRetainOrStoreVersion() {
long v = retainVersion;
long getOldestVersionToKeep() {
long v = currentVersion;
if (fileStore == null) {
return v - versionsToKeep;
}
long storeVersion = currentStoreVersion;
if (storeVersion > -1) {
v = Math.min(v, storeVersion);
......@@ -1618,34 +1628,13 @@ public class MVStore {
return true;
}
/**
* Get the estimated number of unsaved pages. The returned value is not
* accurate, specially after rollbacks, but can be used to estimate the
* memory usage for unsaved data.
*
* @return the number of unsaved pages
*/
public int getUnsavedPageCount() {
return unsavedPageCount;
}
/**
* Get the maximum number of unsaved pages. If this number is exceeded, the
* unsaved changes are stored to disk.
*
* @return the number of maximum unsaved pages
*/
public int getUnsavedPageCountMax() {
return unsavedPageCountMax;
}
/**
* Increment the number of unsaved pages.
*/
void registerUnsavedPage() {
int count = ++unsavedPageCount;
if (count > unsavedPageCountMax && unsavedPageCountMax > 0) {
storeNeeded = true;
if (count > autoCommitPageCount && autoCommitPageCount > 0) {
saveNeeded = true;
}
}
......@@ -1653,9 +1642,9 @@ public class MVStore {
* This method is called before writing to a map.
*/
void beforeWrite() {
if (storeNeeded) {
storeNeeded = false;
store();
if (saveNeeded) {
saveNeeded = false;
commitAndSave();
}
}
......@@ -1682,13 +1671,12 @@ public class MVStore {
markMetaChanged();
meta.put("setting.storeVersion", Integer.toString(version));
}
/**
* Revert to the beginning of the current version.
* Revert to the beginning of the current version, reverting all uncommitted
* changes.
*/
public void rollback() {
// TODO document and test
rollbackTo(currentVersion);
}
......@@ -1841,11 +1829,11 @@ public class MVStore {
private void checkOpen() {
if (closed) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_CLOSED, "This store is closed");
throw DataUtils.newIllegalStateException(DataUtils.ERROR_CLOSED,
"This store is closed");
}
}
/**
* Rename a map.
*
......@@ -1901,25 +1889,25 @@ public class MVStore {
}
/**
* Store all unsaved changes, if there are any that are committed.
* Commit and save all changes, if there are any.
*/
void storeInBackground() {
void commitInBackground() {
if (unsavedPageCount == 0 || closed) {
return;
}
// could also store when there are many unsaved pages,
// but according to a test it doesn't really help
long time = getTime();
if (time <= lastStoreTime + writeDelay) {
if (time <= lastCommitTime + autoCommitDelay) {
return;
}
if (!hasUnsavedChanges()) {
return;
}
try {
store();
commitAndSave();
} catch (Exception e) {
if (backgroundExceptionHandler != null) {
backgroundExceptionHandler.uncaughtException(null, e);
......@@ -1959,25 +1947,21 @@ public class MVStore {
}
/**
* Set the maximum delay in milliseconds to commit changes.
* Set the maximum delay in milliseconds to auto-commit changes.
* <p>
* The default is 1000, meaning changes are committed after at
* most one second.
* To disable auto-commit, set the value to 0. In this case, changes are
* only committed when explicitly calling commit.
* <p>
* When the value is set to -1, changes are only written when
* calling the store method. When the value is set to 0, committed
* changes are immediately written on a commit, but please note this
* decreases performance and does still not guarantee the disk will
* actually write the data.
* The default is 1000, meaning all changes are committed after at most one
* second.
*
* @param millis the maximum delay
*/
public void setWriteDelay(int millis) {
// TODO rename to commitDelay
if (writeDelay == millis) {
public void setAutoCommitDelay(int millis) {
if (autoCommitDelay == millis) {
return;
}
writeDelay = millis;
autoCommitDelay = millis;
if (fileStore == null) {
return;
}
......@@ -1991,8 +1975,36 @@ public class MVStore {
}
}
public int getWriteDelay() {
return writeDelay;
/**
* Get the auto-commit delay.
*
* @return the delay in milliseconds, or 0 if auto-commit is disabled.
*/
public int getAutoCommitDelay() {
return autoCommitDelay;
}
/**
* Get the maximum number of unsaved pages. If this number is exceeded,
* unsaved changes are stored to disk.
*
* @return the number of maximum unsaved pages
*/
public int getAutoCommitPageCount() {
return autoCommitPageCount;
}
/**
* Get the estimated number of unsaved pages. If the value exceeds the
* auto-commit page count, the changes are committed.
* <p>
* The returned value may not be completely accurate, but can be used to
* estimate the memory usage for unsaved data.
*
* @return the number of unsaved pages
*/
public int getUnsavedPageCount() {
return unsavedPageCount;
}
/**
......@@ -2000,9 +2012,9 @@ public class MVStore {
*/
private static class BackgroundWriterThread extends Thread {
public final Object sync = new Object();
private final MVStore store;
private final int sleep;
public final Object sync = new Object();
BackgroundWriterThread(MVStore store, int sleep, String fileStoreName) {
super("MVStore background writer " + fileStoreName);
......@@ -2025,7 +2037,7 @@ public class MVStore {
continue;
}
}
store.storeInBackground();
store.commitInBackground();
}
}
......@@ -2043,6 +2055,38 @@ public class MVStore {
return this;
}
/**
* Disable auto-commit, by setting the auto-commit delay and auto-commit
* buffer size to 0.
*
* @return this
*/
public Builder autoCommitDisabled() {
// we have a separate config option so that
// no thread is started if the write delay is 0
// (if we only had a setter in the MVStore,
// the thread would need to be started in any case)
set("autoCommitBufferSize", 0);
return set("autoCommitDelay", 0);
}
/**
* Set the size of the write buffer, in MB (for file-based stores).
* Unless auto-commit is disabled, changes are automatically saved if
* there are more than this amount of changes.
* <p>
* The default is 4 MB.
* <p>
* When the value is set to 0 or lower, data is not automatically
* stored.
*
* @param mb the write buffer size, in megabytes
* @return this
*/
public Builder autoCommitBufferSize(int mb) {
return set("autoCommitBufferSize", mb);
}
/**
* Use the following file name. If the file does not exist, it is
* automatically created. The parent directory already must exist.
......@@ -2076,8 +2120,8 @@ public class MVStore {
* If this option is not used, the file is locked exclusively.
* <p>
* Please note a store may only be opened once in every JVM (no matter
* whether it is opened in read-only or read-write mode), because each file
* may be locked only once in a process.
* whether it is opened in read-only or read-write mode), because each
* file may be locked only once in a process.
*
* @return this
*/
......@@ -2110,23 +2154,6 @@ public class MVStore {
return set("compress", 1);
}
/**
* Set the size of the write buffer, in MB (for file-based stores).
* Unless auto-commit is disabled, changes are automatically stored if
* the buffer grows larger than this.
* <p>
* The default is 4 MB.
* <p>
* When the value is set to 0 or lower, data is never automatically
* stored.
*
* @param mb the write buffer size, in megabytes
* @return this
*/
public Builder writeBufferSize(int mb) {
return set("writeBufferSize", mb);
}
/**
* Set the amount of memory a page should contain at most, in bytes,
* before it is split. The default is 6 KB. This is not a limit in the
......@@ -2141,8 +2168,8 @@ public class MVStore {
}
/**
* Set the listener to be used for exceptions that occur in the background
* thread.
* Set the listener to be used for exceptions that occur when writing in
* the background thread.
*
* @param exceptionHandler the handler
* @return this
......@@ -2162,20 +2189,6 @@ public class MVStore {
return set("fileStore", store);
}
/**
* Set the initial write delay.
*
* @param writeDelay the write delay
* @return this
*/
public Builder writeDelay(int writeDelay) {
// we have a separate config option so that
// no thread is started if the write delay is 0
// (if we only had a setter in the MVStore,
// the thread would need to be started in any case)
return set("writeDelay", writeDelay);
}
/**
* Open the store.
*
......
......@@ -96,7 +96,7 @@ public class MVSecondaryIndex extends BaseIndex {
}
}
try {
map.put(array, ValueLong.get(0));
map.put(array, ValueNull.INSTANCE);
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, table.getName());
}
......
......@@ -54,10 +54,11 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
private final String mapName;
private TransactionMap<SpatialKey, Value> dataMap;
private MVRTreeMap<VersionedValue> spatialMap;
/**
* Constructor.
*
* @param db the database
* @param table the table instance
* @param id the index id
* @param indexName the index name
......@@ -66,7 +67,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
*/
public MVSpatialIndex(
Database db, MVTable table, int id, String indexName,
IndexColumn[] columns, IndexType indexType) {
IndexColumn[] columns, IndexType indexType) {
if (columns.length != 1) {
throw DbException.getUnsupportedException("Can only index one column");
}
......@@ -92,7 +93,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
mapName = "index." + getId();
ValueDataType vt = new ValueDataType(null, null, null);
VersionedValueType valueType = new VersionedValueType(vt);
MVRTreeMap.Builder<VersionedValue> mapBuilder =
MVRTreeMap.Builder<VersionedValue> mapBuilder =
new MVRTreeMap.Builder<VersionedValue>().
valueType(valueType);
spatialMap = db.getMvStore().getStore().openMap(mapName, mapBuilder);
......@@ -144,7 +145,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
}
}
}
private SpatialKey getKey(SearchRow r) {
if (r == null) {
return null;
......@@ -171,7 +172,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, table.getName());
}
}
@Override
public Cursor find(TableFilter filter, SearchRow first, SearchRow last) {
return find(filter.getSession());
......@@ -200,7 +201,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
Iterator<SpatialKey> it = map.wrapIterator(cursor, false);
return new MVStoreCursor(session, it);
}
private SpatialKey getEnvelope(SearchRow row) {
Value v = row.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry();
......@@ -232,7 +233,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex {
public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return getCostRangeIndex(masks, table.getRowCountApproximation(), filter, sortOrder);
}
@Override
protected long getCostRangeIndex(int[] masks, long rowCount, TableFilter filter, SortOrder sortOrder) {
rowCount += Constants.COST_ROW_OFFSET;
......
......@@ -399,7 +399,7 @@ public class MVTable extends TableBase {
indexName, primaryIndex, indexType);
} else if (indexType.isSpatial()) {
index = new MVSpatialIndex(session.getDatabase(),
this, indexId,
this, indexId,
indexName, cols, indexType);
} else {
index = new MVSecondaryIndex(session.getDatabase(),
......
......@@ -168,13 +168,13 @@ public class MVTableEngine implements TableEngine {
/**
* Store all pending changes.
*/
public void store() {
public void flush() {
FileStore s = store.getFileStore();
if (s == null || s.isReadOnly()) {
return;
}
if (!store.compact(50)) {
store.store();
store.commit();
}
}
......@@ -213,9 +213,7 @@ public class MVTableEngine implements TableEngine {
Transaction t = session.getTransaction();
t.setName(transactionName);
t.prepare();
if (store.getFileStore() != null) {
store.store();
}
store.commit();
}
public ArrayList<InDoubtTransaction> getInDoubtTransactions() {
......@@ -245,7 +243,7 @@ public class MVTableEngine implements TableEngine {
* Force the changes to disk.
*/
public void sync() {
store();
flush();
store.sync();
}
......@@ -316,9 +314,7 @@ public class MVTableEngine implements TableEngine {
} else {
transaction.rollback();
}
if (store.getFileStore() != null) {
store.store();
}
store.commit();
this.state = state;
}
......
......@@ -170,9 +170,7 @@ public class TransactionStore {
public synchronized void close() {
// to avoid losing transaction ids
settings.put(LAST_TRANSACTION_ID, "" + lastTransactionId);
if (store.getFileStore() != null) {
store.store();
}
store.commit();
}
/**
......@@ -192,9 +190,7 @@ public class TransactionStore {
private void commitIfNeeded() {
if (store.getUnsavedPageCount() > MAX_UNSAVED_PAGES) {
if (store.getFileStore() != null) {
store.store();
}
store.commit();
}
}
......@@ -354,10 +350,8 @@ public class TransactionStore {
if (t.getId() == firstOpenTransaction) {
firstOpenTransaction = -1;
}
if (store.getWriteDelay() == 0) {
if (store.getFileStore() != null) {
store.store();
}
if (store.getAutoCommitDelay() == 0) {
store.commit();
return;
}
// to avoid having to store the transaction log,
......@@ -365,10 +359,10 @@ public class TransactionStore {
// and if there have been many changes, store them now
if (undoLog.isEmpty()) {
int unsaved = store.getUnsavedPageCount();
int max = store.getUnsavedPageCountMax();
int max = store.getAutoCommitPageCount();
// save at 3/4 capacity
if (unsaved * 4 > max * 3) {
store.store();
store.commit();
}
}
}
......@@ -658,7 +652,15 @@ public class TransactionStore {
int mapId = map.getId();
return new TransactionMap<K, V>(this, map, mapId);
}
/**
* Open the transactional version of the given map.
*
* @param <K> the key type
* @param <V> the value type
* @param map the base map
* @return the transactional map
*/
public <K, V> TransactionMap<K, V> openMap(MVMap<K, VersionedValue> map) {
checkNotClosed();
int mapId = map.getId();
......@@ -726,9 +728,11 @@ public class TransactionStore {
DataUtils.ERROR_CLOSED, "Transaction is closed");
}
}
/**
* Remove the map.
*
* @param map the map
*/
public <K, V> void removeMap(TransactionMap<K, V> map) {
store.store.removeMap(map.map);
......@@ -1258,7 +1262,7 @@ public class TransactionStore {
}
};
}
public Transaction getTransaction() {
return transaction;
}
......
......@@ -56,33 +56,32 @@ public class TestConcurrent extends TestMVStore {
testConcurrentWrite();
testConcurrentRead();
}
private void testConcurrentFree() throws InterruptedException {
String fileName = "memFS:testConcurrentFree.h3";
for (int test = 0; test < 10; test++) {
FileUtils.delete(fileName);
final MVStore s1 = new MVStore.Builder().
fileName(fileName).writeDelay(-1).open();
fileName(fileName).autoCommitDisabled().open();
s1.setRetentionTime(0);
final int count = 200;
for (int i = 0; i < count; i++) {
MVMap<Integer, Integer> m = s1.openMap("d" + i);
m.put(1, 1);
if (i % 2 == 0) {
s1.store();
s1.commit();
}
}
s1.store();
s1.close();
final MVStore s = new MVStore.Builder().
fileName(fileName).writeDelay(-1).open();
fileName(fileName).autoCommitDisabled().open();
s.setRetentionTime(0);
final ArrayList<MVMap<Integer, Integer>> list = New.arrayList();
for (int i = 0; i < count; i++) {
MVMap<Integer, Integer> m = s.openMap("d" + i);
list.add(m);
}
final AtomicInteger counter = new AtomicInteger();
Task task = new Task() {
@Override
......@@ -113,8 +112,8 @@ public class TestConcurrent extends TestMVStore {
}
}
task.get();
s.store();
s.commit();
MVMap<String, String> meta = s.getMetaMap();
int chunkCount = 0;
for (String k : meta.keyList()) {
......@@ -142,7 +141,7 @@ public class TestConcurrent extends TestMVStore {
public void call() throws Exception {
while (!stop) {
counter.incrementAndGet();
s.store();
s.commit();
}
}
};
......@@ -172,7 +171,7 @@ public class TestConcurrent extends TestMVStore {
public void call() throws Exception {
while (!stop) {
s.setStoreVersion(counter.incrementAndGet());
s.store();
s.commit();
}
}
};
......@@ -270,9 +269,9 @@ public class TestConcurrent extends TestMVStore {
for (int i = 0; i < 10; i++) {
map.put(i, new byte[100 * r.nextInt(100)]);
}
s.store();
s.commit();
map.clear();
s.store();
s.commit();
long len = s.getFileStore().size();
if (len > 1024 * 1024) {
// slow down writing a lot
......@@ -322,6 +321,7 @@ public class TestConcurrent extends TestMVStore {
private void testConcurrentIterate() {
MVStore s = new MVStore.Builder().pageSplitSize(3).open();
s.setVersionsToKeep(100);
final MVMap<Integer, Integer> map = s.openMap("test");
final int len = 10;
final Random r = new Random();
......@@ -343,7 +343,6 @@ public class TestConcurrent extends TestMVStore {
Iterator<Integer> it = map.keyIterator(r.nextInt(len));
long old = s.getCurrentVersion();
s.commit();
s.setRetainVersion(old - 100);
while (map.getVersion() == old) {
Thread.yield();
}
......
......@@ -84,9 +84,8 @@ public class TestKillProcessWhileWriting extends TestBase {
s = new MVStore.Builder().
fileName(fileName).
pageSplitSize(50).
writeDelay(0).
autoCommitDisabled().
open();
s.setWriteDelay(0);
m = s.openMap("data");
Random r = new Random(seed);
int op = 0;
......@@ -107,7 +106,7 @@ public class TestKillProcessWhileWriting extends TestBase {
m.remove(k);
break;
case 6:
s.store();
s.commit();
break;
case 7:
s.compact(80);
......@@ -120,12 +119,12 @@ public class TestKillProcessWhileWriting extends TestBase {
s = new MVStore.Builder().
fileName(fileName).
pageSplitSize(50).
writeDelay(0).open();
autoCommitDisabled().
open();
m = s.openMap("data");
break;
}
}
s.store();
s.close();
return 0;
} catch (Exception e) {
......
......@@ -54,7 +54,7 @@ public class TestMVRTree extends TestMVStore {
testRandom();
testRandomFind();
}
private void testSpatialKey() {
SpatialKey a0 = new SpatialKey(0, 1, 2, 3, 4);
SpatialKey a1 = new SpatialKey(0, 1, 2, 3, 4);
......@@ -119,7 +119,7 @@ public class TestMVRTree extends TestMVStore {
SpatialKey k = new SpatialKey(i, x - p, x + p, y - p, y + p);
r.add(k, "" + i);
if (i > 0 && (i % len / 10) == 0) {
s.store();
s.commit();
}
if (i > 0 && (i % 10000) == 0) {
render(r, getBaseDir() + "/test.png");
......@@ -127,7 +127,6 @@ public class TestMVRTree extends TestMVStore {
}
// System.out.println(prof.getTop(5));
// System.out.println("add: " + (System.currentTimeMillis() - t));
s.store();
s.close();
s = openStore(fileName);
r = s.openMap("data",
......
......@@ -48,6 +48,8 @@ public class TestMVStore extends TestBase {
public void test() throws Exception {
FileUtils.deleteRecursive(getBaseDir(), true);
FileUtils.createDirectories(getBaseDir());
testRollback();
testVersionsToKeep();
testRemoveMap();
testIsEmpty();
testOffHeapStorage();
......@@ -97,6 +99,26 @@ public class TestMVStore extends TestBase {
testLargerThan2G();
}
private void testVersionsToKeep() throws Exception {
MVStore s = new MVStore.Builder().open();
MVMap<Integer, Integer> map;
map = s.openMap("data");
for (int i = 0; i < 20; i++) {
long version = s.getCurrentVersion();
map.put(i, i);
s.commit();
if (version >= 6) {
map.openVersion(version - 6);
try {
map.openVersion(version - 7);
fail();
} catch (IllegalArgumentException e) {
// expected
}
}
}
}
private void testRemoveMap() throws Exception {
String fileName = getBaseDir() + "/testCloseMap.h3";
FileUtils.delete(fileName);
......@@ -108,15 +130,14 @@ public class TestMVStore extends TestBase {
map = s.openMap("data");
map.put(1, 1);
assertEquals(1, map.get(1).intValue());
s.store();
s.commit();
s.removeMap(map);
s.store();
s.commit();
map = s.openMap("data");
assertTrue(map.isEmpty());
map.put(2, 2);
s.store();
s.close();
}
......@@ -145,7 +166,7 @@ public class TestMVStore extends TestBase {
Map<Integer, String> map = s.openMap("data");
for (int i = 0; i < 1000; i++) {
map.put(i, "Hello " + i);
s.store();
s.commit();
}
assertTrue(1000 < offHeap.getWriteCount());
s.close();
......@@ -173,7 +194,6 @@ public class TestMVStore extends TestBase {
header.put("format", "2");
MVMap<Integer, String> m = s.openMap("data");
m.put(0, "Hello World");
s.store();
s.close();
try {
......@@ -218,12 +238,12 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 10; i++) {
m = s.openMap("data" + i);
m.put(0, "Hello World");
s.store();
s.commit();
}
for (int i = 0; i < 10; i += 2) {
m = s.openMap("data" + i);
s.removeMap(m);
s.store();
s.commit();
}
long sizeOld = s.getFileStore().size();
s.compactMoveChunks();
......@@ -248,7 +268,7 @@ public class TestMVStore extends TestBase {
}).
open();
s.setWriteDelay(2);
s.setAutoCommitDelay(2);
MVMap<Integer, String> m;
m = s.openMap("data");
s.getFileStore().getFile().close();
......@@ -313,7 +333,7 @@ public class TestMVStore extends TestBase {
for (int bs = 0; bs <= 1; bs++) {
s = new MVStore.Builder().
fileName(fileName).
writeBufferSize(bs).
autoCommitBufferSize(bs).
open();
m = s.openMap("data");
for (int i = 0; i < len; i++) {
......@@ -332,7 +352,7 @@ public class TestMVStore extends TestBase {
assertTrue(m.containsKey(1));
m.put(-1, data);
s.store();
s.commit();
m.put(-2, data);
s.close();
......@@ -354,15 +374,15 @@ public class TestMVStore extends TestBase {
FileUtils.delete(fileName);
s = new MVStore.Builder().
autoCommitDisabled().
fileName(fileName).open();
s.setWriteDelay(0);
m = s.openMap("data");
m.put(1, "1");
s.commit();
s.close();
s = new MVStore.Builder().
autoCommitDisabled().
fileName(fileName).open();
s.setWriteDelay(0);
m = s.openMap("data");
assertEquals(1, m.size());
s.close();
......@@ -371,10 +391,10 @@ public class TestMVStore extends TestBase {
s = new MVStore.Builder().
fileName(fileName).
open();
s.setWriteDelay(1);
s.setAutoCommitDelay(1);
m = s.openMap("data");
m.put(1, "Hello");
s.store();
s.commit();
long v = s.getCurrentVersion();
m.put(2, "World.");
Thread.sleep(5);
......@@ -383,12 +403,11 @@ public class TestMVStore extends TestBase {
s = new MVStore.Builder().
fileName(fileName).
open();
s.setWriteDelay(1);
s.setAutoCommitDelay(1);
m = s.openMap("data");
assertEquals("World.", m.get(2));
m.put(2, "World");
s.commit();
s.store();
v = s.getCurrentVersion();
m.put(3, "!");
......@@ -433,7 +452,6 @@ public class TestMVStore extends TestBase {
m = s.openMap("test");
m.put(1, "Hello");
assertEquals("Hello", m.get(1));
s.store();
s.close();
passwordChars = "008".toCharArray();
......@@ -485,7 +503,6 @@ public class TestMVStore extends TestBase {
int format = Integer.parseInt(header.get("format"));
assertEquals(1, format);
header.put("format", Integer.toString(format + 1));
s.store();
s.close();
try {
openStore(fileName).close();
......@@ -503,9 +520,8 @@ public class TestMVStore extends TestBase {
MVStore s = openStore(fileName);
MVMap<Integer, Integer> m = s.openMap("test");
m.put(1, 1);
s.store();
s.commit();
s.removeMap(m);
s.store();
s.close();
s = openStore(fileName);
m = s.openMap("test");
......@@ -548,17 +564,16 @@ public class TestMVStore extends TestBase {
MVMap<Integer, String> map;
s = new MVStore.Builder().
fileName(fileName).
writeDelay(-1).
autoCommitDisabled().
compressData().open();
map = s.openMap("test");
// add 10 MB of data
for (int i = 0; i < 1024; i++) {
map.put(i, new String(new char[10240]));
}
s.store();
s.close();
int[] expectedReadsForCacheSize = {
3405, 2590, 1924, 1440, 1108, 956, 918
3413, 2590, 1924, 1440, 1112, 956, 918
};
for (int cacheSize = 0; cacheSize <= 6; cacheSize += 4) {
s = new MVStore.Builder().
......@@ -613,7 +628,6 @@ public class TestMVStore extends TestBase {
s.getStoreHeader().put("test", "123");
MVMap<Integer, Integer> map = s.openMap("test");
map.put(10, 100);
s.store();
s.close();
s = openStore(fileName);
assertEquals("123", s.getStoreHeader().get("test"));
......@@ -630,14 +644,13 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 10; i++) {
map = s.openMap("test" + i);
map.put(0, new byte[1000]);
s.store();
s.commit();
}
FileStore fs = s.getFileStore();
long size = fs.getFile().size();
for (int i = 0; i < 10; i++) {
map = s.openMap("test" + i);
s.removeMap(map);
s.store();
s.commit();
s.compact(100);
if (fs.getFile().size() <= size) {
......@@ -818,14 +831,13 @@ public class TestMVStore extends TestBase {
assertEquals(0, s.getCurrentVersion());
assertEquals(0, s.getStoreVersion());
s.setStoreVersion(0);
s.store();
s.commit();
s.setStoreVersion(1);
s.closeImmediately();
s = MVStore.open(fileName);
assertEquals(1, s.getCurrentVersion());
assertEquals(0, s.getStoreVersion());
s.setStoreVersion(1);
s.store();
s.close();
s = MVStore.open(fileName);
assertEquals(2, s.getCurrentVersion());
......@@ -866,7 +878,6 @@ public class TestMVStore extends TestBase {
map.put(1, "Hello");
map.put("2", 200);
map.put(new Object[1], new Object[]{1, "2"});
s.store();
s.close();
s = new MVStore.Builder().fileName(fileName).open();
......@@ -958,7 +969,7 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 3; i++) {
Integer x = m.get("value");
m.put("value", x == null ? 0 : x + 1);
s.store();
s.commit();
}
s.close();
}
......@@ -972,7 +983,7 @@ public class TestMVStore extends TestBase {
for (int op = 0; op <= 1; op++) {
for (int i = 0; i < 5; i++) {
s = openStore(null);
s.setRetainVersion(0);
s.setVersionsToKeep(Integer.MAX_VALUE);
MVMap<String, String> m;
m = s.openMap("data");
for (int j = 0; j < 5; j++) {
......@@ -1021,7 +1032,7 @@ public class TestMVStore extends TestBase {
assertEquals("World", mOld.get("2"));
assertTrue(mOld.isReadOnly());
s.getCurrentVersion();
long old3 = s.store();
long old3 = s.commit();
// the old version is still available
assertEquals("Hello", mOld.get("1"));
......@@ -1033,7 +1044,6 @@ public class TestMVStore extends TestBase {
m.put("1", "Hi");
assertEquals("Welt", m.remove("2"));
s.store();
s.close();
s = openStore(fileName);
......@@ -1064,14 +1074,12 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 1000; i++) {
m.put(i, "Hello World");
}
s.store();
s.close();
long len = FileUtils.size(fileName);
s = openStore(fileName);
s.setRetentionTime(0);
m = s.openMap("data");
m.clear();
s.store();
s.compact(100);
s.close();
long len2 = FileUtils.size(fileName);
......@@ -1091,7 +1099,7 @@ public class TestMVStore extends TestBase {
}
assertEquals(1000, m.size());
assertEquals(285, s.getUnsavedPageCount());
s.store();
s.commit();
assertEquals(2, s.getFileStore().getWriteCount());
s.close();
......@@ -1099,13 +1107,27 @@ public class TestMVStore extends TestBase {
m = s.openMap("data");
m.clear();
assertEquals(0, m.size());
s.store();
s.commit();
// ensure only nodes are read, but not leaves
assertEquals(42, s.getFileStore().getReadCount());
assertEquals(1, s.getFileStore().getWriteCount());
s.close();
}
private void testRollback() {
MVStore s = MVStore.open(null);
MVMap<Integer, Integer> m = s.openMap("m");
m.put(1, -1);
s.commit();
for (int i = 0; i < 10; i++) {
m.put(1, i);
s.rollback();
assertEquals(i - 1, m.get(1).intValue());
m.put(1, i);
s.commit();
}
}
private void testRollbackStored() {
String fileName = getBaseDir() + "/testRollback.h3";
FileUtils.delete(fileName);
......@@ -1129,7 +1151,7 @@ public class TestMVStore extends TestBase {
// so a new version is created
m.put("1", "Hello");
long v2 = s.store();
long v2 = s.commit();
assertEquals(2, v2);
assertEquals(2, s.getCurrentVersion());
assertFalse(s.hasUnsavedChanges());
......@@ -1155,7 +1177,7 @@ public class TestMVStore extends TestBase {
assertNull(meta.get("name.data1"));
assertNull(m0.get("1"));
assertEquals("Hello", m.get("1"));
assertEquals(2, s.store());
assertEquals(2, s.commit());
s.close();
s = openStore(fileName);
......@@ -1179,7 +1201,6 @@ public class TestMVStore extends TestBase {
assertEquals(3, s.getCurrentVersion());
m = s.openMap("data");
m.put("1", "Hi");
s.store();
s.close();
s = openStore(fileName);
......@@ -1243,7 +1264,7 @@ public class TestMVStore extends TestBase {
MVMap<String, String> data = s.openMap("data");
data.put("1", "Hello");
data.put("2", "World");
s.store();
s.commit();
assertEquals(1, s.getCurrentVersion());
assertTrue(m.containsKey("chunk.1"));
assertFalse(m.containsKey("chunk.2"));
......@@ -1252,7 +1273,7 @@ public class TestMVStore extends TestBase {
assertEquals("name:data", m.get("map." + id));
assertTrue(m.containsKey("chunk.1"));
assertEquals("Hello", data.put("1", "Hallo"));
s.store();
s.commit();
assertEquals("name:data", m.get("map." + id));
assertTrue(m.get("root.1").length() > 0);
assertTrue(m.containsKey("chunk.1"));
......@@ -1324,10 +1345,9 @@ public class TestMVStore extends TestBase {
m.put(i, o);
i++;
if (i % 10000 == 0) {
s.store();
s.commit();
}
}
s.store();
s.close();
// System.out.println(prof.getTop(5));
// System.out.println("store time " + (System.currentTimeMillis() - t));
......@@ -1356,7 +1376,7 @@ public class TestMVStore extends TestBase {
// p = new Profiler();
//p.startCollecting();
// t = System.currentTimeMillis();
s.store();
s.commit();
// System.out.println("store: " + (System.currentTimeMillis() - t));
// System.out.println(p.getTop(5));
assertEquals("hello 0", m.remove(0));
......@@ -1364,7 +1384,6 @@ public class TestMVStore extends TestBase {
for (int i = 1; i < count; i++) {
assertEquals("hello " + i, m.get(i));
}
s.store();
s.close();
s = openStore(fileName);
......@@ -1376,7 +1395,7 @@ public class TestMVStore extends TestBase {
for (int i = 1; i < count; i++) {
m.remove(i);
}
s.store();
s.commit();
assertNull(m.get(0));
for (int i = 0; i < count; i++) {
assertNull(m.get(i));
......@@ -1394,7 +1413,7 @@ public class TestMVStore extends TestBase {
for (int i = j * factor; i < 10 * factor; i++) {
m.put(i, "Hello" + j);
}
s.store();
s.commit();
}
s.close();
......@@ -1450,7 +1469,6 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 100; i++) {
m.put(j + i, "Hello " + j);
}
s.store();
s.compact(80);
s.close();
long len = FileUtils.size(fileName);
......@@ -1468,7 +1486,6 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 100; i++) {
m.remove(i);
}
s.store();
s.compact(80);
s.close();
// len = FileUtils.size(fileName);
......@@ -1492,12 +1509,11 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 10; i++) {
m.put(i, "Hello");
}
s.store();
s.commit();
for (int i = 0; i < 10; i++) {
assertEquals("Hello", m.get(i));
assertEquals("Hello", m.remove(i));
}
s.store();
s.close();
long len = FileUtils.size(fileName);
if (initialLength == 0) {
......@@ -1584,7 +1600,6 @@ public class TestMVStore extends TestBase {
si.put("Test", 10);
MVMap<String, String> ss = s.openMap("stringString");
ss.put("Hello", "World");
s.store();
s.close();
s = openStore(fileName);
is = s.openMap("intString");
......@@ -1608,7 +1623,7 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 10; i++) {
m.put(i, "hello " + i);
}
s.store();
s.commit();
it = m.keyIterator(null);
it.next();
assertThrows(UnsupportedOperationException.class, it).remove();
......@@ -1639,7 +1654,6 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 3; i++) {
m.put(i, "hello " + i);
}
s.store();
// closing twice should be fine
s.close();
s.close();
......@@ -1653,14 +1667,13 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < 3; i++) {
m.put(i, "hello " + i);
}
s.store();
s.commit();
assertEquals("hello 0", m.remove(0));
assertNull(m.get(0));
for (int i = 1; i < 3; i++) {
assertEquals("hello " + i, m.get(i));
}
s.store();
s.close();
s = openStore(fileName);
......@@ -1686,8 +1699,7 @@ public class TestMVStore extends TestBase {
for (int i = 0;; i++) {
map.put(i, data);
if (i % 10000 == 0) {
long version = store.commit();
store.setRetainVersion(version);
store.commit();
long time = System.currentTimeMillis();
if (time - last > 2000) {
long mb = store.getFileStore().size() / 1024 / 1024;
......
......@@ -92,7 +92,7 @@ public class TestRandomMapOps extends TestBase {
for (; op < size; op++) {
int k = r.nextInt(100);
byte[] v = new byte[r.nextInt(10) * 10];
int type = r.nextInt(13);
int type = r.nextInt(12);
switch (type) {
case 0:
case 1:
......@@ -109,23 +109,19 @@ public class TestRandomMapOps extends TestBase {
map.remove(k);
break;
case 6:
log(op, k, v, "s.store()");
s.store();
break;
case 7:
log(op, k, v, "s.compact(90)");
s.compact(90);
break;
case 8:
case 7:
log(op, k, v, "m.clear()");
m.clear();
map.clear();
break;
case 9:
case 8:
log(op, k, v, "s.commit()");
s.commit();
break;
case 10:
case 9:
log(op, k, v, "s.commit()");
s.commit();
log(op, k, v, "s.close()");
......@@ -135,13 +131,13 @@ public class TestRandomMapOps extends TestBase {
log(op, k, v, "m = s.openMap(\"data\")");
m = s.openMap("data");
break;
case 11:
case 10:
log(op, k, v, "s.commit()");
s.commit();
log(op, k, v, "s.compactMoveChunks()");
s.compactMoveChunks();
break;
case 12:
case 11:
log(op, k, v, "m.getKeyIndex({0})");
ArrayList<Integer> keyList = new ArrayList<Integer>(map.keySet());
int index = Collections.binarySearch(keyList, k, null);
......@@ -165,13 +161,12 @@ public class TestRandomMapOps extends TestBase {
assertEquals(map.lastKey(), m.lastKey());
}
}
s.store();
s.close();
}
private static MVStore openStore(String fileName) {
MVStore s = new MVStore.Builder().fileName(fileName).
pageSplitSize(50).writeDelay(0).open();
pageSplitSize(50).autoCommitDisabled().open();
s.setRetentionTime(0);
return s;
}
......
......@@ -65,7 +65,7 @@ public class TestStreamStore extends TestBase {
for (int i = 0; i < 100; i++) {
streamStore.put(new RandomStream(size, i));
}
s.store();
s.commit();
MVMap<Long, byte[]> map = s.openMap("data");
assertTrue("size: " + map.size(), map.sizeAsLong() >= 100);
s.close();
......@@ -77,7 +77,7 @@ public class TestStreamStore extends TestBase {
for (int i = 0; i < 100; i++) {
streamStore.put(new RandomStream(size, -i));
}
s.store();
s.commit();
long readCount = s.getFileStore().getReadCount();
// the read count should be low because new blocks
// are appended at the end (not between existing blocks)
......@@ -92,7 +92,7 @@ public class TestStreamStore extends TestBase {
return new StreamStore(map) {
@Override
protected void onStore(int len) {
if (s.getUnsavedPageCount() > s.getUnsavedPageCountMax() / 2) {
if (s.getUnsavedPageCount() > s.getAutoCommitPageCount() / 2) {
s.commit();
}
}
......@@ -111,12 +111,11 @@ public class TestStreamStore extends TestBase {
@Override
protected void onStore(int len) {
count.incrementAndGet();
s.store();
s.commit();
}
};
long size = 1 * 1024 * 1024;
streamStore.put(new RandomStream(size, 0));
s.store();
s.close();
assertEquals(4, count.get());
}
......
......@@ -86,7 +86,7 @@ public class TestTransactionStore extends TestBase {
for (int i = 0; !stop; i++) {
state.set(i);
other.put(i, value);
store.store();
store.commit();
}
}
};
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论