1*299aba38Shyche /* 2*299aba38Shyche * Copyright 2011, Jérôme Duval, korli@users.berlios.de. 3*299aba38Shyche * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de. 4*299aba38Shyche * This file may be used under the terms of the MIT License. 5*299aba38Shyche */ 6*299aba38Shyche 7*299aba38Shyche 8*299aba38Shyche //! BTree implementation 9*299aba38Shyche 10*299aba38Shyche 11*299aba38Shyche #include "BTree.h" 12*299aba38Shyche #include "CachedBlock.h" 13*299aba38Shyche 14*299aba38Shyche 15*299aba38Shyche //#define TRACE_BTRFS 16*299aba38Shyche #ifdef TRACE_BTRFS 17*299aba38Shyche # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x) 18*299aba38Shyche #else 19*299aba38Shyche # define TRACE(x...) ; 20*299aba38Shyche #endif 21*299aba38Shyche # define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x) 22*299aba38Shyche 23*299aba38Shyche 24*299aba38Shyche BTree::BTree(Volume* volume, btrfs_stream* stream) 25*299aba38Shyche : 26*299aba38Shyche fStream(stream), 27*299aba38Shyche fRootBlock(0), 28*299aba38Shyche fVolume(volume) 29*299aba38Shyche { 30*299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 31*299aba38Shyche } 32*299aba38Shyche 33*299aba38Shyche 34*299aba38Shyche BTree::BTree(Volume* volume, fsblock_t rootBlock) 35*299aba38Shyche : 36*299aba38Shyche fStream(NULL), 37*299aba38Shyche fRootBlock(rootBlock), 38*299aba38Shyche fVolume(volume) 39*299aba38Shyche { 40*299aba38Shyche mutex_init(&fIteratorLock, "btrfs b+tree iterator"); 41*299aba38Shyche } 42*299aba38Shyche 43*299aba38Shyche 44*299aba38Shyche BTree::~BTree() 45*299aba38Shyche { 46*299aba38Shyche // if there are any TreeIterators left, we need to stop them 47*299aba38Shyche // (can happen when the tree's inode gets deleted while 48*299aba38Shyche // traversing the tree - a TreeIterator doesn't lock the inode) 49*299aba38Shyche mutex_lock(&fIteratorLock); 50*299aba38Shyche 51*299aba38Shyche SinglyLinkedList<TreeIterator>::Iterator iterator 52*299aba38Shyche = fIterators.GetIterator(); 53*299aba38Shyche while (iterator.HasNext()) 54*299aba38Shyche iterator.Next()->Stop(); 55*299aba38Shyche mutex_destroy(&fIteratorLock); 56*299aba38Shyche } 57*299aba38Shyche 58*299aba38Shyche 59*299aba38Shyche int32 60*299aba38Shyche BTree::_CompareKeys(btrfs_key& key1, btrfs_key& key2) 61*299aba38Shyche { 62*299aba38Shyche if (key1.ObjectID() > key2.ObjectID()) 63*299aba38Shyche return 1; 64*299aba38Shyche if (key1.ObjectID() < key2.ObjectID()) 65*299aba38Shyche return -1; 66*299aba38Shyche if (key1.Type() > key2.Type()) 67*299aba38Shyche return 1; 68*299aba38Shyche if (key1.Type() < key2.Type()) 69*299aba38Shyche return -1; 70*299aba38Shyche if (key1.Offset() > key2.Offset()) 71*299aba38Shyche return 1; 72*299aba38Shyche if (key1.Offset() < key2.Offset()) 73*299aba38Shyche return -1; 74*299aba38Shyche return 0; 75*299aba38Shyche } 76*299aba38Shyche 77*299aba38Shyche 78*299aba38Shyche /*! Searches the key in the tree, and stores the allocated found item in 79*299aba38Shyche _value, if successful. 80*299aba38Shyche Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not. 81*299aba38Shyche It can also return other errors to indicate that something went wrong. 82*299aba38Shyche */ 83*299aba38Shyche status_t 84*299aba38Shyche BTree::_Find(btrfs_key& key, void** _value, size_t* _size, 85*299aba38Shyche btree_traversing type) 86*299aba38Shyche { 87*299aba38Shyche TRACE("Find() objectid %" B_PRId64 " type %d offset %" B_PRId64 " \n", 88*299aba38Shyche key.ObjectID(), key.Type(), key.Offset()); 89*299aba38Shyche btrfs_stream* stream = fStream; 90*299aba38Shyche CachedBlock cached(fVolume); 91*299aba38Shyche fsblock_t physical; 92*299aba38Shyche if (stream == NULL) { 93*299aba38Shyche if (fVolume->FindBlock(fRootBlock, physical) != B_OK) { 94*299aba38Shyche ERROR("Find() unmapped block %" B_PRId64 "\n", fRootBlock); 95*299aba38Shyche return B_ERROR; 96*299aba38Shyche } 97*299aba38Shyche stream = (btrfs_stream*)cached.SetTo(physical); 98*299aba38Shyche } 99*299aba38Shyche 100*299aba38Shyche while (stream->header.Level() != 0) { 101*299aba38Shyche TRACE("Find() level %d\n", stream->header.Level()); 102*299aba38Shyche uint32 i = 1; 103*299aba38Shyche for (; i < stream->header.ItemCount(); i++) { 104*299aba38Shyche int32 comp = _CompareKeys(stream->index[i].key, key); 105*299aba38Shyche TRACE("Find() found index %" B_PRIu32 " at %" B_PRId64 " comp %" 106*299aba38Shyche B_PRId32 "\n", i, stream->index[i].BlockNum(), comp); 107*299aba38Shyche if (comp < 0) 108*299aba38Shyche continue; 109*299aba38Shyche if (comp > 0 || type == BTREE_BACKWARD) 110*299aba38Shyche break; 111*299aba38Shyche } 112*299aba38Shyche TRACE("Find() getting index %" B_PRIu32 " at %" B_PRId64 "\n", i - 1, 113*299aba38Shyche stream->index[i - 1].BlockNum()); 114*299aba38Shyche 115*299aba38Shyche if (fVolume->FindBlock(stream->index[i - 1].BlockNum(), physical) 116*299aba38Shyche != B_OK) { 117*299aba38Shyche ERROR("Find() unmapped block %" B_PRId64 "\n", 118*299aba38Shyche stream->index[i - 1].BlockNum()); 119*299aba38Shyche return B_ERROR; 120*299aba38Shyche } 121*299aba38Shyche stream = (btrfs_stream*)cached.SetTo(physical); 122*299aba38Shyche } 123*299aba38Shyche 124*299aba38Shyche uint32 i; 125*299aba38Shyche #ifdef TRACE_BTRFS 126*299aba38Shyche TRACE("Find() dump count %" B_PRId32 "\n", stream->header.ItemCount()); 127*299aba38Shyche for (i = 0; i < stream->header.ItemCount(); i++) { 128*299aba38Shyche int32 comp = _CompareKeys(key, stream->entries[i].key); 129*299aba38Shyche TRACE("Find() dump %" B_PRIu32 " %" B_PRIu32 " offset %" B_PRId64 130*299aba38Shyche " comp %" B_PRId32 "\n", stream->entries[i].Offset(), 131*299aba38Shyche stream->entries[i].Size(), stream->entries[i].key.Offset(), comp); 132*299aba38Shyche } 133*299aba38Shyche #endif 134*299aba38Shyche 135*299aba38Shyche for (i = 0; i < stream->header.ItemCount(); i++) { 136*299aba38Shyche int32 comp = _CompareKeys(key, stream->entries[i].key); 137*299aba38Shyche TRACE("Find() found %" B_PRIu32 " %" B_PRIu32 " oid %" B_PRId64 138*299aba38Shyche " type %d offset %" B_PRId64 " comp %" B_PRId32 "\n", 139*299aba38Shyche stream->entries[i].Offset(), stream->entries[i].Size(), 140*299aba38Shyche stream->entries[i].key.ObjectID(), stream->entries[i].key.Type(), 141*299aba38Shyche stream->entries[i].key.Offset(), comp); 142*299aba38Shyche if (comp == 0) 143*299aba38Shyche break; 144*299aba38Shyche if (comp < 0 && i > 0) { 145*299aba38Shyche if (type == BTREE_EXACT) 146*299aba38Shyche return B_ENTRY_NOT_FOUND; 147*299aba38Shyche if (type == BTREE_BACKWARD) 148*299aba38Shyche i--; 149*299aba38Shyche break; 150*299aba38Shyche } 151*299aba38Shyche } 152*299aba38Shyche 153*299aba38Shyche if (i == stream->header.ItemCount()) { 154*299aba38Shyche if (type == BTREE_BACKWARD) 155*299aba38Shyche i--; 156*299aba38Shyche else 157*299aba38Shyche return B_ENTRY_NOT_FOUND; 158*299aba38Shyche } 159*299aba38Shyche 160*299aba38Shyche if (i < stream->header.ItemCount() 161*299aba38Shyche && stream->entries[i].key.Type() == key.Type()) { 162*299aba38Shyche TRACE("Find() found %" B_PRIu32 " %" B_PRIu32 "\n", 163*299aba38Shyche stream->entries[i].Offset(), stream->entries[i].Size()); 164*299aba38Shyche 165*299aba38Shyche if (_value != NULL) { 166*299aba38Shyche *_value = malloc(stream->entries[i].Size()); 167*299aba38Shyche uint32 totalOffset = stream->entries[i].Offset() + sizeof(btrfs_header); 168*299aba38Shyche 169*299aba38Shyche 170*299aba38Shyche if ((fVolume->BlockSize() - totalOffset % fVolume->BlockSize()) 171*299aba38Shyche >= stream->entries[i].Size()) { 172*299aba38Shyche //If there is enough space for *_value 173*299aba38Shyche memcpy(*_value, ((uint8*)cached.SetTo(physical 174*299aba38Shyche + totalOffset / fVolume->BlockSize()) 175*299aba38Shyche + totalOffset % fVolume->BlockSize()), 176*299aba38Shyche stream->entries[i].Size()); 177*299aba38Shyche } else { 178*299aba38Shyche read_pos(fVolume->Device(), physical 179*299aba38Shyche * fVolume->BlockSize() + totalOffset, 180*299aba38Shyche *_value, stream->entries[i].Size()); 181*299aba38Shyche } 182*299aba38Shyche 183*299aba38Shyche key.SetOffset(stream->entries[i].key.Offset()); 184*299aba38Shyche if (_size != NULL) 185*299aba38Shyche *_size = stream->entries[i].Size(); 186*299aba38Shyche } 187*299aba38Shyche return B_OK; 188*299aba38Shyche } 189*299aba38Shyche 190*299aba38Shyche 191*299aba38Shyche TRACE("Find() not found %" B_PRId64 " %" B_PRId64 "\n", key.Offset(), 192*299aba38Shyche key.ObjectID()); 193*299aba38Shyche 194*299aba38Shyche return B_ENTRY_NOT_FOUND; 195*299aba38Shyche } 196*299aba38Shyche 197*299aba38Shyche 198*299aba38Shyche status_t 199*299aba38Shyche BTree::FindNext(btrfs_key& key, void** _value, size_t* _size) 200*299aba38Shyche { 201*299aba38Shyche return _Find(key, _value, _size, BTREE_FORWARD); 202*299aba38Shyche } 203*299aba38Shyche 204*299aba38Shyche 205*299aba38Shyche status_t 206*299aba38Shyche BTree::FindPrevious(btrfs_key& key, void** _value, size_t* _size) 207*299aba38Shyche { 208*299aba38Shyche return _Find(key, _value, _size, BTREE_BACKWARD); 209*299aba38Shyche } 210*299aba38Shyche 211*299aba38Shyche 212*299aba38Shyche status_t 213*299aba38Shyche BTree::FindExact(btrfs_key& key, void** _value, size_t* _size) 214*299aba38Shyche { 215*299aba38Shyche return _Find(key, _value, _size, BTREE_EXACT); 216*299aba38Shyche } 217*299aba38Shyche 218*299aba38Shyche 219*299aba38Shyche void 220*299aba38Shyche BTree::_AddIterator(TreeIterator* iterator) 221*299aba38Shyche { 222*299aba38Shyche MutexLocker _(fIteratorLock); 223*299aba38Shyche fIterators.Add(iterator); 224*299aba38Shyche } 225*299aba38Shyche 226*299aba38Shyche 227*299aba38Shyche void 228*299aba38Shyche BTree::_RemoveIterator(TreeIterator* iterator) 229*299aba38Shyche { 230*299aba38Shyche MutexLocker _(fIteratorLock); 231*299aba38Shyche fIterators.Remove(iterator); 232*299aba38Shyche } 233*299aba38Shyche 234*299aba38Shyche 235*299aba38Shyche // #pragma mark - 236*299aba38Shyche 237*299aba38Shyche 238*299aba38Shyche TreeIterator::TreeIterator(BTree* tree, btrfs_key& key) 239*299aba38Shyche : 240*299aba38Shyche fTree(tree), 241*299aba38Shyche fCurrentKey(key) 242*299aba38Shyche { 243*299aba38Shyche Rewind(); 244*299aba38Shyche tree->_AddIterator(this); 245*299aba38Shyche } 246*299aba38Shyche 247*299aba38Shyche 248*299aba38Shyche TreeIterator::~TreeIterator() 249*299aba38Shyche { 250*299aba38Shyche if (fTree) 251*299aba38Shyche fTree->_RemoveIterator(this); 252*299aba38Shyche } 253*299aba38Shyche 254*299aba38Shyche 255*299aba38Shyche /*! Iterates through the tree in the specified direction. 256*299aba38Shyche */ 257*299aba38Shyche status_t 258*299aba38Shyche TreeIterator::Traverse(btree_traversing direction, btrfs_key& key, 259*299aba38Shyche void** value, size_t* size) 260*299aba38Shyche { 261*299aba38Shyche if (fTree == NULL) 262*299aba38Shyche return B_INTERRUPTED; 263*299aba38Shyche 264*299aba38Shyche fCurrentKey.SetOffset(fCurrentKey.Offset() + direction); 265*299aba38Shyche status_t status = fTree->_Find(fCurrentKey, value, size, 266*299aba38Shyche direction); 267*299aba38Shyche if (status != B_OK) { 268*299aba38Shyche TRACE("TreeIterator::Traverse() Find failed\n"); 269*299aba38Shyche return B_ENTRY_NOT_FOUND; 270*299aba38Shyche } 271*299aba38Shyche 272*299aba38Shyche return B_OK; 273*299aba38Shyche } 274*299aba38Shyche 275*299aba38Shyche 276*299aba38Shyche /*! just sets the current key in the iterator. 277*299aba38Shyche */ 278*299aba38Shyche status_t 279*299aba38Shyche TreeIterator::Find(btrfs_key& key) 280*299aba38Shyche { 281*299aba38Shyche if (fTree == NULL) 282*299aba38Shyche return B_INTERRUPTED; 283*299aba38Shyche fCurrentKey = key; 284*299aba38Shyche return B_OK; 285*299aba38Shyche } 286*299aba38Shyche 287*299aba38Shyche 288*299aba38Shyche void 289*299aba38Shyche TreeIterator::Stop() 290*299aba38Shyche { 291*299aba38Shyche fTree = NULL; 292*299aba38Shyche } 293