KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * com.mckoi.database.TableBackedCache 12 Mar 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.util.Cache;
28 import com.mckoi.util.IntegerVector;
29
30 /**
31  * A TableBackedCache is a special type of a cache in a DataTableConglomerate
32  * that is backed by a table in the database. The purpose of this object is to
33  * provide efficient access to some specific information in a table via a
34  * cache.
35  * <p>
36  * For example, we use this object to provide cached access to the system
37  * privilege tables. The engine often performs identical types of priv
38  * queries on the database and it's desirable to cache the access to this
39  * table.
40  * <p>
41  * This class provides the following services;
42  * 1) Allows for an instance of this object to be attached to a single
43  * DatabaseConnection
44  * 2) Listens for any changes that are committed to the table(s) and flushes the
45  * cache as neccessary.
46  * <p>
47  * Note that this object is designed to fit into the pure serializable
48  * transaction isolation system that Mckoi employs. This object will provide
49  * a view of the table as it was when the transaction started. When the
50  * transaction commits (or rollsback) the view is updated to the most current
51  * version. If a change is committed to the tables this cache is backed by,
52  * the cache is only flushed when there are no open transactions on the
53  * connection.
54  *
55  * @author Tobias Downer
56  */

57
58 abstract class TableBackedCache {
59
60   /**
61    * The table that this cache is backed by.
62    */

63   private TableName backed_by_table;
64
65   /**
66    * The list of added rows to the table above when a change is
67    * committed.
68    */

69   private IntegerVector added_list;
70
71   /**
72    * The list of removed rows from the table above when a change is
73    * committed.
74    */

75   private IntegerVector removed_list;
76
77   /**
78    * Set to true when the backing DatabaseConnection has a transaction open.
79    */

80   private boolean transaction_active;
81   
82   /**
83    * The listener object.
84    */

85   private TransactionModificationListener listener;
86   
87   /**
88    * Constructs this object.
89    */

90   protected TableBackedCache(TableName table) {
91     this.backed_by_table = table;
92
93     added_list = new IntegerVector();
94     removed_list = new IntegerVector();
95   }
96
97   /**
98    * Adds new row ids to the given list.
99    */

100   private void addRowsToList(int[] from, IntegerVector list) {
101     if (from != null) {
102       for (int i = 0; i < from.length; ++i) {
103         list.addInt(from[i]);
104       }
105     }
106   }
107
108   /**
109    * Attaches this object to a conglomerate. This applies the appropriate
110    * listeners to the tables.
111    */

112   final void attachTo(TableDataConglomerate conglomerate) {
113 // TableDataConglomerate conglomerate = connection.getConglomerate();
114
TableName table_name = backed_by_table;
115     listener = new TransactionModificationListener() {
116       public void tableChange(TableModificationEvent evt) {
117         // Ignore.
118
}
119       public void tableCommitChange(TableCommitModificationEvent evt) {
120         TableName table_name = evt.getTableName();
121         if (table_name.equals(backed_by_table)) {
122           synchronized (removed_list) {
123             addRowsToList(evt.getAddedRows(), added_list);
124             addRowsToList(evt.getRemovedRows(), removed_list);
125           }
126         }
127       }
128     };
129     conglomerate.addTransactionModificationListener(table_name, listener);
130   }
131
132   /**
133    * Call to detach this object from a TableDataConglomerate.
134    */

135   final void detatchFrom(TableDataConglomerate conglomerate) {
136 // TableDataConglomerate conglomerate = connection.getConglomerate();
137
TableName table_name = backed_by_table;
138     conglomerate.removeTransactionModificationListener(table_name, listener);
139   }
140
141   /**
142    * Called from DatabaseConnection to notify this object that a new transaction
143    * has been started. When a transaction has started, any committed changes
144    * to the table must NOT be immediately reflected in this cache. Only
145    * when the transaction commits is there a possibility of the cache
146    * information being incorrect.
147    */

148   final void transactionStarted() {
149     transaction_active = true;
150     internalPurgeCache();
151   }
152
153   /**
154    * Called from DatabaseConnection to notify that object that a transaction
155    * has closed. When a transaction is closed, information in the cache may
156    * be invalidated. For example, if rows 10 - 50 were delete then any
157    * information in the cache that touches this data must be flushed from the
158    * cache.
159    */

160   final void transactionFinished() {
161     transaction_active = false;
162     internalPurgeCache();
163   }
164
165   /**
166    * Internal method which copies the 'added' and 'removed' row lists and
167    * calls the 'purgeCacheOfInvalidatedEntries' method.
168    */

169   private void internalPurgeCache() {
170     // Make copies of the added_list and removed_list
171
IntegerVector add, remove;
172     synchronized (removed_list) {
173       add = new IntegerVector(added_list);
174       remove = new IntegerVector(removed_list);
175       // Clear the added and removed list
176
added_list.clear();
177       removed_list.clear();
178     }
179     // Make changes to the cache
180
purgeCacheOfInvalidatedEntries(add, remove);
181   }
182
183   /**
184    * This method is called when the transaction starts and finishes and must
185    * purge the cache of all invalidated entries.
186    * <p>
187    * Note that this method must NOT make any queries on the database. It must
188    * only, at the most, purge the cache of invalid entries. A trivial
189    * implementation of this might completely clear the cache of all data if
190    * removed_row.size() > 0.
191    */

192   abstract void purgeCacheOfInvalidatedEntries(
193                          IntegerVector added_rows, IntegerVector removed_rows);
194
195 }
196
197
Popular Tags