1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.treetank.access;
29
30 import static com.google.common.base.Objects.toStringHelper;
31 import static com.google.common.base.Preconditions.checkState;
32
33 import java.io.File;
34 import java.util.Map;
35 import java.util.concurrent.ConcurrentHashMap;
36 import java.util.concurrent.ConcurrentMap;
37
38 import org.treetank.access.conf.ConstructorProps;
39 import org.treetank.access.conf.ResourceConfiguration;
40 import org.treetank.access.conf.SessionConfiguration;
41 import org.treetank.access.conf.StorageConfiguration;
42 import org.treetank.api.ISession;
43 import org.treetank.api.IStorage;
44 import org.treetank.bucket.IConstants;
45 import org.treetank.bucket.IndirectBucket;
46 import org.treetank.bucket.MetaBucket;
47 import org.treetank.bucket.DataBucket;
48 import org.treetank.bucket.RevisionRootBucket;
49 import org.treetank.bucket.UberBucket;
50 import org.treetank.bucket.interfaces.IReferenceBucket;
51 import org.treetank.exception.TTException;
52 import org.treetank.exception.TTIOException;
53 import org.treetank.io.IBackend;
54 import org.treetank.io.IBackendReader;
55 import org.treetank.io.IBackendWriter;
56 import org.treetank.io.IOUtils;
57
58
59
60
61
62
63
64 public final class Storage implements IStorage {
65
66
67 private static final ConcurrentMap<File, Storage> STORAGEMAP = new ConcurrentHashMap<File, Storage>();
68
69
70 protected final Map<String, Session> mSessions;
71
72
73 private final StorageConfiguration mStorageConfig;
74
75
76
77
78
79
80
81
82
83 private Storage(final StorageConfiguration pStorageConf) throws TTException {
84 mStorageConfig = pStorageConf;
85 mSessions = new ConcurrentHashMap<String, Session>();
86
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public static synchronized boolean createStorage(final StorageConfiguration pStorageConfig)
104 throws TTIOException {
105 boolean returnVal = true;
106
107 if (!pStorageConfig.mFile.exists() && pStorageConfig.mFile.mkdirs()) {
108 returnVal =
109 IOUtils.createFolderStructure(pStorageConfig.mFile, StorageConfiguration.Paths.values());
110
111 StorageConfiguration.serialize(pStorageConfig);
112
113
114 if (!returnVal) {
115 pStorageConfig.mFile.delete();
116 }
117 return returnVal;
118 } else {
119 return false;
120 }
121 }
122
123
124
125
126
127
128
129
130
131
132 public static synchronized void truncateStorage(final StorageConfiguration pConf) throws TTException {
133
134 if (!STORAGEMAP.containsKey(pConf.mFile)) {
135 if (existsStorage(pConf.mFile)) {
136 final IStorage storage = new Storage(pConf);
137 final File[] resources =
138 new File(pConf.mFile, StorageConfiguration.Paths.Data.getFile().getName()).listFiles();
139 for (final File resource : resources) {
140 storage.truncateResource(new SessionConfiguration(resource.getName(), null));
141 }
142 storage.close();
143
144 IOUtils.recursiveDelete(pConf.mFile);
145 }
146 }
147 }
148
149
150
151
152
153
154
155
156 public static synchronized boolean existsStorage(final File pStoragePath) {
157
158 if (pStoragePath.exists()
159 && IOUtils.compareStructure(pStoragePath, StorageConfiguration.Paths.values()) == 0) {
160 return true;
161 } else {
162 return false;
163 }
164
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178 @Override
179 public synchronized boolean createResource(final ResourceConfiguration pResConf) throws TTException {
180 boolean returnVal = true;
181
182
183 final File path = new File(pResConf.mProperties.getProperty(ConstructorProps.RESOURCEPATH));
184 if (!path.exists() && path.mkdir()) {
185 returnVal = IOUtils.createFolderStructure(path, ResourceConfiguration.Paths.values());
186
187
188 ResourceConfiguration.serialize(pResConf);
189
190
191
192 bootstrap(this, pResConf);
193 return returnVal;
194 } else {
195 return false;
196 }
197 }
198
199
200
201
202
203 @Override
204 public synchronized boolean truncateResource(final SessionConfiguration pSesConf) throws TTException {
205
206 checkState(!mSessions.containsKey(pSesConf.getResource()),
207 "Please close all session before truncating!");
208 if (existsResource(pSesConf.getResource())) {
209 ISession session = getSession(pSesConf);
210 if (session.truncate()) {
211 return true;
212 } else {
213 return false;
214 }
215 } else {
216 return false;
217 }
218
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239 public static synchronized IStorage openStorage(final File pFile) throws TTException {
240 checkState(existsStorage(pFile), "DB could not be opened (since it was not created?) at location %s",
241 pFile);
242 StorageConfiguration config = StorageConfiguration.deserialize(pFile);
243 final Storage storage = new Storage(config);
244 final IStorage returnVal = STORAGEMAP.putIfAbsent(pFile, storage);
245 if (returnVal == null) {
246 return storage;
247 } else {
248 return returnVal;
249 }
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263 @Override
264 public synchronized ISession getSession(final SessionConfiguration pSessionConf) throws TTException {
265
266 final File resourceFile =
267 new File(new File(mStorageConfig.mFile, StorageConfiguration.Paths.Data.getFile().getName()),
268 pSessionConf.getResource());
269 Session returnVal = mSessions.get(pSessionConf.getResource());
270 if (returnVal == null) {
271 checkState(resourceFile.exists(),
272 "Resource could not be opened (since it was not created?) at location %s", resourceFile);
273 ResourceConfiguration config =
274 ResourceConfiguration.deserialize(mStorageConfig.mFile, pSessionConf.getResource());
275 config.mBackend.initialize();
276
277 final IBackendReader backendReader = config.mBackend.getReader();
278 UberBucket bucket = backendReader.readUber();
279 backendReader.close();
280
281 returnVal = new Session(this, config, pSessionConf, bucket);
282 mSessions.put(pSessionConf.getResource(), returnVal);
283 }
284 return returnVal;
285 }
286
287
288
289
290 @Override
291 public synchronized boolean close() throws TTException {
292 for (final ISession session : mSessions.values()) {
293 session.close();
294 }
295 return STORAGEMAP.remove(mStorageConfig.mFile) != null;
296 }
297
298
299
300
301
302
303
304
305 @Override
306 public boolean existsResource(String pResourceName) {
307 final File resourceFile =
308 new File(new File(mStorageConfig.mFile, StorageConfiguration.Paths.Data.getFile().getName()),
309 pResourceName);
310 return resourceFile.exists();
311 }
312
313
314
315
316 @Override
317 public String[] listResources() {
318 return new File(mStorageConfig.mFile, StorageConfiguration.Paths.Data.getFile().getName()).list();
319 }
320
321
322
323
324 @Override
325 public File getLocation() {
326 return mStorageConfig.mFile;
327 }
328
329
330
331
332
333
334
335
336
337
338 private static void bootstrap(final Storage pStorage, final ResourceConfiguration pResourceConf)
339 throws TTException {
340
341 final IBackend storage = pResourceConf.mBackend;
342 storage.initialize();
343 final IBackendWriter writer = storage.getWriter();
344
345 final UberBucket uberBucket = new UberBucket(1, 0, 1);
346 long newBucketKey = uberBucket.incrementBucketCounter();
347 uberBucket.setReferenceKey(IReferenceBucket.GUARANTEED_INDIRECT_OFFSET, newBucketKey);
348 uberBucket.setReferenceHash(IReferenceBucket.GUARANTEED_INDIRECT_OFFSET, IConstants.BOOTSTRAP_HASHED);
349 writer.write(uberBucket);
350
351
352
353
354
355
356 IReferenceBucket bucket;
357 for (int i = 0; i < IConstants.INDIRECT_BUCKET_COUNT.length; i++) {
358 bucket = new IndirectBucket(newBucketKey);
359 newBucketKey = uberBucket.incrementBucketCounter();
360 bucket.setReferenceKey(0, newBucketKey);
361 bucket.setReferenceHash(0, IConstants.BOOTSTRAP_HASHED);
362 writer.write(bucket);
363 }
364
365 RevisionRootBucket revBucket = new RevisionRootBucket(newBucketKey, 0, 0);
366
367 newBucketKey = uberBucket.incrementBucketCounter();
368
369 MetaBucket metaBucker = new MetaBucket(newBucketKey);
370 revBucket.setReferenceKey(RevisionRootBucket.META_REFERENCE_OFFSET, newBucketKey);
371 revBucket.setReferenceHash(RevisionRootBucket.META_REFERENCE_OFFSET, IConstants.BOOTSTRAP_HASHED);
372
373 newBucketKey = uberBucket.incrementBucketCounter();
374 bucket = new IndirectBucket(newBucketKey);
375 revBucket.setReferenceKey(IReferenceBucket.GUARANTEED_INDIRECT_OFFSET, newBucketKey);
376 revBucket.setReferenceHash(IReferenceBucket.GUARANTEED_INDIRECT_OFFSET, IConstants.BOOTSTRAP_HASHED);
377 writer.write(revBucket);
378 writer.write(metaBucker);
379
380
381
382
383
384
385
386 for (int i = 0; i < IConstants.INDIRECT_BUCKET_COUNT.length; i++) {
387 newBucketKey = uberBucket.incrementBucketCounter();
388 bucket.setReferenceKey(0, newBucketKey);
389 bucket.setReferenceHash(0, IConstants.BOOTSTRAP_HASHED);
390 writer.write(bucket);
391 bucket = new IndirectBucket(newBucketKey);
392 }
393
394 final DataBucket ndp = new DataBucket(newBucketKey, IConstants.NULLDATA);
395 writer.write(ndp);
396 writer.writeUberBucket(uberBucket);
397 writer.close();
398 storage.close();
399
400 }
401
402
403
404
405 @Override
406 public String toString() {
407 return toStringHelper(this).add("mSessions", mSessions).add("mStorageConfig", mStorageConfig)
408 .toString();
409 }
410
411 }