📄 persistentstorage.java
字号:
/** * Renames the given object to the new id. This method is potentially faster * than store/cache and unstore/uncache. * * @param oldId The id of the object in question. * @param newId The new id of the object in question. * @param c The command to run once the operation is complete */ public void rename(final Id oldId, final Id newId, Continuation c) { printStats(); environment.getProcessor().processBlockingIO( new WorkRequest(c, environment.getSelectorManager()) { public String toString() { return "rename " + oldId + " " + newId; } public Object doWork() throws Exception { synchronized (statLock) { numRenames++; } File f = getFile(oldId); if ((f != null) && (f.exists())) { File g = getFile(newId); renameFile(f, g); checkDirectory(g.getParentFile()); if (index) { synchronized (metadata) { metadata.put(newId, metadata.get(oldId)); metadata.remove(oldId); } } return Boolean.TRUE; } else { return Boolean.FALSE; } } }); } /** * Makes the object persistent to disk and stored permanantly If the object is * already persistent, this method will simply update the object's serialized * image. This is implemented atomically so that this may succeed and store * the new object, or fail and leave the previous object intact. This method * completes by calling recieveResult() of the provided continuation with the * success or failure of the operation. * * @param obj The object to be made persistent. * @param id The object's id. * @param metadata The object's metadata * @param c The command to run once the operation is complete */ public void store(final Id id, final Serializable metadata, final Serializable obj, Continuation c) { if (id == null || obj == null) { c.receiveResult(new Boolean(false)); return; } printStats(); environment.getProcessor().processBlockingIO( new WorkRequest(c, environment.getSelectorManager()) { public String toString() { return "store " + id; } public Object doWork() throws Exception { synchronized (statLock) { numWrites++; } if (logger.level <= Logger.FINER) { logger.log("Storing object " + obj + " under id " + id.toStringFull() + " in root " + appDirectory); } /* * first, create a temporary file */ File objFile = getFile(id); File transcFile = makeTemporaryFile(id); if (logger.level <= Logger.FINER) { logger.log("Writing object " + obj + " to temporary file " + transcFile + " and renaming to " + objFile); } /* * next, write out the data to a new copy of the original file */ try { writeObject(obj, metadata, id, environment.getTimeSource().currentTimeMillis(), transcFile); if (logger.level <= Logger.FINER) { logger.log("Done writing object " + obj + " under id " + id.toStringFull() + " in root " + appDirectory); } /* * abort if this will put us over quota */ if (getUsedSpace() + getFileLength(transcFile) > getStorageSize()) { throw new OutofDiskSpaceException(); } } catch (Exception e) { /* * if an IOException is thrown, delete the temporary file and abort */ if (logger.level <= Logger.WARNING) { logger.logException("", e); } deleteFile(transcFile); throw e; } if (logger.level <= Logger.FINER) { logger.log("COUNT: Storing data of class " + obj.getClass().getName() + " under " + id.toStringFull() + " of size " + transcFile.length() + " in " + name); } /* * recalculate amount used */ decreaseUsedSpace(getFileLength(objFile)); increaseUsedSpace(getFileLength(transcFile)); /* * now, rename the temporary file to be the real file */ renameFile(transcFile, objFile); /* * mark the metadata cache of this file to be dirty */ if (index) { synchronized (PersistentStorage.this.metadata) { PersistentStorage.this.metadata.put(id, metadata); dirty.add(objFile.getParentFile()); } } /* * finally, check to see if this directory needs to be split */ checkDirectory(objFile.getParentFile()); return Boolean.TRUE; } }); } /** * Request to remove the object from the list of persistend objects. Delete * the serialized image of the object from stable storage. If necessary. If * the object was not in the cached list in the first place, nothing happens * and <code>false</code> is returned. This method also guarantees that the * data on disk will remain consistent, even after a crash by performing the * delete atomically. This method completes by calling recieveResult() of the * provided continuation with the success or failure of the operation. * * @param id The object's persistence id * @param c The command to run once the operation is complete */ public void unstore(final Id id, Continuation c) { printStats(); environment.getProcessor().processBlockingIO( new WorkRequest(c, environment.getSelectorManager()) { public String toString() { return "unstore " + id; } public Object doWork() throws Exception { synchronized (statLock) { numDeletes++; } /* * first get the file */ File objFile = getFile(id); if (logger.level <= Logger.FINER) { logger.log("COUNT: Unstoring data under " + id.toStringFull() + " of size " + objFile.length() + " in " + name); } /* * remove id from stored list */ if (index) { synchronized (metadata) { metadata.remove(id); dirty.add(objFile.getParentFile()); } } /* * check to make sure file exists */ if ((objFile == null) || (!objFile.exists())) { return Boolean.FALSE; } /* * record the space collected and delete the file */ decreaseUsedSpace(objFile.length()); deleteFile(objFile); return Boolean.TRUE; } }); } /** * Returns whether or not an object is present in the location <code>id</code> * . * * @param id The id of the object in question. * @return Whether or not an object is present at id. */ public boolean exists(Id id) { if (index) { synchronized (metadata) { return metadata.containsKey(id); } } else { throw new UnsupportedOperationException("exists() not supported without indexing"); } } /** * Return the objects identified by the given range of ids. The IdSet returned * contains the Ids of the stored objects. The range is partially inclusive, * the lower range is inclusive, and the upper exclusive. NOTE: This method * blocks so if the behavior of this method changes and uses the disk, this * method may be deprecated. * * @param range The range to query * @return The idset containg the keys */ public IdSet scan(IdRange range) { if (index) { if (range.isEmpty()) { return factory.buildIdSet(); } else if (range.getCCWId().equals(range.getCWId())) { return scan(); } else { synchronized (metadata) { return factory.buildIdSet(new ImmutableSortedMap(metadata.keySubMap(range.getCCWId(), range.getCWId()))); } } } else { throw new UnsupportedOperationException("scan() not supported without indexing"); } } /** * Return the objects identified by the given range of ids. The IdSet returned * contains the Ids of the stored objects. The range is partially inclusive, * the lower range is inclusive, and the upper exclusive. NOTE: This method * blocks so if the behavior of this method changes and uses the disk, this * method may be deprecated. * * @return The idset containg the keys */ public IdSet scan() { if (index) { synchronized (metadata) { return factory.buildIdSet(new ImmutableSortedMap(metadata.keyMap())); } } else { throw new UnsupportedOperationException("scan() not supported without indexing"); } } /** * Returns a map which contains keys mapping ids to the associated metadata. * * @param range The range to query * @return The map containg the keys */ public SortedMap scanMetadata(IdRange range) { if (index) { if (range.isEmpty()) { return new RedBlackMap(); } else if (range.getCCWId().equals(range.getCWId())) { return scanMetadata(); } else { synchronized (metadata) { return new ImmutableSortedMap(metadata.keySubMap(range.getCCWId(), range.getCWId())); } } } else { throw new UnsupportedOperationException("scanMetadata() not supported without indexing"); } } /** * Returns a map which contains keys mapping ids to the associated metadata. * * @return The treemap mapping ids to metadata */ public SortedMap scanMetadata() { if (index) { return new ImmutableSortedMap(metadata.keyMap()); } else { throw new UnsupportedOperationException("scanMetadata() not supported without indexing"); } } /** * Returns the submapping of ids which have metadata less than the provided * value. * * @param value The maximal metadata value * @return The submapping */ public SortedMap scanMetadataValuesHead(Object value) { if (index) { return new ImmutableSortedMap(metadata.valueHeadMap(value)); } else { throw new UnsupportedOperationException("scanMetadataValuesHead() not supported without indexing"); } } /** * Returns the submapping of ids which have metadata null * * @return The submapping */ public SortedMap scanMetadataValuesNull() { if (index) { return new ImmutableSortedMap(metadata.valueNullMap()); } else { throw new UnsupportedOperationException("scanMetadataValuesNull() not supported without indexing"); } } /** * Method which is used to erase all data stored in the Catalog. Use this * method with care! * * @param c The command to run once done */ public void flush(Continuation c) { environment.getProcessor().processBlockingIO( new WorkRequest(c, environment.getSelectorManager()) { public String toString() { return "flush"; } public Object doWork() throws Exception { if (logger.level <= Logger.FINER) { logger.log("COUNT: Flushing all data in " + name); } flushDirectory(appDirectory); return Boolean.TRUE; } }); } /** * @exception IOException DESCRIBE THE EXCEPTION */ /* * Functions for init/crash recovery */ /** * @exception IOException DESCRIBE THE EXCEPTION */ /** * Perform all the miscealanious house keeping that must be done when we start * up * * @exception IOException DESCRIBE THE EXCEPTION */ private void init() throws IOException { if (logger.level <= Logger.INFO) { logger.log("Initing directories"); } initDirectories(); if (logger.level <= Logger.INFO) { logger.log("Initing directory map"); } initDirectoryMap(appDirectory); if (logger.level <= Logger.INFO) { logger.log("Initing files"); } initFiles(appDirectory); if (logger.level <= Logger.INFO) { logger.log("Initing file map"); } initFileMap(appDirectory); if (logger.level <= Logger.INFO) { logger.log("Syncing metadata"); } if (index) { writeDirty(); } if (logger.level <= Logger.INFO) { logger.log("Done initing"); } } /** * Verify that the directory name passed to the PersistenceManagerImpl * constructor is valid and creates the necessary subdirectories. * * @exception IOException DESCRIBE THE EXCEPTION */ private void initDirectories() throws IOException { rootDirectory = new File(rootDir); createDirectory(rootDirectory); backupDirectory = new File(rootDirectory, BACKUP_DIRECTORY); createDirectory(backupDirectory); appDirectory = new File(backupDirectory, getName());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -