1 9 package org.ozoneDB.core.storage.magicStore; 10 11 import java.io.*; 12 import java.util.Iterator ; 13 import java.util.Set ; 14 15 import org.ozoneDB.DxLib.*; 16 import org.ozoneDB.*; 17 import org.ozoneDB.io.stream.ResolvingObjectInputStream; 18 import org.ozoneDB.core.*; 19 import org.ozoneDB.core.storage.ClusterID; 20 import org.ozoneDB.core.storage.Cluster; 21 import org.ozoneDB.core.storage.StorageObjectContainer; 22 import org.ozoneDB.util.LogWriter; 23 24 25 32 public final class MagicStore 33 extends ServerComponent 34 implements StoreManager { 35 36 protected final static String ID_TABLE_NAME = "idTable.wizard"; 37 38 protected final static String NAME_TABLE_NAME = "nameTable.wizard"; 39 40 protected final static String COMMIT_FLAG_NAME = "commitflag.wizard"; 41 42 45 protected DxMap idTable; 46 47 50 protected DxMap nameTable; 51 52 protected ClusterStore clusterStore; 53 54 61 protected GarbageCollector garbageCollector; 62 63 public MagicStore(Env env) { 64 super(env); 65 } 66 67 68 public synchronized void init(Env _env) { 69 env = _env; 70 71 int idTableBufferSize = env.config.intProperty(Setup.WS_TABLE_BUFF_SIZE, -1); 72 int idTableCacheSize = env.config.intProperty(Setup.WS_TABLE_CACHE_SIZE, -1); 73 int[] idTableSubtableSize = env.config.intArrayProperty(Setup.WS_TABLE_SUBTABLE_SIZE, new int[] {-1}); 74 75 idTable = new IDTable(env.getDatabaseDir() + "ostab" + File.separator + "tab", idTableBufferSize, idTableCacheSize, idTableSubtableSize); 76 nameTable = new DxHashMap(100); 78 79 clusterStore = new ClusterStore(env); 80 clusterStore.setMagicStore(this); 81 82 this.garbageCollector = env.getGarbageCollector(); 83 } 84 85 86 public synchronized void startup() throws Exception { 87 env.logWriter.newEntry(this, "startup...", LogWriter.INFO); 88 env.logWriter.newEntry(this, "CAUTION: MagicStore is still in early development phase, use with caution!", LogWriter.INFO); 89 clusterStore.startup(); 90 91 env.logWriter.newEntry(this, "checking for pending shadow clusters...", LogWriter.INFO); 92 93 boolean isCleanShutdown = isCleanShutdown() && clusterStore.isCleanShutdown(); 94 95 boolean isSuccessfullyStarted = false; 96 97 if (isCleanShutdown) { 98 ObjectInputStream nameTableIn = null; 99 ObjectInputStream idTableIn = null; 100 try { 101 nameTableIn = new ResolvingObjectInputStream(new FileInputStream(env.getDatabaseDir() + NAME_TABLE_NAME)); 103 int count = nameTableIn.readInt(); 104 for (int i = 0; i < count; i++) { 105 nameTable.addForKey(nameTableIn.readObject(), nameTableIn.readObject()); 106 } 107 nameTableIn.close(); 108 109 if (!(idTable instanceof DxDiskHashMap)) { 111 idTableIn = new ResolvingObjectInputStream(new FileInputStream(env.getDatabaseDir() + ID_TABLE_NAME)); 112 count = idTableIn.readInt(); 113 for (int i = 0; i < count; i++) { 114 idTable.addForKey(idTableIn.readObject(), idTableIn.readObject()); 115 } 116 idTableIn.close(); 117 } else { 118 ((DxDiskHashMap) idTable).re_use(); 119 ((DxDiskHashMap) idTable).setReusable(true); 120 } 121 122 isSuccessfullyStarted = true; 123 } catch (FileNotFoundException fe) { 124 env.logWriter.newEntry(this, " " + fe.toString(), LogWriter.INFO); 125 } catch (Exception e) { 126 env.logWriter.newEntry(this, " error while starting up... ", LogWriter.INFO); 127 env.logWriter.newEntry(this, " exception: ", e, LogWriter.DEBUG); 128 } finally { 129 if (nameTableIn != null) { 130 nameTableIn.close(); 131 } 132 if (idTableIn != null) { 133 idTableIn.close(); 134 } 135 } 136 } 137 138 if (!isCleanShutdown || !isSuccessfullyStarted) { 139 env.logWriter.newEntry(this, " recovering...", LogWriter.INFO); 140 recover(); 141 } 142 143 env.logWriter.newEntry(this, " " + idTable.count() + " IDs, " + nameTable.count() + " name(s))", 144 LogWriter.INFO); 145 } 146 147 148 public synchronized void shutdown() throws Exception { 149 env.logWriter.newEntry(this, "shutdown...", LogWriter.INFO); 150 clusterStore.shutdown(); 151 152 commitNameTable(); 153 154 commitIDTable(); 155 if (idTable instanceof DxDiskHashMap) { 156 ((DxDiskHashMap) idTable).printStatistics(); 157 ((DxDiskHashMap) idTable).close(); 158 } 159 } 160 161 162 public void save() throws Exception { 163 } 164 165 166 public DxIterator objectIDIterator() { 167 return idTable.iterator(); 168 } 169 170 171 protected void commitNameTable() throws IOException { 172 env.logWriter.newEntry(this, "commitNameTable...", LogWriter.DEBUG3); 173 174 String filename = env.getDatabaseDir() + NAME_TABLE_NAME; 175 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename)); 176 try { 177 out.writeInt(nameTable.count()); 178 DxIterator it = nameTable.iterator(); 179 while (it.next() != null) { 180 out.writeObject(it.object()); 181 out.writeObject(it.key()); 182 } 183 } catch (Exception e) { 184 new File(filename).delete(); 185 } finally { 186 out.close(); 187 } 188 } 189 190 191 protected void commitIDTable() throws IOException { 192 env.logWriter.newEntry(this, "commitIDTable...", LogWriter.DEBUG3); 193 194 if (!(idTable instanceof DxDiskHashMap)) { 195 String filename = env.getDatabaseDir() + ID_TABLE_NAME; 196 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename)); 197 198 try { 199 out.writeInt(idTable.count()); 200 DxIterator it = idTable.iterator(); 201 while (it.next() != null) { 202 out.writeObject(it.object()); 203 out.writeObject(it.key()); 204 } 205 } catch (Exception e) { 206 new File(filename).delete(); 207 } finally { 208 out.close(); 209 } 210 } else { 211 ((IDTable) idTable).setReusable(false); 212 ((IDTable) idTable).writeDirtyTables(); 213 ((IDTable) idTable).setReusable(true); 214 } 215 } 216 217 218 224 protected synchronized void recover() throws Exception { 225 env.logWriter.newEntry(this, " cleaning ID table...", LogWriter.INFO); 226 ((DxDiskHashMap) idTable).cleanFiles(); 227 (idTable).clear(); 228 229 env.logWriter.newEntry(this, " cleaning name table...", LogWriter.INFO); 230 nameTable.clear(); 231 232 Set cids = clusterStore.recoverClusterIDs(); 233 Set uncommittedTaIDs = clusterStore.uncommittedTaIDs(); 234 235 int totalNumClusters = cids.size(); 236 int processedNumClusters = 1; 237 for (Iterator it = cids.iterator(); it.hasNext(); ) { 238 ClusterID cid = (ClusterID) it.next(); 239 240 Cluster cluster = null; 241 boolean exceptionWhileLoading = false; 242 243 env.logWriter.newEntry(this, " cluster: " + cid + " (" + processedNumClusters++ + " of " + totalNumClusters + ")", LogWriter.INFO); 244 try { 245 cluster = clusterStore.restoreCluster(cid, uncommittedTaIDs); 246 env.logWriter.newEntry(this, " " + cluster.containers().count() + " containers", LogWriter.INFO); 247 } catch (Exception e) { 248 env.logWriter.newEntry(this, "exception while loading cluster: " + cid + " (" + e + ")", LogWriter.WARN); 249 env.logWriter.newEntry(this, "", e, LogWriter.DEBUG); 250 exceptionWhileLoading = true; 251 } 252 253 if (exceptionWhileLoading || cluster.containers().isEmpty()) { 254 if (exceptionWhileLoading) { 255 env.logWriter.newEntry(this, " unable to read cluster - should be deleted!", LogWriter.INFO); 256 } else { 257 env.logWriter.newEntry(this, " cluster is empty - should be deleted!", LogWriter.INFO); 258 } 259 if (cluster != null) { 260 env.logWriter.newEntry(this, " try to delete cluster...", LogWriter.INFO); 261 cluster.delete(); 262 } 263 } else { 264 DxIterator it2 = cluster.containers().iterator(); 266 StorageObjectContainer container; 267 while ((container = (StorageObjectContainer) it2.next()) != null) { 268 if (env.logWriter.hasTarget(LogWriter.DEBUG)) { 269 if (container.id().value()==1) { 270 env.logWriter.newEntry(this, "Adding container "+container+".", LogWriter.DEBUG); 271 } 272 } 273 if (idTable.addForKey(cluster.clusterID(), container.id()) == false) { 274 throw new IllegalStateException ("Unable to add container "+container+" to ID table because cluster ID "+idTable.elementForKey(container.id())+" is already registered for container ID "+container.id()+"."); 275 } 276 if (container.name() != null) { 277 env.logWriter.newEntry(this, " adding name: " + container.name(), LogWriter.INFO); 278 if (nameTable.addForKey(container.id(), container.name()) == false) { 279 throw new IllegalStateException ("Unable to add name to name table: " + container.name()); 280 } 281 } 282 } 283 } 284 clusterStore.unloadCluster(cid, false); 285 } 286 commitIDTable(); 287 commitNameTable(); 288 } 289 290 291 public synchronized ObjectContainer newContainerAndLock(Transaction ta, OzoneCompatible target, ObjectID objID, 292 Permissions permissions, int lockLevel) throws Exception { 293 294 295 StorageObjectContainer container = new MagicObjectContainer(objID); 296 297 if (target != null) { 298 container.setTarget(target); 299 } 300 301 clusterStore.registerContainerAndLock(container, permissions, ta, lockLevel); 302 303 boolean alright = false; 304 305 try { 306 307 garbageCollector.notifyNewObjectContainer(container); 308 309 MagicTransaction transaction = (MagicTransaction) ta; 310 ClusterID cid = container.getCluster().clusterID(); 311 ObjectID oid = container.id(); 312 313 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 314 env.logWriter.newEntry(this, "newContainer(): cid=" + cid + ",oid=" + oid + ".", LogWriter.DEBUG3); 315 } 316 317 transaction.idTable.addForKey(cid, oid); 318 transaction.idTableChanges_push(new IDTableChange(oid, cid, IDTableChange.STATE_ADDED)); 319 320 alright = true; 321 322 return container; 323 } finally { 324 if (!alright) { 325 container.getCluster().lock().release(ta); 326 } 327 } 328 } 329 330 331 339 340 public void updateLockLevel(Transaction _ta, ObjectContainer _container) throws IOException { 341 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 342 env.logWriter.newEntry(this, "updateLockLevel()", LogWriter.DEBUG3); 343 } 344 345 if (_container instanceof StorageObjectContainer) { 346 StorageObjectContainer container = (StorageObjectContainer) _container; 347 container.getCluster().updateLockLevel(_ta); 348 349 MagicTransaction wizardTa = (MagicTransaction) _ta; 350 wizardTa.idTable.addForKey(container.getCluster().clusterID(), container.id()); 351 } 352 } 353 354 355 366 public ObjectContainer containerForID(Transaction ta, ObjectID id) throws ObjectNotFoundException, IOException, ClassNotFoundException { 367 368 StorageObjectContainer container = null; 369 MagicTransaction magicTa = (MagicTransaction) ta; 370 MagicTransaction transaction = (MagicTransaction) ta; 371 372 381 ClusterID cid = null; 382 383 if (ta != null) { 385 DxMap taDataIDTable = transaction.idTable; 386 cid = (ClusterID) taDataIDTable.elementForKey(id); 387 388 if (cid == null && transaction.lrucid != null) { 389 Cluster lru = clusterStore.loadCluster(transaction.lrucid, magicTa); 390 391 if (lru != null) { 392 container = lru.lock() != null ? lru.containerForID(id) : null; 393 if (container != null) { 394 if (container.isDeleted()) { 396 return null; 397 } else { 398 return container; 399 } 400 } 401 } 402 } 403 } 404 405 if (cid == null) { 407 cid = (ClusterID) idTable.elementForKey(id); 408 } 409 410 411 if (cid == null) { 412 return null; 413 } else { 414 Cluster cluster = clusterStore.loadCluster(cid, magicTa); 416 417 if (cluster == null) { 418 throw new ObjectNotFoundException("No object registered for ID: " + id); 419 } 420 421 if (transaction != null) { 422 transaction.lrucid = cid; 423 } 424 425 try { 426 container = cluster.containerForID(id); 427 428 if (container.isDeleted()) { 429 return null; 430 } else { 431 return container; 432 } 433 } catch (NullPointerException e) { 434 env.logWriter.newEntry(this, "NullPointerException during " + cluster + ".containerForID(" + id + "). We were able to load a cluster for that ID but the cluster did not contain the container. This is an inconsistent view.", e, LogWriter.ERROR); 435 throw e; 436 } 437 438 } 439 } 440 441 public DxSet objectNames(Transaction ta) { 442 env.logWriter.newEntry(this, "Returning objectnames", LogWriter.DEBUG); 443 444 return nameTable.keySet(); 445 } 446 447 public synchronized ObjectContainer containerForName(Transaction ta, String name) throws Exception { 448 if (name == null) { 449 return null; 450 } 451 452 MagicTransaction wizardTa = (MagicTransaction) ta; 453 454 if (ta == null || wizardTa.nameTable == null) { 455 ObjectID oid = (ObjectID) nameTable.elementForKey(name); 456 return oid != null ? containerForID(ta, oid) : null; 457 } 458 459 if (ta != null) { 460 ObjectID oid = (ObjectID) wizardTa.nameTable.elementForKey(name); 461 return oid != null ? containerForID(ta, oid) : null; 462 } 463 return null; 464 } 465 466 467 public synchronized void nameContainer(Transaction ta, ObjectContainer container, String name) 468 throws PermissionDeniedException { 469 470 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 471 env.logWriter.newEntry(this, "nameContainer(), nameTable=" + nameTable + ".", LogWriter.DEBUG3); 472 } 473 474 MagicTransaction transaction = (MagicTransaction) ta; 475 if (transaction.nameTable == null) { 476 Object o = null; 477 try { 478 java.lang.reflect.Method method = nameTable.getClass().getDeclaredMethod("clone", null); 479 if (env.logWriter.hasTarget(LogWriter.DEBUG)) { 480 env.logWriter.newEntry(this, "nameContainer(), nameTable=" + nameTable + ", nameTable.getClass().getDeclaredMethod(\"clone\",null)=" + method + ".", LogWriter.DEBUG); 481 } 482 o = method.invoke(nameTable, null); 483 } catch (Exception e) { 484 env.logWriter.newEntry(this, "nameContainer(): caught: ", e, LogWriter.INFO); 485 } 486 487 if (o == null) { 488 o = nameTable.clone(); 489 } 490 491 492 transaction.nameTable = (DxMap) o; 493 } 494 495 String oldName = container.name(); 496 if (oldName != null) { 497 transaction.nameTable.removeForKey(oldName); 498 transaction.nameTableChanges_push(new NameTableChange(container.id(), oldName, 499 NameTableChange.STATE_REMOVED)); 500 } 501 502 container.nameTarget(name); 503 504 if (name != null) { 505 if (oldName == null) { 506 garbageCollector.notifyNewObjectName(container); 507 } 508 transaction.nameTable.addForKey(container.id(), name); 509 transaction.nameTableChanges_push(new NameTableChange(container.id(), name, NameTableChange.STATE_ADDED)); 510 } 511 } 512 513 514 public synchronized DxBag clusterOfID(ObjectID id) throws Exception { 515 throw new RuntimeException ("this method is implementation specific and should be removed from StoreManager"); 516 } 517 518 519 public synchronized void prepareCommitTransaction(Transaction ta) throws IOException, ClassNotFoundException { 520 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 521 env.logWriter.newEntry(this, "prepareCommitTransaction()", LogWriter.DEBUG3); 522 } 523 524 MagicTransaction transaction = (MagicTransaction) ta; 525 526 transaction.commitClusterIDs = new DxHashSet(64); 528 529 DxIterator it = transaction.idTable.iterator(); 530 ClusterID cid; 532 533 while ((cid = (ClusterID) it.next()) != null) { 534 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 535 env.logWriter.newEntry(this, "checking cluster: " + cid + " ...", LogWriter.DEBUG3); 536 } 537 538 if (!transaction.commitClusterIDs.contains(cid)) { 539 transaction.commitClusterIDs.add(cid); 541 542 Cluster cluster = clusterStore.loadCluster(cid, transaction); 543 544 if (cluster.lock().level(ta) >= Lock.LEVEL_WRITE) { 547 548 DxIterator it2 = cluster.containers().iterator(); 551 StorageObjectContainer container; 552 while ((container = (StorageObjectContainer) it2.next()) != null) { 553 554 if (container.isDeleted()) { 555 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 556 env.logWriter.newEntry(this, "container deleted: " + container.id(), LogWriter.DEBUG3); 557 } 558 559 clusterStore.invalidateContainer(container); 560 transaction.idTableChanges_push(new IDTableChange(container.id(), cid, IDTableChange.STATE_REMOVED)); 561 562 if (container.name() != null) { 563 transaction.nameTableChanges_push(new NameTableChange(container.id(), container.name(), NameTableChange.STATE_REMOVED)); 564 } 565 } 566 container.clearState(); 567 } 568 } 569 clusterStore.prepareCommitCluster(ta, cid); 570 } 571 } 572 } 573 574 575 protected boolean isCleanShutdown() { 576 return !(new File(COMMIT_FLAG_NAME).exists()); 577 } 578 579 580 protected void beginCommit(Transaction ta) throws IOException { 581 583 if (ta.maxLockLevel() < Lock.LEVEL_WRITE) { 585 return; 586 } 587 588 int commitCount = 0; 589 590 File f = new File(env.getDatabaseDir() + COMMIT_FLAG_NAME); 592 if (f.exists()) { 593 DataInputStream in = null; 594 try { 595 in = new DataInputStream(new FileInputStream(f)); 596 commitCount = in.readInt(); 597 } finally { 598 if (in != null) { 599 in.close(); 600 } 601 } 602 } 603 commitCount++; 604 605 DataOutputStream out = null; 606 try { 607 out = new DataOutputStream(new FileOutputStream(f)); 608 out.writeInt(commitCount); 609 } finally { 610 if (out != null) { 611 out.close(); 612 } 613 } 614 } 615 616 617 protected void endCommit(Transaction ta) throws IOException { 618 620 if (ta.maxLockLevel() < Lock.LEVEL_WRITE) { 622 return; 623 } 624 625 int commitCount = 0; 626 627 File f = new File(env.getDatabaseDir() + COMMIT_FLAG_NAME); 629 if (f.exists()) { 630 DataInputStream in = null; 631 try { 632 in = new DataInputStream(new FileInputStream(f)); 633 commitCount = in.readInt(); 634 } finally { 635 if (in != null) { 636 in.close(); 637 } 638 } 639 } else { 640 throw new RuntimeException ("No commit flag file present."); 641 } 642 commitCount--; 643 644 if (commitCount > 0) { 645 DataOutputStream out = null; 646 try { 647 out = new DataOutputStream(new FileOutputStream(f)); 648 out.writeInt(commitCount); 649 } finally { 650 if (out != null) { 651 out.close(); 652 } 653 } 654 } else { 655 if (!(f.delete())) { 656 throw new RuntimeException ("Unable to delete commit flag file. "); 657 } 658 } 659 } 660 661 662 public synchronized void commitTransaction(Transaction ta) throws IOException, ClassNotFoundException { 663 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 664 env.logWriter.newEntry(this, "commitTransaction()", LogWriter.DEBUG3); 665 } 666 667 beginCommit(ta); 668 669 MagicTransaction transaction = (MagicTransaction) ta; 670 671 DxSet commitClusterIDs = transaction.commitClusterIDs; 673 DxIterator it = commitClusterIDs.iterator(); 674 675 ClusterID cid; 676 while ((cid = (ClusterID) it.next()) != null) { 677 if (env.logWriter.hasTarget(LogWriter.DEBUG2)) { 678 env.logWriter.newEntry(this, "commit cluster: " + cid, LogWriter.DEBUG2); 679 } 680 clusterStore.commitCluster(ta, cid); 681 } 682 683 boolean isIDTableChanged = false; 685 IDTableChange idChange = null; 686 687 while ((idChange = transaction.idTableChanges_pop()) != null) { 688 isIDTableChanged = true; 689 690 switch (idChange.state) { 691 case IDTableChange.STATE_ADDED: 692 { 693 if (idTable.addForKey(idChange.cid, idChange.oid) == false) { 695 throw new IllegalStateException ("Unable to add OID to global ID table."); 696 } 697 break; 698 } 699 case IDTableChange.STATE_REMOVED: 700 { 701 if (false) { 702 env.logWriter.newEntry(this, "commit removed oid: " + idChange.oid, LogWriter.DEBUG2); 703 } 704 705 if (idTable.removeForKey(idChange.oid) == null) { 706 throw new IllegalStateException ("Unable to remove OID from global ID table."); 707 } 708 break; 709 } 710 default: 711 { 712 throw new RuntimeException ("ID change table entry has inproper state."); 713 } 714 } 715 } 716 717 if (isIDTableChanged) { 719 commitIDTable(); 720 } 721 722 boolean isNameTableChanged = false; 724 NameTableChange nameChange = transaction.nameTableChanges_pop(); 725 726 while (nameChange != null) { 727 isNameTableChanged = true; 728 729 switch (nameChange.state) { 730 case NameTableChange.STATE_ADDED: 731 { 732 nameTable.addForKey(nameChange.oid, nameChange.name); 733 break; 734 } 735 case NameTableChange.STATE_REMOVED: 736 { 737 nameTable.removeForKey(nameChange.name); 738 break; 739 } 740 default: 741 { 742 throw new RuntimeException ("Name change table entry has inproper state."); 743 } 744 } 745 nameChange = transaction.nameTableChanges_pop(); 746 } 747 748 if (isNameTableChanged) { 750 commitNameTable(); 751 } 752 753 endCommit(ta); 754 755 if (env.logWriter.hasTarget(LogWriter.DEBUG2)) { 756 env.logWriter.newEntry(this, " idTable.count(): " + idTable.count(), LogWriter.DEBUG2); 757 env.logWriter.newEntry(this, " nameTable.count(): " + nameTable.count(), LogWriter.DEBUG2); 758 } 759 } 760 761 762 765 public synchronized void abortTransaction(Transaction ta) throws IOException, ClassNotFoundException { 766 if (env.logWriter.hasTarget(LogWriter.DEBUG3)) { 767 env.logWriter.newEntry(this, "abortTransaction()", LogWriter.DEBUG3); 768 } 769 770 clusterStore.abortTransaction((MagicTransaction) ta); 771 } 772 773 776 public void reportNamedObjectsToGarbageCollector() { 777 synchronized (this) { 778 DxIterator i = nameTable.elementSet().iterator(); 779 780 while (i.next() != null) { 781 garbageCollector.notifyNamedObject((ObjectID) i.object()); 782 } 783 } 784 } 785 786 public Transaction createTransaction(Env env, User user) { 787 return new MagicTransaction(env, user); 788 } 789 790 } 791 | Popular Tags |