1299aba38Shyche /* 2299aba38Shyche * Copyright 2011, Jérôme Duval, korli@users.berlios.de. 3299aba38Shyche * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de. 4299aba38Shyche * This file may be used under the terms of the MIT License. 5299aba38Shyche */ 6299aba38Shyche 7299aba38Shyche 8299aba38Shyche //! BTree implementation 9299aba38Shyche 10299aba38Shyche 11299aba38Shyche #include "BTree.h" 12299aba38Shyche 13299aba38Shyche 14299aba38Shyche //#define TRACE_BTRFS 15299aba38Shyche #ifdef TRACE_BTRFS 16299aba38Shyche # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x) 17299aba38Shyche #else 18299aba38Shyche # define TRACE(x...) ; 19299aba38Shyche #endif 20299aba38Shyche # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x) 21299aba38Shyche 22299aba38Shyche 23548a0d80Shyche BTree::Node::Node(void* cache) 241481c49cShyche : 251481c49cShyche fNode(NULL), 261481c49cShyche fCache(cache), 271481c49cShyche fBlockNumber(0), 281481c49cShyche fCurrentSlot(0), 291481c49cShyche fWritable(false) 301481c49cShyche { 311481c49cShyche } 321481c49cShyche 331481c49cShyche 34548a0d80Shyche BTree::Node::Node(void* cache, off_t block) 351481c49cShyche : 361481c49cShyche fNode(NULL), 371481c49cShyche fCache(cache), 381481c49cShyche fBlockNumber(0), 391481c49cShyche fCurrentSlot(0), 401481c49cShyche fWritable(false) 411481c49cShyche { 421481c49cShyche SetTo(block); 431481c49cShyche } 441481c49cShyche 451481c49cShyche 46548a0d80Shyche BTree::Node::~Node() 471481c49cShyche { 481481c49cShyche Unset(); 491481c49cShyche } 501481c49cShyche 511481c49cShyche 521481c49cShyche void 53548a0d80Shyche BTree::Node::Keep() 541481c49cShyche { 551481c49cShyche fNode = NULL; 561481c49cShyche } 571481c49cShyche 581481c49cShyche void 59548a0d80Shyche BTree::Node::Unset() 601481c49cShyche { 611481c49cShyche if (fNode != NULL) { 621481c49cShyche block_cache_put(fCache, fBlockNumber); 631481c49cShyche fNode = NULL; 641481c49cShyche } 651481c49cShyche } 661481c49cShyche 671481c49cShyche 681481c49cShyche void 69548a0d80Shyche BTree::Node::SetTo(off_t block) 701481c49cShyche { 711481c49cShyche Unset(); 721481c49cShyche fBlockNumber = block; 731481c49cShyche fNode = (btrfs_stream*)block_cache_get(fCache, block); 741481c49cShyche } 751481c49cShyche 761481c49cShyche 771481c49cShyche void 78548a0d80Shyche BTree::Node::SetToWritable(off_t block, int32 transactionId, bool empty) 791481c49cShyche { 801481c49cShyche Unset(); 811481c49cShyche fBlockNumber = block; 821481c49cShyche fWritable = true; 831481c49cShyche if (empty) { 841481c49cShyche fNode = (btrfs_stream*)block_cache_get_empty(fCache, block, 851481c49cShyche transactionId); 861481c49cShyche } else { 871481c49cShyche fNode = (btrfs_stream*)block_cache_get_writable(fCache, block, 881481c49cShyche transactionId); 891481c49cShyche } 901481c49cShyche } 911481c49cShyche 921481c49cShyche 9391d7f850Shyche int32 94548a0d80Shyche BTree::Node::SearchSlot(const btrfs_key& key, int* slot, btree_traversing type) const 9591d7f850Shyche { 9691d7f850Shyche //binary search for item slot in a node 9791d7f850Shyche int entrySize = sizeof(btrfs_entry); 9891d7f850Shyche if (Level() != 0) { 9991d7f850Shyche // internal node 10091d7f850Shyche entrySize = sizeof(btrfs_index); 10191d7f850Shyche } 10291d7f850Shyche 10391d7f850Shyche int low = 0; 10491d7f850Shyche int high = ItemCount(); 1050d726c5cShyche int mid, comp; 10691d7f850Shyche int base = sizeof(btrfs_header); 10791d7f850Shyche const btrfs_key* other; 10891d7f850Shyche while (low < high) { 10991d7f850Shyche mid = (low + high) / 2; 11091d7f850Shyche other = (const btrfs_key*)((uint8*)fNode + base + mid * entrySize); 1110d726c5cShyche comp = key.Compare(*other); 11291d7f850Shyche if (comp < 0) 11391d7f850Shyche high = mid; 11491d7f850Shyche else if (comp > 0) 11591d7f850Shyche low = mid + 1; 11691d7f850Shyche else { 11791d7f850Shyche *slot = mid; 1180d726c5cShyche return B_OK; //if key is in node 11991d7f850Shyche } 12091d7f850Shyche } 1210d726c5cShyche 1220d726c5cShyche TRACE("SearchSlot() found slot %" B_PRId32 " comp %" B_PRId32 "\n", 1230d726c5cShyche *slot, comp); 1240d726c5cShyche if (type == BTREE_BACKWARD) 1250d726c5cShyche *slot = low - 1; 1260d726c5cShyche else if (type == BTREE_FORWARD) 12791d7f850Shyche *slot = low; 1280d726c5cShyche 1290d726c5cShyche if (*slot < 0 || type == BTREE_EXACT) 13091d7f850Shyche return B_ENTRY_NOT_FOUND; 1310d726c5cShyche return B_OK; 13291d7f850Shyche } 13391d7f850Shyche 13491d7f850Shyche 1351481c49cShyche //-pragma mark 1361481c49cShyche 1371481c49cShyche 138fc4a1e78Shyche BTree::BTree(Volume* volume) 139fc4a1e78Shyche : 140fc4a1e78Shyche fRootBlock(0), 141fc4a1e78Shyche fVolume(volume) 142fc4a1e78Shyche { 143fc4a1e78Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 144fc4a1e78Shyche } 145fc4a1e78Shyche 146fc4a1e78Shyche 147299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream) 148299aba38Shyche : 149299aba38Shyche fRootBlock(0), 150299aba38Shyche fVolume(volume) 151299aba38Shyche { 152299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 153299aba38Shyche } 154299aba38Shyche 155299aba38Shyche 156299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock) 157299aba38Shyche : 158299aba38Shyche fRootBlock(rootBlock), 159299aba38Shyche fVolume(volume) 160299aba38Shyche { 161299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 162299aba38Shyche } 163299aba38Shyche 164299aba38Shyche 165299aba38Shyche BTree::~BTree() 166299aba38Shyche { 167299aba38Shyche // if there are any TreeIterators left, we need to stop them 168299aba38Shyche // (can happen when the tree's inode gets deleted while 169299aba38Shyche // traversing the tree - a TreeIterator doesn't lock the inode) 170299aba38Shyche mutex_lock(&fIteratorLock); 171299aba38Shyche 172299aba38Shyche SinglyLinkedList<TreeIterator>::Iterator iterator 173299aba38Shyche = fIterators.GetIterator(); 174299aba38Shyche while (iterator.HasNext()) 175299aba38Shyche iterator.Next()->Stop(); 176299aba38Shyche mutex_destroy(&fIteratorLock); 177299aba38Shyche } 178299aba38Shyche 179299aba38Shyche 180299aba38Shyche int32 181875a0552Shyche btrfs_key::Compare(const btrfs_key& key) const 182299aba38Shyche { 183875a0552Shyche if (ObjectID() > key.ObjectID()) 184299aba38Shyche return 1; 185875a0552Shyche if (ObjectID() < key.ObjectID()) 186299aba38Shyche return -1; 187875a0552Shyche if (Type() > key.Type()) 188299aba38Shyche return 1; 189875a0552Shyche if (Type() < key.Type()) 190299aba38Shyche return -1; 191875a0552Shyche if (Offset() > key.Offset()) 192299aba38Shyche return 1; 193875a0552Shyche if (Offset() < key.Offset()) 194299aba38Shyche return -1; 195299aba38Shyche return 0; 196299aba38Shyche } 197299aba38Shyche 198299aba38Shyche 199299aba38Shyche /*! Searches the key in the tree, and stores the allocated found item in 200299aba38Shyche _value, if successful. 201299aba38Shyche Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not. 202299aba38Shyche It can also return other errors to indicate that something went wrong. 203299aba38Shyche */ 204299aba38Shyche status_t 205299aba38Shyche BTree::_Find(btrfs_key& key, void** _value, size_t* _size, 206299aba38Shyche btree_traversing type) 207299aba38Shyche { 208299aba38Shyche TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n", 209299aba38Shyche key.ObjectID(), key.Type(), key.Offset()); 210548a0d80Shyche BTree::Node node(fVolume->BlockCache(), fRootBlock); 21135a5e5adShyche int slot, ret; 21235a5e5adShyche fsblock_t physicalBlock; 213299aba38Shyche 21435a5e5adShyche while (node.Level() != 0) { 21535a5e5adShyche TRACE("Find() level %d\n", node.Level()); 21635a5e5adShyche ret = node.SearchSlot(key, &slot, BTREE_BACKWARD); 21735a5e5adShyche if (ret != B_OK) 21835a5e5adShyche return ret; 21935a5e5adShyche TRACE("Find() getting index %" B_PRIu32 "\n", slot); 220299aba38Shyche 22135a5e5adShyche if (fVolume->FindBlock(node.Index(slot)->LogicalAddress(), physicalBlock) 222299aba38Shyche != B_OK) { 223299aba38Shyche ERROR("Find() unmapped block %" B_PRId64 "\n", 22435a5e5adShyche node.Index(slot)->LogicalAddress()); 225299aba38Shyche return B_ERROR; 226299aba38Shyche } 22735a5e5adShyche node.SetTo(physicalBlock); 228299aba38Shyche } 229299aba38Shyche 23035a5e5adShyche TRACE("Find() dump count %" B_PRId32 "\n", node.ItemCount()); 23135a5e5adShyche ret = node.SearchSlot(key, &slot, type); 232299aba38Shyche 23335a5e5adShyche if ( ret == B_OK && node.Item(slot)->key.Type() == key.Type()) { 234299aba38Shyche TRACE("Find() found %" B_PRIu32 " %" B_PRIu32 "\n", 23535a5e5adShyche node.Item(slot)->Offset(), node.Item(slot)->Size()); 236299aba38Shyche 237299aba38Shyche if (_value != NULL) { 23835a5e5adShyche *_value = malloc(node.Item(slot)->Size()); 23935a5e5adShyche memcpy(*_value, node.ItemData(slot), 24035a5e5adShyche node.Item(slot)->Size()); 24135a5e5adShyche key.SetOffset(node.Item(slot)->key.Offset()); 242299aba38Shyche if (_size != NULL) 24335a5e5adShyche *_size = node.Item(slot)->Size(); 244299aba38Shyche } 245299aba38Shyche return B_OK; 246299aba38Shyche } 247299aba38Shyche 248299aba38Shyche 249299aba38Shyche TRACE("Find() not found %" B_PRId64 " %" B_PRId64 "\n", key.Offset(), 250299aba38Shyche key.ObjectID()); 251299aba38Shyche 252299aba38Shyche return B_ENTRY_NOT_FOUND; 253299aba38Shyche } 254299aba38Shyche 255299aba38Shyche 256299aba38Shyche status_t 257299aba38Shyche BTree::FindNext(btrfs_key& key, void** _value, size_t* _size) 258299aba38Shyche { 259299aba38Shyche return _Find(key, _value, _size, BTREE_FORWARD); 260299aba38Shyche } 261299aba38Shyche 262299aba38Shyche 263299aba38Shyche status_t 264299aba38Shyche BTree::FindPrevious(btrfs_key& key, void** _value, size_t* _size) 265299aba38Shyche { 266299aba38Shyche return _Find(key, _value, _size, BTREE_BACKWARD); 267299aba38Shyche } 268299aba38Shyche 269299aba38Shyche 270299aba38Shyche status_t 271299aba38Shyche BTree::FindExact(btrfs_key& key, void** _value, size_t* _size) 272299aba38Shyche { 273299aba38Shyche return _Find(key, _value, _size, BTREE_EXACT); 274299aba38Shyche } 275299aba38Shyche 276299aba38Shyche 277fc4a1e78Shyche status_t 278fc4a1e78Shyche BTree::SetRoot(off_t logical, fsblock_t* block) 279fc4a1e78Shyche { 280fc4a1e78Shyche if (block != NULL) { 281fc4a1e78Shyche fRootBlock = *block; 282*370ee09fShyche //TODO: mapping physical block -> logical address 283fc4a1e78Shyche } else { 284*370ee09fShyche fLogicalRoot = logical; 285fc4a1e78Shyche if (fVolume->FindBlock(logical, fRootBlock) != B_OK) { 286fc4a1e78Shyche ERROR("Find() unmapped block %" B_PRId64 "\n", fRootBlock); 287fc4a1e78Shyche return B_ERROR; 288fc4a1e78Shyche } 289fc4a1e78Shyche } 290fc4a1e78Shyche return B_OK; 291fc4a1e78Shyche } 292fc4a1e78Shyche 293fc4a1e78Shyche 294299aba38Shyche void 295299aba38Shyche BTree::_AddIterator(TreeIterator* iterator) 296299aba38Shyche { 297299aba38Shyche MutexLocker _(fIteratorLock); 298299aba38Shyche fIterators.Add(iterator); 299299aba38Shyche } 300299aba38Shyche 301299aba38Shyche 302299aba38Shyche void 303299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator) 304299aba38Shyche { 305299aba38Shyche MutexLocker _(fIteratorLock); 306299aba38Shyche fIterators.Remove(iterator); 307299aba38Shyche } 308299aba38Shyche 309299aba38Shyche 310299aba38Shyche // #pragma mark - 311299aba38Shyche 312299aba38Shyche 313299aba38Shyche TreeIterator::TreeIterator(BTree* tree, btrfs_key& key) 314299aba38Shyche : 315299aba38Shyche fTree(tree), 316299aba38Shyche fCurrentKey(key) 317299aba38Shyche { 318299aba38Shyche Rewind(); 319299aba38Shyche tree->_AddIterator(this); 320299aba38Shyche } 321299aba38Shyche 322299aba38Shyche 323299aba38Shyche TreeIterator::~TreeIterator() 324299aba38Shyche { 325299aba38Shyche if (fTree) 326299aba38Shyche fTree->_RemoveIterator(this); 327299aba38Shyche } 328299aba38Shyche 329299aba38Shyche 330299aba38Shyche /*! Iterates through the tree in the specified direction. 331299aba38Shyche */ 332299aba38Shyche status_t 333299aba38Shyche TreeIterator::Traverse(btree_traversing direction, btrfs_key& key, 334299aba38Shyche void** value, size_t* size) 335299aba38Shyche { 336299aba38Shyche if (fTree == NULL) 337299aba38Shyche return B_INTERRUPTED; 338299aba38Shyche 339299aba38Shyche fCurrentKey.SetOffset(fCurrentKey.Offset() + direction); 340299aba38Shyche status_t status = fTree->_Find(fCurrentKey, value, size, 341299aba38Shyche direction); 342299aba38Shyche if (status != B_OK) { 343299aba38Shyche TRACE("TreeIterator::Traverse() Find failed\n"); 344299aba38Shyche return B_ENTRY_NOT_FOUND; 345299aba38Shyche } 346299aba38Shyche 347299aba38Shyche return B_OK; 348299aba38Shyche } 349299aba38Shyche 350299aba38Shyche 351299aba38Shyche /*! just sets the current key in the iterator. 352299aba38Shyche */ 353299aba38Shyche status_t 354299aba38Shyche TreeIterator::Find(btrfs_key& key) 355299aba38Shyche { 356299aba38Shyche if (fTree == NULL) 357299aba38Shyche return B_INTERRUPTED; 358299aba38Shyche fCurrentKey = key; 359299aba38Shyche return B_OK; 360299aba38Shyche } 361299aba38Shyche 362299aba38Shyche 363299aba38Shyche void 364299aba38Shyche TreeIterator::Stop() 365299aba38Shyche { 366299aba38Shyche fTree = NULL; 367299aba38Shyche } 368