comparison src/org/dancres/blitz/entry/EntryReposImpl.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 package org.dancres.blitz.entry;
2
3 import java.io.IOException;
4
5 import java.util.logging.*;
6
7 import net.jini.config.ConfigurationException;
8
9 import org.dancres.blitz.mangler.MangledField;
10 import org.dancres.blitz.mangler.MangledEntry;
11
12 import org.dancres.blitz.Logging;
13 import org.dancres.blitz.config.EntryConstraints;
14
15 import org.dancres.blitz.oid.OID;
16
17 import org.dancres.blitz.arc.CacheBlockDescriptor;
18 import org.dancres.blitz.arc.RecoverySummary;
19
20 import org.dancres.blitz.lease.Reapable;
21 import org.dancres.blitz.lease.ReapFilter;
22
23 import org.dancres.blitz.txn.TxnManager;
24
25 class EntryReposImpl implements EntryReposRecovery, Reapable {
26 private static Logger theLogger =
27 Logging.newLogger("org.dancres.disk.EntryRepository");
28
29 private Storage theStore;
30 private SleeveCache theSleeveCache;
31
32 private boolean haveLoggedCount = false;
33
34 private EntryConstraints theConstraints;
35
36 EntryReposImpl(Storage aStore) throws IOException {
37 try {
38 theConstraints = EntryConstraints.getConstraints(aStore.getType());
39 } catch (ConfigurationException aCE) {
40 IOException myIOE = new IOException("Couldn't load constraints");
41 myIOE.initCause(aCE);
42 throw myIOE;
43 }
44
45 theStore = aStore;
46 theSleeveCache = new SleeveCache(theStore);
47
48 // Don't configure for reaping if it's configured off
49 if (EntryRepositoryFactory.getReaper().isActive())
50 EntryRepositoryFactory.getReaper().add(this);
51 }
52
53 /**
54 This method is designed to log a record of the number of instances of
55 this repository's type the first time the repository is updated.
56
57 It's expected that checkpoints will store instance counts for all
58 repositories loaded at that time. This code ensures that any
59 repositories that come into being between checkpoints also have an
60 appropriate record to which following logged actions can be applied.
61
62 We only need to log the record once because at the next checkpoint
63 it's counts will be in the checkpoint record. This step is the
64 responsibility of <code>EntryRepositoryFactory</code>
65 */
66 private void logInstanceBarrier() {
67 if (TxnManager.get().isRecovery()) {
68 return;
69 }
70
71 if (EntryRepositoryFactory.get().isDebugLogging()) {
72 synchronized(this) {
73 if (haveLoggedCount)
74 return;
75
76 try {
77 /*
78 We must use the live stats for this count as the
79 storage's count may not be up-to-date due to actions
80 performed during recovery still sitting in cache.
81 I _think_ the fact that we checkpoint should prevent
82 this from actually happening but better safe than sorry.
83
84 We only attempt to log this - we can fail due to being
85 blocked on the transaction log lock for too long.
86 If that has happened, chances are we've done a checkpoint
87 and a record will have been emitted anyways.
88 */
89 TxnManager.get().tryLog(new CountAction(theStore.getType(),
90 theSleeveCache.getCounters().getInstanceCount()), 100);
91 } catch (Exception anE) {
92 theLogger.log(Level.SEVERE, "Failed to log instance count",
93 anE);
94 }
95
96 haveLoggedCount = true;
97 }
98 }
99 }
100
101 public String getType() {
102 return theStore.getName();
103 }
104
105 public int getTotalStoredEntries() throws IOException {
106 return theStore.getNumEntries();
107 }
108
109 public int getTotalLiveEntries() {
110 return theSleeveCache.getCounters().getInstanceCount();
111 }
112
113 public void reap(ReapFilter aFilter) {
114 logInstanceBarrier();
115
116 try {
117 theStore.bringOutTheDead(new CleanerImpl(theSleeveCache, aFilter));
118 } catch (IOException anIOE) {
119 theLogger.log(Level.SEVERE, "Couldn't bring out the dead",
120 anIOE);
121 }
122 }
123
124 public boolean renew(OID aOID, long anExpiry) throws IOException {
125 logInstanceBarrier();
126
127 return theSleeveCache.renew(aOID, anExpiry);
128 }
129
130 public boolean cancel(OID aOID) throws IOException {
131 logInstanceBarrier();
132
133 return theSleeveCache.cancel(aOID);
134 }
135
136 /*
137 These methods are only used during commit/abort and thus there will
138 have been activity previously generating a log entry for instance counts.
139
140 If there hasn't been activity, this operation is coming from the log
141 file which means there's been activity in the previous run and so
142 either we have an instance count in the checkpoint record or we'll have
143 logged one ourselves as part of activity prior to logging the transaction
144 which has generated these operations.
145 */
146 public CacheBlockDescriptor load(OID aOID) throws IOException {
147 return theSleeveCache.load(aOID);
148 }
149
150 public void flush(CacheBlockDescriptor aCBD) throws IOException {
151 theSleeveCache.forceSync(aCBD);
152 }
153
154 CacheBlockDescriptor add(EntrySleeveImpl aSleeve) throws IOException {
155 return theSleeveCache.add(aSleeve);
156 }
157
158 public RecoverySummary recover(EntrySleeveImpl aSleeve)
159 throws IOException {
160 return theSleeveCache.recover(aSleeve);
161 }
162
163 public Counters getCounters() {
164 return theSleeveCache.getCounters();
165 }
166
167 /*
168 These methods indicate new activity and we want to make sure we have
169 an up-to-date instance count
170 */
171 public void write(MangledEntry anEntry, long anExpiry,
172 WriteEscort anEscort)
173 throws IOException {
174 logInstanceBarrier();
175 theSleeveCache.write(anEntry, anExpiry, anEscort);
176 }
177
178 public void find(MangledEntry aTemplate, SearchVisitor aVisitor)
179 throws IOException {
180 logInstanceBarrier();
181 theSleeveCache.find(aTemplate, aVisitor);
182 }
183
184 public boolean find(SearchVisitor aVisitor, OID aOID, MangledEntry aPreload)
185 throws IOException {
186 logInstanceBarrier();
187 return theSleeveCache.find(aVisitor, aOID, aPreload);
188 }
189
190 public LongtermOffer getOffer(OID anOID) throws IOException {
191 logInstanceBarrier();
192 return theSleeveCache.getOffer(anOID);
193 }
194
195 public EntryConstraints getConstraints() {
196 return theConstraints;
197 }
198
199 public void setFields(MangledField[] aListOfFields)
200 throws IOException {
201 theStore.setFields(aListOfFields);
202 }
203
204 public boolean noSchemaDefined() {
205 return theStore.noSchemaDefined();
206 }
207
208 public void addSubtype(String aType) throws IOException {
209 theStore.addSubtype(aType);
210 }
211
212 public String[] getSubtypes() {
213 return theStore.getSubtypes();
214 }
215
216 void deleteAllEntrys() throws IOException {
217 theSleeveCache.deleteAll();
218 }
219
220 void delete() throws IOException {
221 theStore.delete();
222 }
223
224 void sync() throws IOException {
225 theLogger.log(Level.FINE, "Syncing to disk: " + theStore.getType());
226 // System.err.println("Syncing to disk: " + theStore.getType());
227 theSleeveCache.sync();
228 }
229
230 void close() throws IOException {
231 theLogger.log(Level.FINE, "Closing: " + theStore.getType());
232 // System.err.println("Closing: " + theStore.getType());
233 theSleeveCache.close();
234 theStore.close();
235 }
236
237 public String toString() {
238 return "EntryReposImpl: " + theStore.getType() + ", "
239 + theStore.getClass();
240 }
241 }