KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > TransactionJournal


1 /**
2  * com.mckoi.database.TransactionJournal 19 Nov 2000
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import com.mckoi.util.IntegerVector;
28 import com.mckoi.util.BlockIntegerList;
29 import java.util.ArrayList JavaDoc;
30
31 /**
32  * The list of all primitive operations to the database that a transaction
33  * performed. It includes the list of all rows added or removed to all tables,
34  * and the tables created and dropped and any table that had constraint
35  * modifications.
36  * <p>
37  * This journal is updated inside a Transaction. When the transaction is
38  * completed, this journal is used both to determine if the transaction
39  * can be committed, and also to update the changes to the data that a
40  * transaction has made.
41  * <p>
42  * THREADING: The journal update commands are synchronized because they need
43  * to be atomic operations and can be accessed by multiple threads.
44  *
45  * @author Tobias Downer
46  */

47
48 final class TransactionJournal {
49
50   /**
51    * Journal commands.
52    */

53   static byte TABLE_ADD = 1; // Add a row to a table.
54
// (params: table_id, row_index)
55
static byte TABLE_REMOVE = 2; // Remove a row from a table.
56
// (params: table_id, row_index)
57
static byte TABLE_CREATE = 3; // Create a new table.
58
// (params: table_id)
59
static byte TABLE_DROP = 4; // Drop a table.
60
// (params: table_id)
61
static byte TABLE_CONSTRAINT_ALTER = 5; // Alter constraints of a table.
62
// (params: table_id)
63

64   /**
65    * The number of entries in this journal.
66    */

67   private int journal_entries;
68
69   /**
70    * The list of table's that have been touched by this transaction. A table
71    * is touched if the 'getTable' method in the transaction is used to
72    * get the table. This means even if a table is just read from, the
73    * journal will record that the table was touched.
74    * <p>
75    * This object records the 'table_id' of the touched tables in a sorted
76    * list.
77    */

78   private IntegerVector touched_tables;
79
80   /**
81    * A byte[] array that represents the set of commands a transaction
82    * performed on a table.
83    */

84   private byte[] command_journal;
85
86   /**
87    * An IntegerVector that is filled with parameters from the command journal.
88    * For example, a 'TABLE_ADD' journal log will have as parameters the
89    * table id the row was added to, and the row_index that was added.
90    */

91   private IntegerVector command_parameters;
92
93   /**
94    * Optimization, these flags are set to true when various types of journal
95    * entries are made to the transaction journal.
96    */

97   private boolean has_added_table_rows, has_removed_table_rows,
98            has_created_tables, has_dropped_tables, has_constraint_alterations;
99
100   /**
101    * Constructs a blank journal.
102    */

103   TransactionJournal() {
104     journal_entries = 0;
105     command_journal = new byte[16];
106     command_parameters = new IntegerVector(32);
107     touched_tables = new IntegerVector(8);
108
109     has_added_table_rows = false;
110     has_removed_table_rows = false;
111     has_created_tables = false;
112     has_dropped_tables = false;
113     has_constraint_alterations = false;
114   }
115
116   /**
117    * Adds a command to the journal.
118    */

119   private void addCommand(byte command) {
120     if (journal_entries >= command_journal.length) {
121       // Resize command array.
122
int grow_size = Math.min(4000, journal_entries);
123       byte[] new_command_journal = new byte[journal_entries + grow_size];
124       System.arraycopy(command_journal, 0, new_command_journal, 0,
125                        journal_entries);
126       command_journal = new_command_journal;
127     }
128
129     command_journal[journal_entries] = command;
130     ++journal_entries;
131   }
132
133   /**
134    * Adds a parameter to the journal command parameters.
135    */

136   private void addParameter(int param) {
137     command_parameters.addInt(param);
138   }
139
140   /**
141    * Logs in this journal that the transaction touched the given table id.
142    */

143   synchronized void entryAddTouchedTable(int table_id) {
144     int pos = touched_tables.sortedIndexOf(table_id);
145     // If table_id already in the touched table list.
146
if (pos < touched_tables.size() &&
147         touched_tables.intAt(pos) == table_id) {
148       return;
149     }
150     // If position to insert >= size of the touched tables set then add to
151
// the end of the set.
152
if (pos >= touched_tables.size()) {
153       touched_tables.addInt(table_id);
154     }
155     else {
156       // Otherwise, insert into sorted order.
157
touched_tables.insertIntAt(table_id, pos);
158     }
159   }
160
161   /**
162    * Makes a journal entry that a table entry has been added to the table with
163    * the given id.
164    */

165   synchronized void entryAddTableRow(int table_id, int row_index) {
166 // has_added_table_rows = true;
167
addCommand(TABLE_ADD);
168     addParameter(table_id);
169     addParameter(row_index);
170   }
171
172   /**
173    * Makes a journal entry that a table entry has been removed from the table
174    * with the given id.
175    */

176   synchronized void entryRemoveTableRow(int table_id, int row_index) {
177 // has_removed_table_rows = true;
178
addCommand(TABLE_REMOVE);
179     addParameter(table_id);
180     addParameter(row_index);
181   }
182
183   /**
184    * Makes a journal entry that a table with the given 'table_id' has been
185    * created by this transaction.
186    */

187   synchronized void entryTableCreate(int table_id) {
188     has_created_tables = true;
189     addCommand(TABLE_CREATE);
190     addParameter(table_id);
191   }
192
193   /**
194    * Makes a journal entry that a table with the given 'table_id' has been
195    * dropped by this transaction.
196    */

197   synchronized void entryTableDrop(int table_id) {
198     has_dropped_tables = true;
199     addCommand(TABLE_DROP);
200     addParameter(table_id);
201   }
202
203   /**
204    * Makes a journal entry that a table with the given 'table_id' has been
205    * altered by this transaction.
206    */

207   synchronized void entryTableConstraintAlter(int table_id) {
208     has_constraint_alterations = true;
209     addCommand(TABLE_CONSTRAINT_ALTER);
210     addParameter(table_id);
211   }
212
213
214   /**
215    * Generates an array of MasterTableJournal objects that specify the
216    * changes that occur to each table affected by this transaction. Each array
217    * element represents a change to an individual table in the conglomerate
218    * that changed as a result of this transaction.
219    * <p>
220    * This is used when a transaction successfully commits and we need to log
221    * the transaction changes with the master table.
222    * <p>
223    * If no changes occurred to a table, then no entry is returned here.
224    */

225   MasterTableJournal[] makeMasterTableJournals() {
226     ArrayList JavaDoc table_journals = new ArrayList JavaDoc();
227     int param_index = 0;
228
229     MasterTableJournal master_journal = null;
230
231     for (int i = 0 ; i < journal_entries; ++i) {
232       byte c = command_journal[i];
233       if (c == TABLE_ADD || c == TABLE_REMOVE) {
234         int table_id = command_parameters.intAt(param_index);
235         int row_index = command_parameters.intAt(param_index + 1);
236         param_index += 2;
237
238         // Do we already have this table journal?
239
if (master_journal == null ||
240             master_journal.getTableID() != table_id) {
241           // Try to find the journal in the list.
242
int size = table_journals.size();
243           master_journal = null;
244           for (int n = 0; n < size && master_journal == null; ++n) {
245             MasterTableJournal test_journal =
246                                    (MasterTableJournal) table_journals.get(n);
247             if (test_journal.getTableID() == table_id) {
248               master_journal = test_journal;
249             }
250           }
251
252           // Not found so add to list.
253
if (master_journal == null) {
254             master_journal = new MasterTableJournal(table_id);
255             table_journals.add(master_journal);
256           }
257
258         }
259
260         // Add this change to the table journal.
261
master_journal.addEntry(c, row_index);
262
263       }
264       else if (c == TABLE_CREATE ||
265                c == TABLE_DROP ||
266                c == TABLE_CONSTRAINT_ALTER) {
267         param_index += 1;
268       }
269       else {
270         throw new Error JavaDoc("Unknown journal command.");
271       }
272     }
273
274     // Return the array.
275
return (MasterTableJournal[]) table_journals.toArray(
276                                new MasterTableJournal[table_journals.size()]);
277
278   }
279
280   /**
281    * Returns the list of tables id's that were dropped by this journal.
282    */

283   IntegerVector getTablesDropped() {
284     IntegerVector dropped_tables = new IntegerVector();
285     // Optimization, quickly return empty set if we know there are no tables.
286
if (!has_dropped_tables) {
287       return dropped_tables;
288     }
289
290     int param_index = 0;
291     for (int i = 0 ; i < journal_entries; ++i) {
292       byte c = command_journal[i];
293       if (c == TABLE_ADD || c == TABLE_REMOVE) {
294         param_index += 2;
295       }
296       else if (c == TABLE_CREATE || c == TABLE_CONSTRAINT_ALTER) {
297         param_index += 1;
298       }
299       else if (c == TABLE_DROP) {
300         dropped_tables.addInt(command_parameters.intAt(param_index));
301         param_index += 1;
302       }
303       else {
304         throw new Error JavaDoc("Unknown journal command.");
305       }
306     }
307
308     return dropped_tables;
309   }
310
311   /**
312    * Returns the list of tables id's that were created by this journal.
313    */

314   IntegerVector getTablesCreated() {
315     IntegerVector created_tables = new IntegerVector();
316     // Optimization, quickly return empty set if we know there are no tables.
317
if (!has_created_tables) {
318       return created_tables;
319     }
320
321     int param_index = 0;
322     for (int i = 0 ; i < journal_entries; ++i) {
323       byte c = command_journal[i];
324       if (c == TABLE_ADD || c == TABLE_REMOVE) {
325         param_index += 2;
326       }
327       else if (c == TABLE_DROP || c == TABLE_CONSTRAINT_ALTER) {
328         param_index += 1;
329       }
330       else if (c == TABLE_CREATE) {
331         created_tables.addInt(command_parameters.intAt(param_index));
332         param_index += 1;
333       }
334       else {
335         throw new Error JavaDoc("Unknown journal command.");
336       }
337     }
338
339     return created_tables;
340   }
341
342   /**
343    * Returns the list of tables id's that were constraint altered by this
344    * journal.
345    */

346   IntegerVector getTablesConstraintAltered() {
347     IntegerVector caltered_tables = new IntegerVector();
348     // Optimization, quickly return empty set if we know there are no tables.
349
if (!has_constraint_alterations) {
350       return caltered_tables;
351     }
352
353     int param_index = 0;
354     for (int i = 0 ; i < journal_entries; ++i) {
355       byte c = command_journal[i];
356       if (c == TABLE_ADD || c == TABLE_REMOVE) {
357         param_index += 2;
358       }
359       else if (c == TABLE_DROP || c == TABLE_CREATE) {
360         param_index += 1;
361       }
362       else if (c == TABLE_CONSTRAINT_ALTER) {
363         caltered_tables.addInt(command_parameters.intAt(param_index));
364         param_index += 1;
365       }
366       else {
367         throw new Error JavaDoc("Unknown journal command.");
368       }
369     }
370
371     return caltered_tables;
372   }
373
374
375 }
376
Popular Tags