@Override public short unlink(final long parentId, final String fileName, final AtomicDBUpdate update) throws DatabaseException { try { // retrieve the file metadata BufferBackedFileMetadata file = BabuDBStorageHelper.getMetadata(database, parentId, fileName); // determine and set the new link count short newLinkCount = (short) (file.getLinkCount() - 1); file.setLinkCount(newLinkCount); // if there will be links remaining after the deletion, update the // link count; it must be in the FILE_ID_INDEX, because there have // been at least two links if (newLinkCount > 0) update.addUpdate( FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(file.getId(), FileMetadata.RC_METADATA), file.getRCMetadata().getValue()); // remove all entries from the file index update.addUpdate( FILE_INDEX, BabuDBStorageHelper.createFileKey(parentId, fileName, FileMetadata.FC_METADATA), null); update.addUpdate( FILE_INDEX, BabuDBStorageHelper.createFileKey(parentId, fileName, FileMetadata.RC_METADATA), null); return newLinkCount; } catch (BabuDBException exc) { throw new DatabaseException(exc); } }
@Override public void link( final FileMetadata metadata, final long newParentId, final String newFileName, final AtomicDBUpdate update) { // get the link source BufferBackedFileMetadata md = (BufferBackedFileMetadata) metadata; // increment the link count short links = metadata.getLinkCount(); md.setLinkCount((short) (links + 1)); // insert the whole metadata of the original file in the file ID // index update.addUpdate( FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(metadata.getId(), FileMetadata.FC_METADATA), md.getFCMetadataValue()); update.addUpdate( FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(metadata.getId(), FileMetadata.RC_METADATA), md.getRCMetadata().getValue()); // remove the back link update.addUpdate( FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(metadata.getId(), (byte) 3), null); // if the metadata was retrieved from the FILE_INDEX and hasn't // been deleted before (i.e. links == 0), ensure that the original // file in the file index now points to the file ID index, and // remove the FC and XLoc metadata entries if (links != 0 && md.getIndexId() == FILE_INDEX) { update.addUpdate( FILE_INDEX, md.getRCMetadata().getKey(), BabuDBStorageHelper.createLinkTarget(metadata.getId())); update.addUpdate(FILE_INDEX, md.getFCMetadataKey(), null); } // create an entry for the new link to the metadata in the file // index update.addUpdate( FILE_INDEX, BabuDBStorageHelper.createFileKey(newParentId, newFileName, FileMetadata.RC_METADATA), BabuDBStorageHelper.createLinkTarget(metadata.getId())); }
@Override public FileMetadata getMetadata(long fileId) throws DatabaseException { try { // create the key for the file ID index lookup byte[] key = BabuDBStorageHelper.createFileIdIndexKey(fileId, (byte) -1); ByteBuffer.wrap(key).putLong(fileId); byte[][] valBufs = new byte[BufferBackedFileMetadata.NUM_BUFFERS][]; // retrieve the metadata from the link index ResultSet<byte[], byte[]> it = database.prefixLookup(BabuDBStorageManager.FILE_ID_INDEX, key, null).get(); while (it.hasNext()) { Entry<byte[], byte[]> curr = it.next(); int type = BabuDBStorageHelper.getType(curr.getKey(), BabuDBStorageManager.FILE_ID_INDEX); // if the value is a back link, resolve it if (type == 3) { long parentId = ByteBuffer.wrap(curr.getValue()).getLong(); String fileName = new String(curr.getValue(), 8, curr.getValue().length - 8); return getMetadata(parentId, fileName); } valBufs[type] = curr.getValue(); } it.free(); // if not metadata was found for the file ID, return null if (valBufs[FileMetadata.RC_METADATA] == null) return null; byte[][] keyBufs = new byte[][] {null, BabuDBStorageHelper.createFileKey(0, "", FileMetadata.RC_METADATA)}; // otherwise, a hard link target is contained in the index; create a // new metadata object in this case return new BufferBackedFileMetadata(keyBufs, valBufs, BabuDBStorageManager.FILE_ID_INDEX); } catch (BabuDBException exc) { throw new DatabaseException(exc); } }
@Override public short delete(final long parentId, final String fileName, final AtomicDBUpdate update) throws DatabaseException { try { // retrieve the file metadata BufferBackedFileMetadata file = BabuDBStorageHelper.getMetadata(database, parentId, fileName); // check whether there is only one link remaining short newLinkCount = (short) (file.getLinkCount() - 1); assert (newLinkCount >= 0); // decrement the link count file.setLinkCount(newLinkCount); // if there will be links remaining after the deletion, update the // link count if (newLinkCount > 0) update.addUpdate( FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(file.getId(), FileMetadata.RC_METADATA), file.getRCMetadata().getValue()); // delete all keys ... // remove all content from the file index update.addUpdate( BabuDBStorageManager.FILE_INDEX, BabuDBStorageHelper.createFileKey(parentId, fileName, FileMetadata.FC_METADATA), null); update.addUpdate( BabuDBStorageManager.FILE_INDEX, BabuDBStorageHelper.createFileKey(parentId, fileName, FileMetadata.RC_METADATA), null); // if the last link to the file is supposed to be deleted, remove // the remaining metadata, including ACLs and XAttrs if (newLinkCount == 0) { // remove the back link from the file ID index update.addUpdate( BabuDBStorageManager.FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(file.getId(), (byte) 3), null); // remove potentially existing metadata from the file ID index update.addUpdate( BabuDBStorageManager.FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(file.getId(), FileMetadata.FC_METADATA), null); update.addUpdate( BabuDBStorageManager.FILE_ID_INDEX, BabuDBStorageHelper.createFileIdIndexKey(file.getId(), FileMetadata.RC_METADATA), null); byte[] idBytes = new byte[8]; ByteBuffer.wrap(idBytes).putLong(file.getId()); // remove all ACLs ResultSet<byte[], byte[]> it = database.prefixLookup(BabuDBStorageManager.ACL_INDEX, idBytes, null).get(); while (it.hasNext()) update.addUpdate(BabuDBStorageManager.ACL_INDEX, it.next().getKey(), null); it.free(); // remove all extended attributes it = database.prefixLookup(BabuDBStorageManager.XATTRS_INDEX, idBytes, null).get(); while (it.hasNext()) update.addUpdate(BabuDBStorageManager.XATTRS_INDEX, it.next().getKey(), null); it.free(); // if a file is deleted, update file count and volume size if (file.isDirectory()) { updateCount(NUM_DIRS_KEY, false, update); } else if (file.getXLocList() != null) { volume.updateVolumeSize(-file.getSize(), update); updateCount(NUM_FILES_KEY, false, update); } } return file.getLinkCount(); } catch (BabuDBException exc) { throw new DatabaseException(exc); } }
@Override public void createSnapshot(String snapName, long parentId, String dirName, boolean recursive) throws DatabaseException { try { // determine the prefixes for the snapshot byte[][][] prefixes = null; FileMetadata snapDir = getMetadata(parentId, dirName); // for a full volume snapshot, simply use a 'null' prefix (full: // dirID == 1 && recursive) if (snapDir.getId() != 1 || !recursive) { // get the IDs of all files and directories contained in the // given directory; if recursive == true, include subdirectories List<FileMetadata> nestedFiles = new LinkedList<FileMetadata>(); BabuDBStorageHelper.getNestedFiles(nestedFiles, database, snapDir.getId(), recursive); List<byte[]> dirEntryPrefixes = new ArrayList<byte[]>(nestedFiles.size()); List<byte[]> filePrefixes = new ArrayList<byte[]>(nestedFiles.size()); // include the extended attributes of the volume's root // directory if it's not the snapshot directory - they are // needed to access volume-wide parameters in the snapshot, such // as the access control policy if (snapDir.getId() != 1) filePrefixes.add(ByteBuffer.wrap(new byte[8]).putLong(1).array()); // include all metadata of the snapshot (i.e. top level) dir byte[] idxKey = BabuDBStorageHelper.createFileKey(parentId, dirName, (byte) -1); byte[] fileKey = BabuDBStorageHelper.createFilePrefixKey(snapDir.getId()); dirEntryPrefixes.add(idxKey); filePrefixes.add(fileKey); // include the snapshot directory content idxKey = BabuDBStorageHelper.createFilePrefixKey(snapDir.getId()); dirEntryPrefixes.add(idxKey); // determine the key prefixes of all nested files to include and // exclude for (FileMetadata file : nestedFiles) { // create a prefix key for the nested file byte[] key = BabuDBStorageHelper.createFilePrefixKey(file.getId()); // if the nested file is a directory, ... if (file.isDirectory()) { // include the directory in the file prefixes // and the directory prefix in the dir entry prefixes filePrefixes.add(key); dirEntryPrefixes.add(key); } // if the nested file is a file, ... else filePrefixes.add(key); } byte[][] dirEntryPrefixesA = dirEntryPrefixes.toArray(new byte[dirEntryPrefixes.size()][]); byte[][] filePrefixesA = filePrefixes.toArray(new byte[filePrefixes.size()][]); Arrays.sort(dirEntryPrefixesA, DefaultByteRangeComparator.getInstance()); Arrays.sort(filePrefixesA, DefaultByteRangeComparator.getInstance()); // FILE_INDEX, XATTRS_INDEX, ACL_INDEX, FILE_ID_INDEX, // VOLUME_INDEX prefixes = new byte[][][] {dirEntryPrefixesA, filePrefixesA, filePrefixesA, filePrefixesA, null}; } // create the snapshot SnapshotConfig snap = new DefaultSnapshotConfig(snapName, ALL_INDICES, prefixes, null); snapMan.createPersistentSnapshot(database.getName(), snap); } catch (BabuDBException exc) { throw new DatabaseException(exc); } }