//------------------------------------------------------------------ // HeapPage::DeleteRecord // // Input : Record ID // Output : None // Purpose : Delete a record from the page // Return : OK if successful, FAIL otherwise //------------------------------------------------------------------ Status HeapPage::DeleteRecord(RecordID rid) { if ((rid.pageNo!=pid) || (rid.slotNo>numOfSlots-1))return FAIL; Slot *slot =GetSlotAtIndex(rid.slotNo); if (slot->length==INVALID_SLOT) return FAIL; if (HasNoOtherValidSlot(rid.slotNo)) { // if it's the only valid slot left freeSpace = freeSpace + numOfSlots* sizeof(Slot)+slot->length; freePtr = HEAPPAGE_DATA_SIZE - 1; // reset freePtr numOfSlots=0; } else { if (SmallestOffset() == slot->offset) freePtr += slot->length; // increase freePtr if deleted record is the last if (rid.slotNo==numOfSlots-1) { // if it's the last slot //delete slot; numOfSlots--; freeSpace = freeSpace + sizeof(Slot)+slot->length; int k=numOfSlots-1; while (k>=0) { // delete previous slots (that are now the last ones) that might be invalid if (SlotIsEmpty(GetSlotAtIndex(k))) { numOfSlots--; freeSpace += sizeof(Slot); } else break; k--; } } else { // if it's just a normal slot freeSpace=freeSpace+slot->length; slot ->length= INVALID_SLOT; } } return OK; }
//------------------------------------------------------------------ // HeapPage::IsEmpty // // Input : None // Output : None // Purpose : Check if there is any record in the page. // Return : true if the HeapPage is empty, and false otherwise. //------------------------------------------------------------------ bool HeapPage::IsEmpty(void) { for (int i=0; i<numOfSlots; i++) { if (!SlotIsEmpty(GetSlotAtIndex(i))) return false; } return true; }
//------------------------------------------------------------------ // HeapPage::HasNoOtherValidSlot // // Input : Index of the slot that's checked against // Output : If all slots before it are invalid, false otherwise // Purpose : A helper function for DeleteRecord // Return : True if all slots before it are invalid, false otherwise //------------------------------------------------------------------ bool HeapPage::HasNoOtherValidSlot(int slotNO) { for (int i=0; i<numOfSlots; i++) { if ((i!=slotNO)&&(!SlotIsEmpty(GetSlotAtIndex(i)))) return false; } return true; }
//------------------------------------------------------------------ // HeapPage::GetNumOfRecords // // Input : None // Output : None. // Purpose : To determine the number of records on the page (not necessarily equal to the number of slots). // Return : The number of records in the page. //------------------------------------------------------------------ int HeapPage::GetNumOfRecords() { int num = 0; for (int i=0; i<numOfSlots; i++) { if (!SlotIsEmpty(GetSlotAtIndex(i))) num++; } return num; }
//------------------------------------------------------------------ // HeapPage::FirstRecord // // Input : None // Output : record id of the first record on a page // Purpose : To find the first record on a page // Return : OK if successful, DONE otherwise //------------------------------------------------------------------ Status HeapPage::FirstRecord(RecordID& rid) { for (short i=0; i<numOfSlots; i++) { if (!SlotIsEmpty(GetSlotAtIndex(i))) { rid.pageNo = pid; rid.slotNo = i; return OK; } } return DONE; }
//------------------------------------------------------------------ // HeapPage::NextRecord // // Input : ID of the current record // Output : ID of the next record // Return : Return DONE if no more records exist on the page; // otherwise OK //------------------------------------------------------------------ Status HeapPage::NextRecord (RecordID curRid, RecordID& nextRid) { if (curRid.pageNo != pid || curRid.slotNo < 0 || curRid.slotNo >= numOfSlots) return FAIL; for (short i=curRid.slotNo+1; i<numOfSlots; i++) { if (!SlotIsEmpty(GetSlotAtIndex(i))) { nextRid.pageNo = pid; nextRid.slotNo = i; return OK; } } return DONE; }
//------------------------------------------------------------------- // SortedKVPage::CutFromRecord // // Input : relativeStartOffset, The offset relative to the start of the // record at which to start cutting. // length, The length of data to cut. // rid, The record id of the record in which to cut. // Output : None. // Return : OK if successful. // FAIL if rid is invalid or tries // to cut after the end of the record. // Purpose : Cuts data from an existing record and compacts appropriately. //------------------------------------------------------------------- Status ResizableRecordPage::CutFromRecord(int relativeStartOffset, int length, const RecordID &rid) { if (rid.pageNo != pid || rid.slotNo < 0 || rid.slotNo >= numOfSlots) { return FAIL; } Slot *slot = GetFirstSlotPointer() - rid.slotNo; // Use the DeleteRecord method to cut the entire record. if ((relativeStartOffset == 0) && (length == slot->length)) { std::cout << "Returning HeapPage::DeleteRecord " << rid.pageNo << ", " << rid.slotNo << std::endl; return HeapPage::DeleteRecord(rid); } if (relativeStartOffset + length > slot->length) { std::cerr << "Error: Trying to cut too much from record." << "Record length=" << slot->length << std::endl; return FAIL; } // Move data up to fill in cut region. int mvLength = freePtr - (slot->offset + relativeStartOffset + length); char *src = data + slot->offset + relativeStartOffset + length; char *dest = data + slot->offset + relativeStartOffset; memmove(dest, src, mvLength); // Update free space appropriately. freePtr -= length; freeSpace += length; slot->length -= length; // Update offsets for slots following deleted region. for (int k = 0; k < numOfSlots; k++) { assert(!SlotIsEmpty(GetFirstSlotPointer() - k)); Slot *curSlot = GetFirstSlotPointer() - k; if (curSlot->offset > slot->offset) { curSlot->offset -= length; } } return OK; }
//------------------------------------------------------------------- // SortedKVPage::AppendToRecord // // Input : newData, A pointer to the data to append. // dataLength, The length of the data to append. // rid, The record id of the record to append to. // Output : None. // Return : OK if successful. // FAIL if rid is invalid or there isn't space on this page. // Purpose : Appends data to an existing record, shifting other // records as appropriate. //------------------------------------------------------------------- Status ResizableRecordPage::AppendToRecord(const char *newData, int dataLength, const RecordID &rid) { // Invalid record id. if (rid.pageNo != pid || (rid.slotNo < 0 || rid.slotNo > numOfSlots)) { return FAIL; } // Not enough space to append new data. if (AvailableSpaceForAppend() < dataLength) { return FAIL; } Slot *slot = (Slot *)GetFirstSlotPointer() - rid.slotNo; // Move records following the target location to make space. memmove(data + slot->offset + slot->length + dataLength, data + slot->offset + slot->length, freePtr - (slot->offset + slot->length)); // Copy data to append to appropriate spot on page. memcpy(data + slot->offset + slot->length, newData, dataLength); slot->length += dataLength; // Change the offset of all slots pointing to pages after the one we modified. for (int i = 0; i < numOfSlots; i++) { assert(!SlotIsEmpty(GetFirstSlotPointer() - i)); Slot *curSlot = GetFirstSlotPointer() - i; if (curSlot->offset > slot->offset) { curSlot->offset += dataLength; } } // Update freePtr and freeSpace appropriately. freePtr += dataLength; freeSpace -= dataLength; return OK; }