/** * Return a <code>BufferInfo</code> reflecting the state of a page containing the specified key. * The <code>volumeName</code> and <code>treeName</code> parameters specify a {@link Tree} in * which to seach for the key. The <code>level</code> parameter indicates whether the data page, * or one of the pages on the index path to that data page should be returned. Level 0 refers to * the data path, level 1 is the lowest index level, and level d-1 where d is the number of levels * in the the tree represents the three's root page. * * <p>Specify <code>treeName</code> as <code>null</code> to access the volume's directory tree. * * @param volumeName the name of the volume * @param treeName the name of the tree within the volume, or <code>null</code> for the directory * tree * @param key a <code>KeyState</code> representing a key * @param level tree level: 0 for root, 1...d-1 for index pages of a tree having depth d. * @return a <code>BufferInfo</code> object reflecting the selected page, or <code>null</code> if * the specified tree does not exist. * @throws RemoteException */ @Override public BufferInfo getBufferInfo( final String volumeName, final String treeName, final KeyState key, final int level) throws RemoteException { try { Exchange exchange; final Volume volume = _persistit.getVolume(volumeName); if (volume == null) { return null; } if (treeName == null) { exchange = volume.getStructure().directoryExchange(); } else { exchange = _persistit.getExchange(volume, treeName, false); } key.copyTo(exchange.getKey()); final Buffer buffer = exchange.fetchBufferCopy(level); final BufferInfo info = new BufferInfo(); buffer.populateInfo(info); return info; } catch (final TreeNotFoundException tnfe) { return null; } catch (final PersistitException pe) { throw new WrappedRemoteException(pe); } }
@Test public void useOldVSpecInducesExpectedFailure() throws Exception { VolumeSpecification volumeSpec; final Configuration configuration = _persistit.getConfiguration(); _persistit.close(); int remainingJournalFiles = 0; configuration.setUseOldVSpec(true); for (int i = 5; --i >= 0; ) { final Persistit db = new Persistit(_config); try { volumeSpec = new VolumeSpecification( DATA_PATH + "/hwdemo" + i, null, 16384, 1, 1000, 1, true, false, false); db.loadVolume(volumeSpec); final Exchange dbex = db.getExchange("hwdemo" + i, "greetings", true); dbex.getKey().append("Hello"); dbex.getValue().put("World"); dbex.store(); dbex.getKey().to(Key.BEFORE); db.releaseExchange(dbex); } finally { if (i == 0) { db.copyBackPages(); } remainingJournalFiles = db.getJournalManager().getJournalFileCount(); db.close(); } } assertTrue("Should be only one remaining journal file", remainingJournalFiles > 1); }
/** * Test for bug https://bugs.launchpad.net/akiban-persistit/+bug/1045983 * * Truncating a dynamically created volume results in corrupted journal If * you dynamically load a volume, truncate it (without adding any trees), * and then close it, the next time the database is initialized a fatal * exception is thrown: * * <code><pre> * * [JOURNAL_COPIER] WARNING Missing volume truncated referenced at journal address 364 * [main] WARNING Missing volume truncated referenced at journal address 17,004 (6 similar occurrences in 0 seconds) * Exception in thread "main" com.persistit.exception.InvalidPageAddressException: Page 1 out of bounds [0-1] * at com.persistit.VolumeStorageV2.readPage(VolumeStorageV2.java:426) * at com.persistit.Buffer.load(Buffer.java:456) * at com.persistit.BufferPool.get(BufferPool.java:780) * at com.persistit.Tree.setRootPageAddress(Tree.java:203) * at com.persistit.VolumeStructure.init(VolumeStructure.java:70) * at com.persistit.VolumeStorageV2.open(VolumeStorageV2.java:217) * at com.persistit.Volume.open(Volume.java:442) * at com.persistit.Persistit.loadVolume(Persistit.java:1066) * at Truncate.main(Truncate.java:30) * * @throws Exception * * </pre></code> * * This test is currently disabled pending a fix. * */ @Test @Ignore public void truncateDynamicVolumes() throws Exception { VolumeSpecification volumeSpec; _persistit.close(); final Persistit db = new Persistit(_config); for (int i = 0; i < 2; i++) { try { volumeSpec = new VolumeSpecification( DATA_PATH + "/truncated", null, 16384, 1, 1000, 1, true, false, false); final Volume volume = db.loadVolume(volumeSpec); volume.truncate(); // the following may be omitted, and the problem still exhibited final Exchange dbex = db.getExchange("truncated", "greetings", true); dbex.getKey().append("ave"); dbex.getValue().put("mundus"); dbex.store(); dbex.getKey().to(Key.BEFORE); while (dbex.next()) { System.out.println(dbex.getKey().reset().decode() + " " + dbex.getValue().get()); } db.releaseExchange(dbex); // the preceding may be omitted, and the problem still exhibited } finally { db.close(); } } }
@Override public LogicalRecord[] getLogicalRecordArray( final String volumeName, final String treeName, final String keyFilterString, final KeyState fromKey, final Key.Direction direction, final int maxCount, final int maxValueBytes, final boolean decodeStrings) throws RemoteException { LogicalRecord[] records = new LogicalRecord[maxCount]; int count = 0; final boolean forward = direction == Key.GT || direction == Key.GTEQ; Exchange exchange = null; try { if (treeName.equals(VolumeStructure.DIRECTORY_TREE_NAME)) { exchange = _persistit.getVolume(volumeName).getStructure().directoryExchange(); } else { exchange = _persistit.getExchange(volumeName, treeName, false); } exchange.ignoreMVCCFetch(true); KeyFilter filter = null; if (keyFilterString != null && keyFilterString.length() > 0) { filter = new KeyFilter(keyFilterString); } fromKey.copyTo(exchange.getKey()); for (; count < maxCount; count++) { if (!exchange.traverse(direction, filter, maxValueBytes)) { break; } else { final LogicalRecord record = new LogicalRecord(); record._key = new KeyState(exchange.getKey()); record._value = new ValueState(exchange.getValue(), maxValueBytes); if (decodeStrings) { record._keyString = _displayFilter.toKeyDisplayString(exchange); record._valueString = _displayFilter.toValueDisplayString(exchange); } if (forward) { records[count] = record; } else { records[maxCount - count - 1] = record; } } } } catch (final Exception e) { throw new WrappedRemoteException(e); } finally { exchange.ignoreMVCCFetch(false); } if (count < maxCount) { final LogicalRecord[] trimmed = new LogicalRecord[count]; System.arraycopy(records, forward ? 0 : maxCount - count, trimmed, 0, count); records = trimmed; } return records; }
private Exchange getExchange() throws PersistitException { try { final Volume volume = _persistit.getSystemVolume(); return _persistit.getExchange(volume, CLASS_INDEX_TREE_NAME, true); } catch (final PersistitException pe) { throw new ConversionException(pe); } }
@Override public LogicalRecordCount getLogicalRecordCount( final String volumeName, final String treeName, final String keyFilterString, final KeyState fromKey, final Key.Direction direction, final int maxCount) throws RemoteException { int count = 0; Exchange exchange = null; KeyState endKeyState = null; try { exchange = _persistit.getExchange(volumeName, treeName, false); exchange.getAuxiliaryKey2().clear(); KeyFilter filter = null; if (keyFilterString != null && keyFilterString.length() > 0) { filter = new KeyFilter(keyFilterString); } fromKey.copyTo(exchange.getKey()); for (; count < maxCount; count++) { if (!exchange.traverse(direction, filter, 0)) { break; } else { exchange.getKey().copyTo(exchange.getAuxiliaryKey2()); } } endKeyState = new KeyState(exchange.getAuxiliaryKey2()); } catch (final Exception pe) { throw new WrappedRemoteException(pe); } finally { if (exchange != null) _persistit.releaseExchange(exchange); } return new LogicalRecordCount(endKeyState, count); }