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.defragment;
022:
023: import java.io.*;
024:
025: import com.db4o.*;
026: import com.db4o.config.*;
027: import com.db4o.ext.*;
028: import com.db4o.foundation.*;
029: import com.db4o.foundation.io.*;
030: import com.db4o.internal.*;
031: import com.db4o.internal.btree.*;
032: import com.db4o.internal.classindex.*;
033: import com.db4o.internal.handlers.*;
034: import com.db4o.internal.mapping.*;
035: import com.db4o.internal.marshall.*;
036: import com.db4o.internal.slots.*;
037:
038: /**
039: * @exclude
040: */
041: public class DefragContextImpl implements DefragContext {
042:
043: public static abstract class DbSelector {
044: DbSelector() {
045: }
046:
047: abstract LocalObjectContainer db(DefragContextImpl context);
048:
049: Transaction transaction(DefragContextImpl context) {
050: return db(context).systemTransaction();
051: }
052: }
053:
054: public final static DbSelector SOURCEDB = new DbSelector() {
055: LocalObjectContainer db(DefragContextImpl context) {
056: return context._sourceDb;
057: }
058: };
059:
060: public final static DbSelector TARGETDB = new DbSelector() {
061: LocalObjectContainer db(DefragContextImpl context) {
062: return context._targetDb;
063: }
064: };
065:
066: private static final long CLASSCOLLECTION_POINTER_ADDRESS = 2 + 2 * Const4.INT_LENGTH;
067:
068: public final LocalObjectContainer _sourceDb;
069: final LocalObjectContainer _targetDb;
070: private final ContextIDMapping _mapping;
071: private DefragmentListener _listener;
072: private Queue4 _unindexed = new NonblockingQueue();
073: private final Hashtable4 _hasFieldIndexCache = new Hashtable4();
074:
075: public DefragContextImpl(DefragmentConfig defragConfig,
076: DefragmentListener listener) {
077: _listener = listener;
078: Config4Impl originalConfig = (Config4Impl) defragConfig
079: .db4oConfig();
080: Configuration sourceConfig = (Configuration) originalConfig
081: .deepClone(null);
082: sourceConfig.weakReferences(false);
083: sourceConfig.flushFileBuffers(false);
084: sourceConfig.readOnly(true);
085: _sourceDb = (LocalObjectContainer) Db4o.openFile(sourceConfig,
086: defragConfig.tempPath()).ext();
087: _targetDb = freshYapFile(defragConfig);
088: _mapping = defragConfig.mapping();
089: _mapping.open();
090: }
091:
092: static LocalObjectContainer freshYapFile(String fileName,
093: int blockSize) {
094: File4.delete(fileName);
095: return (LocalObjectContainer) Db4o
096: .openFile(
097: DefragmentConfig.vanillaDb4oConfig(blockSize),
098: fileName).ext();
099: }
100:
101: static LocalObjectContainer freshYapFile(DefragmentConfig config) {
102: File4.delete(config.origPath());
103: return (LocalObjectContainer) Db4o.openFile(
104: config.clonedDb4oConfig(), config.origPath()).ext();
105: }
106:
107: public int mappedID(int oldID, int defaultID) {
108: int mapped = internalMappedID(oldID, false);
109: return (mapped != 0 ? mapped : defaultID);
110: }
111:
112: public int mappedID(int oldID) throws MappingNotFoundException {
113: int mapped = internalMappedID(oldID, false);
114: if (mapped == 0) {
115: throw new MappingNotFoundException(oldID);
116: }
117: return mapped;
118: }
119:
120: public int mappedID(int id, boolean lenient)
121: throws MappingNotFoundException {
122: if (id == 0) {
123: return 0;
124: }
125: int mapped = internalMappedID(id, lenient);
126: if (mapped == 0) {
127: _listener.notifyDefragmentInfo(new DefragmentInfo(
128: "No mapping found for ID " + id));
129: return 0;
130: }
131: return mapped;
132: }
133:
134: private int internalMappedID(int oldID, boolean lenient)
135: throws MappingNotFoundException {
136: if (oldID == 0) {
137: return 0;
138: }
139: if (_sourceDb.handlers().isSystemHandler(oldID)) {
140: return oldID;
141: }
142: return _mapping.mappedID(oldID, lenient);
143: }
144:
145: public void mapIDs(int oldID, int newID, boolean isClassID) {
146: _mapping.mapIDs(oldID, newID, isClassID);
147: }
148:
149: public void close() {
150: _sourceDb.close();
151: _targetDb.close();
152: _mapping.close();
153: }
154:
155: public Buffer bufferByID(DbSelector selector, int id) {
156: Slot slot = readPointer(selector, id);
157: return bufferByAddress(selector, slot.address(), slot.length());
158: }
159:
160: public Buffer sourceBufferByAddress(int address, int length)
161: throws IOException {
162: return bufferByAddress(SOURCEDB, address, length);
163: }
164:
165: public Buffer targetBufferByAddress(int address, int length)
166: throws IOException {
167: return bufferByAddress(TARGETDB, address, length);
168: }
169:
170: public Buffer bufferByAddress(DbSelector selector, int address,
171: int length) {
172: return selector.db(this ).bufferByAddress(address, length);
173: }
174:
175: public StatefulBuffer targetStatefulBufferByAddress(int address,
176: int length) throws IllegalArgumentException {
177: return _targetDb.readWriterByAddress(
178: TARGETDB.transaction(this ), address, length);
179: }
180:
181: public Slot allocateTargetSlot(int length) {
182: return _targetDb.getSlot(length);
183: }
184:
185: public void targetWriteBytes(BufferPair readers, int address) {
186: readers.write(_targetDb, address);
187: }
188:
189: public void targetWriteBytes(Buffer reader, int address) {
190: _targetDb.writeBytes(reader, address, 0);
191: }
192:
193: public StoredClass[] storedClasses(DbSelector selector) {
194: LocalObjectContainer db = selector.db(this );
195: db.showInternalClasses(true);
196: try {
197: return db.classCollection().storedClasses();
198: } finally {
199: db.showInternalClasses(false);
200: }
201: }
202:
203: public LatinStringIO stringIO() {
204: return _sourceDb.stringIO();
205: }
206:
207: public void targetCommit() {
208: _targetDb.commit();
209: }
210:
211: public TypeHandler4 sourceHandler(int id) {
212: return _sourceDb.handlerByID(id);
213: }
214:
215: public int sourceClassCollectionID() {
216: return _sourceDb.classCollection().getID();
217: }
218:
219: public static void targetClassCollectionID(String file, int id)
220: throws IOException {
221: RandomAccessFile raf = new RandomAccessFile(file, "rw");
222: try {
223: Buffer reader = new Buffer(Const4.INT_LENGTH);
224:
225: raf.seek(CLASSCOLLECTION_POINTER_ADDRESS);
226: reader._offset = 0;
227: reader.writeInt(id);
228: raf.write(reader._buffer);
229: } finally {
230: raf.close();
231: }
232: }
233:
234: private Hashtable4 _classIndices = new Hashtable4(16);
235:
236: public int classIndexID(ClassMetadata yapClass) {
237: return classIndex(yapClass).id();
238: }
239:
240: public void traverseAll(ClassMetadata yapClass, Visitor4 command) {
241: if (!yapClass.hasClassIndex()) {
242: return;
243: }
244: yapClass.index().traverseAll(SOURCEDB.transaction(this ),
245: command);
246: }
247:
248: public void traverseAllIndexSlots(ClassMetadata yapClass,
249: Visitor4 command) {
250: Iterator4 slotIDIter = yapClass.index().allSlotIDs(
251: SOURCEDB.transaction(this ));
252: while (slotIDIter.moveNext()) {
253: command.visit(slotIDIter.current());
254: }
255: }
256:
257: public void traverseAllIndexSlots(BTree btree, Visitor4 command) {
258: Iterator4 slotIDIter = btree.allNodeIds(SOURCEDB
259: .transaction(this ));
260: while (slotIDIter.moveNext()) {
261: command.visit(slotIDIter.current());
262: }
263: }
264:
265: public int databaseIdentityID(DbSelector selector) {
266: LocalObjectContainer db = selector.db(this );
267: Db4oDatabase identity = db.identity();
268: if (identity == null) {
269: return 0;
270: }
271: return identity.getID(selector.transaction(this ));
272: }
273:
274: private ClassIndexStrategy classIndex(ClassMetadata yapClass) {
275: ClassIndexStrategy classIndex = (ClassIndexStrategy) _classIndices
276: .get(yapClass);
277: if (classIndex == null) {
278: classIndex = new BTreeClassIndexStrategy(yapClass);
279: _classIndices.put(yapClass, classIndex);
280: classIndex.initialize(_targetDb);
281: }
282: return classIndex;
283: }
284:
285: public Transaction systemTrans() {
286: return SOURCEDB.transaction(this );
287: }
288:
289: public void copyIdentity() {
290: _targetDb.setIdentity(_sourceDb.identity());
291: }
292:
293: public void targetClassCollectionID(int newClassCollectionID) {
294: _targetDb.systemData().classCollectionID(newClassCollectionID);
295: }
296:
297: public Buffer sourceBufferByID(int sourceID) throws IOException {
298: return bufferByID(SOURCEDB, sourceID);
299: }
300:
301: public BTree sourceUuidIndex() {
302: if (sourceUuidIndexID() == 0) {
303: return null;
304: }
305: return _sourceDb.uUIDIndex().getIndex(systemTrans());
306: }
307:
308: public void targetUuidIndexID(int id) {
309: _targetDb.systemData().uuidIndexId(id);
310: }
311:
312: public int sourceUuidIndexID() {
313: return _sourceDb.systemData().uuidIndexId();
314: }
315:
316: public ClassMetadata yapClass(int id) {
317: return _sourceDb.classMetadataForId(id);
318: }
319:
320: public void registerUnindexed(int id) {
321: _unindexed.add(new Integer(id));
322: }
323:
324: public Iterator4 unindexedIDs() {
325: return _unindexed.iterator();
326: }
327:
328: public ObjectHeader sourceObjectHeader(Buffer buffer) {
329: return new ObjectHeader(_sourceDb, buffer);
330: }
331:
332: private Slot readPointer(DbSelector selector, int id) {
333: Buffer reader = bufferByAddress(selector, id,
334: Const4.POINTER_LENGTH);
335: if (Deploy.debug) {
336: reader.readBegin(Const4.YAPPOINTER);
337: }
338: int address = reader.readInt();
339: int length = reader.readInt();
340: if (Deploy.debug) {
341: reader.readEnd();
342: }
343: return new Slot(address, length);
344: }
345:
346: public boolean hasFieldIndex(ClassMetadata clazz) {
347: // actually only two states are used here, the third is implicit in null
348: TernaryBool cachedHasFieldIndex = ((TernaryBool) _hasFieldIndexCache
349: .get(clazz));
350: if (cachedHasFieldIndex != null) {
351: return cachedHasFieldIndex.definiteYes();
352: }
353: boolean hasFieldIndex = false;
354: Iterator4 fieldIter = clazz.fields();
355: while (fieldIter.moveNext()) {
356: FieldMetadata curField = (FieldMetadata) fieldIter
357: .current();
358: if (curField.hasIndex()
359: && (curField.getHandler() instanceof StringHandler)) {
360: hasFieldIndex = true;
361: break;
362: }
363: }
364: _hasFieldIndexCache.put(clazz, TernaryBool
365: .forBoolean(hasFieldIndex));
366: return hasFieldIndex;
367: }
368:
369: public int blockSize() {
370: return _sourceDb.config().blockSize();
371: }
372:
373: public int sourceAddressByID(int sourceID) {
374: return readPointer(SOURCEDB, sourceID).address();
375: }
376:
377: }
|