Exemplo n.º 1
0
size_t BinaryTree<T>::_Depth(Node *root){
	if(root==NULL){
		return 0;
	}
	size_t leftD = _Depth(root->_left);
	size_t rightD = _Depth(root->_right);
	return leftD>rightD?leftD+1:rightD+1;
}
Exemplo n.º 2
0
	size_t _Depth(Node<T> *pRoot)
	{
		if (NULL == pRoot)
			return -1;

		if (NULL == pRoot->pLeft && NULL == pRoot->pRight)
			return 0;
		
		size_t left = _Depth(pRoot->pLeft);
		size_t right = _Depth(pRoot->pRight);

		return left > right ? left + 1 : right + 1;
	}
Exemplo n.º 3
0
status_t
DirEntryTree::_InsertEntryIncrementDepth(LevelInfo* infos,
	Transaction& transaction)
{
	FUNCTION("depth: %u -> %u\n", _Depth(), _Depth() + 1);

	if (_Depth() >= kCheckSumFSMaxDirEntryTreeDepth)
		RETURN_ERROR(B_DEVICE_FULL);

	// allocate a new block
	AllocatedBlock allocatedBlock(
		fDirectory->GetVolume()->GetBlockAllocator(), transaction);

	status_t error = allocatedBlock.Allocate(fDirectory->BlockIndex());
	if (error != B_OK)
		RETURN_ERROR(error);
	fDirectory->SetSize(fDirectory->Size() + B_PAGE_SIZE);

	LevelInfo& newInfo = infos[1];
	if (!newInfo.block.GetZero(fDirectory->GetVolume(),
			allocatedBlock.Index(), transaction)) {
		RETURN_ERROR(B_ERROR);
	}

	allocatedBlock.Detach();

	newInfo.entryBlock.SetTo(
		(checksumfs_dir_entry_block*)newInfo.block.Data(), B_PAGE_SIZE);
ASSERT(newInfo.entryBlock.Check());

	// move the old root block contents to the new block
	LevelInfo& rootInfo = infos[0];
	rootInfo.entryBlock.SplitBlock(0, newInfo.entryBlock);

	// add an entry for the new block to the root block
	size_t nameLength;
	const char* name = newInfo.entryBlock.NameAt(0, nameLength);
	rootInfo.entryBlock.InsertEntry(0, name, nameLength,
		newInfo.block.Index());

	PRINT("  -> new block: %" B_PRIu64 "\n", newInfo.block.Index());

	newInfo.index = rootInfo.index;
	rootInfo.index = 0;
	fTree->depth++;

	return B_OK;
}
Exemplo n.º 4
0
status_t
DirEntryTree::FreeTree(Transaction& transaction)
{
	status_t error = _InitReadOnly();
	if (error != B_OK)
		RETURN_ERROR(error);

	int32 depth = _Depth();
	if (depth == 0)
		return B_OK;

	LevelInfo* infos = new(std::nothrow) LevelInfo[
		kCheckSumFSMaxDirEntryTreeDepth + 1];
	if (infos == NULL)
		RETURN_ERROR(B_NO_MEMORY);
	ArrayDeleter<LevelInfo> infosDeleter(infos);

	infos[0].entryBlock.SetTo(fRootEntryBlock, fRootEntryBlockSize);
	infos[0].index = 0;

	// Iterate through the tree in post order. We don't touch the content of
	// any block, we only free the blocks.
	int32 level = 0;
	while (true) {
		LevelInfo& info = infos[level];

		if (level == depth || info.index >= info.entryBlock.EntryCount()) {
			// we're through with the block
			if (level == 0)
				break;

			// free it
			error = fDirectory->GetVolume()->GetBlockAllocator()->Free(
				info.block.Index(), 1, transaction);

			// continue with the next sibling branch
			infos[--level].index++;
		}

		// descend to next level
		uint64 nextBlockIndex = info.entryBlock.BlockIndexAt(info.index);

		LevelInfo& nextInfo = infos[++level];
		if (!nextInfo.block.GetReadable(fDirectory->GetVolume(),
				nextBlockIndex)) {
			RETURN_ERROR(B_ERROR);
		}

		nextInfo.entryBlock.SetTo(
			(checksumfs_dir_entry_block*)nextInfo.block.Data(),
			B_PAGE_SIZE);
	}

	return B_OK;
}
Exemplo n.º 5
0
status_t
DirEntryTree::_InitCommon()
{
	fTree = (checksumfs_dir_entry_tree*)
		((uint8*)fRootBlock.Data() + sizeof(checksumfs_node));

	fRootEntryBlock = (checksumfs_dir_entry_block*)(fTree + 1);
	fRootEntryBlockSize = B_PAGE_SIZE
		- ((addr_t)fRootEntryBlock - (addr_t)fRootBlock.Data());

	if (_Depth() > kCheckSumFSMaxDirEntryTreeDepth)
		RETURN_ERROR(B_BAD_DATA);

	return B_OK;
}
Exemplo n.º 6
0
	size_t _Depth(GeneralListNode* head)
	{
		size_t depth = 1;
		GeneralListNode* cur = head;
		while (cur)
		{
			if (cur->_type == SUB)
			{
				size_t subDepth = _Depth(cur->_subLink);
				if ((subDepth + 1) > depth)
				{
					depth = subDepth + 1;
				}
			}
			cur = cur->_next;
		}
		return depth;
	}
