/** * Converts the given DBIN slot, leaving bin/index set to the inserted BIN slot. * * <p>Enter/leave with bin field latched, although bin field may change. * * <p>If slot is inserted into current bin, leave bin field unchanged and set index field to * inserted slot. * * <p>If slot is inserted into a different bin, set bin/index fields to inserted slot. */ private void convertDbinSlot(final DBIN dbin, final int dbinIndex, final byte[] binKey) { final byte[] newKey = DupKeyData.replaceData(binKey, dbin.getKey(dbinIndex)); if (DEBUG) { System.out.println("DupConvert DBIN LN " + Key.dumpString(newKey, 0)); } /* * If the current BIN can hold the new slot, don't bother to do a * search to find it. */ if (bin.needsSplitting() || !bin.isKeyInBounds(newKey)) { /* Compact keys after finishing with a BIN. */ bin.compactMemory(); /* Evict without latches, before moving to a new BIN. */ bin.releaseLatch(); envImpl.daemonEviction(false /*backgroundIO*/); /* Find a BIN for insertion, split if necessary. */ bin = dbin.getDatabase().getTree().searchSplitsAllowed(newKey, CacheMode.UNCHANGED); } final int newIndex = bin.insertEntry1( null /*ln*/, newKey, null /*data*/, dbin.getLsn(dbinIndex), dbin.getState(dbinIndex), false); if ((newIndex & IN.INSERT_SUCCESS) == 0) { throw EnvironmentFailureException.unexpectedState( "Key not inserted: " + Key.dumpString(newKey, 0) + " DB: " + dbin.getDatabase().getId()); } index = newIndex & ~IN.INSERT_SUCCESS; /* * Evict LN from DBIN slot. Although we don't explicitly load DBIN LNs, * it may have been loaded by recovery. */ dbin.detachNode(dbinIndex, false /*updateLsn*/, -1 /*lsn*/); nConverted += 1; }
/** * For unit test support: * * @return a string that dumps information about this IN, without */ @Override public String dumpString(int nSpaces, boolean dumpTags) { StringBuilder sb = new StringBuilder(); sb.append(TreeUtils.indent(nSpaces)); sb.append(beginTag()); sb.append('\n'); sb.append(TreeUtils.indent(nSpaces + 2)); sb.append("<dupkey>"); sb.append(dupKey == null ? "" : Key.dumpString(dupKey, 0)); sb.append("</dupkey>"); sb.append('\n'); sb.append(super.dumpString(nSpaces, false)); sb.append(TreeUtils.indent(nSpaces)); sb.append(endTag()); return sb.toString(); }
/** * 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); }
/** DBINS need to dump their dup key */ @Override protected void dumpLogAdditional(StringBuilder sb) { super.dumpLogAdditional(sb); sb.append(Key.dumpString(dupKey, 0)); }