KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > db4o > defragment > Defragment


1 /* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com
2
3 This file is part of the db4o open source object database.
4
5 db4o is free software; you can redistribute it and/or modify it under
6 the terms of version 2 of the GNU General Public License as published
7 by the Free Software Foundation and as clarified by db4objects' GPL
8 interpretation policy, available at
9 http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
10 Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
11 Suite 350, San Mateo, CA 94403, USA.
12
13 db4o is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

21 package com.db4o.defragment;
22
23 import java.io.*;
24
25 import com.db4o.*;
26 import com.db4o.ext.*;
27 import com.db4o.foundation.*;
28 import com.db4o.foundation.io.*;
29 import com.db4o.inside.btree.*;
30 import com.db4o.inside.classindex.*;
31
32 /**
33  * defragments database files.
34  *
35  * <br><br>db4o structures storage inside database files as free and occupied slots, very
36  * much like a file system - and just like a file system it can be fragmented.<br><br>
37  *
38  * The simplest way to defragment a database file:<br><br>
39  *
40  * <code>Defragment.defrag("sample.yap");</code><br><br>
41  *
42  * This will move the file to "sample.yap.backup", then create a defragmented
43  * version of this file in the original position, using a temporary file
44  * "sample.yap.mapping". If the backup file already exists, this will throw an
45  * exception and no action will be taken.<br><br>
46  *
47  * For more detailed configuration of the defragmentation process, provide a
48  * DefragmentConfig instance:<br><br>
49  *
50  * <code>DefragmentConfig config=new DefragmentConfig("sample.yap","sample.bap","sample.map");<br>
51  * config.forceBackupDelete(true);<br>
52  * config.yapClassFilter(new AvailableClassFilter());<br>
53  * Defragment.defrag(config);</code><br><br>
54  *
55  * This will move the file to "sample.bap", then create a defragmented version
56  * of this file in the original position, using a temporary file "sample.map".
57  * If the backup file already exists, it will be deleted. The defragmentation
58  * process will skip all classes that have instances stored within the yap file,
59  * but that are not available on the class path (through the current
60  * classloader).
61  */

