in hfs/btree.c [1374:1540]
static uint32_t removeRecord(BTree* tree, uint32_t root, BTKey* searchKey, int* callAgain, int* gone) {
BTNodeDescriptor* descriptor;
int length;
int i;
int res;
uint32_t newNode;
uint32_t nodeToTraverse;
uint32_t newNodeBigEndian;
BTKey* key;
off_t recordOffset;
off_t recordDataOffset;
off_t lastRecordDataOffset;
int childGone;
int checkForChangedKey ;
size_t freeSpace;
descriptor = readBTNodeDescriptor(root, tree);
freeSpace = getFreeSpace(root, descriptor, tree);
nodeToTraverse = 0;
lastRecordDataOffset = 0;
newNode = 0;
(*gone) = FALSE;
checkForChangedKey = FALSE;
for(i = 0; i < descriptor->numRecords; i++) {
recordOffset = getRecordOffset(i, root, tree);
key = READ_KEY(tree, recordOffset, tree->io);
recordDataOffset = recordOffset + key->keyLength + sizeof(key->keyLength);
res = COMPARE(tree, key, searchKey);
if(res == 0) {
free(key);
if(descriptor->kind == kBTLeafNode) {
if(i != (descriptor->numRecords - 1)) {
length = getRecordOffset(i + 1, root, tree) - recordOffset;
moveRecordsDown(tree, descriptor, i + 1, root, -length, -1);
} // don't need to do that if we're the last record, because our old offset pointer will be the new free space pointer
descriptor->numRecords--;
tree->headerRec->leafRecords--;
ASSERT(writeBTNodeDescriptor(descriptor, root, tree), "writeBTNodeDescriptor");
ASSERT(writeBTHeaderRec(tree), "writeBTHeaderRec");
if(descriptor->numRecords >= 1) {
free(descriptor);
return 0;
} else {
free(descriptor);
removeNode(tree, root);
(*gone) = TRUE;
return 0;
}
} else {
nodeToTraverse = getNodeNumberFromPointerRecord(recordDataOffset, tree->io);
checkForChangedKey = TRUE;
break;
}
} else if(res > 0) {
free(key);
if(lastRecordDataOffset == 0 || descriptor->kind == kBTLeafNode) {
// not found;
free(descriptor);
return 0;
} else {
nodeToTraverse = getNodeNumberFromPointerRecord(lastRecordDataOffset, tree->io);
break;
}
}
lastRecordDataOffset = recordDataOffset;
free(key);
}
if(nodeToTraverse == 0) {
nodeToTraverse = getNodeNumberFromPointerRecord(lastRecordDataOffset, tree->io);
}
if(i == descriptor->numRecords) {
i = descriptor->numRecords - 1;
}
newNode = removeRecord(tree, nodeToTraverse, searchKey, callAgain, &childGone);
if(childGone) {
if(i != (descriptor->numRecords - 1)) {
length = getRecordOffset(i + 1, root, tree) - recordOffset;
moveRecordsDown(tree, descriptor, i + 1, root, -length, -1);
} // don't need to do that if we're the last record, because our old offset pointer will be the new free space pointer
descriptor->numRecords--;
ASSERT(writeBTNodeDescriptor(descriptor, root, tree), "writeBTNodeDescriptor");
} else {
if(checkForChangedKey) {
// we will remove the first item in the child node, so our index has to change
key = READ_KEY(tree, getRecordOffset(0, nodeToTraverse, tree), tree->io);
if(searchKey->keyLength != key->keyLength) {
if(key->keyLength > searchKey->keyLength && freeSpace < (key->keyLength - searchKey->keyLength)) {
// very unlikely. We need to split this node before we can resize the key of this index. Do that first, and tell them to call again.
*callAgain = TRUE;
return splitNode(root, descriptor, tree);
}
moveRecordsDown(tree, descriptor, i + 1, root, key->keyLength - searchKey->keyLength, 0);
}
ASSERT(WRITE_KEY(tree, recordOffset, key, tree->io), "WRITE_KEY");
FLIPENDIAN(nodeToTraverse);
ASSERT(WRITE(tree->io, recordOffset + sizeof(uint16_t) + key->keyLength, sizeof(uint32_t), &nodeToTraverse), "WRITE");
FLIPENDIAN(nodeToTraverse);
free(key);
}
}
if(newNode == 0) {
if(descriptor->numRecords == 0) {
removeNode(tree, root);
(*gone) = TRUE;
}
free(descriptor);
return 0;
} else {
newNodeBigEndian = newNode;
key = READ_KEY(tree, newNode * tree->headerRec->nodeSize + 14, tree->io);
FLIPENDIAN(newNodeBigEndian);
if(freeSpace < (sizeof(key->keyLength) + key->keyLength + sizeof(newNodeBigEndian) + sizeof(uint16_t))) {
newNode = splitNode(root, descriptor, tree);
if(i < descriptor->numRecords) {
doAddRecord(tree, root, key, sizeof(newNodeBigEndian), (unsigned char*)(&newNodeBigEndian));
} else {
doAddRecord(tree, newNode, key, sizeof(newNodeBigEndian), (unsigned char*)(&newNodeBigEndian));
}
if(descriptor->numRecords == 0) {
removeNode(tree, root);
(*gone) = TRUE;
}
free(key);
free(descriptor);
return newNode;
} else {
doAddRecord(tree, root, key, sizeof(newNodeBigEndian), (unsigned char*)(&newNodeBigEndian));
free(key);
free(descriptor);
return 0;
}
}
return FALSE;
}