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.util.*; 24 import java.io.*; 25 import java.text.*; 26 27 48 public abstract class Btree extends Object implements Index, Streamable, 49 StorageClient { 50 51 protected BtreePageSource pageSource; 52 protected BtreeStorage storage; 53 protected Storage.EntryType keyType; 54 protected Storage.EntryType dataType; 55 protected String name; 56 57 protected EntryTypeInfo keyInfo; 58 protected EntryTypeInfo dataInfo; 59 protected int dataLength; 60 protected int pageIdLength; 61 protected int pageSize; 62 protected byte[] rootPageId; 63 64 protected boolean uniqueKeys; 65 protected boolean uniqueValues; 66 protected boolean hasBigKeys; 67 68 71 static final byte ADD = 0; 72 static final byte REPLACE = 1; 73 static final byte REPLACE_IF_EXISTS = 2; 74 78 boolean failed; 79 boolean replaced; 80 81 84 private int activeReaders = 0; 85 private int activeWriters = 0; 86 private int waitingWriters = 0; 87 int modCount = 0; 88 89 public Btree(String name, Storage.EntryType keyType, 90 Storage.EntryType dataType, 91 BtreePageSource pageSource) 92 throws StorageException { 93 94 this.keyType = keyType; 95 this.dataType = dataType; 96 this.name = name; 97 this.pageSource = pageSource; 98 pageSize = pageSource.getPageSize(); 99 storage = pageSource.getStorage (); 100 101 init(); 102 } 103 104 108 protected void init() throws StorageException { 109 110 BtreePage root; 111 112 if (keyInfo != null) { 113 114 return; 115 } 116 117 keyInfo = EntryTypeInfo.getEntryTypeInfo(keyType, storage); 118 dataInfo = EntryTypeInfo.getEntryTypeInfo(dataType, storage); 119 if (keyInfo == null) { 120 throw new StorageBadRequestException( 121 MessageFormat.format( 122 "Invalid index key type: ", 123 new Object [] {keyType})); 124 } 125 if (dataInfo == null) { 126 throw new StorageBadRequestException( 127 MessageFormat.format( 128 "Invalid index data type: ", 129 new Object [] {dataType})); 130 } 131 132 dataLength = dataInfo.getLength(); 134 135 pageIdLength = pageSource.getPageIdLength(); 136 137 if (rootPageId == null) { 138 145 root = pageSource.getRootPage(this); 146 rootPageId = new byte[pageIdLength]; 147 System.arraycopy(root.pageId, 0, rootPageId, 0, root.pageId.length); 148 root.makeRoot(); 149 } else { 150 151 root = pageSource.getPage(rootPageId, this); 152 } 153 154 if (pageSource.isNoPage(root.nextPage)) { 155 hasBigKeys = false; 156 } else { 157 hasBigKeys = true; 158 } 159 pageSource.unpinPage(root); 160 } 161 162 166 167 public Btree() { 168 } 169 170 175 public void write(OutputStream outputStream) throws StorageException { 176 177 181 try { 182 DataOutputStream out = new DataOutputStream(outputStream); 183 184 byte[] n = name.getBytes(); 185 out.writeShort(n.length); 186 out.write(n); 187 out.writeByte(keyType.encode()); 188 out.writeByte(dataType.encode()); 189 out.writeBoolean(uniqueValues); 190 out.writeInt(pageSize); 191 out.write(rootPageId); 192 } catch (IOException e) { 193 throw new StorageIOException(e); 194 } 195 } 196 197 203 public void read(InputStream inputStream) throws StorageException { 204 205 try { 206 DataInputStream in = new DataInputStream(inputStream); 207 208 short length = in.readShort(); 209 byte[] n = new byte[length]; 210 in.read(n, 0, length); 211 name = new String (n).intern(); 212 213 keyType = Storage.EntryType.decodeEntryType(in.readByte()); 214 dataType = Storage.EntryType.decodeEntryType(in.readByte()); 215 uniqueValues = in.readBoolean(); 216 pageSize = in.readInt(); 217 218 pageSource = new BtreeMDRSource(storage, pageSize); 219 220 rootPageId = new byte[pageSource.getPageIdLength()]; 221 in.read(rootPageId, 0, rootPageId.length); 222 } catch (IOException e) { 223 throw new StorageIOException(e); 224 } 225 226 227 init(); 228 } 229 230 public void setStorage(Storage storage) { 231 this.storage = (BtreeStorage) storage; 232 } 233 238 239 243 public Storage.EntryType getKeyType() { 244 return keyType; 245 } 246 247 251 public Storage.EntryType getValueType() { 252 return dataType; 253 } 254 255 259 public String getName() { 260 return name; 261 } 262 263 268 public Set keySet() throws StorageException { 269 return new BtreeKeySet(this); 270 } 271 272 284 public void add(Object key, Object data) throws StorageException { 285 beginWrite(); 286 try { 287 failed = false; 288 btreePut(key, data, ADD, 0); 289 290 if (failed) { 291 String message; 292 if (uniqueKeys) { 293 message = 294 MessageFormat.format("Key {0} already exists in index", 295 new Object [] {key}); 296 } else { 297 message = 298 MessageFormat.format( 299 "Key-value pair {0}, {1} already exists in index", 300 new Object [] {key, data}); 301 } 302 throw new StorageBadRequestException(message); 303 } 304 } finally { 305 endWrite(); 306 } 307 } 308 309 319 public boolean remove(Object key) throws StorageException { 320 321 beginWrite(); 322 try { 323 boolean result; 324 byte[] keyBuffer; 325 326 if ((keyBuffer = keyInfo.toBuffer(key)) == null) { 327 throw new StorageBadRequestException( 328 MessageFormat.format( 329 "Invalid key type for this index: {0} received, {1} expected", 330 new Object [] { 331 key.getClass().getName(), 332 keyInfo.typeName()} )); 333 } 334 BtreePage root = pageSource.getPage(rootPageId, this); 335 result = root.remove(keyBuffer); 336 pageSource.unpinPage(root); 337 return result; 338 } finally { 339 endWrite(); 340 } 341 } 342 343 348 349 352 public BtreePage pageFactory() { 353 354 if (!dataInfo.isFixedLength()) 355 return new VarRecordPage(); 356 if (keyInfo.isFixedLength()) { 357 if ((keyInfo instanceof MOFIDInfo) && (dataInfo instanceof MOFIDInfo)) { 358 return new ShrinkablePage (); 359 } else { 360 return new FixedKeyPage(); 361 } 362 } else { 363 return new VarKeyPage(); 364 } 365 } 366 367 372 SearchResult getFirst() throws StorageException { 373 SearchResult result; 374 375 BtreePage root = pageSource.getPage(rootPageId, this); 376 result = root.getFirst(); 377 if (result.page != root) { 378 pageSource.unpinPage(root); 379 } 380 return result; 381 } 382 383 389 SearchResult getLocation(byte[] key) throws StorageException { 390 SearchResult result; 391 392 BtreePage root = pageSource.getPage(rootPageId, this); 393 result = root.getLocation(key); 394 if (result.page != root) { 395 pageSource.unpinPage(root); 396 } 397 return result; 398 } 399 400 protected void btreePut(Object key, Object data, byte operation, int index) 401 throws StorageException { 402 403 byte[] keyBuffer; 404 byte[] dataBuffer; 405 406 if ((keyBuffer = keyInfo.toBuffer(key)) == null) { 407 throw new StorageBadRequestException( 408 MessageFormat.format( 409 "Invalid key type for this index: {0} received, {1} expected", 410 new Object [] { 411 key.getClass().getName(), 412 keyInfo.typeName()} )); 413 } 414 415 if ((dataBuffer = dataInfo.toBuffer(data)) == null) { 416 throw new StorageBadRequestException( 417 MessageFormat.format( 418 "Invalid data type for this index: {0} received, {1} expected", 419 new Object [] { 420 data.getClass().getName(), 421 dataInfo.typeName()} )); 422 } 423 424 BtreePage root = pageSource.getPage(rootPageId, this); 425 root.put(keyBuffer, dataBuffer, operation, index); 426 pageSource.unpinPage(root); 427 } 428 429 432 int countRecords() throws StorageException { 433 434 SearchResult location; 435 BtreePage savePage; 436 int count = 0; 437 438 location = getFirst(); 439 if (!location.matched) { 440 return 0; 441 } 442 443 do { 444 savePage = location.page; 445 BtreePage.getNext((byte[]) null, location); 446 count++; 447 if ((savePage != null) && (savePage != location.page)) { 448 pageSource.unpinPage(savePage); 449 } 450 } while (location.matched); 451 452 if (location.page != null) { 453 pageSource.unpinPage(location.page); 454 } 455 return count; 456 } 457 458 boolean hasBigKeys() { 459 return hasBigKeys; 460 } 461 462 void setHasBigKeys() { 463 hasBigKeys = true; 464 } 465 466 void unsetHasBigKeys() { 467 hasBigKeys = false; 468 } 469 470 473 private boolean allowReader() { 474 return waitingWriters == 0 && activeWriters == 0; 475 } 476 477 private boolean allowWriter() { 478 return activeReaders == 0 && activeWriters == 0; 479 } 480 481 protected synchronized void beginRead() { 482 while (!allowReader()) { 483 try { wait(); } catch (InterruptedException e) {} 484 } 485 activeReaders++; 486 } 487 488 protected synchronized void endRead() { 489 activeReaders--; 490 notifyAll(); 491 } 492 493 protected synchronized void beginWrite() { 494 waitingWriters++; 495 while (!allowWriter()) { 496 try { wait(); } catch (InterruptedException e) {} 497 } 498 waitingWriters--; 499 activeWriters++; 500 } 501 502 protected synchronized void endWrite() { 503 activeWriters--; 504 modCount++; 505 notifyAll(); 506 } 507 508 511 516 public void dumpTree(PrintWriter out) throws StorageException { 517 518 BtreePage root = pageSource.getPage(rootPageId, this); 519 root.dumpTree(out); 520 pageSource.unpinPage(root); 521 } 522 523 public TreeMetrics computeMetrics() throws StorageException { 524 BtreePage root = pageSource.getPage(rootPageId, this); 525 TreeMetrics m = root.computeMetrics(); 526 pageSource.unpinPage(root); 527 return m; 528 } 529 530 537 public int consistencyCheck(PrintWriter out) throws StorageException { 538 int result; 539 540 BtreePage root = pageSource.getPage(rootPageId, this); 541 result = root.consistencyCheck(out); 542 pageSource.unpinPage(root); 543 return result; 544 } 545 546 } 547 | Popular Tags |