KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * com.mckoi.database.StateStore 10 Feb 2003
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.store.*;
28 import com.mckoi.util.ByteArrayUtil;
29 import java.io.*;
30 import java.util.ArrayList JavaDoc;
31 import com.mckoi.debug.DebugLogger;
32
33 /**
34  * A store that manages the current state of all tables in a Conglomerate. It
35  * persistantly manages three pieces of information about a conglomerate - the
36  * tables that are visible, the tables that are deleted, and a table_id value
37  * assigned to new tables that are created.
38  *
39  * @author Tobias Downer
40  */

41
42 class StateStore {
43
44   /**
45    * The MAGIC value used for state header areas.
46    */

47   private int MAGIC = 0x0BAC8001;
48
49   /**
50    * The Store object this state store wraps around.
51    */

52   private Store store;
53
54   /**
55    * The current table identifier.
56    */

57   private int table_id;
58
59   /**
60    * The header area of the state store. The format of the header area is;
61    * MAGIC(4) - RESERVED(4) - TABLE_ID(8) -
62    * VISIBLE_TABLES_POINTER(8) - DELETED_TABLES_POINTER(8)
63    */

64   private MutableArea header_area;
65
66   /**
67    * Pointer to the visible table area in the store.
68    */

69   private long vis_p;
70   
71   /**
72    * Pointer to the delete table area in the store.
73    */

74   private long del_p;
75   
76   /**
77    * The list of visible state resources.
78    */

79   private ArrayList JavaDoc visible_list;
80
81   /**
82    * The list of deleted state resources.
83    */

84   private ArrayList JavaDoc delete_list;
85
86   /**
87    * Set to true if the visible list was changed.
88    */

89   private boolean vis_list_change;
90   
91   /**
92    * Set to true if the delete list was changed.
93    */

94   private boolean del_list_change;
95
96   /**
97    * Constructs the StateStore.
98    */

99   public StateStore(Store store) {
100     this.store = store;
101     vis_list_change = false;
102     del_list_change = false;
103   }
104
105
106   /**
107    * Removes the given resource from the list.
108    */

109   private void removeResource(ArrayList JavaDoc list, String JavaDoc name) {
110     int sz = list.size();
111     for (int i = 0; i < sz; ++i) {
112       StateResource resource = (StateResource) list.get(i);
113       if (name.equals(resource.name)) {
114         list.remove(i);
115         return;
116       }
117     }
118     throw new RuntimeException JavaDoc("Couldn't find resource '" + name + "' in list.");
119   }
120
121   /**
122    * Reads the state resource list from the given area in the store.
123    */

124   private void readStateResourceList(ArrayList JavaDoc list, long pointer)
125                                                           throws IOException {
126     DataInputStream d_in = new DataInputStream(
127                                             store.getAreaInputStream(pointer));
128     int version = d_in.readInt(); // version
129
int count = (int) d_in.readLong();
130     for (int i = 0; i < count; ++i) {
131       long table_id = d_in.readLong();
132       String JavaDoc name = d_in.readUTF();
133       StateResource resource = new StateResource(table_id, name);
134       list.add(resource);
135     }
136     d_in.close();
137   }
138
139   /**
140    * Writes the state resource list to the given area in the store.
141    */

142   private void writeStateResourceList(ArrayList JavaDoc list, DataOutputStream d_out)
143                                                          throws IOException {
144     d_out.writeInt(1);
145     int sz = list.size();
146     d_out.writeLong(sz);
147     for (int i = 0; i < sz; ++i) {
148       StateResource resource = (StateResource) list.get(i);
149       d_out.writeLong(resource.table_id);
150       d_out.writeUTF(resource.name);
151     }
152   }
153
154   /**
155    * Writes the given list to the store and returns a pointer to the area once
156    * the write has finished.
157    */

158   private long writeListToStore(ArrayList JavaDoc list) throws IOException {
159     ByteArrayOutputStream bout = new ByteArrayOutputStream();
160     DataOutputStream d_out = new DataOutputStream(bout);
161     writeStateResourceList(list, d_out);
162     d_out.flush();
163     d_out.close();
164
165     byte[] buf = bout.toByteArray();
166
167     AreaWriter a = store.createArea(buf.length);
168     long list_p = a.getID();
169     a.put(buf);
170     a.finish();
171     
172     return list_p;
173   }
174
175   /**
176    * Creates the state store in the store and returns a pointer to the header
177    * used later for initializing the state.
178    */

179   public synchronized long create() throws IOException {
180     // Allocate empty visible and deleted tables area
181
AreaWriter vis_tables_area = store.createArea(12);
182     AreaWriter del_tables_area = store.createArea(12);
183     vis_p = vis_tables_area.getID();
184     del_p = del_tables_area.getID();
185
186     // Write empty entries for both of these
187
vis_tables_area.putInt(1);
188     vis_tables_area.putLong(0);
189     vis_tables_area.finish();
190     del_tables_area.putInt(1);
191     del_tables_area.putLong(0);
192     del_tables_area.finish();
193
194     // Now allocate an empty state header
195
AreaWriter header_writer = store.createArea(32);
196     long header_p = header_writer.getID();
197     header_writer.putInt(MAGIC);
198     header_writer.putInt(0);
199     header_writer.putLong(0);
200     header_writer.putLong(vis_p);
201     header_writer.putLong(del_p);
202     header_writer.finish();
203
204     header_area = store.getMutableArea(header_p);
205     
206     // Reset table_id
207
table_id = 0;
208
209     visible_list = new ArrayList JavaDoc();
210     delete_list = new ArrayList JavaDoc();
211     
212     // Return pointer to the header area
213
return header_p;
214   }
215
216   /**
217    * Initializes the state store given a pointer to the header area in the
218    * store.
219    */

220   public synchronized void init(long header_p) throws IOException {
221     header_area = store.getMutableArea(header_p);
222     int mag_value = header_area.getInt();
223     if (mag_value != MAGIC) {
224       throw new IOException("Magic value for state header area is incorrect.");
225     }
226     if (header_area.getInt() != 0) {
227       throw new IOException("Unknown version for state header area.");
228     }
229     table_id = (int) header_area.getLong();
230     vis_p = header_area.getLong();
231     del_p = header_area.getLong();
232
233     // Setup the visible and delete list
234
visible_list = new ArrayList JavaDoc();
235     delete_list = new ArrayList JavaDoc();
236
237     // Read the resource list for the visible and delete list.
238
readStateResourceList(visible_list, vis_p);
239     readStateResourceList(delete_list, del_p);
240     
241   }
242
243   /**
244    * Reads a legacy state file (pre version 1) and converts it to a state store
245    * format compatible with this store. Fortunately the conversion is fairly
246    * straight-forward. This is otherwise the same as using the 'create' method.
247    */

248   public synchronized long convert(File legacy_sf, DebugLogger debug)
249                                                            throws IOException {
250     // Create a blank area in the store.
251
long header_p = create();
252                                                              
253     // Open the state file.
254
FixedSizeDataStore state_file =
255                                 new FixedSizeDataStore(legacy_sf, 507, debug);
256     state_file.open(true);
257
258     // Read the header.
259
byte[] reserved_buffer = new byte[64];
260     state_file.readReservedBuffer(reserved_buffer, 0, 64);
261
262     // Read the list of visible tables....
263
int tables_sector = ByteArrayUtil.getInt(reserved_buffer, 4);
264     InputStream sin = state_file.getSectorInputStream(tables_sector);
265     DataInputStream din = new DataInputStream(sin);
266     int vtver = din.readInt(); // The version.
267
int size = din.readInt();
268     // For each committed table,
269
for (int i = 0 ; i < size; ++i) {
270       int table_id = din.readInt();
271       String JavaDoc resource_name = din.readUTF();
272       // Convert to new resource type
273
if (!resource_name.startsWith(":")) {
274         resource_name = ":1" + resource_name;
275       }
276       // Add this entry to the visible resource.
277
addVisibleResource(new StateResource(table_id, resource_name));
278     }
279     din.close();
280     
281     // Read the list of dropped tables....
282
int dropped_sector = ByteArrayUtil.getInt(reserved_buffer, 12);
283     if (dropped_sector > -1) {
284       sin = state_file.getSectorInputStream(dropped_sector);
285       din = new DataInputStream(sin);
286       int dsver = din.readInt(); // The version.
287
size = din.readInt();
288       // For each deleted table file name,
289
for (int i = 0; i < size; ++i) {
290         String JavaDoc resource_name = din.readUTF();
291         // Convert to new resource type
292
if (!resource_name.startsWith(":")) {
293           resource_name = ":1" + resource_name;
294         }
295         // Add this entry to the delete resource.
296
addDeleteResource(new StateResource(-1, resource_name));
297       }
298       din.close();
299
300     }
301
302     // The sector that contains state information (the table id value)....
303
int state_sector = ByteArrayUtil.getInt(reserved_buffer, 8);
304     sin = state_file.getSectorInputStream(state_sector);
305     din = new DataInputStream(sin);
306     din.readInt(); // The version
307
int conv_table_id = din.readInt();
308     din.close();
309
310     // Close the state file.
311
state_file.close();
312     
313     // Update the table_id state
314
header_area.position(8);
315     header_area.putLong(conv_table_id);
316     // Check out the change
317
header_area.checkOut();
318     
319     // Finally commit the changes
320
commit();
321     
322     // Return a pointer to the structure
323
return header_p;
324   }
325
326   /**
327    * Returns the next table id and increments the table_id counter.
328    */

329   public synchronized int nextTableID() throws IOException {
330     int cur_counter = table_id;
331     ++table_id;
332
333     try {
334       store.lockForWrite();
335
336       // Update the state in the file
337
header_area.position(8);
338       header_area.putLong(table_id);
339       // Check out the change
340
header_area.checkOut();
341
342     }
343     finally {
344       store.unlockForWrite();
345     }
346
347     return cur_counter;
348   }
349
350   /**
351    * Returns a list of all table resources that are currently in the visible
352    * list.
353    */

354   public synchronized StateResource[] getVisibleList() {
355     return (StateResource[])
356                  visible_list.toArray(new StateResource[visible_list.size()]);
357   }
358   
359   /**
360    * Returns a list of all table resources that are currently in the deleted
361    * list.
362    */

363   public synchronized StateResource[] getDeleteList() {
364     return (StateResource[])
365                    delete_list.toArray(new StateResource[delete_list.size()]);
366   }
367
368   /**
369    * Returns true if the visible list contains a state resource with the given
370    * table id value.
371    */

372   public synchronized boolean containsVisibleResource(int table_id) {
373     int sz = visible_list.size();
374     for (int i = 0; i < sz; ++i) {
375       if (((StateResource) visible_list.get(i)).table_id == table_id) {
376         return true;
377       }
378     }
379     return false;
380   }
381   
382   /**
383    * Adds the given StateResource to the visible table list. This does not
384    * persist the state. To persist this change a call to 'commit' must be
385    * called.
386    */

387   public synchronized void addVisibleResource(StateResource resource) {
388     visible_list.add(resource);
389     vis_list_change = true;
390   }
391   
392   /**
393    * Adds the given StateResource to the deleted table list. This does not
394    * persist the state. To persist this change a call to 'commit' must be
395    * called.
396    */

397   public synchronized void addDeleteResource(StateResource resource) {
398     delete_list.add(resource);
399     del_list_change = true;
400   }
401   
402   /**
403    * Removes the resource with the given name from the visible list. This does
404    * not persist the state. To persist this change a call to 'commit' must be
405    * called.
406    */

407   public synchronized void removeVisibleResource(String JavaDoc name) {
408     removeResource(visible_list, name);
409     vis_list_change = true;
410   }
411   
412   /**
413    * Removes the resource with the given name from the deleted list. This does
414    * not persist the state. To persist this change a call to 'commit' must be
415    * called.
416    */

417   public synchronized void removeDeleteResource(String JavaDoc name) {
418     removeResource(delete_list, name);
419     del_list_change = true;
420   }
421
422   /**
423    * Commits the current state to disk so that it makes a persistent change to
424    * the state. A further call to 'synch()' will synchronize the file. This
425    * will only commit changes if there were modifications to the state.
426    * Returns true if this commit caused any changes to the persistant state.
427    */

428   public synchronized boolean commit() throws IOException {
429     boolean changes = false;
430     long new_vis_p = vis_p;
431     long new_del_p = del_p;
432     
433     try {
434       store.lockForWrite();
435
436       // If the lists changed, then write new state areas to the store.
437
if (vis_list_change) {
438         new_vis_p = writeListToStore(visible_list);
439         vis_list_change = false;
440         changes = true;
441       }
442       if (del_list_change) {
443         new_del_p = writeListToStore(delete_list);
444         del_list_change = false;
445         changes = true;
446       }
447       // Commit the changes,
448
if (changes) {
449         header_area.position(16);
450         header_area.putLong(new_vis_p);
451         header_area.putLong(new_del_p);
452         // Check out the change.
453
header_area.checkOut();
454         if (vis_p != new_vis_p) {
455           store.deleteArea(vis_p);
456           vis_p = new_vis_p;
457         }
458         if (del_p != new_del_p) {
459           store.deleteArea(del_p);
460           del_p = new_del_p;
461         }
462       }
463
464     }
465     finally {
466       store.unlockForWrite();
467     }
468
469     return changes;
470   }
471
472   // ---------- Inner classes ----------
473

474   /**
475    * Represents a single StateResource in either a visible or delete list in
476    * this state file.
477    */

478   static class StateResource {
479
480     /**
481      * The unique identifier for the resource.
482      */

483     long table_id;
484
485     /**
486      * The unique name given to the resource to distinguish it from all other
487      * resources.
488      */

489     String JavaDoc name;
490
491     public StateResource(long table_id, String JavaDoc name) {
492       this.table_id = table_id;
493       this.name = name;
494     }
495     
496   }
497   
498 }
499
500
Popular Tags