/** * Open an old, stored version of a map. * * @param version the version * @return the read-only map */ @SuppressWarnings("unchecked") <T extends BTreeMap<?, ?>> T openMapVersion(long version) { BTreeChunk c = getChunkForVersion(version); DataUtils.checkArgument(c != null, "Unknown version {0}", version); BTreeMap<?, ?> m = map.openReadOnly(); m.setRootPos(c.rootPagePos, version); return (T) m; }
/** * Revert to the beginning of the given version. All later changes (stored or not) are forgotten. * All maps that were created later are closed. A rollback to a version before the last stored * version is immediately persisted. Rollback to version 0 means all data is removed. * * @param version the version to revert to */ public synchronized void rollbackTo(long version) { checkOpen(); if (version == 0) { // special case: remove all data map.close(); chunks.clear(); currentVersion = version; return; } DataUtils.checkArgument(isKnownVersion(version), "Unknown version {0}", version); map.internalRollbackTo(version); boolean loadFromFile = false; // find out which chunks to remove, // and which is the newest chunk to keep // (the chunk list can have gaps) ArrayList<Integer> remove = new ArrayList<Integer>(); BTreeChunk keep = null; for (BTreeChunk c : chunks.values()) { if (c.version > version) { remove.add(c.id); } else if (keep == null || keep.id < c.id) { keep = c; } } if (remove.size() > 0) { // remove the youngest first, so we don't create gaps // (in case we remove many chunks) Collections.sort(remove, Collections.reverseOrder()); map.removeUnusedOldVersions(); loadFromFile = true; for (int id : remove) { BTreeChunk c = chunks.remove(id); c.fileStorage.close(); c.fileStorage.delete(); } lastChunkId = keep.id; setLastChunk(keep); } if (createVersion >= version) { map.close(); } else { if (loadFromFile) { map.setRootPos(lastChunk.rootPagePos, lastChunk.version); } } currentVersion = version; }