KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > scriptio > ScriptWriterBase


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.scriptio;
33
34 import java.io.BufferedOutputStream JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.OutputStream JavaDoc;
37
38 import org.hsqldb.HsqlNameManager.HsqlName;
39 import org.hsqldb.Database;
40 import org.hsqldb.DatabaseManager;
41 import org.hsqldb.DatabaseScript;
42 import org.hsqldb.HsqlException;
43 import org.hsqldb.NumberSequence;
44 import org.hsqldb.Result;
45 import org.hsqldb.Session;
46 import org.hsqldb.Table;
47 import org.hsqldb.Token;
48 import org.hsqldb.Trace;
49 import org.hsqldb.index.RowIterator;
50 import org.hsqldb.lib.FileAccess;
51 import org.hsqldb.lib.FileUtil;
52 import org.hsqldb.lib.HsqlTimer;
53 import org.hsqldb.lib.Iterator;
54
55 //import org.hsqldb.lib.StopWatch;
56
// todo - can lock the database engine as readonly in a wrapper for this when
57
// used at checkpoint
58

59 /**
60  * Handles all logging to file operations. A log consists of three blocks:<p>
61  *
62  * DDL BLOCK: definition of DB objects, users and rights at startup time<br>
63  * DATA BLOCK: all data for MEMORY tables at startup time<br>
64  * LOG BLOCK: SQL statements logged since startup or the last CHECKPOINT<br>
65  *
66  * The implementation of this class and its subclasses support the formats
67  * used for writing the data. In versions up to 1.7.2, this data is written
68  * to the *.script file for the database. Since 1.7.2 the data can also be
69  * written as binray in order to speed up shutdown and startup.<p>
70  *
71  * In 1.7.2, two separate files are used, one for the DDL + DATA BLOCK and
72  * the other for the LOG BLOCK.<p>
73  *
74  * A related use for this class is for saving a current snapshot of the
75  * database data to a user-defined file. This happens in the SHUTDOWN COMPACT
76  * process or done as a result of the SCRIPT command. In this case, the
77  * DATA block contains the CACHED table data as well.<p>
78  *
79  * DatabaseScriptReader and its subclasses read back the data at startup time.
80  *
81  * @author fredt@users
82  * @version 1.8.0
83  * @since 1.7.2
84  */