Exemplo n.º 7
0
	int _Depth(GeneralListNode* head)
	{
		int depth = 1;

		GeneralListNode* begin = head;
		while (begin)
		{
			if(begin->_type == SUB_TYPE)
			{
				int ret = _Depth(begin->_subLink);
				if (depth < ret + 1)
				{
					depth = ret + 1;
				}
			}

			begin = begin->_next;
		}

		return depth;
	}
Exemplo n.º 8
0
size_t BinaryTree<T>::Depth(){
	return _Depth(_root);
}
Exemplo n.º 9
0
	size_t Depth()
	{
		return _Depth(_head);
	}
Exemplo n.º 10
0
status_t
DirEntryTree::RemoveEntry(const char* name, Transaction& transaction)
{
	FUNCTION("name: \"%s\"\n", name);

	status_t error = _InitWritable(transaction);
	if (error != B_OK)
		RETURN_ERROR(error);

	size_t nameLength = strlen(name);
	if (nameLength == 0)
		RETURN_ERROR(B_BAD_VALUE);
	if (nameLength > kCheckSumFSNameLength)
		RETURN_ERROR(B_ENTRY_NOT_FOUND);

	int32 depth = _Depth();

	LevelInfo* infos = new(std::nothrow) LevelInfo[
		kCheckSumFSMaxDirEntryTreeDepth + 1];
	if (infos == NULL)
		RETURN_ERROR(B_NO_MEMORY);
	ArrayDeleter<LevelInfo> infosDeleter(infos);

	infos[0].entryBlock.SetTo(fRootEntryBlock, fRootEntryBlockSize);

	for (int32 level = 0; level <= depth; level++) {
		LevelInfo& info = infos[level];

		if (info.entryBlock.EntryCount() == 0) {
			if (level == 0) {
				// directory is empty
				PRINT("  directory is empty\n");
				RETURN_ERROR(B_ENTRY_NOT_FOUND);
			}

			RETURN_ERROR(B_BAD_DATA);
		}

		info.index = info.entryBlock.FindInsertionIndex(name, nameLength,
			info.exactMatch);

		PRINT("  level %" B_PRId32 ", block %" B_PRIu64 " -> index: %" B_PRId32
			" %sexact\n", level,
			level == 0 ? fDirectory->BlockIndex() : info.block.Index(),
			info.index, info.exactMatch ? "" : " not ");

		if (level == depth) {
			// final level -- here the entry should be found
			if (!info.exactMatch)
				RETURN_ERROR(B_ENTRY_NOT_FOUND);
			break;
		}

		// If we haven't found an exact match, the index points to the first
		// entry that is greater or after the last entry.
		if (!info.exactMatch) {
			if (info.index == 0) {
				// The first entry is already greater, so the branch doesn't
				// contain the entry we're looking for.
				RETURN_ERROR(B_ENTRY_NOT_FOUND);
			}

			info.index--;
		}

		uint64 nextBlockIndex = info.entryBlock.BlockIndexAt(info.index);

		// not the final level -- load the block and descend to the next
		// level
		LevelInfo& nextInfo = infos[level + 1];
		if (!nextInfo.block.GetReadable(fDirectory->GetVolume(),
				nextBlockIndex)) {
			RETURN_ERROR(B_ERROR);
		}

		nextInfo.entryBlock.SetTo(
			(checksumfs_dir_entry_block*)nextInfo.block.Data(),
			B_PAGE_SIZE);
ASSERT(nextInfo.entryBlock.Check());
	}

	// We've found the entry. Insert the key and iterate backwards to perform
	// the potentially necessary updates. Removal at index 0 of the block
	// changes the block's key, requiring an update in the parent block.
	// Removal of the last entry will require removal of the block from its
	// parent. Key update can cause the block to be split (if there's not
	// enough space left in it), requiring an insertion in the parent block.
	// We start with a pending removal in the leaf block and work our way
	// upwards as long as the blocks become empty. As soon as a key update is
	// required, we delegate the remaining to the update/insert backwards loop.

	for (int32 level = depth; level >= 0; level--) {
		LevelInfo& info = infos[level];

		// make the block writable
		if (level > 0) {
			error = info.block.MakeWritable(transaction);
			if (error != B_OK)
				RETURN_ERROR(error);
		}

		PRINT("  level: %" B_PRId32 ", index: %" B_PRId32 ": removing key "
			"\"%.*s\" (%" B_PRIuSIZE ")\n", level, info.index, (int)nameLength,
			name, nameLength);

		if (info.entryBlock.EntryCount() == 1) {
			// That's the last key in the block. Unless that's the root level,
			// we remove the block completely.
			PRINT("  -> block is empty\n");
			if (level == 0) {
				info.entryBlock.RemoveEntry(info.index);
				return B_OK;
			}

			error = fDirectory->GetVolume()->GetBlockAllocator()->Free(
				info.block.Index(), 1, transaction);
			if (error != B_OK)
				RETURN_ERROR(error);
			fDirectory->SetSize(fDirectory->Size() - B_PAGE_SIZE);

			// remove the key (the same one) from the parent block
			continue;
		}

		// There are more entries, so just remove the entry in question. If it
		// is not the first one, we're done, otherwise we have to update the
		// block's key in the parent block.
		info.entryBlock.RemoveEntry(info.index);

		if (info.index > 0 || level == 0)
			return B_OK;

		name = info.entryBlock.NameAt(0, nameLength);
		return _UpdateOrInsertKey(infos, level - 1, name, nameLength, 0, false,
			transaction);
	}

	return B_OK;
}
Exemplo n.º 11
0
status_t
DirEntryTree::LookupNextEntry(const char* name, char* foundName,
	size_t& _foundNameLength, uint64& _blockIndex)
{
	FUNCTION("name: \"%s\"\n", name);

	status_t error = _InitReadOnly();
	if (error != B_OK)
		RETURN_ERROR(error);

	size_t nameLength = strlen(name);
	if (nameLength > kCheckSumFSNameLength)
		RETURN_ERROR(B_ENTRY_NOT_FOUND);

	int32 depth = _Depth();

	LevelInfo* infos = new(std::nothrow) LevelInfo[
		kCheckSumFSMaxDirEntryTreeDepth + 1];
	if (infos == NULL)
		RETURN_ERROR(B_NO_MEMORY);
	ArrayDeleter<LevelInfo> infosDeleter(infos);

	infos[0].entryBlock.SetTo(fRootEntryBlock, fRootEntryBlockSize);
ASSERT(infos[0].entryBlock.Check());

	// descend the tree
	for (int32 level = 0; level <= depth; level++) {
		LevelInfo& info = infos[level];

		if (info.entryBlock.EntryCount() == 0) {
			if (level == 0) {
				// directory is empty
				return B_ENTRY_NOT_FOUND;
			}

			RETURN_ERROR(B_BAD_DATA);
		}

		info.index = info.entryBlock.FindInsertionIndex(name, nameLength,
			info.exactMatch);

		PRINT("  level %" B_PRId32 " -> index: %" B_PRId32 " %sexact\n", level,
			info.index, info.exactMatch ? "" : " not ");

		if (level == depth)
			break;

		// If we haven't found an exact match, the index points to the first
		// entry that is greater or after the last entry.
		if (!info.exactMatch && info.index > 0)
			info.index--;

		uint64 nextBlockIndex = info.entryBlock.BlockIndexAt(info.index);

		// not the final level -- load the block and descend to the next
		// level
		LevelInfo& nextInfo = infos[level + 1];
		if (!nextInfo.block.GetReadable(fDirectory->GetVolume(),
				nextBlockIndex)) {
			RETURN_ERROR(B_ERROR);
		}

		nextInfo.entryBlock.SetTo(
			(checksumfs_dir_entry_block*)nextInfo.block.Data(),
			B_PAGE_SIZE);
ASSERT(nextInfo.entryBlock.Check());
	}

	if (infos[depth].exactMatch)
		infos[depth].index++;

	if (infos[depth].index >= infos[depth].entryBlock.EntryCount()) {
		// We're at the end of the last block -- we need to track back to find a
		// greater branch.
		PRINT("  searching for greater branch\n");

		int32 level;
		for (level = depth - 1; level >= 0; level--) {
			LevelInfo& info = infos[level];
			if (++info.index < info.entryBlock.EntryCount()) {
				PRINT("  found greater branch: level: %" B_PRId32 " -> index: %"
					B_PRId32 "\n", level, info.index);
				break;
			}
		}

		if (level < 0)
			return B_ENTRY_NOT_FOUND;

		// We've found a greater branch -- get the first entry in that branch.
		for (level++; level <= depth; level++) {
			LevelInfo& previousInfo = infos[level - 1];
			LevelInfo& info = infos[level];

			uint64 nextBlockIndex = previousInfo.entryBlock.BlockIndexAt(
				previousInfo.index);

			// load the block
			if (!info.block.GetReadable(fDirectory->GetVolume(),
					nextBlockIndex)) {
				RETURN_ERROR(B_ERROR);
			}

			info.entryBlock.SetTo(
				(checksumfs_dir_entry_block*)info.block.Data(), B_PAGE_SIZE);
ASSERT(info.entryBlock.Check());

			info.index = 0;
			if (info.entryBlock.EntryCount() == 0)
				RETURN_ERROR(B_BAD_DATA);
		}
	}

	// get and check the name
	LevelInfo& info = infos[depth];

	name = info.entryBlock.NameAt(info.index, nameLength);
	if (nameLength > kCheckSumFSNameLength
		|| strnlen(name, nameLength) != nameLength) {
		RETURN_ERROR(B_BAD_DATA);
	}

	// set the return values
	memcpy(foundName, name, nameLength);
	foundName[nameLength] = '\0';
	_foundNameLength = nameLength;
	_blockIndex = info.entryBlock.BlockIndexAt(info.index);

	PRINT("  found entry: \"%s\" -> %" B_PRIu64 "\n", foundName, _blockIndex);

	return B_OK;
}
Exemplo n.º 12
0
status_t
DirEntryTree::LookupEntry(const char* name, uint64& _blockIndex)
{
	FUNCTION("name: \"%s\"\n", name);

	status_t error = _InitReadOnly();
	if (error != B_OK)
		RETURN_ERROR(error);

	size_t nameLength = strlen(name);
	if (nameLength > kCheckSumFSNameLength)
		RETURN_ERROR(B_ENTRY_NOT_FOUND);

	uint32 depth = _Depth();

	DirEntryBlock entryBlock(fRootEntryBlock, fRootEntryBlockSize);
ASSERT(entryBlock.Check());

	Block block;

	for (uint32 level = 0; level <= depth; level++) {
		if (entryBlock.EntryCount() == 0)
			RETURN_ERROR(level == 0 ? B_ENTRY_NOT_FOUND : B_BAD_DATA);

		bool exactMatch;
		int32 index = entryBlock.FindInsertionIndex(name, nameLength,
			exactMatch);

		// If we haven't found an exact match, the index points to the first
		// entry that is greater or after the last entry.
		if (!exactMatch) {
			if (index == 0) {
				// The first entry is already greater, so the branch doesn't
				// contain the entry we're looking for.
				RETURN_ERROR(B_ENTRY_NOT_FOUND);
			}

			index--;
		}

		PRINT("  level %" B_PRId32 " -> index: %" B_PRId32 " %sexact\n", level,
			index, exactMatch ? "" : " not ");

		uint64 blockIndex = entryBlock.BlockIndexAt(index);

		if (level == depth) {
			// final level -- here we should have an exact match
			if (!exactMatch)
				RETURN_ERROR(B_ENTRY_NOT_FOUND);

			_blockIndex = blockIndex;
			return B_OK;
		}

		// not the final level -- load the block and descend to the next
		// level
		if (!block.GetReadable(fDirectory->GetVolume(), blockIndex))
			RETURN_ERROR(B_ERROR);

		entryBlock.SetTo((checksumfs_dir_entry_block*)block.Data(),
			B_PAGE_SIZE);
ASSERT(entryBlock.Check());
	}

	// cannot get here, but keep the compiler happy
	RETURN_ERROR(B_ENTRY_NOT_FOUND);
}
Exemplo n.º 13
0
bool
DirEntryTree::_Check(int32 level, uint64 blockIndex, const char* key,
	size_t keyLength, DirEntryBlock& entryBlock)
{
	// check block for validity
	if (!entryBlock.Check()) {
		ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %"
			B_PRIu64 " not valid!\n", level, blockIndex);
		return false;
	}

	// The root block is allowed to be empty. For all other blocks that is an
	// error.
	uint32 entryCount = entryBlock.EntryCount();
	if (entryCount == 0) {
		if (level == 0)
			return true;

		ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %"
			B_PRIu64 " empty!\n", level, blockIndex);
		return false;
	}

	// Verify that the block's first entry matches the key with which the
	// parent block refers to it.
	if (level > 0) {
		size_t nameLength;
		const char* name = entryBlock.NameAt(0, nameLength);
		if (nameLength != keyLength || strncmp(name, key, keyLength) != 0) {
			ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %"
				B_PRIu64 " key mismatch: is \"%.*s\", should be \"%.*s\"\n",
				level, blockIndex, (int)keyLength, key, (int)nameLength, name);
			return false;
		}
	}

	if (level == _Depth())
		return true;

	// not the final level -- recurse
	for (uint32 i = 0; i < entryCount; i++) {
		size_t nameLength;
		const char* name = entryBlock.NameAt(i, nameLength);
		uint64 childBlockIndex = entryBlock.BlockIndexAt(i);

		Block childBlock;
		if (!childBlock.GetReadable(fDirectory->GetVolume(), childBlockIndex)) {
			ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %"
				B_PRIu64 " failed to get child block %" B_PRIu64 " (entry %"
				B_PRIu32 ")\n", level, blockIndex, childBlockIndex, i);
		}

		DirEntryBlock childEntryBlock(
			(checksumfs_dir_entry_block*)childBlock.Data(), B_PAGE_SIZE);

		if (!_Check(level + 1, childBlockIndex, name, nameLength,
				childEntryBlock)) {
			return false;
		}
	}

	return true;
}
Exemplo n.º 14
0
status_t
DirEntryTree::_UpdateOrInsertKey(LevelInfo* infos, int32 level,
	const char* name, size_t nameLength, uint64 blockIndex, bool insertKey,
	Transaction& transaction)
{
	FUNCTION("level: %" B_PRId32 ": %s name: \"%.*s\" (%" B_PRIuSIZE "), "
		"blockIndex: %" B_PRIu64 "\n", level, insertKey ? "insert" : "update",
		(int)nameLength, name, nameLength, blockIndex);

	// Some temporary blocks: newBlock is used when a block is split. The
	// other three are used when a key update respectively insertion in the
	// parent block becomes necessary. We only need them, since the name
	// we update/insert is potentially from a block and instead of cloning
	// the name, we simple postpone putting the block until we don't need
	// the name anymore.
	Block newBlock;
	Block tempBlockUpdate;
	Block tempBlockUpdateInsert;
	Block tempBlockInsert;

	int32 depth = _Depth();
	status_t error;

	bool updateNextKey = !insertKey;
	bool insertNextKey = insertKey;
	const char* nameToUpdate = name;
	size_t nameToUpdateLength = nameLength;
	const char* nextNameToInsert = name;
	size_t nextNameToInsertLength = nameLength;
	uint64 nextBlockIndexToInsert = blockIndex;

	for (; level >= 0; level--) {
		LevelInfo& info = infos[level];

		bool updateThisKey = updateNextKey;
		bool insertThisKey = insertNextKey;

		if (!updateThisKey && !insertThisKey)
			return B_OK;

		updateNextKey = false;
		insertNextKey = false;

		blockIndex = nextBlockIndexToInsert;
		name = nextNameToInsert;
		nameLength = nextNameToInsertLength;

		// make the block writable
		if (level > 0) {
			error = info.block.MakeWritable(transaction);
			if (error != B_OK)
				RETURN_ERROR(error);
		}

		if (updateThisKey) {
			PRINT("  level: %" B_PRId32 ", index: %" B_PRId32 ": updating key "
				"to \"%.*s\" (%" B_PRIuSIZE ")\n", level, info.index,
				(int)nameToUpdateLength, nameToUpdate, nameToUpdateLength);

			size_t oldNameLength;
			info.entryBlock.NameAt(info.index, oldNameLength);
			size_t spaceNeeded = oldNameLength < nameToUpdateLength
				? nameToUpdateLength - oldNameLength : 0;

			if (spaceNeeded <= info.entryBlock.FreeSpace()) {
				info.entryBlock.ReplaceEntryName(info.index, nameToUpdate,
					nameToUpdateLength);
				if (info.index == 0) {
					// we updated at index 0, so we need to update this
					// block's key in the parent block
					updateNextKey = true;
					nameToUpdate = info.entryBlock.NameAt(0,
						nameToUpdateLength);

					// make sure the new block is kept until we no longer
					// use the name in the next iteration
					tempBlockUpdate.TransferFrom(info.block);
				}
			} else if (level == 0) {
				// We need to split the root block -- clone it first.
				error = _InsertEntryIncrementDepth(infos, transaction);
				if (error != B_OK)
					RETURN_ERROR(error);

				level = 2;
					// _InsertEntryIncrementDepth() moved the root block
					// content to level 1, where we want to continue.
				updateNextKey = true;
				insertNextKey = insertThisKey;
				continue;
			} else {
				// We need to split this non-root block.
				int32 splitIndex;
				error = _InsertEntrySplitBlock(level, info, spaceNeeded,
					transaction, newBlock, splitIndex);
				if (error != B_OK)
					RETURN_ERROR(error);

				nextBlockIndexToInsert = newBlock.Index();

				DirEntryBlock newEntryBlock(
					(checksumfs_dir_entry_block*)newBlock.Data(),
					B_PAGE_SIZE);
ASSERT(newEntryBlock.Check());

				if (info.index < splitIndex) {
					ASSERT(info.entryBlock.FreeSpace() >= spaceNeeded);

					info.entryBlock.ReplaceEntryName(info.index,
						nameToUpdate, nameToUpdateLength);
					if (info.index == 0) {
						// we updated at index 0, so we need to update this
						// block's key in the parent block
						updateNextKey = true;
						nameToUpdate = info.entryBlock.NameAt(0,
							nameToUpdateLength);

						// make sure the new block is kept until we no
						// longer use the name in the next iteration
						tempBlockUpdate.TransferFrom(info.block);
					}
				} else {
					ASSERT(newEntryBlock.FreeSpace() >= spaceNeeded);

					// we need to transfer the block to the info, in case we
					// also need to insert a key below
					info.block.TransferFrom(newBlock);
					info.entryBlock.SetTo(
						(checksumfs_dir_entry_block*)info.block.Data(),
						B_PAGE_SIZE);
ASSERT(info.entryBlock.Check());

					info.index -= splitIndex;

					info.entryBlock.ReplaceEntryName(info.index, nameToUpdate,
						nameToUpdateLength);
				}

				// the newly created block needs to be inserted in the
				// parent
				insertNextKey = true;
				nextNameToInsert = newEntryBlock.NameAt(0,
					nextNameToInsertLength);

				// make sure the new block is kept until we no longer use
				// the name in the next iteration (might already have been
				// transferred to entry.block)
				tempBlockUpdateInsert.TransferFrom(newBlock);
			}
		}

		if (insertThisKey) {
			// insert after the block we descended
			if (level < depth)
				info.index++;

			PRINT("  level: %" B_PRId32 ", index: %" B_PRId32 ": inserting key "
				"\"%.*s\" (%" B_PRIuSIZE "), blockIndex: %" B_PRIu64 "\n",
				level, info.index, (int)nameLength, name, nameLength,
				blockIndex);

			if (info.entryBlock.FreeSpace() >= nameLength + 10) {
				info.entryBlock.InsertEntry(info.index, name,
					nameLength, blockIndex);
				if (info.index == 0) {
					// we inserted at index 0, so we need to update this
					// block's key in the parent block
					updateNextKey = true;
					nameToUpdate = info.entryBlock.NameAt(0,
						nameToUpdateLength);

					// make sure the new block is kept until we no longer
					// use the name in the next iteration
					tempBlockUpdate.TransferFrom(info.block);
				}
				continue;
			}

			// Not enough space left in the block -- we need to split it.
			ASSERT(!insertNextKey);

			// for level == 0 we need to clone the block first
			if (level == 0) {
				error = _InsertEntryIncrementDepth(infos, transaction);
				if (error != B_OK)
					RETURN_ERROR(error);

				level = 2;
					// _InsertEntryIncrementDepth() moved the root block
					// content to level 1, where we want to continue.
				updateNextKey = false;
				insertNextKey = true;
				continue;
			}

			int32 splitIndex;
			error = _InsertEntrySplitBlock(level, info, nameLength + 10,
				transaction, newBlock, splitIndex);
			if (error != B_OK)
				RETURN_ERROR(error);

			DirEntryBlock newEntryBlock(
				(checksumfs_dir_entry_block*)newBlock.Data(),
				B_PAGE_SIZE);
ASSERT(newEntryBlock.Check());

			if (info.index < splitIndex) {
				ASSERT(info.entryBlock.FreeSpace() >= nameLength + 10);

				info.entryBlock.InsertEntry(info.index, name,
					nameLength, blockIndex);
				if (info.index == 0) {
					// we inserted at index 0, so we need to update this
					// block's key in the parent block
					updateNextKey = true;
					nameToUpdate = info.entryBlock.NameAt(0,
						nameToUpdateLength);

					// make sure the new block is kept until we no longer
					// use the name in the next iteration
					tempBlockUpdate.TransferFrom(info.block);
				}
			} else {
				ASSERT(newEntryBlock.FreeSpace() >= nameLength + 10);

				info.index -= splitIndex;

				newEntryBlock.InsertEntry(info.index, name, nameLength,
					blockIndex);
			}

			// the newly created block needs to be inserted in the parent
			insertNextKey = true;
			nextNameToInsert = newEntryBlock.NameAt(0, nextNameToInsertLength);
			nextBlockIndexToInsert = newBlock.Index();

			// make sure the new block is kept until we no longer use
			// the name in the next iteration
			tempBlockInsert.TransferFrom(newBlock);
		}
	}

	return B_OK;
}
Exemplo n.º 15
0
	int Depth()
	{
		return _Depth(_head);
	}
