001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.internal;
022:
023: import com.db4o.*;
024: import com.db4o.config.*;
025: import com.db4o.ext.*;
026: import com.db4o.foundation.*;
027: import com.db4o.internal.btree.*;
028: import com.db4o.internal.convert.*;
029: import com.db4o.internal.fileheader.*;
030: import com.db4o.internal.freespace.*;
031: import com.db4o.internal.query.processor.*;
032: import com.db4o.internal.query.result.*;
033: import com.db4o.internal.slots.*;
034:
035: /**
036: * @exclude
037: */
038: public abstract class LocalObjectContainer extends
039: ExternalObjectContainer implements InternalObjectContainer {
040:
041: private static final int DEFAULT_FREESPACE_ID = 0;
042:
043: protected FileHeader _fileHeader;
044:
045: private Collection4 i_dirty;
046:
047: private FreespaceManager _freespaceManager;
048:
049: private boolean i_isServer = false;
050:
051: private Tree i_prefetchedIDs;
052:
053: private Hashtable4 i_semaphores;
054:
055: private int _blockEndAddress;
056:
057: private Tree _freeOnCommit;
058:
059: private SystemData _systemData;
060:
061: LocalObjectContainer(Configuration config,
062: ObjectContainerBase parentContainer) {
063: super (config, parentContainer);
064: }
065:
066: public Transaction newTransaction(Transaction parentTransaction,
067: TransactionalReferenceSystem referenceSystem) {
068: return new LocalTransaction(this , parentTransaction,
069: referenceSystem);
070: }
071:
072: public FreespaceManager freespaceManager() {
073: return _freespaceManager;
074: }
075:
076: public abstract void blockSize(int size);
077:
078: public void blockSizeReadFromFile(int size) {
079: blockSize(size);
080: setRegularEndAddress(fileLength());
081: }
082:
083: public void setRegularEndAddress(long address) {
084: _blockEndAddress = bytesToBlocks(address);
085: }
086:
087: final protected void close2() {
088: if (!_config.isReadOnly()) {
089: freeInternalResources();
090: commitTransaction();
091: shutdown();
092: }
093: shutdownObjectContainer();
094: }
095:
096: protected abstract void freeInternalResources();
097:
098: public void commit1(Transaction trans) {
099: trans.commit();
100: }
101:
102: void configureNewFile() {
103:
104: newSystemData(configImpl().freespaceSystem());
105: systemData().converterVersion(Converter.VERSION);
106: createStringIO(_systemData.stringEncoding());
107:
108: generateNewIdentity();
109:
110: _freespaceManager = AbstractFreespaceManager.createNew(this );
111:
112: blockSize(configImpl().blockSize());
113:
114: _fileHeader = new FileHeader1();
115:
116: setRegularEndAddress(_fileHeader.length());
117:
118: initNewClassCollection();
119: initializeEssentialClasses();
120:
121: _fileHeader.initNew(this );
122:
123: _freespaceManager.onNew(this );
124: _freespaceManager.start(_systemData.freespaceAddress());
125: }
126:
127: private void newSystemData(byte freespaceSystem) {
128: _systemData = new SystemData();
129: _systemData.stringEncoding(configImpl().encoding());
130: _systemData.freespaceSystem(freespaceSystem);
131: }
132:
133: public int converterVersion() {
134: return _systemData.converterVersion();
135: }
136:
137: public abstract void copy(int oldAddress, int oldAddressOffset,
138: int newAddress, int newAddressOffset, int length);
139:
140: public long currentVersion() {
141: return _timeStampIdGenerator.lastTimeStampId();
142: }
143:
144: void initNewClassCollection() {
145: // overridden in YapObjectCarrier to do nothing
146: classCollection().initTables(1);
147: }
148:
149: public final BTree createBTreeClassIndex(int id) {
150: return new BTree(_transaction, id, new IDHandler(this ));
151: }
152:
153: public final AbstractQueryResult newQueryResult(Transaction trans) {
154: return newQueryResult(trans, config().queryEvaluationMode());
155: }
156:
157: public final AbstractQueryResult newQueryResult(Transaction trans,
158: QueryEvaluationMode mode) {
159: if (mode == QueryEvaluationMode.IMMEDIATE) {
160: return new IdListQueryResult(trans);
161: }
162: return new HybridQueryResult(trans, mode);
163: }
164:
165: public final boolean delete4(Transaction ta, ObjectReference yo,
166: int a_cascade, boolean userCall) {
167: int id = yo.getID();
168: StatefulBuffer reader = readWriterByID(ta, id);
169: if (reader != null) {
170: Object obj = yo.getObject();
171: if (obj != null) {
172: if ((!showInternalClasses())
173: && Const4.CLASS_INTERNAL.isAssignableFrom(obj
174: .getClass())) {
175: return false;
176: }
177: }
178: reader.setCascadeDeletes(a_cascade);
179: reader.slotDelete();
180: ClassMetadata yc = yo.classMetadata();
181: yc.delete(reader, obj);
182:
183: // The following will not work with this approach.
184: // Free blocks are identified in the Transaction by their ID.
185: // TODO: Add a second tree specifically to free pointers.
186:
187: // if(SecondClass.class.isAssignableFrom(yc.getJavaClass())){
188: // ta.freePointer(id);
189: // }
190:
191: return true;
192: }
193: return false;
194: }
195:
196: public abstract long fileLength();
197:
198: public abstract String fileName();
199:
200: public void free(Slot slot) {
201: if (slot.address() == 0) {
202: return;
203:
204: // TODO: This should really be an IllegalArgumentException but old database files
205: // with index-based FreespaceManagers appear to deliver zeroed slots.
206: // throw new IllegalArgumentException();
207: }
208: if (_freespaceManager == null) {
209: // Can happen on early free before freespacemanager
210: // is up, during conversion.
211: return;
212: }
213: Slot blockedSlot = toBlockedLength(slot);
214:
215: if (DTrace.enabled) {
216: DTrace.FILE_FREE.logLength(blockedSlot.address(),
217: blockedSlot.length());
218: }
219:
220: _freespaceManager.free(blockedSlot);
221:
222: }
223:
224: public Slot toBlockedLength(Slot slot) {
225: return new Slot(slot.address(), bytesToBlocks(slot.length()));
226: }
227:
228: public Slot toNonBlockedLength(Slot slot) {
229: return new Slot(slot.address(), blocksToBytes(slot.length()));
230: }
231:
232: public void free(int address, int a_length) {
233: free(new Slot(address, a_length));
234: }
235:
236: final void freePrefetchedPointers() {
237: if (i_prefetchedIDs != null) {
238: i_prefetchedIDs.traverse(new Visitor4() {
239:
240: public void visit(Object a_object) {
241: free(((TreeInt) a_object)._key,
242: Const4.POINTER_LENGTH);
243: }
244: });
245: }
246: i_prefetchedIDs = null;
247: }
248:
249: public void generateNewIdentity() {
250: synchronized (_lock) {
251: setIdentity(Db4oDatabase.generate());
252: }
253: }
254:
255: public AbstractQueryResult getAll(Transaction trans) {
256: return getAll(trans, config().queryEvaluationMode());
257: }
258:
259: public AbstractQueryResult getAll(Transaction trans,
260: QueryEvaluationMode mode) {
261: final AbstractQueryResult queryResult = newQueryResult(trans,
262: mode);
263: queryResult.loadFromClassIndexes(classCollection().iterator());
264: return queryResult;
265: }
266:
267: public final int getPointerSlot() {
268: int id = getSlot(Const4.POINTER_LENGTH).address();
269:
270: // write a zero pointer first
271: // to prevent delete interaction trouble
272: ((LocalTransaction) systemTransaction()).writeZeroPointer(id);
273:
274: // We have to make sure that object IDs do not collide
275: // with built-in type IDs.
276: if (_handlers.isSystemHandler(id)) {
277: return getPointerSlot();
278: }
279:
280: if (DTrace.enabled) {
281: DTrace.GET_POINTER_SLOT.log(id);
282: }
283:
284: return id;
285: }
286:
287: public Slot getSlot(int length) {
288: int blocks = bytesToBlocks(length);
289: Slot slot = getBlockedSlot(blocks);
290: if (DTrace.enabled) {
291: DTrace.GET_SLOT.logLength(slot.address(), slot.length());
292: }
293: return toNonBlockedLength(slot);
294: }
295:
296: private final Slot getBlockedSlot(int blocks) {
297: if (blocks <= 0) {
298: throw new IllegalArgumentException();
299: }
300: if (_freespaceManager != null) {
301: Slot slot = _freespaceManager.getSlot(blocks);
302: if (slot != null) {
303: return slot;
304: }
305: }
306: return appendBlocks(blocks);
307: }
308:
309: protected final Slot appendBlocks(int blockCount) {
310: int blockedStartAddress = _blockEndAddress;
311: int blockedEndAddress = _blockEndAddress + blockCount;
312: checkBlockedAddress(blockedEndAddress);
313: _blockEndAddress = blockedEndAddress;
314: Slot slot = new Slot(blockedStartAddress, blockCount);
315: if (Debug.xbytes && Deploy.overwrite) {
316: overwriteDeletedBlockedSlot(slot);
317: }
318: return slot;
319: }
320:
321: final Slot appendBytes(long bytes) {
322: Slot slot = appendBlocks(bytesToBlocks(bytes));
323: return toNonBlockedLength(slot);
324: }
325:
326: private void checkBlockedAddress(int blockedAddress) {
327: if (blockedAddress < 0) {
328: switchToReadOnlyMode();
329: throw new DatabaseMaximumSizeReachedException();
330: }
331: }
332:
333: private void switchToReadOnlyMode() {
334: _config.readOnly(true);
335: }
336:
337: // When a file gets opened, it uses the file size to determine where
338: // new slots can be appended. If this method would not be called, the
339: // freespace system could already contain a slot that points beyond
340: // the end of the file and this space could be allocated and used twice,
341: // for instance if a slot was allocated and freed without ever being
342: // written to file.
343: void ensureLastSlotWritten() {
344: if (!Debug.xbytes) {
345: if (Deploy.overwrite) {
346: if (_blockEndAddress > bytesToBlocks(fileLength())) {
347: StatefulBuffer writer = getWriter(
348: systemTransaction(), _blockEndAddress - 1,
349: blockSize());
350: writer.write();
351: }
352: }
353: }
354: }
355:
356: public Db4oDatabase identity() {
357: return _systemData.identity();
358: }
359:
360: public void setIdentity(Db4oDatabase identity) {
361: _systemData.identity(identity);
362:
363: // The dirty TimeStampIdGenerator triggers writing of
364: // the variable part of the systemdata. We need to
365: // make it dirty here, so the new identity is persisted:
366: _timeStampIdGenerator.next();
367: }
368:
369: void initialize2() {
370: i_dirty = new Collection4();
371: super .initialize2();
372: }
373:
374: boolean isServer() {
375: return i_isServer;
376: }
377:
378: public final Pointer4 newSlot(int length) {
379: return new Pointer4(getPointerSlot(), getSlot(length));
380: }
381:
382: public final int newUserObject() {
383: return getPointerSlot();
384: }
385:
386: public void prefetchedIDConsumed(int a_id) {
387: i_prefetchedIDs = i_prefetchedIDs.removeLike(new TreeIntObject(
388: a_id));
389: }
390:
391: public int prefetchID() {
392: int id = getPointerSlot();
393: i_prefetchedIDs = Tree.add(i_prefetchedIDs, new TreeInt(id));
394: return id;
395: }
396:
397: public ReferencedSlot produceFreeOnCommitEntry(int id) {
398: Tree node = TreeInt.find(_freeOnCommit, id);
399: if (node != null) {
400: return (ReferencedSlot) node;
401: }
402: ReferencedSlot slot = new ReferencedSlot(id);
403: _freeOnCommit = Tree.add(_freeOnCommit, slot);
404: return slot;
405: }
406:
407: public void reduceFreeOnCommitReferences(ReferencedSlot slot) {
408: if (slot.removeReferenceIsLast()) {
409: _freeOnCommit = _freeOnCommit.removeNode(slot);
410: }
411: }
412:
413: public void freeDuringCommit(ReferencedSlot referencedSlot,
414: Slot slot) {
415: _freeOnCommit = referencedSlot.free(this , _freeOnCommit, slot);
416: }
417:
418: public void raiseVersion(long a_minimumVersion) {
419: synchronized (lock()) {
420: _timeStampIdGenerator.setMinimumNext(a_minimumVersion);
421: }
422: }
423:
424: public StatefulBuffer readWriterByID(Transaction a_ta, int a_id) {
425: return (StatefulBuffer) readReaderOrWriterByID(a_ta, a_id,
426: false);
427: }
428:
429: public StatefulBuffer[] readWritersByIDs(Transaction a_ta,
430: int ids[]) {
431: StatefulBuffer[] yapWriters = new StatefulBuffer[ids.length];
432: for (int i = 0; i < ids.length; ++i) {
433: if (ids[i] == 0) {
434: yapWriters[i] = null;
435: } else {
436: yapWriters[i] = (StatefulBuffer) readReaderOrWriterByID(
437: a_ta, ids[i], false);
438: }
439: }
440: return yapWriters;
441: }
442:
443: public Buffer readReaderByID(Transaction a_ta, int a_id) {
444: return readReaderOrWriterByID(a_ta, a_id, true);
445: }
446:
447: private final Buffer readReaderOrWriterByID(Transaction a_ta,
448: int a_id, boolean useReader) {
449: if (a_id <= 0) {
450: throw new IllegalArgumentException();
451: }
452:
453: if (DTrace.enabled) {
454: DTrace.READ_ID.log(a_id);
455: }
456:
457: Slot slot = ((LocalTransaction) a_ta).getCurrentSlotOfID(a_id);
458: if (slot == null) {
459: return null;
460: }
461:
462: if (slot.address() == 0) {
463: return null;
464: }
465:
466: if (DTrace.enabled) {
467: DTrace.READ_SLOT.logLength(slot.address(), slot.length());
468: }
469:
470: Buffer reader = null;
471: if (useReader) {
472: reader = new Buffer(slot.length());
473: } else {
474: reader = getWriter(a_ta, slot.address(), slot.length());
475: ((StatefulBuffer) reader).setID(a_id);
476: }
477:
478: reader.readEncrypt(this , slot.address());
479: return reader;
480: }
481:
482: protected boolean doFinalize() {
483: return _fileHeader != null;
484: }
485:
486: void readThis() throws OldFormatException {
487:
488: newSystemData(AbstractFreespaceManager.FM_LEGACY_RAM);
489: blockSizeReadFromFile(1);
490:
491: _fileHeader = FileHeader.readFixedPart(this );
492:
493: createStringIO(_systemData.stringEncoding());
494:
495: classCollection().setID(_systemData.classCollectionID());
496: classCollection().read(systemTransaction());
497:
498: Converter
499: .convert(new ConversionStage.ClassCollectionAvailableStage(
500: this ));
501:
502: readHeaderVariablePart();
503:
504: if (!_config.isReadOnly()) {
505: _freespaceManager = AbstractFreespaceManager.createNew(
506: this , _systemData.freespaceSystem());
507: _freespaceManager.read(_systemData.freespaceID());
508: _freespaceManager.start(_systemData.freespaceAddress());
509: }
510:
511: if (needFreespaceMigration()) {
512: migrateFreespace();
513: }
514:
515: if (_config.isReadOnly()) {
516: return;
517: }
518:
519: writeHeader(true, false);
520:
521: LocalTransaction trans = (LocalTransaction) _fileHeader
522: .interruptedTransaction();
523:
524: if (trans != null) {
525: if (!configImpl().commitRecoveryDisabled()) {
526: trans.writeOld();
527: }
528: }
529:
530: if (Converter.convert(new ConversionStage.SystemUpStage(this ))) {
531: _systemData.converterVersion(Converter.VERSION);
532: _fileHeader.writeVariablePart(this , 1);
533: transaction().commit();
534: }
535:
536: }
537:
538: private boolean needFreespaceMigration() {
539: byte readSystem = _systemData.freespaceSystem();
540: byte configuredSystem = configImpl().freespaceSystem();
541: return (configuredSystem != 0 || readSystem == AbstractFreespaceManager.FM_LEGACY_RAM)
542: && (_freespaceManager.systemType() != configuredSystem);
543: }
544:
545: private void migrateFreespace() {
546: FreespaceManager oldFreespaceManager = _freespaceManager;
547: _freespaceManager = AbstractFreespaceManager.createNew(this ,
548: configImpl().freespaceSystem());
549: systemData().freespaceAddress(0);
550: systemData().freespaceSystem(configImpl().freespaceSystem());
551: _freespaceManager.start(_freespaceManager.onNew(this ));
552: AbstractFreespaceManager.migrate(oldFreespaceManager,
553: _freespaceManager);
554: _fileHeader.writeVariablePart(this , 1);
555: }
556:
557: private void readHeaderVariablePart() {
558: _fileHeader.readVariablePart(this );
559: setNextTimeStampId(systemData().lastTimeStampID());
560: }
561:
562: public final int createFreespaceSlot(byte freespaceSystem) {
563: _systemData.freespaceAddress(AbstractFreespaceManager
564: .initSlot(this ));
565: _systemData.freespaceSystem(freespaceSystem);
566: return _systemData.freespaceAddress();
567: }
568:
569: public int ensureFreespaceSlot() {
570: int address = systemData().freespaceAddress();
571: if (address == 0) {
572: return createFreespaceSlot(systemData().freespaceSystem());
573: }
574: return address;
575: }
576:
577: public final void releaseSemaphore(String name) {
578: releaseSemaphore(null, name);
579: }
580:
581: public final void releaseSemaphore(Transaction trans, String name) {
582: synchronized (_lock) {
583: if (i_semaphores == null) {
584: return;
585: }
586: }
587: synchronized (i_semaphores) {
588: trans = checkTransaction(trans);
589: if (i_semaphores != null && trans == i_semaphores.get(name)) {
590: i_semaphores.remove(name);
591: i_semaphores.notifyAll();
592: }
593: }
594: }
595:
596: public void releaseSemaphores(Transaction ta) {
597: if (i_semaphores != null) {
598: final Hashtable4 semaphores = i_semaphores;
599: synchronized (semaphores) {
600: semaphores.forEachKeyForIdentity(new Visitor4() {
601: public void visit(Object a_object) {
602: semaphores.remove(a_object);
603: }
604: }, ta);
605: semaphores.notifyAll();
606: }
607: }
608: }
609:
610: public final void rollback1(Transaction trans) {
611: trans.rollback();
612: }
613:
614: public final void setDirtyInSystemTransaction(
615: PersistentBase a_object) {
616: a_object.setStateDirty();
617: a_object.cacheDirty(i_dirty);
618: }
619:
620: public final boolean setSemaphore(String name, int timeout) {
621: return setSemaphore(null, name, timeout);
622: }
623:
624: public final boolean setSemaphore(Transaction trans, String name,
625: int timeout) {
626: if (name == null) {
627: throw new NullPointerException();
628: }
629: synchronized (_lock) {
630: if (i_semaphores == null) {
631: i_semaphores = new Hashtable4(10);
632: }
633: }
634: synchronized (i_semaphores) {
635: trans = checkTransaction(trans);
636: Object obj = i_semaphores.get(name);
637: if (obj == null) {
638: i_semaphores.put(name, trans);
639: return true;
640: }
641: if (trans == obj) {
642: return true;
643: }
644: long endtime = System.currentTimeMillis() + timeout;
645: long waitTime = timeout;
646: while (waitTime > 0) {
647: try {
648: i_semaphores.wait(waitTime);
649: } catch (InterruptedException e) {
650: // ignore
651: }
652: if (classCollection() == null) {
653: return false;
654: }
655:
656: obj = i_semaphores.get(name);
657:
658: if (obj == null) {
659: i_semaphores.put(name, trans);
660: return true;
661: }
662:
663: waitTime = endtime - System.currentTimeMillis();
664: }
665: return false;
666: }
667: }
668:
669: public void setServer(boolean flag) {
670: i_isServer = flag;
671: }
672:
673: public abstract void syncFiles();
674:
675: public String toString() {
676: if (Debug4.prettyToStrings) {
677: return super .toString();
678: }
679: return fileName();
680: }
681:
682: public void shutdown() {
683: writeHeader(false, true);
684: }
685:
686: public final void commitTransaction() {
687: _transaction.commit();
688: }
689:
690: public abstract void writeBytes(Buffer a_Bytes, int address,
691: int addressOffset);
692:
693: public final void writeDirty() {
694: writeCachedDirty();
695: writeVariableHeader();
696: }
697:
698: private void writeCachedDirty() {
699: Iterator4 i = i_dirty.iterator();
700: while (i.moveNext()) {
701: PersistentBase dirty = (PersistentBase) i.current();
702: dirty.write(systemTransaction());
703: dirty.notCachedDirty();
704: }
705: i_dirty.clear();
706: }
707:
708: public final void writeEncrypt(Buffer buffer, int address,
709: int addressOffset) {
710: _handlers.encrypt(buffer);
711: writeBytes(buffer, address, addressOffset);
712: _handlers.decrypt(buffer);
713: }
714:
715: protected void writeVariableHeader() {
716: if (!_timeStampIdGenerator.isDirty()) {
717: return;
718: }
719: _systemData.lastTimeStampID(_timeStampIdGenerator
720: .lastTimeStampId());
721: _fileHeader.writeVariablePart(this , 2);
722: _timeStampIdGenerator.setClean();
723: }
724:
725: void writeHeader(boolean startFileLockingThread,
726: boolean shuttingDown) {
727:
728: int freespaceID = DEFAULT_FREESPACE_ID;
729: if (shuttingDown) {
730: freespaceID = _freespaceManager.write();
731: _freespaceManager = null;
732: }
733:
734: StatefulBuffer writer = getWriter(systemTransaction(), 0,
735: _fileHeader.length());
736:
737: _fileHeader.writeFixedPart(this , startFileLockingThread,
738: shuttingDown, writer, blockSize(), freespaceID);
739:
740: if (shuttingDown) {
741: ensureLastSlotWritten();
742: }
743: syncFiles();
744: }
745:
746: public final void writeNew(Transaction trans, Pointer4 pointer,
747: ClassMetadata classMetadata, Buffer buffer) {
748: writeEncrypt(buffer, pointer.address(), 0);
749: if (classMetadata == null) {
750: return;
751: }
752: if (maintainsIndices()) {
753: classMetadata.addToIndex(this , trans, pointer.id());
754: }
755: }
756:
757: // This is a reroute of writeBytes to write the free blocks
758: // unchecked.
759:
760: public abstract void overwriteDeletedBytes(int address, int length);
761:
762: public void overwriteDeletedBlockedSlot(Slot slot) {
763: overwriteDeletedBytes(slot.address(), blocksToBytes(slot
764: .length()));
765: }
766:
767: public final void writeTransactionPointer(int address) {
768: _fileHeader.writeTransactionPointer(systemTransaction(),
769: address);
770: }
771:
772: public final void getSlotForUpdate(StatefulBuffer buffer) {
773: Slot slot = getSlotForUpdate(buffer.getTransaction(), buffer
774: .getID(), buffer.length());
775: buffer.address(slot.address());
776: }
777:
778: public final Slot getSlotForUpdate(Transaction trans, int id,
779: int length) {
780: Slot slot = getSlot(length);
781: trans.produceUpdateSlotChange(id, slot);
782: return slot;
783: }
784:
785: public final void writeUpdate(Transaction trans, Pointer4 pointer,
786: ClassMetadata classMetadata, Buffer buffer) {
787: int address = pointer.address();
788: if (address == 0) {
789: address = getSlotForUpdate(trans, pointer.id(),
790: pointer.length()).address();
791: }
792: writeEncrypt(buffer, address, 0);
793: }
794:
795: public void setNextTimeStampId(long val) {
796: _timeStampIdGenerator.setMinimumNext(val);
797: _timeStampIdGenerator.setClean();
798: }
799:
800: public SystemInfo systemInfo() {
801: return new SystemInfoFileImpl(this );
802: }
803:
804: public FileHeader getFileHeader() {
805: return _fileHeader;
806: }
807:
808: public void installDebugFreespaceManager(
809: AbstractFreespaceManager manager) {
810: _freespaceManager = manager;
811: }
812:
813: public SystemData systemData() {
814: return _systemData;
815: }
816:
817: public long[] getIDsForClass(Transaction trans, ClassMetadata clazz) {
818: final IntArrayList ids = new IntArrayList();
819: clazz.index().traverseAll(trans, new Visitor4() {
820: public void visit(Object obj) {
821: ids.add(((Integer) obj).intValue());
822: }
823: });
824: return ids.asLong();
825: }
826:
827: public QueryResult classOnlyQuery(Transaction trans,
828: ClassMetadata clazz) {
829: if (!clazz.hasClassIndex()) {
830:
831: // TODO: If the class does not have an index, we won't be
832: // able to get objects for it, so why not return an
833: // empty QueryResult here, to signal that no further
834: // processing needs to take place?
835: return null;
836: }
837:
838: final AbstractQueryResult queryResult = newQueryResult(trans);
839: queryResult.loadFromClassIndex(clazz);
840: return queryResult;
841: }
842:
843: public QueryResult executeQuery(QQuery query) {
844: AbstractQueryResult queryResult = newQueryResult(query
845: .getTransaction());
846: queryResult.loadFromQuery(query);
847: return queryResult;
848: }
849:
850: public LocalTransaction getLocalSystemTransaction() {
851: return (LocalTransaction) systemTransaction();
852: }
853:
854: public void onCommittedListener() {
855: // do nothing
856: }
857:
858: }
|