85 public abstract class ScriptWriterBase implements Runnable JavaDoc {
86
87     Database database;
88     String JavaDoc outFile;
89     OutputStream JavaDoc fileStreamOut;
90     FileAccess.FileSync outDescriptor;
91     int tableRowCount;
92     HsqlName schemaToLog;
93
94     /**
95      * this determines if the script is the normal script (false) used
96      * internally by the engine or a user-initiated snapshot of the DB (true)
97      */

98     boolean isDump;
99     boolean includeCachedData;
100     long byteCount;
101     volatile boolean needsSync;
102     volatile boolean forceSync;
103     volatile boolean busyWriting;
104     private int syncCount;
105     static final int INSERT = 0;
106     static final int INSERT_WITH_SCHEMA = 1;
107
108     /** the last schema for last sessionId */
109     Session currentSession;
110     public static final String JavaDoc[] LIST_SCRIPT_FORMATS = new String JavaDoc[] {
111         Token.T_TEXT, Token.T_BINARY, null, Token.T_COMPRESSED
112     };
113     public static final int SCRIPT_TEXT_170 = 0;
114     public static final int SCRIPT_BINARY_172 = 1;
115     public static final int SCRIPT_ZIPPED_BINARY_172 = 3;
116
117     public static ScriptWriterBase newScriptWriter(Database db, String JavaDoc file,
118             boolean includeCachedData, boolean newFile,
119             int scriptType) throws HsqlException {
120
121         if (scriptType == SCRIPT_TEXT_170) {
122             return new ScriptWriterText(db, file, includeCachedData, newFile,
123                                         false);
124         } else if (scriptType == SCRIPT_BINARY_172) {
125             return new ScriptWriterBinary(db, file, includeCachedData,
126                                           newFile);
127         } else {
128             return new ScriptWriterZipped(db, file, includeCachedData,
129                                           newFile);
130         }
131     }
132
133     ScriptWriterBase() {}
134
135     ScriptWriterBase(Database db, String JavaDoc file, boolean includeCachedData,
136                      boolean isNewFile, boolean isDump) throws HsqlException {
137
138         this.isDump = isDump;
139
140         initBuffers();
141
142         boolean exists = false;
143
144         if (isDump) {
145             exists = FileUtil.exists(file);
146         } else {
147             exists = db.getFileAccess().isStreamElement(file);
148         }
149
150         if (exists && isNewFile) {
151             throw Trace.error(Trace.FILE_IO_ERROR, file);
152         }
153
154         this.database = db;
155         this.includeCachedData = includeCachedData;
156         outFile = file;
157         currentSession = database.sessionManager.getSysSession();
158
159         // start with neutral schema - no SET SCHEMA to log
160
schemaToLog = currentSession.loggedSchema =
161             currentSession.currentSchema;
162
163         openFile();
164     }
165
166     public void reopen() throws HsqlException {
167         openFile();
168     }
169
170     protected abstract void initBuffers();
171
172     /**
173      * Called internally or externally in write delay intervals.
174      */

175     public synchronized void sync() {
176
177         if (needsSync && fileStreamOut != null) {
178             if (busyWriting) {
179                 forceSync = true;
180
181                 return;
182             }
183
184             try {
185                 fileStreamOut.flush();
186                 outDescriptor.sync();
187
188                 syncCount++;
189             } catch (IOException JavaDoc e) {
190                 Trace.printSystemOut("flush() or sync() error: "
191                                      + e.toString());
192             }
193
194             needsSync = false;
195             forceSync = false;
196         }
197     }
198
199     public void close() throws HsqlException {
200
201         stop();
202
203         try {
204             if (fileStreamOut != null) {
205                 fileStreamOut.flush();
206                 fileStreamOut.close();
207
208                 fileStreamOut = null;
209             }
210         } catch (IOException JavaDoc e) {
211             throw Trace.error(Trace.FILE_IO_ERROR);
212         }
213
214         byteCount = 0;
215     }
216
217     public long size() {
218         return byteCount;
219     }
220
221     public void writeAll() throws HsqlException {
222
223         try {
224             writeDDL();
225             writeExistingData();
226             finishStream();
227         } catch (IOException JavaDoc e) {
228             throw Trace.error(Trace.FILE_IO_ERROR);
229         }
230     }
231
232     /**
233      * File is opened in append mode although in current usage the file
234      * never pre-exists
235      */

236     protected void openFile() throws HsqlException {
237
238         try {
239             FileAccess fa = isDump ? FileUtil.getDefaultInstance()
240                                       : database.getFileAccess();
241             OutputStream JavaDoc fos = fa.openOutputStreamElement(outFile);
242
243             outDescriptor = fa.getFileSync(fos);
244             fileStreamOut = new BufferedOutputStream JavaDoc(fos, 2 << 12);
245         } catch (IOException JavaDoc e) {
246             throw Trace.error(Trace.FILE_IO_ERROR, Trace.Message_Pair,
247                               new Object JavaDoc[] {
248                 e.toString(), outFile
249             });
250         }
251     }
252
253     /**
254      * This is not really useful in the current usage but may be if this
255      * class is used in a different way.
256      */

257     protected void finishStream() throws IOException JavaDoc {}
258
259     protected void writeDDL() throws IOException JavaDoc, HsqlException {
260
261         Result ddlPart = DatabaseScript.getScript(database,
262             !includeCachedData);
263
264         writeSingleColumnResult(ddlPart);
265     }
266
267     protected void writeExistingData() throws HsqlException, IOException JavaDoc {
268
269         // start with blank schema - SET SCHEMA to log
270
currentSession.loggedSchema = null;
271
272         Iterator schemas = database.schemaManager.userSchemaNameIterator();
273
274         while (schemas.hasNext()) {
275             String JavaDoc schema = (String JavaDoc) schemas.next();
276             Iterator tables = database.schemaManager.tablesIterator(schema);
277
278             while (tables.hasNext()) {
279                 Table t = (Table) tables.next();
280
281                 // write all memory table data
282
// write cached table data unless index roots have been written
283
// write all text table data apart from readonly text tables
284
// unless index roots have been written
285
boolean script = false;
286
287                 switch (t.getTableType()) {
288
289                     case Table.MEMORY_TABLE :
290                         script = true;
291                         break;
292
293                     case Table.CACHED_TABLE :
294                         script = includeCachedData;
295                         break;
296
297                     case Table.TEXT_TABLE :
298                         script = includeCachedData &&!t.isReadOnly();
299                         break;
300                 }
301
302                 try {
303                     if (script) {
304                         schemaToLog = t.getName().schema;
305
306                         writeTableInit(t);
307
308                         RowIterator it = t.rowIterator(currentSession);
309
310                         while (it.hasNext()) {
311                             writeRow(currentSession, t, it.next().getData());
312                         }
313
314                         writeTableTerm(t);
315                     }
316                 } catch (Exception JavaDoc e) {
317                     throw Trace.error(Trace.ASSERT_FAILED, e.toString());
318                 }
319             }
320         }
321
322         writeDataTerm();
323     }
324
325     protected void writeTableInit(Table t)
326     throws HsqlException, IOException JavaDoc {}
327
328     protected void writeTableTerm(Table t) throws HsqlException, IOException JavaDoc {
329
330         if (t.isDataReadOnly() &&!t.isTemp() &&!t.isText()) {
331             StringBuffer JavaDoc a = new StringBuffer JavaDoc("SET TABLE ");
332
333             a.append(t.getName().statementName);
334             a.append(" READONLY TRUE");
335             writeLogStatement(currentSession, a.toString());
336         }
337     }
338
339     protected void writeSingleColumnResult(Result r)
340     throws HsqlException, IOException JavaDoc {
341
342         Iterator it = r.iterator();
343
344         while (it.hasNext()) {
345             Object JavaDoc[] data = (Object JavaDoc[]) it.next();
346
347             writeLogStatement(currentSession, (String JavaDoc) data[0]);
348         }
349     }
350
351     abstract void writeRow(Session session, Table table,
352                            Object JavaDoc[] data) throws HsqlException, IOException JavaDoc;
353
354     protected abstract void writeDataTerm() throws IOException JavaDoc;
355
356     protected abstract void addSessionId(Session session) throws IOException JavaDoc;
357
358     public abstract void writeLogStatement(Session session,
359                                            String JavaDoc s)
360                                            throws IOException JavaDoc, HsqlException;
361
362     public abstract void writeInsertStatement(Session session, Table table,
363             Object JavaDoc[] data) throws HsqlException, IOException JavaDoc;
364
365     public abstract void writeDeleteStatement(Session session, Table table,
366             Object JavaDoc[] data) throws HsqlException, IOException JavaDoc;
367
368     public abstract void writeSequenceStatement(Session session,
369             NumberSequence seq) throws HsqlException, IOException JavaDoc;
370
371     public abstract void writeCommitStatement(Session session)
372     throws HsqlException, IOException JavaDoc;
373
374     //
375
private Object JavaDoc timerTask;
376
377     // long write delay for scripts : 60s
378
protected volatile int writeDelay = 60000;
379
380     public void run() {
381
382         try {
383             if (writeDelay != 0) {
384                 sync();
385             }
386
387             // todo: try to do Cache.cleanUp() here, too
388
} catch (Exception JavaDoc e) {
389
390             // ignore exceptions
391
// may be InterruptedException or IOException
392
if (Trace.TRACE) {
393                 Trace.printSystemOut(e.toString());
394             }
395         }
396     }
397
398     public void setWriteDelay(int delay) {
399
400         writeDelay = delay;
401
402         int period = writeDelay == 0 ? 1000
403                                      : writeDelay;
404
405         HsqlTimer.setPeriod(timerTask, period);
406     }
407
408     public void start() {
409
410         int period = writeDelay == 0 ? 1000
411                                      : writeDelay;
412
413         timerTask = DatabaseManager.getTimer().schedulePeriodicallyAfter(0,
414                 period, this, false);
415     }
416
417     public void stop() {
418
419         if (timerTask != null) {
420             HsqlTimer.cancel(timerTask);
421
422             timerTask = null;
423         }
424     }
425
426     public int getWriteDelay() {
427         return writeDelay;
428     }
429 }
430
Popular Tags