1 19 package org.netbeans.mdr.persistence.btreeimpl.btreeindex; 20 21 import org.netbeans.mdr.persistence.*; 22 import org.netbeans.mdr.persistence.btreeimpl.btreestorage.*; 23 import java.io.*; 24 25 29 public class VarRecordPage extends BtreePage { 30 31 private int[] offsets; 32 private int[] keyLengths; 33 private int nextOffset; private static final int SIZE_OF_OFFSET = SIZE_OF_SHORT + SIZE_OF_SHORT; 35 36 42 public void init(Btree btree, byte[] pageId, byte[] pageBuffer, 43 boolean isNew) throws StorageException { 44 45 if (initialized) { 46 47 return; 48 } 49 50 super.init(btree, pageId, pageBuffer, isNew); 51 52 59 if (offsets == null) { 60 int maxOffsets = (btree.pageSize - headerLength)/SIZE_OF_OFFSET; 61 offsets = new int[maxOffsets]; 62 keyLengths = new int[maxOffsets]; 63 } 64 initOffsets(isNew); 65 } 66 67 private void initOffsets(boolean isNew) { 68 int pageOffset = headerLength; 69 if (isNew) { 70 nextOffset = 0; 71 } else { 72 nextOffset = (freeStart - headerLength)/SIZE_OF_OFFSET; 73 for (int i = 0; i < nextOffset; i++) { 74 offsets[i] = Converter.readShort(pageBuffer, pageOffset); 75 keyLengths[i] = Converter.readShort(pageBuffer, pageOffset + SIZE_OF_SHORT); 76 pageOffset += SIZE_OF_OFFSET; 77 } 78 } 79 offsets[nextOffset] = btree.pageSize; 80 } 81 82 85 public void store() { 86 int pageOffset = headerLength; 87 super.store(); 88 if (nextOffset > 0) { 89 for (int i = 0; i < nextOffset; i++) { 90 Converter.writeShort(pageBuffer, pageOffset, (short)offsets[i]); 91 Converter.writeShort(pageBuffer, pageOffset + SIZE_OF_SHORT, (short)keyLengths[i]); 92 pageOffset += SIZE_OF_OFFSET; 93 } } } 96 97 102 int numEntries() { 103 return nextOffset; 104 } 105 106 113 int keyOffset(int entryNum) { 114 return offsets[entryNum]; 115 } 116 117 124 int keyLength(int entryNum) { 125 if (entryNum != nextOffset) { 126 return keyLengths[entryNum]; 127 } else { 128 return 0; 130 } 131 } 132 133 140 int dataLength(int entryNum) { 141 if (entryNum != nextOffset) { 142 return offsets[entryNum+1] - offsets[entryNum] - keyLengths[entryNum]; 143 } else { 144 return 0; 146 } 147 } 148 149 156 byte[] getData(int entryNum) { 157 int length = dataLength(entryNum); 158 byte[] data = new byte[length]; 159 System.arraycopy(pageBuffer, offsets[entryNum+1] - length, 160 data, 0, length); 161 return data; 162 } 163 164 171 byte[] getKey(int entryNum) { 172 byte[] key = new byte[keyLengths[entryNum]]; 173 System.arraycopy(pageBuffer, offsets[entryNum], key, 0, key.length); 174 return key; 175 } 176 177 184 BtreeEntry replace(BtreeEntry entry, int entryNum, SearchResult resultPosition) throws StorageException { 185 delete(entryNum, entryNum); 186 return insert(entry, entryNum, resultPosition); 187 } 188 189 198 BtreeEntry insert(BtreeEntry entry, int entryNum, SearchResult resultPosition) 199 throws StorageException { 200 201 int entriesStart; 202 int entriesSplit; 203 int entryLength = entry.length(); 204 205 pageSource.dirtyPage(this); 206 207 if (!haveSpaceForInsert(entry)) { 208 return split(entry, entryNum, resultPosition); 209 } else { 210 entriesStart = offsets[0]; 211 entriesSplit = offsets[entryNum]; 212 shiftOffsets(this, entryNum, entryLength); 213 if (entryNum != 0) { 214 System.arraycopy(pageBuffer, entriesStart, 215 pageBuffer, entriesStart - entryLength, 216 entriesSplit - entriesStart); 217 } 218 System.arraycopy(entry.key, 0, pageBuffer, offsets[entryNum], 219 entry.key.length); 220 System.arraycopy(entry.data, 0, pageBuffer, 221 offsets[entryNum] + entry.key.length, 222 entry.data.length); 223 keyLengths[entryNum] = entry.key.length; 224 freeStart += SIZE_OF_OFFSET; 225 226 if (resultPosition != null) { 227 resultPosition.entryNum = entryNum; 228 resultPosition.matched = true; 229 resultPosition.page = this; 230 resultPosition.skipCount = 0; 231 } 232 return null; 233 } 234 } 235 236 242 void delete(int first, int last) throws StorageException { 243 244 int startOffset, endOffset; 245 int bytesDeleted; 246 int numDeleted; 247 248 pageSource.dirtyPage(this); 249 250 startOffset = offsets[first]; 251 endOffset = offsets[last+1]; 252 bytesDeleted = endOffset - startOffset; 253 numDeleted = last - first + 1; 254 255 if (first != 0) { 256 System.arraycopy(pageBuffer, offsets[0], 257 pageBuffer, offsets[0] + bytesDeleted, 258 startOffset - offsets[0]); 259 } 260 for (int i = last + 1; i <= nextOffset; i++) { 262 offsets[i - numDeleted] = offsets[i]; 263 keyLengths[i - numDeleted] = keyLengths[i]; 264 } 265 nextOffset -= numDeleted; 266 freeStart -= numDeleted*SIZE_OF_OFFSET; 267 268 if (first != 0) { 270 for (int i = 0; i < first; i++) { 271 offsets[i] += bytesDeleted; 272 } 273 } 274 } 275 276 289 byte[] splitEntries(BtreePage leftBP, BtreePage rightBP, BtreeEntry entry, 290 int newEntryNum, SearchResult resultPosition) throws StorageException { 291 292 int halfBytes; 293 int splitEntryNum; 294 int rightNewEntryNum; 295 int spaceAvailable; 296 int spaceNeeded; 297 boolean insertLeft; 298 int pageSize; VarRecordPage left, right; 300 int rightKeyLength; 301 byte[] rightKey; 302 303 left = (VarRecordPage) leftBP; 304 right = (VarRecordPage) rightBP; 305 pageSize = btree.pageSize; 306 307 spaceAvailable = pageSize - headerLength; 308 if (entry.length() > spaceAvailable) 309 throw new StorageBadRequestException ("Entry too big to fit in a VarRecordPage, size: " + entry.length()); 310 311 halfBytes = (spaceAvailable - nextOffset*SIZE_OF_OFFSET)/2; 312 splitEntryNum = 0; 313 while ((offsets[splitEntryNum] < halfBytes) 314 && (splitEntryNum < nextOffset)) { 315 splitEntryNum++; 316 } 317 318 if (newEntryNum < splitEntryNum) { 321 do { 322 spaceNeeded = splitEntryNum*SIZE_OF_OFFSET 323 + offsets[splitEntryNum] - offsets[0] 324 + entry.length() + SIZE_OF_OFFSET; 325 if (spaceNeeded > spaceAvailable) { 326 splitEntryNum--; 327 } 328 } while ((spaceNeeded > spaceAvailable) 329 && (newEntryNum < splitEntryNum)); 330 } 331 insertLeft = newEntryNum < splitEntryNum ? true : false; 332 333 if (resultPosition != null) { 335 resultPosition.matched = true; 336 resultPosition.skipCount = 0; 337 if (insertLeft) { 338 resultPosition.page = left; 339 resultPosition.entryNum = newEntryNum; 340 } else { 341 resultPosition.page = right; 342 resultPosition.entryNum = newEntryNum - splitEntryNum; 343 } 344 } 345 346 if (!insertLeft) { 347 spaceNeeded = splitEntryNum*SIZE_OF_OFFSET 348 + pageSize - offsets[splitEntryNum] 349 + entry.length() + SIZE_OF_OFFSET; 350 } 351 352 for (int from = splitEntryNum, to = 0; from < nextOffset; 356 from++, to++) { 357 right.offsets[to] = this.offsets[from]; 358 right.keyLengths[to] = this.keyLengths[from]; 359 } 360 right.nextOffset = this.nextOffset - splitEntryNum; 361 right.offsets[right.nextOffset] = btree.pageSize; 362 right.freeStart = headerLength + right.nextOffset*SIZE_OF_OFFSET; 363 364 if (insertLeft) { 365 System.arraycopy(this.pageBuffer, offsets[splitEntryNum], 367 right.pageBuffer, offsets[splitEntryNum], 368 pageSize - offsets[splitEntryNum]); 369 } else { 370 rightNewEntryNum = newEntryNum - splitEntryNum; 372 shiftOffsets(right, rightNewEntryNum, entry.length()); 373 right.keyLengths[rightNewEntryNum] = entry.key.length; 374 right.freeStart += SIZE_OF_OFFSET; 375 376 if (newEntryNum != splitEntryNum) { 378 System.arraycopy(this.pageBuffer, this.offsets[splitEntryNum], 379 right.pageBuffer, right.offsets[0], 380 this.offsets[newEntryNum] - this.offsets[splitEntryNum]); 381 } 382 System.arraycopy(entry.key, 0, right.pageBuffer, 384 right.offsets[rightNewEntryNum], entry.key.length); 385 System.arraycopy(entry.data, 0, right.pageBuffer, 386 right.offsets[rightNewEntryNum] + entry.key.length, 387 entry.data.length); 388 389 if (newEntryNum != nextOffset) { 391 System.arraycopy(this.pageBuffer, this.offsets[newEntryNum], 392 right.pageBuffer, right.offsets[rightNewEntryNum + 1], 393 pageSize - this.offsets[newEntryNum]); 394 } 395 } 396 397 404 int bytesRemoved = pageSize - this.offsets[splitEntryNum]; 406 int splitPoint = this.offsets[splitEntryNum]; 407 int entriesStart = this.offsets[0]; 408 int insertPoint = this.offsets[newEntryNum]; 409 410 for (int i = 0; i < splitEntryNum; i++) { 411 left.offsets[i] = this.offsets[i] + bytesRemoved; 412 left.keyLengths[i] = this.keyLengths[i]; 413 } 414 left.nextOffset = splitEntryNum; 415 left.offsets[left.nextOffset] = pageSize; 416 left.freeStart = headerLength + left.nextOffset*SIZE_OF_OFFSET; 417 418 if (!insertLeft) { 419 System.arraycopy(this.pageBuffer, entriesStart, left.pageBuffer, 420 left.offsets[0], splitPoint - entriesStart); 421 } else { 422 shiftOffsets(left, newEntryNum, entry.length()); 424 left.keyLengths[newEntryNum] = entry.key.length; 425 left.freeStart += SIZE_OF_OFFSET; 426 427 430 if (insertPoint != splitPoint) { 432 System.arraycopy(this.pageBuffer, insertPoint, 433 left.pageBuffer, left.offsets[newEntryNum + 1], 434 splitPoint - insertPoint); 435 } 436 if (insertPoint != entriesStart) { 440 System.arraycopy(this.pageBuffer, entriesStart, 441 left.pageBuffer, left.offsets[0], 442 insertPoint - entriesStart); 443 } 444 445 System.arraycopy(entry.key, 0, left.pageBuffer, 447 left.offsets[newEntryNum], entry.key.length); 448 System.arraycopy(entry.data, 0, left.pageBuffer, 449 left.offsets[newEntryNum] + entry.key.length, 450 entry.data.length); 451 } 452 453 if (left != this) { 454 this.nextOffset = 0; 455 this.freeStart = headerLength; 456 this.offsets[0] = pageSize; 457 } 458 459 rightKeyLength = right.keyLength(0); 461 rightKey = new byte[rightKeyLength]; 462 System.arraycopy(right.pageBuffer, right.offsets[0], rightKey, 0, 463 rightKeyLength); 464 return rightKey; 465 } 466 467 private void shiftOffsets(VarRecordPage page, int entryNum, int entryLength) { 468 469 if (entryNum != page.nextOffset) { 470 for (int i = page.nextOffset; i > entryNum; i--) { 473 page.offsets[i] = page.offsets[i-1]; 474 page.keyLengths[i] = page.keyLengths[i-1]; 475 } 476 } 477 page.nextOffset++; 478 page.offsets[page.nextOffset] = btree.pageSize; 479 480 484 for (int i = entryNum; i >= 0; i--) { 485 page.offsets[i] -= entryLength; 486 } 487 } 488 489 boolean haveSpaceForInsert(BtreeEntry entry) { 490 491 int freeSpace = offsets[0] - freeStart; 492 493 if ((entry.length() + SIZE_OF_OFFSET) <= freeSpace) { 494 return true; 495 } else { 496 return false; 497 } 498 } 499 500 508 509 } 510 | Popular Tags |