Exemplo n.º 16
0
status_t
DirEntryTree::InsertEntry(const char* name, uint64 blockIndex,
	Transaction& transaction)
{
	FUNCTION("name: \"%s\", blockIndex: %" B_PRIu64 "\n", name, blockIndex);

	status_t error = _InitWritable(transaction);
	if (error != B_OK)
		RETURN_ERROR(error);

	size_t nameLength = strlen(name);
	if (nameLength == 0)
		RETURN_ERROR(B_BAD_VALUE);
	if (nameLength > kCheckSumFSNameLength)
		RETURN_ERROR(B_NAME_TOO_LONG);

	int32 depth = _Depth();

	LevelInfo* infos = new(std::nothrow) LevelInfo[
		kCheckSumFSMaxDirEntryTreeDepth + 1];
	if (infos == NULL)
		RETURN_ERROR(B_NO_MEMORY);
	ArrayDeleter<LevelInfo> infosDeleter(infos);

	infos[0].entryBlock.SetTo(fRootEntryBlock, fRootEntryBlockSize);

	for (int32 level = 0; level <= depth; level++) {
		LevelInfo& info = infos[level];

		if (info.entryBlock.EntryCount() == 0) {
			if (level == 0) {
				PRINT("  directory is empty\n");
				// directory is empty
				info.index = 0;
				break;
			}

			RETURN_ERROR(B_BAD_DATA);
		}

		info.index = info.entryBlock.FindInsertionIndex(name, nameLength,
			info.exactMatch);

		PRINT("  level %" B_PRId32 ", block %" B_PRIu64 " -> index: %" B_PRId32
			" %sexact\n", level,
			level == 0 ? fDirectory->BlockIndex() : info.block.Index(),
			info.index, info.exactMatch ? "" : " not ");

		// Finding an exact match -- even in the non-final level -- means
		// that there's an entry with that name.
		if (info.exactMatch)
			RETURN_ERROR(B_FILE_EXISTS);

		if (level == depth) {
			// final level -- here we need to insert the entry
			break;
		}

		// Since we haven't found an exact match, the index points to the
		// first entry that is greater or after the last entry.
		info.index--;

		uint64 nextBlockIndex = info.entryBlock.BlockIndexAt(info.index);

		// not the final level -- load the block and descend to the next
		// level
		LevelInfo& nextInfo = infos[level + 1];
		if (!nextInfo.block.GetReadable(fDirectory->GetVolume(),
				nextBlockIndex)) {
			RETURN_ERROR(B_ERROR);
		}

		nextInfo.entryBlock.SetTo(
			(checksumfs_dir_entry_block*)nextInfo.block.Data(),
			B_PAGE_SIZE);
ASSERT(nextInfo.entryBlock.Check());
	}

	// We've found the insertion point. Insert the key and iterate backwards
	// to perform the potentially necessary updates. Insertion at index 0 of
	// the block changes the block's key, requiring an update in the parent
	// block. Insertion or key update can cause the block to be split (if
	// there's not enough space left in it), requiring an insertion in the
	// parent block. So we start with a pending insertion in the leaf block
	// and work our way upwards, performing key updates and insertions as
	// necessary.

	return _UpdateOrInsertKey(infos, depth, name, nameLength, blockIndex, true,
		transaction);
}
Exemplo n.º 17
0
	size_t Depth()
	{
		return _Depth(pRoot);
	}