예제 #1
1
 private void init() {
   String s = settings.get(LAST_TRANSACTION_ID);
   if (s != null) {
     lastTransactionId = Long.parseLong(s);
     lastTransactionIdStored = lastTransactionId;
   }
   Long lastKey = openTransactions.lastKey();
   if (lastKey != null && lastKey.longValue() > lastTransactionId) {
     throw DataUtils.newIllegalStateException("Last transaction not stored");
   }
   Cursor<Long> cursor = openTransactions.keyIterator(null);
   while (cursor.hasNext()) {
     long id = cursor.next();
     Object[] data = openTransactions.get(id);
     int status = (Integer) data[0];
     String name = (String) data[1];
     long[] next = {id + 1, -1};
     long[] last = undoLog.floorKey(next);
     if (last == null) {
       // no entry
     } else if (last[0] == id) {
       Transaction t = new Transaction(this, id, status, name, last[1]);
       t.setStored(true);
       openTransactionMap.put(id, t);
     }
   }
 }
예제 #2
0
 private Object[] getArray(K key, long maxLog) {
   Object[] data = map.get(key);
   while (true) {
     long tx;
     if (data == null) {
       // doesn't exist or deleted by a committed transaction
       return null;
     }
     tx = (Long) data[0];
     long logId = (Long) data[1];
     if (tx == transaction.transactionId) {
       // added by this transaction
       if (logId < maxLog) {
         return data;
       }
     }
     // added or updated by another transaction
     boolean open = transaction.store.openTransactions.containsKey(tx);
     if (!open) {
       // it is committed
       return data;
     }
     // get the value before the uncommitted transaction
     long[] x = new long[] {tx, logId};
     data = transaction.store.undoLog.get(x);
     data = (Object[]) data[3];
   }
 }
 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);
   }
 }
예제 #4
0
 /**
  * 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 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);
    }
  }
예제 #6
0
 @Override
 public void init() {
   if (init) {
     return;
   }
   init = true;
   Store s = database.getMvStore();
   MVStore mvStore;
   if (s == null) {
     // in-memory database
     mvStore = MVStore.open(null);
   } else {
     mvStore = s.getStore();
   }
   lobMap = mvStore.openMap("lobMap");
   refMap = mvStore.openMap("lobRef");
   dataMap = mvStore.openMap("lobData");
   streamStore = new StreamStore(dataMap);
   // garbage collection of the last blocks
   if (database.isReadOnly()) {
     return;
   }
   if (dataMap.isEmpty()) {
     return;
   }
   // search the last referenced block
   // (a lob may not have any referenced blocks if data is kept inline,
   // so we need to loop)
   long lastUsedKey = -1;
   Long lobId = lobMap.lastKey();
   while (lobId != null) {
     Object[] v = lobMap.get(lobId);
     byte[] id = (byte[]) v[0];
     lastUsedKey = streamStore.getMaxBlockKey(id);
     if (lastUsedKey >= 0) {
       break;
     }
     lobId = lobMap.lowerKey(lobId);
   }
   // delete all blocks that are newer
   while (true) {
     Long last = dataMap.lastKey();
     if (last == null || last <= lastUsedKey) {
       break;
     }
     dataMap.remove(last);
   }
   // don't re-use block ids, except at the very end
   Long last = dataMap.lastKey();
   if (last != null) {
     streamStore.setNextKey(last + 1);
   }
 }
예제 #7
0
 /** 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();
 }
예제 #8
0
 /**
  * Commit a transaction.
  *
  * @param t the transaction
  * @param maxLogId the last log id
  */
 void commit(Transaction t, long maxLogId) {
   for (long logId = 0; logId < maxLogId; logId++) {
     long[] undoKey = new long[] {t.getId(), logId};
     Object[] op = undoLog.get(undoKey);
     int opType = (Integer) op[0];
     if (opType == Transaction.OP_REMOVE) {
       int mapId = (Integer) op[1];
       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[] value = map.get(key);
       // possibly the entry was added later on
       // so we have to check
       if (value[2] == null) {
         // remove the value
         map.remove(key);
       }
     }
     undoLog.remove(undoKey);
   }
   endTransaction(t);
 }
