private void testConcurrentStoreAndRemoveMap() throws InterruptedException { String fileName = "memFS:testConcurrentStoreAndRemoveMap.h3"; final MVStore s = openStore(fileName); int count = 200; for (int i = 0; i < count; i++) { MVMap<Integer, Integer> m = s.openMap("d" + i); m.put(1, 1); } final AtomicInteger counter = new AtomicInteger(); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { counter.incrementAndGet(); s.commit(); } } }; task.execute(); Thread.sleep(1); for (int i = 0; i < count || counter.get() < count; i++) { MVMap<Integer, Integer> m = s.openMap("d" + i); m.put(1, 10); s.removeMap(m); if (task.isFinished()) { break; } } task.get(); s.close(); FileUtils.deleteRecursive("memFS:", false); }
/** * Add a key-value pair if it does not yet exist. * * @param key the key (may not be null) * @param value the new value * @return the old value if the key existed, or null otherwise */ public synchronized V putIfAbsent(K key, V value) { V old = get(key); if (old == null) { put(key, value); } return old; }
/** * Prepare a transaction. * * @param transactionId the transaction id */ void prepare(Transaction t) { storeTransaction(t); Object[] old = openTransactions.get(t.getId()); Object[] v = {Transaction.STATUS_PREPARED, old[1]}; openTransactions.put(t.getId(), v); store.commit(); }
void persistMovieSet(MovieSet movieSet) throws Exception { String newValue = movieSetObjectWriter.writeValueAsString(movieSet); String oldValue = movieMap.get(movieSet.getDbId()); if (!StringUtils.equals(newValue, oldValue)) { movieSetMap.put(movieSet.getDbId(), newValue); } }
/** * Replace a value for an existing key. * * @param key the key (may not be null) * @param value the new value * @return the old value, if the value was replaced, or null */ public synchronized V replace(K key, V value) { V old = get(key); if (old != null) { put(key, value); return old; } return null; }
/** * Replace a value for an existing key, if the value matches. * * @param key the key (may not be null) * @param oldValue the expected value * @param newValue the new value * @return true if the value was replaced */ public synchronized boolean replace(K key, V oldValue, V newValue) { V old = get(key); if (areValuesEqual(old, oldValue)) { put(key, newValue); return true; } return false; }
private void storeTransaction(Transaction t) { if (store.getUnsavedPageCount() > MAX_UNSAVED_PAGES) { store.commit(); } if (t.isStored()) { return; } t.setStored(true); long transactionId = t.getId(); Object[] v = {t.getStatus(), null}; openTransactions.put(transactionId, v); openTransactionMap.put(transactionId, t); if (lastTransactionId > lastTransactionIdStored) { lastTransactionIdStored += 32; settings.put(LAST_TRANSACTION_ID, "" + lastTransactionIdStored); } }
void persistMovie(Movie movie) throws Exception { String newValue = movieObjectWriter.writeValueAsString(movie); String oldValue = movieMap.get(movie.getDbId()); if (!StringUtils.equals(newValue, oldValue)) { // write movie to DB movieMap.put(movie.getDbId(), newValue); } }
@Override public void setTable(ValueLobDb lob, int tableId) { init(); long lobId = lob.getLobId(); Object[] value = lobMap.remove(lobId); if (TRACE) { trace("move " + lob.getTableId() + "/" + lob.getLobId() + " > " + tableId + "/" + lobId); } value[1] = tableId; lobMap.put(lobId, value); }
private ValueLobDb createLob(InputStream in, int type) throws IOException { byte[] streamStoreId; try { streamStoreId = streamStore.put(in); } catch (Exception e) { throw DbException.convertToIOException(e); } long lobId = generateLobId(); long length = streamStore.length(streamStoreId); int tableId = LobStorageFrontend.TABLE_TEMP; Object[] value = new Object[] {streamStoreId, tableId, length, 0}; lobMap.put(lobId, value); Object[] key = new Object[] {streamStoreId, lobId}; refMap.put(key, Boolean.TRUE); ValueLobDb lob = ValueLobDb.create(type, database, tableId, lobId, null, length); if (TRACE) { trace("create " + tableId + "/" + lobId); } return lob; }
private void testConcurrentRead() throws InterruptedException { final MVStore s = openStore(null); final MVMap<Integer, Integer> m = s.openMap("data"); final int size = 3; int x = (int) s.getCurrentVersion(); for (int i = 0; i < size; i++) { m.put(i, x); } s.commit(); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { long v = s.getCurrentVersion() - 1; Map<Integer, Integer> old = m.openVersion(v); for (int i = 0; i < size; i++) { Integer x = old.get(i); if (x == null || (int) v != x) { Map<Integer, Integer> old2 = m.openVersion(v); throw new AssertionError(x + "<>" + v + " at " + i + " " + old2); } } } } }; task.execute(); Thread.sleep(1); for (int j = 0; j < 100; j++) { x = (int) s.getCurrentVersion(); for (int i = 0; i < size; i++) { m.put(i, x); } s.commit(); Thread.sleep(1); } task.get(); s.close(); }
@Override public ValueLobDb copyLob(ValueLobDb old, int tableId, long length) { init(); int type = old.getType(); long oldLobId = old.getLobId(); long oldLength = old.getPrecision(); if (oldLength != length) { throw DbException.throwInternalError("Length is different"); } Object[] value = lobMap.get(oldLobId); value = value.clone(); byte[] streamStoreId = (byte[]) value[0]; long lobId = generateLobId(); value[1] = tableId; lobMap.put(lobId, value); Object[] key = new Object[] {streamStoreId, lobId}; refMap.put(key, Boolean.TRUE); ValueLobDb lob = ValueLobDb.create(type, database, tableId, lobId, null, length); if (TRACE) { trace("copy " + old.getTableId() + "/" + old.getLobId() + " > " + tableId + "/" + lobId); } return lob; }
/** Test the concurrent map implementation. */ private void testConcurrentMap() throws InterruptedException { final MVStore s = openStore(null); final MVMap<Integer, Integer> m = s.openMap("data", new MVMapConcurrent.Builder<Integer, Integer>()); final int size = 20; final Random rand = new Random(1); Task task = new Task() { @Override public void call() throws Exception { try { while (!stop) { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 1); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); m.firstKey(); m.lastKey(); m.ceilingKey(5); m.floorKey(5); m.higherKey(5); m.lowerKey(5); for (Iterator<Integer> it = m.keyIterator(null); it.hasNext(); ) { it.next(); } } } catch (Exception e) { e.printStackTrace(); } } }; task.execute(); Thread.sleep(1); for (int j = 0; j < 100; j++) { for (int i = 0; i < 100; i++) { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 2); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); } s.commit(); Thread.sleep(1); } task.get(); s.close(); }
/** * Rollback to an old savepoint. * * @param t the transaction * @param maxLogId the last log id * @param toLogId the log id to roll back to */ void rollbackTo(Transaction t, long maxLogId, long toLogId) { for (long logId = maxLogId - 1; logId >= toLogId; logId--) { Object[] op = undoLog.get(new long[] {t.getId(), logId}); int mapId = ((Integer) op[1]).intValue(); Map<String, String> meta = store.getMetaMap(); String m = meta.get("map." + mapId); String mapName = DataUtils.parseMap(m).get("name"); MVMap<Object, Object[]> map = store.openMap(mapName); Object key = op[2]; Object[] oldValue = (Object[]) op[3]; if (oldValue == null) { // this transaction added the value map.remove(key); } else { // this transaction updated the value map.put(key, oldValue); } undoLog.remove(op); } }
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).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.commit(); } } s1.close(); final MVStore s = new MVStore.Builder().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 public void call() throws Exception { while (!stop) { int x = counter.getAndIncrement(); if (x >= count) { break; } MVMap<Integer, Integer> m = list.get(x); m.clear(); s.removeMap(m); } } }; task.execute(); Thread.sleep(1); while (true) { int x = counter.getAndIncrement(); if (x >= count) { break; } MVMap<Integer, Integer> m = list.get(x); m.clear(); s.removeMap(m); if (x % 5 == 0) { s.commit(); } } task.get(); s.commit(); MVMap<String, String> meta = s.getMetaMap(); int chunkCount = 0; for (String k : meta.keyList()) { if (k.startsWith("chunk.")) { chunkCount++; } } assertEquals(1, chunkCount); s.close(); } FileUtils.deleteRecursive("memFS:", false); }
/** * Set the name of a transaction. * * @param t the transaction * @param name the new name */ void setTransactionName(Transaction t, String name) { storeTransaction(t); Object[] old = openTransactions.get(t.getId()); Object[] v = {old[0], name}; openTransactions.put(t.getId(), v); }
private void testConcurrentWrite(final AtomicInteger detected, final AtomicInteger notDetected) throws InterruptedException { final MVStore s = openStore(null); final MVMap<Integer, Integer> m = s.openMap("data"); final int size = 20; final Random rand = new Random(1); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { try { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 1); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); } catch (ConcurrentModificationException e) { detected.incrementAndGet(); } catch (NegativeArraySizeException e) { notDetected.incrementAndGet(); } catch (ArrayIndexOutOfBoundsException e) { notDetected.incrementAndGet(); } catch (IllegalArgumentException e) { notDetected.incrementAndGet(); } catch (NullPointerException e) { notDetected.incrementAndGet(); } } } }; task.execute(); Thread.sleep(1); for (int j = 0; j < 10; j++) { for (int i = 0; i < 10; i++) { try { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 2); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); } catch (ConcurrentModificationException e) { detected.incrementAndGet(); } catch (NegativeArraySizeException e) { notDetected.incrementAndGet(); } catch (ArrayIndexOutOfBoundsException e) { notDetected.incrementAndGet(); } catch (IllegalArgumentException e) { notDetected.incrementAndGet(); } catch (NullPointerException e) { notDetected.incrementAndGet(); } } s.commit(); Thread.sleep(1); } task.get(); s.close(); }
/** * Log an entry. * * @param t the transaction * @param logId the log id * @param opType the operation type * @param mapId the map id * @param key the key * @param oldValue the old value */ void log(Transaction t, long logId, int opType, int mapId, Object key, Object oldValue) { storeTransaction(t); long[] undoKey = {t.getId(), logId}; Object[] log = new Object[] {opType, mapId, key, oldValue}; undoLog.put(undoKey, log); }
/** Close the transaction store. */ public synchronized void close() { // to avoid losing transaction ids settings.put(LAST_TRANSACTION_ID, "" + lastTransactionId); store.commit(); }