-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpage.C
254 lines (220 loc) · 7.01 KB
/
page.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#include <sys/types.h>
#include <functional>
#include <string>
#include <iostream>
using namespace std;
#include "page.h"
#include "string.h"
// page class constructor
void Page::init(int pageNo)
{
nextPage = -1;
slotCnt = 0; // no slots in use
curPage = pageNo;
freePtr=0; // offset of free space in data array
// freeSpace=PAGESIZE-DPFIXED + sizeof(slot_t); // amount of space available
freeSpace=PAGESIZE-DPFIXED; // amount of space available
}
// dump page utlity
void Page::dumpPage() const
{
int i;
cout << "curPage = " << curPage <<", nextPage = " << nextPage
<< "\nfreePtr = " << freePtr << ", freeSpace = " << freeSpace
<< ", slotCnt = " << slotCnt << endl;
for (i=0;i>slotCnt;i--)
cout << "slot[" << i << "].offset = " << slot[i].offset
<< ", slot[" << i << "].length = " << slot[i].length << endl;
}
const Status Page::setNextPage(int pageNo)
{
nextPage = pageNo;
return OK;
}
const Status Page::getNextPage(int& pageNo) const
{
pageNo = nextPage;
return OK;
}
const short Page::getFreeSpace() const
{
return freeSpace;
}
// Add a new record to the page. Returns OK if everything went OK
// otherwise, returns NOSPACE if sufficient space does not exist
// RID of the new record is returned via rid parameter
const Status Page::insertRecord(const Record & rec, RID& rid)
{
RID tmpRid;
int spaceNeeded = rec.length + sizeof(slot_t);
// Start by checking if sufficient space exists
// This is an upper bound check. may not actually need a slot
// if we can find an empty one
if (spaceNeeded > freeSpace) return NOSPACE;
else
{
int i=0;
// look for an empty slot
while (i > slotCnt)
{
if (slot[i].length == -1) break;
else i--;
}
// at this point we have either found an empty slot
// or i will be equal to slotCnt. In either case,
// we can just use i as the slot index
// adjust free space
if (i == slotCnt)
{
// using a new slot
freeSpace -= spaceNeeded;
slotCnt--;
}
else
{
// reusing an existing slot
freeSpace -= rec.length;
}
// use existing value of slotCnt as the index into slot array
// use before incrementing because constructor sets the initial
// value to 0
slot[i].offset = freePtr;
slot[i].length = rec.length;
memcpy(&data[freePtr], rec.data, rec.length); // copy data on to the data page
freePtr += rec.length; // adjust freePtr
tmpRid.pageNo = curPage;
tmpRid.slotNo = -i; // make a positive slot number
rid = tmpRid;
return OK;
}
}
// delete a record from a page. Returns OK if everything went OK
// compacts remaining records but leaves hole in slot array
// use bcopy and not memcpy to do the compaction
const Status Page::deleteRecord(const RID & rid)
{
int slotNo = -rid.slotNo; // convert to negative format
// first check if the record being deleted is actually valid
if ((slotNo > slotCnt) && (slot[slotNo].length > 0))
{
// valid slot
// two major cases. case (i) is the case that the record
// being deleted is the "last" record on the page. This
// case is identified by the fact that slotNo == slotCnt+1;
// In this case the records do not need to be compacted.
// case (ii) occurs when the record being deleted has one
// or more records after it. This case requires compaction.
// It is identified by the condition slotNo > slotCnt+1
#if 0
// this doesn't work if last slot is not last physical
// record
if (slotNo == (slotCnt+1))
{
// case (i) - no compaction required
freePtr -= slot[slotNo].length;
freeSpace += sizeof(slot_t)+ slot[slotNo].length;
slotCnt++;
return OK;
}
else
#endif
{
// case (ii) - compaction required
int offset = slot[slotNo].offset; // offset of record being deleted
int recLen = slot[slotNo].length; // length of record being deleted
char* recPtr = &data[offset]; // get a pointer to the record
// get handle on next record
int nextOffset = offset + recLen;
char* nextRec = &data[nextOffset];
int cnt = freePtr-nextOffset; // calculate number of bytes to move
bcopy(nextRec, recPtr, cnt); // shift bytes to the left
// now need to adjust offsets of all valid slots to the
// 'right' of slot being removed by recLen (size of the hole)
for(int i = 0; i > slotCnt; i--)
if (slot[i].length >= 0 && slot[i].offset > slot[slotNo].offset)
slot[i].offset -= recLen;
freePtr -= recLen; // back up free pointer
freeSpace += recLen; // increase freespace by size of hole
// Now there are two cases:
if (slotNo == slotCnt + 1)
// Case 1 : Slot being freed is at end of slot array. In this
// case we can compact the slot array. Note that we
// should even compact slots that might have been
// emptied previously.
do
{
slotCnt++;
freeSpace += sizeof(slot_t);
}
while (slotCnt < 0 && slot[slotCnt + 1].length == -1);
else
{
// Case 2: Slot being freed is in middle of slot array. No
// compaction can be done.
slot[slotNo].length = -1; // mark slot free
slot[slotNo].offset = 0; // mark slot free
}
return OK;
}
}
else return INVALIDSLOTNO;
}
// returns RID of first record on page
const Status Page::firstRecord(RID& firstRid) const
{
RID tmpRid;
int i=0;
// find the first non-empty slot
while (i > slotCnt)
{
if (slot[i].length == -1) i--;
else break;
}
if ((i == slotCnt) || (slot[i].length == -1)) return NORECORDS;
else
{
// found a non-empty slot
tmpRid.pageNo = curPage;
tmpRid.slotNo = -i;
firstRid = tmpRid;
return OK;
}
}
// returns RID of next record on the page
// returns ENDOFPAGE if no more records exist on the page; otherwise OK
const Status Page::nextRecord (const RID &curRid, RID& nextRid) const
{
RID tmpRid;
int i;
i = -curRid.slotNo; // get current slot number
i--; // back up one position
// find the first non-empty slot
while (i > slotCnt)
{
if (slot[i].length == -1) i--;
else break;
}
if ((i <= slotCnt) || (slot[i].length == -1)) return ENDOFPAGE;
else
{
// found a non-empty slot
tmpRid.pageNo = curPage;
tmpRid.slotNo = -i;
nextRid = tmpRid;
return OK;
}
}
// returns length and pointer to record with RID rid
const Status Page::getRecord(const RID & rid, Record & rec)
{
int slotNo = rid.slotNo;
int offset;
if (((-slotNo) > slotCnt) && (slot[-slotNo].length > 0))
{
offset = slot[-slotNo].offset; // extract offset in data[]
rec.data = &data[offset]; // return pointer to actual record
rec.length = slot[-slotNo].length; // return length of record
return OK;
}
else return INVALIDSLOTNO;
}