예제 #9
0
 private void testConcurrentOnlineBackup() throws Exception {
   String fileName = getBaseDir() + "/onlineBackup.h3";
   String fileNameRestore = getBaseDir() + "/onlineRestore.h3";
   final MVStore s = openStore(fileName);
   final MVMap<Integer, byte[]> map = s.openMap("test");
   final Random r = new Random();
   Task t =
       new Task() {
         @Override
         public void call() throws Exception {
           while (!stop) {
             for (int i = 0; i < 10; i++) {
               map.put(i, new byte[100 * r.nextInt(100)]);
             }
             s.commit();
             map.clear();
             s.commit();
             long len = s.getFileStore().size();
             if (len > 1024 * 1024) {
               // slow down writing a lot
               Thread.sleep(200);
             } else if (len > 20 * 1024) {
               // slow down writing
               Thread.sleep(20);
             }
           }
         }
       };
   t.execute();
   for (int i = 0; i < 10; i++) {
     // System.out.println("test " + i);
     s.setReuseSpace(false);
     byte[] buff = readFileSlowly(s.getFileStore().getFile(), s.getFileStore().size());
     s.setReuseSpace(true);
     FileOutputStream out = new FileOutputStream(fileNameRestore);
     out.write(buff);
     MVStore s2 = openStore(fileNameRestore);
     MVMap<Integer, byte[]> test = s2.openMap("test");
     for (Integer k : test.keySet()) {
       test.get(k);
     }
     s2.close();
     // let it compact
     Thread.sleep(10);
   }
   t.get();
   s.close();
 }
예제 #10
0
 @Override
 public InputStream getInputStream(ValueLobDb lob, byte[] hmac, long byteCount)
     throws IOException {
   init();
   Object[] value = lobMap.get(lob.getLobId());
   if (value == null) {
     if (lob.getTableId() == LobStorageFrontend.TABLE_RESULT
         || lob.getTableId() == LobStorageFrontend.TABLE_ID_SESSION_VARIABLE) {
       throw DbException.get(
           ErrorCode.LOB_CLOSED_ON_TIMEOUT_1, "" + lob.getLobId() + "/" + lob.getTableId());
     }
     throw DbException.throwInternalError(
         "Lob not found: " + lob.getLobId() + "/" + lob.getTableId());
   }
   byte[] streamStoreId = (byte[]) value[0];
   return streamStore.get(streamStoreId);
 }
예제 #11
0
 /**
  * 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);
   }
 }
예제 #12
0
 @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;
 }
예제 #13
0
 /**
  * Try to set or remove the value. When updating only unchanged entries, then the value is only
  * changed if it was not changed after opening the map.
  *
  * @param key the key
  * @param value the new value (null to remove the value)
  * @param onlyIfUnchanged only set the value if it was not changed (by this or another
  *     transaction) since the map was opened
  * @return true if the value was set
  */
 public boolean trySet(K key, V value, boolean onlyIfUnchanged) {
   Object[] current = map.get(key);
   if (onlyIfUnchanged) {
     Object[] old = getArray(key, readLogId);
     if (!map.areValuesEqual(old, current)) {
       long tx = (Long) current[0];
       if (tx == transaction.transactionId) {
         if (value == null) {
           // ignore removing an entry
           // if it was added or changed
           // in the same statement
           return true;
         } else if (current[2] == null) {
           // add an entry that was removed
           // in the same statement
         } else {
           return false;
         }
       } else {
         return false;
       }
     }
   }
   int opType;
   if (current == null || current[2] == null) {
     if (value == null) {
       // remove a removed value
       opType = Transaction.OP_SET;
     } else {
       opType = Transaction.OP_ADD;
     }
   } else {
     if (value == null) {
       opType = Transaction.OP_REMOVE;
     } else {
       opType = Transaction.OP_SET;
     }
   }
   Object[] newValue = {transaction.transactionId, transaction.logId, value};
   if (current == null) {
     // a new value
     Object[] old = map.putIfAbsent(key, newValue);
     if (old == null) {
       transaction.log(opType, mapId, key, current);
       return true;
     }
     return false;
   }
   long tx = (Long) current[0];
   if (tx == transaction.transactionId) {
     // added or updated by this transaction
     if (map.replace(key, current, newValue)) {
       transaction.log(opType, mapId, key, current);
       return true;
     }
     // strange, somebody overwrite the value
     // even thought the change was not committed
     return false;
   }
   // added or updated by another transaction
   boolean open = transaction.store.openTransactions.containsKey(tx);
   if (!open) {
     // the transaction is committed:
     // overwrite the value
     if (map.replace(key, current, newValue)) {
       transaction.log(opType, mapId, key, current);
       return true;
     }
     // somebody else was faster
     return false;
   }
   // the transaction is not yet committed
   return false;
 }
예제 #14
0
 /**
  * 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);
 }
예제 #15
0
 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();
 }