KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jofti > store > FileManager


1 package com.jofti.store;
2
3 import java.io.File JavaDoc;
4 import java.io.FileNotFoundException JavaDoc;
5 import java.io.IOException JavaDoc;
6 import java.util.Properties JavaDoc;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogConfigurationException;
10 import org.apache.commons.logging.LogFactory;
11
12
13 import com.jofti.exception.InsufficientSpaceException;
14 import com.jofti.exception.JoftiException;
15
16 import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
17
18 /**
19  *
20  * Manages files set up in Jofti. This manager sets up the files, allocates space in the files and
21  * keeps track of the current poaitions in each file.
22  * <p>
23  * This is based on some of the ideas found in HOWL.
24  * </p>
25  *
26  * @author xenephon
27  *
28  */

29 class FileManager {
30
31     private static Log log = LogFactory.getLog(FileManager.class);
32
33     // lock controlling access to block allocation
34
private Object JavaDoc recordLock = new Object JavaDoc();
35
36
37     /**
38      * set of FileStore objects associated with the physical files.
39      *
40      * @see #open()
41      */

42     FileStore[] fileSet = null;
43
44     /**
45      * array of unalloctaed blocks fro each store.
46      *
47      * @see #open()
48      */

49     long[] unallocatedBlocks = null;
50
51     /**
52      * array of positions for each store.
53      *
54      */

55     long[] filePositions = null;
56
57     /**
58      * current store
59      *
60      */

61     FileStore currentStore = null;
62
63     // where the old blocks are put - should just be a queue of FilePositionHolders
64
protected LinkedBlockingQueue removedBlockQueue = new LinkedBlockingQueue(); //this is unbounded
65

66     //default max files
67
private int maxFiles = 10;
68
69     // max size of each file
70
private long maxSize = 0;
71
72     /**
73      * keys into properties
74      *
75      */

76     protected String JavaDoc OVERFLOW_DIRECTORY = "overflow-directory";
77
78     protected String JavaDoc fileName = "jofti";
79
80     protected String JavaDoc extension = "str";
81
82     protected String JavaDoc logFileDirectory = "../tmp";
83
84     private Properties JavaDoc props = null;
85
86     // block size to be used
87
int blockSize = 0;
88
89     // block size- (header size + footer size)
90
int payloadSize = 0;
91
92
93     FileManager() {
94
95     }
96
97     void init(int blockSize, String JavaDoc directory, String JavaDoc fileName, long size,
98             int maxFiles) throws JoftiException
99     {
100
101         //set up the properties we need
102

103         this.blockSize = blockSize;
104         this.logFileDirectory = directory;
105         this.fileName = fileName;
106         this.maxSize = size;
107         this.maxFiles = maxFiles;
108
109         // open all the files
110
try {
111             open();
112         } catch (Exception JavaDoc e) {
113             throw new JoftiException(e);
114         }
115         
116         // set up the initial free blocks for each file
117
unallocatedBlocks = new long[fileSet.length];
118         filePositions = new long[fileSet.length];
119
120         long initialBlocks = maxSize / blockSize;
121         
122         // set up the unallocated blocks
123
for (int i = 0; i < fileSet.length; i++) {
124             unallocatedBlocks[i] = initialBlocks;
125         }
126
127         //set up the payload size
128
payloadSize = blockSize
129                 - (BlockBuffer.bufferHeaderSize + BlockBuffer.bufferFooterSize);
130
131     }
132
133     
134     public synchronized void reset(){
135 // set up the initial free blocks for each file
136
unallocatedBlocks = new long[fileSet.length];
137         filePositions = new long[fileSet.length];
138
139         long initialBlocks = maxSize / blockSize;
140         
141         // set up the unallocated blocks
142
for (int i = 0; i < fileSet.length; i++) {
143             unallocatedBlocks[i] = initialBlocks;
144         }
145         removedBlockQueue.clear();
146     }
147     /**
148      * Allocates an array of FilePositionHolder objects which encompasses the locations
149      * of the page data across one or more files.
150      * <p>
151      * @param blocks - existing file positions (if any)
152      * @param size - total number of bytes to store
153      * @return
154      * @throws JoftiException
155      */

156     public FilePositionHolder[] allocateBlocks(FilePositionHolder[] blocks,
157             int size) throws JoftiException
158     {
159
160         FilePositionHolder[] returnBlocks = null;
161
162         // empty storage
163
if (size == 0) {
164             return blocks;
165         }
166         
167         // see how many keys we need
168
int keysNeeded = size / payloadSize;
169         int remainder = size % payloadSize;
170
171         // is there a bit left over?
172
if (remainder != 0) {
173             keysNeeded++;
174         }
175         
176         if (log.isDebugEnabled()) {
177             log.debug("payloadSize " + payloadSize + " number keys needed "
178                     + keysNeeded + " for data size:" + size);
179         }
180
181         // we now know the number of keys needed - but we do not know what original ones we have?
182

183         try {
184             returnBlocks = allocateRecords(blocks, keysNeeded);
185         } catch (Exception JavaDoc e) {
186             throw new JoftiException(e);
187         }
188
189         return returnBlocks;
190
191     }
192
193     private FilePositionHolder[] allocateRecords(FilePositionHolder[] blocks,
194             int number) throws InsufficientSpaceException, Exception JavaDoc
195     {
196
197         int originalRecordNumber = 0;
198         FilePositionHolder[] temp = null;
199
200         if (blocks != null) {
201             originalRecordNumber += blocks.length;
202         }
203         
204         if (number == originalRecordNumber) {
205             // return the same blocks
206
temp = blocks;
207         } else if (number < originalRecordNumber) {
208             // otherwise we need to free some up
209

210             temp = new FilePositionHolder[number];
211
212             //free up blocks we do not need
213
for (int i = 0; i < blocks.length; i++) {
214                 if (i < number) {
215                     temp[i] = blocks[i];
216                 } else {
217                     removedBlockQueue.put(blocks[i]);
218                 }
219
220             }
221             return temp;
222         }
223
224         // we need more than we have
225
else if (number > originalRecordNumber) {
226
227             // we need to add some more records here
228
temp = new FilePositionHolder[number];
229             // copy the existing records into the new array
230

231             System.arraycopy(blocks, 0, temp, 0, blocks.length);
232
233             for (int i = blocks.length; i < temp.length; i++) {
234                 // try and get from the freeQueue first
235

236                 temp[i] = getNextPosition();
237             }
238
239         }
240         return temp;
241
242     }
243
244     public void removePosition(FilePositionHolder holder) throws JoftiException {
245             removedBlockQueue.offer(holder);
246     }
247
248     public FilePositionHolder getNextPosition() throws JoftiException {
249         FileStore file = null;
250
251         //see if we can get one from the free queue first
252
FilePositionHolder fileHolder = null;
253
254
255         fileHolder = (FilePositionHolder) removedBlockQueue.poll();
256
257
258         if (fileHolder != null) {
259             return fileHolder;
260         }
261
262     
263         file = currentStore;
264
265         // store we started at
266
int marker = file.fileId;
267         long position = 0;
268
269         do {
270             synchronized (recordLock) {
271                 if (unallocatedBlocks[file.fileId] > 0) {
272                     position = filePositions[file.fileId];
273                     fileHolder = new FilePositionHolder(file.fileId, position);
274                     filePositions[file.fileId] = position + blockSize;
275                     unallocatedBlocks[file.fileId]--;
276                     
277                     //we rotate the store so we get even spread of entries in all stores
278
if (file.fileId == unallocatedBlocks.length - 1) {
279                         currentStore = getFileStore(0);
280                     } else {
281                         currentStore = getFileStore(file.fileId + 1);
282                     }
283                     return fileHolder;
284                 } else {
285
286                     // ok we can't get as key here - try the next one
287
file = getFileStore(file.fileId + 1);
288
289                     if (file != null) {
290                         currentStore = file;
291                         if (log.isInfoEnabled()) {
292                             log.info("Storing in:" + file.fileId
293                                     + " moving to next store");
294                         }
295                     }
296                 }
297             }
298             // loop around until we have run out of stores to try
299
} while (file != null && file.fileId != marker);
300         // we have dropped through with no file available
301

302         throw new JoftiException("No space available in any file");
303     }
304
305
306     FileStore getFileStore(int id) {
307         FileStore lf = null;
308         int fsl = fileSet.length;
309
310         if (id >= fsl) {
311             return null;
312         } else {
313             return fileSet[id];
314         }
315
316     }
317
318     
319     /**
320      * open pool of FileStore(s).
321      *
322      * @throws FileNotFoundException
323      * @throws LogConfigurationException
324      * @throws IOException
325      * @throws InvalidFileSetException
326      */

327     void open() throws JoftiException, IOException JavaDoc, FileNotFoundException JavaDoc,
328             JoftiException
329     {
330
331         // get configuration information for log file names.
332
String JavaDoc logDir = logFileDirectory;
333         String JavaDoc logFileName = fileName;
334         String JavaDoc logFileExt = extension;
335
336         // make sure the directory exists
337
File JavaDoc dir = new File JavaDoc(logDir);
338         dir.mkdirs();
339
340         int existingFiles = 0;
341
342         // allocate the set of log files
343
fileSet = new FileStore[maxFiles];
344         for (int i = 0; i < maxFiles; ++i) {
345             File JavaDoc name = new File JavaDoc(logDir + "/" + logFileName + "_" + (i + 1)
346                     + "." + logFileExt);
347             if (name.exists()) {
348                 name.delete();
349                 name.createNewFile();
350             }
351
352             try {
353                 fileSet[i] = new FileStore(name, i).open("rw");
354
355             } catch (FileNotFoundException JavaDoc e) {
356                 while (--i >= 0) {
357                     fileSet[i].close();
358                     fileSet[i] = null;
359                 }
360
361                 throw e;
362             }
363
364         }
365         currentStore = fileSet[0];
366
367     }
368
369     /**
370      * close the log files.
371      *
372      * @throws IOException
373      * If FileChannel.close() encounters an error.
374      * @see java.nio.channels.FileChannel#close()
375      */

376     void close() throws IOException JavaDoc, InterruptedException JavaDoc {
377
378         if (fileSet == null)
379             return;
380
381         // close the log files
382
for (int i = 0; i < fileSet.length; ++i) {
383             if (fileSet[i] != null)
384                 fileSet[i].close();
385         }
386
387     }
388
389 }
Popular Tags