/** * Converts the bin/index slot, whether a singleton LN or a DIN root. * * <p>Enter/leave with bin field latched, although bin field may change. * * <p>When a singleton LN is converted, leaves with bin/index fields unchanged. * * <p>When a dup tree is converted, leaves with bin/index fields set to last inserted slot. This * is the slot of the highest key in the dup tree. */ private void convertBinSlot() { if (DEBUG) { System.out.println( "DupConvert BIN LSN " + DbLsn.getNoFormatString(bin.getLsn(index)) + " index " + index + " nEntries " + bin.getNEntries()); } /* Delete slot if LN is deleted. */ final boolean isDeleted; if (isLNDeleted(bin, index)) { deleteSlot(); return; } final Node node = bin.fetchLNOrDIN(index, CacheMode.DEFAULT); if (!node.containsDuplicates()) { if (DEBUG) { System.out.println("DupConvert BIN LN " + Key.dumpString(bin.getKey(index), 0)); } /* Fetching a non-deleted LN updates the slot key; we're done. */ assert node instanceof LN; nConverted += 1; return; } /* * Delete the slot containing the DIN before re-inserting the dup tree, * so that the DIN slot key doesn't interfere with insertions. * * The DIN is evicted and memory usage is decremented. This is not * exactly correct because we keep a local reference to the DIN until * the dup tree is converted, but we tolerate this temporary * inaccuracy. */ final byte[] binKey = bin.getKey(index); final DIN din = (DIN) node; deleteSlot(); convertDin(din, binKey); }
/** Helper for doCheckpoint. Same args only this is called with the evictor locked out. */ private synchronized void doCheckpointInternal( CheckpointConfig config, boolean allowDeltas, boolean flushAll, boolean deleteAllCleanedFiles, String invokingSource) throws DatabaseException { if (!isRunnable(config)) { return; } /* * If there are cleaned files to be deleted, flush an extra level to * write out the parents of cleaned nodes. This ensures that the * no node will contain the LSN of a cleaned files. */ boolean flushExtraLevel = false; Set cleanedFiles = null; Cleaner cleaner = envImpl.getCleaner(); if (cleaner != null) { cleanedFiles = cleaner.getCleanedFiles(deleteAllCleanedFiles); if (cleanedFiles != null) { flushExtraLevel = true; } } lastCheckpointMillis = System.currentTimeMillis(); resetPerRunCounters(); LogManager logManager = envImpl.getLogManager(); /* Get the next checkpoint id. */ checkpointId++; nCheckpoints++; boolean success = false; boolean traced = false; try { /* Log the checkpoint start. */ CheckpointStart startEntry = new CheckpointStart(checkpointId, invokingSource); DbLsn checkpointStart = logManager.log(startEntry); /* * Remember the first active lsn -- before this position in the * log, there are no active transactions at this point in time. */ DbLsn firstActiveLsn = envImpl.getTxnManager().getFirstActiveLsn(); if (firstActiveLsn != null && checkpointStart.compareTo(firstActiveLsn) < 0) { firstActiveLsn = checkpointStart; } /* Flush IN nodes. */ flushDirtyNodes(flushAll, allowDeltas, flushExtraLevel); /* * Flush utilization info AFTER flushing IN nodes to reduce the * inaccuracies caused by the sequence FileSummaryLN-LN-BIN. */ flushUtilizationInfo(); /* Log the checkpoint end. */ if (firstActiveLsn == null) { firstActiveLsn = checkpointStart; } CheckpointEnd endEntry = new CheckpointEnd( invokingSource, checkpointStart, envImpl.getRootLsn(), firstActiveLsn, Node.getLastId(), envImpl.getDbMapTree().getLastDbId(), envImpl.getTxnManager().getLastTxnId(), checkpointId); /* * Log checkpoint end and update state kept about the last * checkpoint location. Send a trace message *before* the * checkpoint end log entry. This is done so that the normal * trace message doesn't affect the time-based isRunnable() * calculation, which only issues a checkpoint if a log record * has been written since the last checkpoint. */ trace(envImpl, invokingSource, true); traced = true; /* * Always flush to ensure that cleaned files are not referenced, * and to ensure that this checkpoint is not wasted if we crash. */ lastCheckpointEnd = logManager.logForceFlush(endEntry); lastFirstActiveLsn = firstActiveLsn; lastCheckpointStart = checkpointStart; success = true; if (cleaner != null && cleanedFiles != null) { cleaner.deleteCleanedFiles(cleanedFiles); } } catch (DatabaseException e) { Tracer.trace(envImpl, "Checkpointer", "doCheckpoint", "checkpointId=" + checkpointId, e); throw e; } finally { if (!traced) { trace(envImpl, invokingSource, success); } } }
public void testEntryData() throws Throwable { try { ByteBuffer buffer = ByteBuffer.allocate(1000); database = new DatabaseImpl("foo", new DatabaseId(1), env, new DatabaseConfig()); /* * For each loggable object, can we write the entry data out? */ /* * Tracer records. */ Tracer dMsg = new Tracer("Hello there"); writeAndRead(buffer, LogEntryType.LOG_TRACE, dMsg, new Tracer()); /* * LNs */ String data = "abcdef"; LN ln = new LN(data.getBytes()); LN lnFromLog = new LN(); writeAndRead(buffer, LogEntryType.LOG_LN, ln, lnFromLog); lnFromLog.verify(null); assertTrue(LogEntryType.LOG_LN.marshallOutsideLatch()); FileSummaryLN fsLN = new FileSummaryLN(new FileSummary()); FileSummaryLN fsLNFromLog = new FileSummaryLN(); writeAndRead(buffer, LogEntryType.LOG_FILESUMMARYLN, fsLN, fsLNFromLog); assertFalse(LogEntryType.LOG_FILESUMMARYLN.marshallOutsideLatch()); /* * INs */ IN in = new IN(database, new byte[] {1, 0, 1, 0}, 7, 5); in.latch(); in.insertEntry(new ChildReference(null, new byte[] {1, 0, 1, 0}, DbLsn.makeLsn(12, 200))); in.insertEntry(new ChildReference(null, new byte[] {1, 1, 1, 0}, DbLsn.makeLsn(29, 300))); in.insertEntry(new ChildReference(null, new byte[] {0, 0, 1, 0}, DbLsn.makeLsn(35, 400))); /* Write it. */ IN inFromLog = new IN(); inFromLog.latch(); writeAndRead(buffer, LogEntryType.LOG_IN, in, inFromLog); inFromLog.releaseLatch(); in.releaseLatch(); /* * IN - long form */ in = new IN(database, new byte[] {1, 0, 1, 0}, 7, 5); in.latch(); in.insertEntry(new ChildReference(null, new byte[] {1, 0, 1, 0}, DbLsn.makeLsn(12, 200))); in.insertEntry(new ChildReference(null, new byte[] {1, 1, 1, 0}, DbLsn.makeLsn(29, 300))); in.insertEntry(new ChildReference(null, new byte[] {0, 0, 1, 0}, DbLsn.makeLsn(1235, 400))); in.insertEntry( new ChildReference(null, new byte[] {0, 0, 1, 0}, DbLsn.makeLsn(0xFFFFFFF0L, 400))); /* Write it. */ inFromLog = new IN(); inFromLog.latch(); writeAndRead(buffer, LogEntryType.LOG_IN, in, inFromLog); inFromLog.releaseLatch(); in.releaseLatch(); /* * BINs */ BIN bin = new BIN(database, new byte[] {3, 2, 1}, 8, 5); bin.latch(); bin.insertEntry(new ChildReference(null, new byte[] {1, 0, 1, 0}, DbLsn.makeLsn(212, 200))); bin.insertEntry(new ChildReference(null, new byte[] {1, 1, 1, 0}, DbLsn.makeLsn(229, 300))); bin.insertEntry(new ChildReference(null, new byte[] {0, 0, 1, 0}, DbLsn.makeLsn(235, 400))); BIN binFromLog = new BIN(); binFromLog.latch(); writeAndRead(buffer, LogEntryType.LOG_BIN, bin, binFromLog); binFromLog.verify(null); binFromLog.releaseLatch(); bin.releaseLatch(); /* * DINs */ DIN din = new DIN( database, new byte[] {1, 0, 0, 1}, 7, new byte[] {0, 1, 1, 0}, new ChildReference(null, new byte[] {1, 0, 0, 1}, DbLsn.makeLsn(10, 100)), 5); din.latch(); din.insertEntry(new ChildReference(null, new byte[] {1, 0, 1, 0}, DbLsn.makeLsn(12, 200))); din.insertEntry(new ChildReference(null, new byte[] {1, 1, 1, 0}, DbLsn.makeLsn(29, 300))); din.insertEntry(new ChildReference(null, new byte[] {0, 0, 1, 0}, DbLsn.makeLsn(35, 400))); /* Write it. */ DIN dinFromLog = new DIN(); dinFromLog.latch(); writeAndRead(buffer, LogEntryType.LOG_DIN, din, dinFromLog); din.releaseLatch(); dinFromLog.releaseLatch(); /* * DBINs */ DBIN dbin = new DBIN(database, new byte[] {3, 2, 1}, 8, new byte[] {1, 2, 3}, 5); dbin.latch(); dbin.insertEntry(new ChildReference(null, new byte[] {1, 0, 1, 0}, DbLsn.makeLsn(212, 200))); dbin.insertEntry(new ChildReference(null, new byte[] {1, 1, 1, 0}, DbLsn.makeLsn(229, 300))); dbin.insertEntry(new ChildReference(null, new byte[] {0, 0, 1, 0}, DbLsn.makeLsn(235, 400))); DBIN dbinFromLog = new DBIN(); dbinFromLog.latch(); writeAndRead(buffer, LogEntryType.LOG_DBIN, dbin, dbinFromLog); dbinFromLog.verify(null); dbin.releaseLatch(); dbinFromLog.releaseLatch(); /* * Root */ DbTree dbTree = new DbTree(env); DbTree dbTreeFromLog = new DbTree(); writeAndRead(buffer, LogEntryType.LOG_ROOT, dbTree, dbTreeFromLog); /* * MapLN */ MapLN mapLn = new MapLN(database); MapLN mapLnFromLog = new MapLN(); writeAndRead(buffer, LogEntryType.LOG_MAPLN, mapLn, mapLnFromLog); /* * UserTxn */ /* * Disabled for now because these txns don't compare equal, * because one has a name of "main" and the other has a name of * null because it was read from the log. Txn txn = new Txn(env, new TransactionConfig()); Txn txnFromLog = new Txn(); writeAndRead(buffer, LogEntryType.TXN_COMMIT, txn, txnFromLog); txn.commit(); */ /* * TxnCommit */ TxnCommit commit = new TxnCommit(111, DbLsn.makeLsn(10, 10)); TxnCommit commitFromLog = new TxnCommit(); writeAndRead(buffer, LogEntryType.LOG_TXN_COMMIT, commit, commitFromLog); /* * TxnAbort */ TxnAbort abort = new TxnAbort(111, DbLsn.makeLsn(11, 11)); TxnAbort abortFromLog = new TxnAbort(); writeAndRead(buffer, LogEntryType.LOG_TXN_ABORT, abort, abortFromLog); /* * TxnPrepare */ byte[] gid = new byte[64]; byte[] bqual = new byte[64]; TxnPrepare prepare = new TxnPrepare(111, new LogUtils.XidImpl(1, gid, bqual)); TxnPrepare prepareFromLog = new TxnPrepare(); writeAndRead(buffer, LogEntryType.LOG_TXN_PREPARE, prepare, prepareFromLog); prepare = new TxnPrepare(111, new LogUtils.XidImpl(1, null, bqual)); prepareFromLog = new TxnPrepare(); writeAndRead(buffer, LogEntryType.LOG_TXN_PREPARE, prepare, prepareFromLog); prepare = new TxnPrepare(111, new LogUtils.XidImpl(1, gid, null)); prepareFromLog = new TxnPrepare(); writeAndRead(buffer, LogEntryType.LOG_TXN_PREPARE, prepare, prepareFromLog); /* * IN delete info */ INDeleteInfo info = new INDeleteInfo(77, new byte[1], new DatabaseId(100)); INDeleteInfo infoFromLog = new INDeleteInfo(); writeAndRead(buffer, LogEntryType.LOG_IN_DELETE_INFO, info, infoFromLog); /* * Checkpoint start */ CheckpointStart start = new CheckpointStart(177, "test"); CheckpointStart startFromLog = new CheckpointStart(); writeAndRead(buffer, LogEntryType.LOG_CKPT_START, start, startFromLog); /* * Checkpoint end */ CheckpointEnd end = new CheckpointEnd( "test", DbLsn.makeLsn(20, 55), env.getRootLsn(), env.getTxnManager().getFirstActiveLsn(), Node.getLastId(), env.getDbMapTree().getLastDbId(), env.getTxnManager().getLastTxnId(), 177); CheckpointEnd endFromLog = new CheckpointEnd(); writeAndRead(buffer, LogEntryType.LOG_CKPT_END, end, endFromLog); } catch (Throwable t) { t.printStackTrace(); throw t; } }