KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > persist > DataFileDefrag


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb.persist;
33
34 import java.io.BufferedOutputStream JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.OutputStream JavaDoc;
37
38 import org.hsqldb.Database;
39 import org.hsqldb.HsqlException;
40 import org.hsqldb.Session;
41 import org.hsqldb.Table;
42 import org.hsqldb.Trace;
43 import org.hsqldb.index.RowIterator;
44 import org.hsqldb.lib.DoubleIntIndex;
45 import org.hsqldb.lib.HsqlArrayList;
46 import org.hsqldb.lib.StopWatch;
47 import org.hsqldb.lib.Storage;
48 import org.hsqldb.rowio.RowInputInterface;
49 import org.hsqldb.rowio.RowOutputBinary;
50
51 // oj@openoffice.org - changed to file access api
52

53 /**
54  * Routine to defrag the *.data file.
55  *
56  * This method iterates over the primary index of a table to find the
57  * disk position for each row and stores it, together with the new position
58  * in an array.
59  *
60  * A second pass over the primary index writes each row to the new disk
61  * image after translating the old pointers to the new.
62  *
63  * @author fredt@users
64  * @version 1.8.0
65  * @since 1.7.2
66  */

67 final class DataFileDefrag {
68
69     BufferedOutputStream JavaDoc fileStreamOut;
70     long fileOffset;
71     StopWatch stopw = new StopWatch();
72     String JavaDoc filename;
73     int[][] rootsList;
74     Database database;
75     DataFileCache cache;
76     int scale;
77     DoubleIntIndex transactionRowLookup;
78
79     DataFileDefrag(Database db, DataFileCache cache, String JavaDoc filename) {
80
81         this.database = db;
82         this.cache = cache;
83         this.scale = cache.cacheFileScale;
84         this.filename = filename;
85     }
86
87     void process() throws HsqlException, IOException JavaDoc {
88
89         boolean complete = false;
90
91         Trace.printSystemOut("Defrag Transfer begins");
92
93         transactionRowLookup = database.txManager.getTransactionIDList();
94
95         HsqlArrayList allTables = database.schemaManager.getAllTables();
96
97         rootsList = new int[allTables.size()][];
98
99         Storage dest = null;
100
101         try {
102             OutputStream JavaDoc fos =
103                 database.getFileAccess().openOutputStreamElement(filename
104                     + ".new");
105
106             fileStreamOut = new BufferedOutputStream JavaDoc(fos, 1 << 12);
107
108             for (int i = 0; i < DataFileCache.INITIAL_FREE_POS; i++) {
109                 fileStreamOut.write(0);
110             }
111
112             fileOffset = DataFileCache.INITIAL_FREE_POS;
113
114             for (int i = 0, tSize = allTables.size(); i < tSize; i++) {
115                 Table t = (Table) allTables.get(i);
116
117                 if (t.getTableType() == Table.CACHED_TABLE) {
118                     int[] rootsArray = writeTableToDataFile(t);
119
120                     rootsList[i] = rootsArray;
121                 } else {
122                     rootsList[i] = null;
123                 }
124
125                 Trace.printSystemOut(t.getName().name + " complete");
126             }
127
128             writeTransactionRows();
129             fileStreamOut.close();
130
131             fileStreamOut = null;
132
133             // write out the end of file position
134
dest = ScaledRAFile.newScaledRAFile(
135                 database, filename
136                 + ".new", false, ScaledRAFile.DATA_FILE_RAF, database
137                     .getURLProperties().getProperty(
138                         "storage_class_name"), database.getURLProperties()
139                             .getProperty("storage_key"));
140
141             dest.seek(DataFileCache.LONG_FREE_POS_POS);
142             dest.writeLong(fileOffset);
143             dest.close();
144
145             dest = null;
146
147             for (int i = 0, size = rootsList.length; i < size; i++) {
148                 int[] roots = rootsList[i];
149
150                 if (roots != null) {
151                     Trace.printSystemOut(
152                         org.hsqldb.lib.StringUtil.getList(roots, ",", ""));
153                 }
154             }
155
156             complete = true;
157         } catch (IOException JavaDoc e) {
158             throw Trace.error(Trace.FILE_IO_ERROR, filename + ".new");
159         } catch (OutOfMemoryError JavaDoc e) {
160             throw Trace.error(Trace.OUT_OF_MEMORY);
161         } finally {
162             if (fileStreamOut != null) {
163                 fileStreamOut.close();
164             }
165
166             if (dest != null) {
167                 dest.close();
168             }
169
170             if (!complete) {
171                 database.getFileAccess().removeElement(filename + ".new");
172             }
173         }
174
175         //Trace.printSystemOut("Transfer complete: ", stopw.elapsedTime());
176
}
177
178     /**
179      * called from outside after the complete end of defrag
180      */

181     void updateTableIndexRoots() throws HsqlException {
182
183         HsqlArrayList allTables = database.schemaManager.getAllTables();
184
185         for (int i = 0, size = allTables.size(); i < size; i++) {
186             Table t = (Table) allTables.get(i);
187
188             if (t.getTableType() == Table.CACHED_TABLE) {
189                 int[] rootsArray = rootsList[i];
190
191                 t.setIndexRoots(rootsArray);
192             }
193         }
194     }
195
196     /**
197      * called from outside after the complete end of defrag
198      */

199     void updateTransactionRowIDs() throws HsqlException {
200         database.txManager.convertTransactionIDs(transactionRowLookup);
201     }
202
203     int[] writeTableToDataFile(Table table)
204     throws IOException JavaDoc, HsqlException {
205
206         Session session = database.getSessionManager().getSysSession();
207         RowOutputBinary rowOut = new RowOutputBinary();
208         DoubleIntIndex pointerLookup =
209             new DoubleIntIndex(table.getPrimaryIndex().sizeEstimate(), false);
210         int[] rootsArray = table.getIndexRootsArray();
211         long pos = fileOffset;
212         int count = 0;
213
214         pointerLookup.setKeysSearchTarget();
215         Trace.printSystemOut("lookup begins: " + stopw.elapsedTime());
216
217         RowIterator it = table.rowIterator(session);
218
219         for (; it.hasNext(); count++) {
220             CachedObject row = (CachedObject) it.next();
221
222             pointerLookup.addUnsorted(row.getPos(), (int) (pos / scale));
223
224             if (count % 50000 == 0) {
225                 Trace.printSystemOut("pointer pair for row " + count + " "
226                                      + row.getPos() + " " + pos);
227             }
228
229             pos += row.getStorageSize();
230         }
231
232         Trace.printSystemOut(table.getName().name + " list done ",
233                              stopw.elapsedTime());
234
235         count = 0;
236         it = table.rowIterator(session);
237
238         for (; it.hasNext(); count++) {
239             CachedObject row = it.next();
240
241             rowOut.reset();
242             row.write(rowOut, pointerLookup);
243             fileStreamOut.write(rowOut.getOutputStream().getBuffer(), 0,
244                                 rowOut.size());
245
246             fileOffset += row.getStorageSize();
247
248             if ((count) % 50000 == 0) {
249                 Trace.printSystemOut(count + " rows " + stopw.elapsedTime());
250             }
251         }
252
253         for (int i = 0; i < rootsArray.length; i++) {
254             if (rootsArray[i] == -1) {
255                 continue;
256             }
257
258             int lookupIndex =
259                 pointerLookup.findFirstEqualKeyIndex(rootsArray[i]);
260
261             if (lookupIndex == -1) {
262                 throw Trace.error(Trace.DATA_FILE_ERROR);
263             }
264
265             rootsArray[i] = pointerLookup.getValue(lookupIndex);
266         }
267
268         setTransactionRowLookups(pointerLookup);
269         Trace.printSystemOut(table.getName().name + " : table converted");
270
271         return rootsArray;
272     }
273
274     void setTransactionRowLookups(DoubleIntIndex pointerLookup) {
275
276         for (int i = 0, size = transactionRowLookup.size(); i < size; i++) {
277             int key = transactionRowLookup.getKey(i);
278             int lookupIndex = pointerLookup.findFirstEqualKeyIndex(key);
279
280             if (lookupIndex != -1) {
281                 transactionRowLookup.setValue(
282                     i, pointerLookup.getValue(lookupIndex));
283             }
284         }
285     }
286
287     void writeTransactionRows() {
288
289         for (int i = 0, size = transactionRowLookup.size(); i < size; i++) {
290             if (transactionRowLookup.getValue(i) != 0) {
291                 continue;
292             }
293
294             int key = transactionRowLookup.getKey(i);
295
296             try {
297                 transactionRowLookup.setValue(i, (int) (fileOffset / scale));
298
299                 RowInputInterface rowIn = cache.readObject(key);
300
301                 fileStreamOut.write(rowIn.getBuffer(), 0, rowIn.getSize());
302
303                 fileOffset += rowIn.getSize();
304             } catch (IOException JavaDoc e) {}
305         }
306     }
307 }
308
Popular Tags