62 public class Defragment {
63
64     /**
65      * Renames the file at the given original path to a backup file and then
66      * builds a defragmented version of the file in the original place.
67      *
68      * @param origPath
69      * The path to the file to be defragmented.
70      * @throws IOException
71      * if the original file cannot be moved to the backup location
72      */

73     public static void defrag(String JavaDoc origPath) throws IOException {
74         defrag(new DefragmentConfig(origPath), new NullListener());
75     }
76
77     /**
78      * Renames the file at the given original path to the given backup file and
79      * then builds a defragmented version of the file in the original place.
80      *
81      * @param origPath
82      * The path to the file to be defragmented.
83      * @param backupPath
84      * The path to the backup file to be created.
85      * @throws IOException
86      * if the original file cannot be moved to the backup location
87      */

88     public static void defrag(String JavaDoc origPath, String JavaDoc backupPath)
89             throws IOException {
90         defrag(new DefragmentConfig(origPath, backupPath), new NullListener());
91     }
92
93     /**
94      * Renames the file at the configured original path to the configured backup
95      * path and then builds a defragmented version of the file in the original
96      * place.
97      *
98      * @param config
99      * The configuration for this defragmentation run.
100      * @throws IOException
101      * if the original file cannot be moved to the backup location
102      */

103     public static void defrag(DefragmentConfig config) throws IOException {
104         defrag(config, new NullListener());
105     }
106
107     /**
108      * Renames the file at the configured original path to the configured backup
109      * path and then builds a defragmented version of the file in the original
110      * place.
111      *
112      * @param config
113      * The configuration for this defragmentation run.
114      * @param listener
115      * A listener for status notifications during the defragmentation
116      * process.
117      * @throws IOException
118      * if the original file cannot be moved to the backup location
119      */

120     public static void defrag(DefragmentConfig config, DefragmentListener listener) throws IOException {
121         File backupFile = new File(config.backupPath());
122         if (backupFile.exists()) {
123             if (!config.forceBackupDelete()) {
124                 throw new IOException("Could not use '" + config.backupPath()
125                         + "' as backup path - file exists.");
126             }
127             backupFile.delete();
128         }
129         File4.rename(config.origPath(), config.backupPath());
130         DefragContextImpl context = new DefragContextImpl(config, listener);
131         int newClassCollectionID = 0;
132         int targetIdentityID = 0;
133         int targetUuidIndexID = 0;
134         try {
135             firstPass(context, config);
136             secondPass(context, config);
137             defragUnindexed(context);
138             newClassCollectionID = context.mappedID(context
139                     .sourceClassCollectionID());
140             int sourceIdentityID = context
141                     .databaseIdentityID(DefragContextImpl.SOURCEDB);
142             targetIdentityID = context.mappedID(sourceIdentityID);
143             context.targetClassCollectionID(newClassCollectionID);
144             targetUuidIndexID = context
145                     .mappedID(context.sourceUuidIndexID(), 0);
146         } catch (CorruptionException exc) {
147             exc.printStackTrace();
148         } finally {
149             context.close();
150         }
151         setIdentity(config.origPath(), targetIdentityID, targetUuidIndexID);
152     }
153
154     private static void defragUnindexed(DefragContextImpl context)
155             throws CorruptionException {
156         Iterator4 unindexedIDs = context.unindexedIDs();
157         while (unindexedIDs.moveNext()) {
158             final int origID = ((Integer JavaDoc) unindexedIDs.current()).intValue();
159             ReaderPair.processCopy(context, origID, new SlotCopyHandler() {
160                 public void processCopy(ReaderPair readers)
161                         throws CorruptionException {
162                     YapClass.defragObject(readers);
163                 }
164
165             }, true);
166         }
167     }
168
169     private static void setIdentity(String JavaDoc targetFile, int targetIdentityID,
170             int targetUuidIndexID) {
171         YapFile targetDB = (YapFile) Db4o.openFile(DefragmentConfig
172                 .vanillaDb4oConfig(), targetFile);
173         try {
174             Db4oDatabase identity = (Db4oDatabase) targetDB
175                     .getByID(targetIdentityID);
176             targetDB.setIdentity(identity);
177             targetDB.systemData().uuidIndexId(targetUuidIndexID);
178         } finally {
179             targetDB.close();
180         }
181     }
182
183     private static void firstPass(DefragContextImpl context,
184             DefragmentConfig config) throws CorruptionException {
185         // System.out.println("FIRST");
186
pass(context, config, new FirstPassCommand());
187     }
188
189     private static void secondPass(final DefragContextImpl context,
190             DefragmentConfig config) throws CorruptionException {
191         // System.out.println("SECOND");
192
pass(context, config, new SecondPassCommand());
193     }
194
195     private static void pass(DefragContextImpl context,
196             DefragmentConfig config, PassCommand command)
197             throws CorruptionException {
198         command.processClassCollection(context);
199         StoredClass[] classes = context
200                 .storedClasses(DefragContextImpl.SOURCEDB);
201         for (int classIdx = 0; classIdx < classes.length; classIdx++) {
202             YapClass yapClass = (YapClass) classes[classIdx];
203             if (!config.storedClassFilter().accept(yapClass)) {
204                 continue;
205             }
206             processYapClass(context, yapClass, command);
207             command.flush(context);
208         }
209         BTree uuidIndex = context.sourceUuidIndex();
210         if (uuidIndex != null) {
211             command.processBTree(context, uuidIndex);
212         }
213         command.flush(context);
214         context.targetCommit();
215     }
216
217     // TODO order of class index/object slot processing is crucial:
218
// - object slots before field indices (object slots register addresses for
219
// use by string indices)
220
// - class index before object slots, otherwise phantom btree entries from
221
// deletions appear in the source class index?!?
222
// reproducable with SelectiveCascadingDeleteTestCase and ObjectSetTestCase
223
// - investigate.
224
private static void processYapClass(final DefragContextImpl context,
225             final YapClass curClass, final PassCommand command)
226             throws CorruptionException {
227         processClassIndex(context, curClass, command);
228         if (!parentHasIndex(curClass)) {
229             processObjectsForYapClass(context, curClass, command);
230         }
231         processYapClassAndFieldIndices(context, curClass, command);
232     }
233
234     private static boolean parentHasIndex(YapClass curClass) {
235         YapClass parentClass = curClass.i_ancestor;
236         while (parentClass != null) {
237             if (parentClass.hasIndex()) {
238                 return true;
239             }
240             parentClass = parentClass.i_ancestor;
241         }
242         return false;
243     }
244
245     private static void processObjectsForYapClass(
246             final DefragContextImpl context, final YapClass curClass,
247             final PassCommand command) {
248         final boolean withStringIndex = withFieldIndex(curClass);
249         context.traverseAll(curClass, new Visitor4() {
250             public void visit(Object JavaDoc obj) {
251                 int id = ((Integer JavaDoc) obj).intValue();
252                 try {
253                     command.processObjectSlot(context, curClass, id,
254                             withStringIndex);
255                 } catch (CorruptionException e) {
256                     e.printStackTrace();
257                 }
258             }
259         });
260     }
261
262     private static boolean withFieldIndex(YapClass clazz) {
263         Iterator4 fieldIter = clazz.fields();
264         while (fieldIter.moveNext()) {
265             YapField curField = (YapField) fieldIter.current();
266             if (curField.hasIndex()
267                     && (curField.getHandler() instanceof YapString)) {
268                 return true;
269             }
270         }
271         return false;
272     }
273
274     private static void processYapClassAndFieldIndices(
275             final DefragContextImpl context, final YapClass curClass,
276             final PassCommand command) throws CorruptionException {
277         int sourceClassIndexID = 0;
278         int targetClassIndexID = 0;
279         if (curClass.hasIndex()) {
280             sourceClassIndexID = curClass.index().id();
281             targetClassIndexID = context.mappedID(sourceClassIndexID, -1);
282         }
283         command.processClass(context, curClass, curClass.getID(),
284                 targetClassIndexID);
285     }
286
287     private static void processClassIndex(final DefragContextImpl context,
288             final YapClass curClass, final PassCommand command)
289             throws CorruptionException {
290         if (curClass.hasIndex()) {
291             BTreeClassIndexStrategy indexStrategy = (BTreeClassIndexStrategy) curClass
292                     .index();
293             final BTree btree = indexStrategy.btree();
294             command.processBTree(context, btree);
295         }
296     }
297
298     static class NullListener implements DefragmentListener {
299         public void notifyDefragmentInfo(DefragmentInfo info) {
300         }
301     }
302 }
303
Popular Tags