KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > store > LoggingBufferManager


1 /**
2  * com.mckoi.store.LoggingBufferManager 10 Jun 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.store;
26
27 import java.util.ArrayList JavaDoc;
28 import java.util.Comparator JavaDoc;
29 import java.util.Arrays JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.io.File JavaDoc;
32 import com.mckoi.debug.DebugLogger;
33 import com.mckoi.debug.Lvl;
34
35 /**
36  * A paged random access buffer manager that caches access between a Store and
37  * the underlying filesystem and that also handles check point logging and
38  * crash recovery (via a JournalledSystem object).
39  *
40  * @author Tobias Downer
41  */

42
43 public class LoggingBufferManager {
44
45   /**
46    * Set to true for extra assertions.
47    */

48   private static boolean PARANOID_CHECKS = false;
49   
50   /**
51    * A timer that represents the T value in buffer pages.
52    */

53   private long current_T;
54
55   /**
56    * The number of pages in this buffer.
57    */

58   private int current_page_count;
59   
60   /**
61    * The list of all pages.
62    */

63   private ArrayList JavaDoc page_list;
64   
65   /**
66    * A lock used when accessing the current_T, page_list and current_page_count
67    * members.
68    */

69   private final Object JavaDoc T_lock = new Object JavaDoc();
70   
71   /**
72    * A hash map of all pages currently in memory keyed by store_id and page
73    * number.
74    * NOTE: This MUST be final for the 'fetchPage' method to be safe.
75    */

76   private final BMPage[] page_map;
77   
78   /**
79    * A unique id key counter for all stores using this buffer manager.
80    */

81   private int unique_id_seq;
82
83   /**
84    * The JournalledSystem object that handles journalling of all data.
85    */

86   private JournalledSystem journalled_system;
87
88   /**
89    * The maximum number of pages that should be kept in memory before pages
90    * are written out to disk.
91    */

92   private final int max_pages;
93
94   /**
95    * The size of each page.
96    */

97   private final int page_size;
98
99   // ---------- Write locks ----------
100

101   /**
102    * Set to true when a 'setCheckPoint' is in progress.
103    */

104   private boolean check_point_in_progress;
105   
106   /**
107    * The number of write locks currently on the buffer. Any number of write
108    * locks can be obtained, however a 'setCheckpoint' can only be achieved
109    * when there are no write operations in progress.
110    */

111   private int write_lock_count;
112
113   /**
114    * A mutex for when modifying the write lock information.
115    */

116   private final Object JavaDoc write_lock = new Object JavaDoc();
117   
118   
119 // /**
120
// * The number of cache hits.
121
// */
122
// private long cache_hit_count;
123
//
124
// /**
125
// * The number of cache misses.
126
// */
127
// private long cache_miss_count;
128

129
130   
131   /**
132    * Constructs the manager.
133    */

134   public LoggingBufferManager(File JavaDoc journal_path, boolean read_only,
135                               int max_pages, int page_size,
136                               StoreDataAccessorFactory sda_factory,
137                               DebugLogger debug, boolean enable_logging) {
138     this.max_pages = max_pages;
139     this.page_size = page_size;
140
141     check_point_in_progress = false;
142     write_lock_count = 0;
143     
144     current_T = 0;
145     page_list = new ArrayList JavaDoc();
146     page_map = new BMPage[257];
147     unique_id_seq = 0;
148
149     journalled_system = new JournalledSystem(journal_path, read_only,
150                                page_size, sda_factory, debug, enable_logging);
151   }
152
153   /**
154    * Constructs the manager with a scattering store implementation that
155    * converts the resource to a file in the given path.
156    */

157   public LoggingBufferManager(final File JavaDoc resource_path,
158         final File JavaDoc journal_path, final boolean read_only, final int max_pages,
159         final int page_size, final String JavaDoc file_ext, final long max_slice_size,
160         DebugLogger debug, boolean enable_logging) {
161     this(journal_path, read_only, max_pages, page_size,
162          new StoreDataAccessorFactory() {
163       public StoreDataAccessor createStoreDataAccessor(String JavaDoc resource_name) {
164         return new ScatteringStoreDataAccessor(resource_path, resource_name,
165                                                file_ext, max_slice_size);
166       }
167     }, debug, enable_logging);
168   }
169
170   /**
171    * Starts the buffer manager.
172    */

173   public void start() throws IOException JavaDoc {
174     journalled_system.start();
175   }
176
177   /**
178    * Stops the buffer manager.
179    */

180   public void stop() throws IOException JavaDoc {
181     journalled_system.stop();
182   }
183
184   // ----------
185

186   /**
187    * Creates a new resource.
188    */

189   JournalledResource createResource(String JavaDoc resource_name) {
190     return journalled_system.createResource(resource_name);
191   }
192
193   /**
194    * Obtains a write lock on the buffer. This will block if a 'setCheckPoint'
195    * is in progress, otherwise it will always succeed.
196    */

197   public void lockForWrite() throws InterruptedException JavaDoc {
198     synchronized (write_lock) {
199       while (check_point_in_progress) {
200         write_lock.wait();
201       }
202       ++write_lock_count;
203     }
204   }
205
206   /**
207    * Releases a write lock on the buffer. This MUST be called if the
208    * 'lockForWrite' method is called. This should be called from a 'finally'
209    * clause.
210    */

211   public void unlockForWrite() {
212     synchronized (write_lock) {
213       --write_lock_count;
214       write_lock.notifyAll();
215     }
216   }
217
218   /**
219    * Sets a check point in the log. This logs a point in which a recovery
220    * process should at least be able to be rebuild back to. This will block
221    * if there are any write locks.
222    * <p>
223    * Some things to keep in mind when using this. You must ensure that no
224    * writes can occur while this operation is occuring. Typically this will
225    * happen at the end of a commit but you need to ensure that nothing can
226    * happen in the background, such as records being deleted or items being
227    * inserted. It is required that the 'no write' restriction is enforced at
228    * a high level. If care is not taken then the image written will not be
229    * clean and if a crash occurs the image that is recovered will not be
230    * stable.
231    */

232   public void setCheckPoint(boolean flush_journals)
233                                      throws IOException JavaDoc, InterruptedException JavaDoc {
234
235     // Wait until the writes have finished, and then set the
236
// 'check_point_in_progress' boolean.
237
synchronized (write_lock) {
238       while (write_lock_count > 0) {
239         write_lock.wait();
240       }
241       check_point_in_progress = true;
242     }
243     
244     try {
245 // System.out.println("SET CHECKPOINT");
246
synchronized (page_map) {
247         // Flush all the pages out to the log.
248
for (int i = 0; i < page_map.length; ++i) {
249           BMPage page = page_map[i];
250           BMPage prev = null;
251
252           while (page != null) {
253             boolean deleted_hash = false;
254             synchronized (page) {
255               // Flush the page (will only actually flush if there are changes)
256
page.flush();
257
258               // Remove this page if it is no longer in use
259
if (page.notInUse()) {
260                 deleted_hash = true;
261                 if (prev == null) {
262                   page_map[i] = page.hash_next;
263                 }
264                 else {
265                   prev.hash_next = page.hash_next;
266                 }
267               }
268
269             }
270             // Go to next page in hash chain
271
if (!deleted_hash) {
272               prev = page;
273             }
274             page = page.hash_next;
275           }
276         }
277       }
278
279       journalled_system.setCheckPoint(flush_journals);
280
281     }
282     finally {
283       // Make sure we unset the 'check_point_in_progress' boolean and notify
284
// any blockers.
285
synchronized (write_lock) {
286         check_point_in_progress = false;
287         write_lock.notifyAll();
288       }
289     }
290
291   }
292
293
294   /**
295    * Called when a new page is created.
296    */

297   private void pageCreated(final BMPage page) throws IOException JavaDoc {
298     synchronized (T_lock) {
299
300       if (PARANOID_CHECKS) {
301         int i = page_list.indexOf(page);
302         if (i != -1) {
303           BMPage f = (BMPage) page_list.get(i);
304           if (f == page) {
305             throw new Error JavaDoc("Same page added multiple times.");
306           }
307           if (f != null) {
308             throw new Error JavaDoc("Duplicate pages.");
309           }
310         }
311       }
312
313       page.t = current_T;
314       ++current_T;
315
316       ++current_page_count;
317       page_list.add(page);
318
319       // Below is the page purge algorithm. If the maximum number of pages
320
// has been created we sort the page list weighting each page by time
321
// since last accessed and total number of accesses and clear the bottom
322
// 20% of this list.
323

324       // Check if we should purge old pages and purge some if we do...
325
if (current_page_count > max_pages) {
326         // Purge 20% of the cache
327
// Sort the pages by the current formula,
328
// ( 1 / page_access_count ) * (current_t - page_t)
329
// Further, if the page has written data then we multiply by 0.75.
330
// This scales down page writes so they have a better chance of
331
// surviving in the cache than page writes.
332
Object JavaDoc[] pages = page_list.toArray();
333         Arrays.sort(pages, PAGE_CACHE_COMPARATOR);
334
335         int purge_size = Math.max((int) (pages.length * 0.20f), 2);
336         for (int i = 0; i < purge_size; ++i) {
337           BMPage dpage = (BMPage) pages[pages.length - (i + 1)];
338           synchronized (dpage) {
339             dpage.dispose();
340           }
341         }
342
343         // Remove all the elements from page_list and set it with the sorted
344
// list (minus the elements we removed).
345
page_list.clear();
346         for (int i = 0; i < pages.length - purge_size; ++i) {
347           page_list.add(pages[i]);
348         }
349
350         current_page_count -= purge_size;
351       
352       }
353     }
354   }
355   
356   /**
357    * Called when a page is accessed.
358    */

359   private void pageAccessed(BMPage page) {
360     synchronized (T_lock) {
361       page.t = current_T;
362       ++current_T;
363       ++page.access_count;
364     }
365   }
366   
367   /**
368    * Calculates a hash code given an id value and a page_number value.
369    */

370   private static int calcHashCode(long id, long page_number) {
371     return (int) ((id << 6) + (page_number * ((id + 25) << 2)));
372   }
373   
374   /**
375    * Fetches and returns a page from a store. Pages may be cached. If the
376    * page is not available in the cache then a new BMPage object is created
377    * for the page requested.
378    */

379   private BMPage fetchPage(JournalledResource data,
380                            final long page_number) throws IOException JavaDoc {
381     final long id = data.getID();
382
383     BMPage prev_page = null;
384     boolean new_page = false;
385     BMPage page;
386
387     synchronized (page_map) {
388       // Generate the hash code for this page.
389
final int p = (calcHashCode(id, page_number) & 0x07FFFFFFF) %
390                                                              page_map.length;
391       // Search for this page in the hash
392
page = page_map[p];
393       while (page != null && !page.isPage(id, page_number)) {
394         prev_page = page;
395         page = page.hash_next;
396       }
397
398       // Page isn't found so create it and add to the cache
399
if (page == null) {
400         page = new BMPage(data, page_number, page_size);
401         // Add this page to the map
402
page.hash_next = page_map[p];
403         page_map[p] = page;
404       }
405       else {
406         // Move this page to the head if it's not already at the head.
407
if (prev_page != null) {
408           prev_page.hash_next = page.hash_next;
409           page.hash_next = page_map[p];
410           page_map[p] = page;
411         }
412       }
413
414       synchronized (page) {
415         // If page not in use then it must be newly setup, so add a
416
// reference.
417
if (page.notInUse()) {
418           page.reset();
419           new_page = true;
420           page.referenceAdd();
421         }
422         // Add a reference for this fetch
423
page.referenceAdd();
424       }
425
426     }
427
428     // If the page is new,
429
if (new_page) {
430       pageCreated(page);
431     }
432     else {
433       pageAccessed(page);
434     }
435
436     // Return the page.
437
return page;
438
439   }
440
441
442   // ------
443
// Buffered access methods. These are all thread safe methods. When a page
444
// is accessed the page is synchronized so no 2 or more operations can
445
// read/write from the page at the same time. An operation can read/write to
446
// different pages at the same time, however, and this requires thread safety
447
// at a lower level (in the JournalledResource implementation).
448
// ------
449

450   int readByteFrom(JournalledResource data, long position) throws IOException JavaDoc {
451     final long page_number = position / page_size;
452     int v;
453
454     BMPage page = fetchPage(data, page_number);
455     synchronized (page) {
456       try {
457         page.initialize();
458         v = ((int) page.read((int) (position % page_size))) & 0x0FF;
459       }
460       finally {
461         page.dispose();
462       }
463     }
464
465     return v;
466   }
467   
468   int readByteArrayFrom(JournalledResource data,
469               long position, byte[] buf, int off, int len) throws IOException JavaDoc {
470
471     final int orig_len = len;
472     long page_number = position / page_size;
473     int start_offset = (int) (position % page_size);
474     int to_read = Math.min(len, page_size - start_offset);
475
476     BMPage page = fetchPage(data, page_number);
477     synchronized (page) {
478       try {
479         page.initialize();
480         page.read(start_offset, buf, off, to_read);
481       }
482       finally {
483         page.dispose();
484       }
485     }
486
487     len -= to_read;
488     while (len > 0) {
489       off += to_read;
490       position += to_read;
491       ++page_number;
492       to_read = Math.min(len, page_size);
493
494       page = fetchPage(data, page_number);
495       synchronized (page) {
496         try {
497           page.initialize();
498           page.read(0, buf, off, to_read);
499         }
500         finally {
501           page.dispose();
502         }
503       }
504       len -= to_read;
505     }
506
507     return orig_len;
508   }
509   
510   void writeByteTo(JournalledResource data,
511                    long position, int b) throws IOException JavaDoc {
512
513     if (PARANOID_CHECKS) {
514       synchronized (write_lock) {
515         if (write_lock_count == 0) {
516           System.out.println("Write without a lock!");
517           new Error JavaDoc().printStackTrace();
518         }
519       }
520     }
521
522     final long page_number = position / page_size;
523
524     BMPage page = fetchPage(data, page_number);
525     synchronized (page) {
526       try {
527         page.initialize();
528         page.write((int) (position % page_size), (byte) b);
529       }
530       finally {
531         page.dispose();
532       }
533     }
534   }
535
536   void writeByteArrayTo(JournalledResource data,
537               long position, byte[] buf, int off, int len) throws IOException JavaDoc {
538
539     if (PARANOID_CHECKS) {
540       synchronized (write_lock) {
541         if (write_lock_count == 0) {
542           System.out.println("Write without a lock!");
543           new Error JavaDoc().printStackTrace();
544         }
545       }
546     }
547
548     long page_number = position / page_size;
549     int start_offset = (int) (position % page_size);
550     int to_write = Math.min(len, page_size - start_offset);
551
552     BMPage page = fetchPage(data, page_number);
553     synchronized (page) {
554       try {
555         page.initialize();
556         page.write(start_offset, buf, off, to_write);
557       }
558       finally {
559         page.dispose();
560       }
561     }
562     len -= to_write;
563
564     while (len > 0) {
565       off += to_write;
566       position += to_write;
567       ++page_number;
568       to_write = Math.min(len, page_size);
569
570       page = fetchPage(data, page_number);
571       synchronized (page) {
572         try {
573           page.initialize();
574           page.write(0, buf, off, to_write);
575         }
576         finally {
577           page.dispose();
578         }
579       }
580       len -= to_write;
581     }
582
583   }
584
585   void setDataAreaSize(JournalledResource data,
586                        long new_size) throws IOException JavaDoc {
587     data.setSize(new_size);
588   }
589
590   long getDataAreaSize(JournalledResource data) throws IOException JavaDoc {
591     return data.getSize();
592   }
593
594   void close(JournalledResource data) throws IOException JavaDoc {
595     long id = data.getID();
596     // Flush all changes made to the resource then close.
597
synchronized (page_map) {
598 // System.out.println("Looking for id: " + id);
599
// Flush all the pages out to the log.
600
// This scans the entire hash for values and could be an expensive
601
// operation. Fortunately 'close' isn't used all that often.
602
for (int i = 0; i < page_map.length; ++i) {
603         BMPage page = page_map[i];
604         BMPage prev = null;
605
606         while (page != null) {
607           boolean deleted_hash = false;
608           if (page.getID() == id) {
609 // System.out.println("Found page id: " + page.getID());
610
synchronized (page) {
611               // Flush the page (will only actually flush if there are changes)
612
page.flush();
613
614               // Remove this page if it is no longer in use
615
if (page.notInUse()) {
616                 deleted_hash = true;
617                 if (prev == null) {
618                   page_map[i] = page.hash_next;
619                 }
620                 else {
621                   prev.hash_next = page.hash_next;
622                 }
623               }
624             }
625
626           }
627
628           // Go to next page in hash chain
629
if (!deleted_hash) {
630             prev = page;
631           }
632           page = page.hash_next;
633
634         }
635       }
636     }
637
638     data.close();
639   }
640   
641
642
643   // ---------- Inner classes ----------
644

645   /**
646    * A page from a store that is currently being cached in memory. This is
647    * also an element in the cache.
648    */

649   private static final class BMPage {
650
651     /**
652      * The StoreDataAccessor that the page content is part of.
653      */

654     private final JournalledResource data;
655     
656     /**
657      * The page number.
658      */

659     private final long page;
660
661     /**
662      * The size of the page.
663      */

664     private final int page_size;
665     
666
667     /**
668      * The buffer that contains the data for this page.
669      */

670     private byte[] buffer;
671
672     /**
673      * True if this page is initialized.
674      */

675     private boolean initialized;
676
677
678     /**
679      * A reference to the next page with this hash key.
680      */

681     BMPage hash_next;
682
683
684     /**
685      * The time this page was last accessed. This value is reset each time
686      * the page is requested.
687      */

688     long t;
689
690     /**
691      * The number of times this page has been accessed since it was created.
692      */

693     int access_count;
694
695
696     /**
697      * The first position in the buffer that was last written.
698      */

699     private int first_write_position;
700
701     /**
702      * The last position in the buffer that was last written.
703      */

704     private int last_write_position;
705
706     /**
707      * The number of references on this page.
708      */

709     private int reference_count;
710
711
712     /**
713      * Constructs the page.
714      */

715     BMPage(JournalledResource data, long page, int page_size) {
716       this.data = data;
717       this.page = page;
718       this.reference_count = 0;
719       this.page_size = page_size;
720       reset();
721     }
722
723     /**
724      * Resets this object.
725      */

726     void reset() {
727       // Assert that this is 0
728
if (reference_count != 0) {
729         throw new Error JavaDoc("reset when 'reference_count' is != 0 ( = " +
730                         reference_count + " )");
731       }
732       this.initialized = false;
733       this.t = 0;
734       this.access_count = 0;
735     }
736     
737     /**
738      * Returns the id of the JournalledResource that is being buffered.
739      */

740     long getID() {
741       return data.getID();
742     }
743     
744     /**
745      * Adds 1 to the reference counter on this page.
746      */

747     void referenceAdd() {
748       ++reference_count;
749     }
750
751     /**
752      * Removes 1 from the reference counter on this page.
753      */

754     private void referenceRemove() {
755       if (reference_count <= 0) {
756         throw new Error JavaDoc("Too many reference remove.");
757       }
758       --reference_count;
759     }
760
761     /**
762      * Returns true if this PageBuffer is not in use (has 0 reference count and
763      * is not inialized.
764      */

765     boolean notInUse() {
766       return reference_count == 0;
767 // return (reference_count <= 0 && !initialized);
768
}
769
770     /**
771      * Returns true if this page matches the given id/page_number.
772      */

773     boolean isPage(long in_id, long in_page) {
774       return (getID() == in_id &&
775               page == in_page);
776     }
777     
778     /**
779      * Reads the current page content into memory. This may read from the
780      * data files or from a log.
781      */

782     private void readPageContent(
783                    long page_number, byte[] buf, int pos) throws IOException JavaDoc {
784       if (pos != 0) {
785         throw new Error JavaDoc("Assert failed: pos != 0");
786       }
787       // Read from the resource
788
data.read(page_number, buf, pos);
789     }
790
791     /**
792      * Flushes this page out to disk, but does not remove from memory. In a
793      * logging system this will flush the changes out to a log.
794      */

795     void flush() throws IOException JavaDoc {
796       if (initialized) {
797         if (last_write_position > -1) {
798           // Write to the store data.
799
data.write(page, buffer, first_write_position,
800                      last_write_position - first_write_position);
801 // System.out.println("FLUSH " + data + " off = " + first_write_position +
802
// " len = " + (last_write_position - first_write_position));
803
}
804         first_write_position = Integer.MAX_VALUE;
805         last_write_position = -1;
806       }
807     }
808     
809     /**
810      * Initializes the page buffer. If the buffer is already initialized then
811      * we just return. If it's not initialized we set up any internal
812      * structures that are required to be set up for access to this page.
813      */

814     void initialize() throws IOException JavaDoc {
815       if (!initialized) {
816
817         try {
818
819           // Create the buffer to contain the page in memory
820
buffer = new byte[page_size];
821           // Read the page. This will either read the page from the backing
822
// store or from a log.
823
readPageContent(page, buffer, 0);
824           initialized = true;
825
826 // access_count = 0;
827
first_write_position = Integer.MAX_VALUE;
828           last_write_position = -1;
829
830         }
831         catch (IOException JavaDoc e) {
832           // This makes debugging a little clearer if 'readPageContent' fails.
833
// When 'readPageContent' fails, the dispose method fails also.
834
System.out.println("IO Error during page initialize: " + e.getMessage());
835           e.printStackTrace();
836           throw e;
837         }
838
839       }
840     }
841
842     /**
843      * Disposes of the page buffer if it can be disposed (there are no
844      * references to the page and the page is initialized). When disposed the
845      * memory used by the page is reclaimed and the content is written out to
846      * disk.
847      */

848     void dispose() throws IOException JavaDoc {
849       referenceRemove();
850       if (reference_count == 0) {
851         if (initialized) {
852           
853           // Flushes the page from memory. This will write the page out to the
854
// log.
855
flush();
856
857           // Page is no longer initialized.
858
initialized = false;
859           // Clear the buffer from memory.
860
buffer = null;
861
862         }
863         else {
864           // This happens if initialization failed. If this case we don't
865
// flush out the changes, but we do allow the page to be disposed
866
// in the normal way.
867
// Note that any exception generated by the initialization failure
868
// will propogate correctly.
869
buffer = null;
870 // throw new RuntimeException(
871
// "Assertion failed: tried to dispose an uninitialized page.");
872
}
873       }
874     }
875
876
877     /**
878      * Reads a single byte from the cached page from memory.
879      */

880     byte read(int pos) {
881       return buffer[pos];
882     }
883
884     /**
885      * Reads a part of this page into the cached page from memory.
886      */

887     void read(int pos, byte[] buf, int off, int len) {
888       System.arraycopy(buffer, pos, buf, off, len);
889     }
890
891     /**
892      * Writes a single byte to the page in memory.
893      */

894     void write(int pos, byte v) {
895       first_write_position = Math.min(pos, first_write_position);
896       last_write_position = Math.max(pos + 1, last_write_position);
897
898       buffer[pos] = v;
899     }
900
901     /**
902      * Writes to the given part of the page in memory.
903      */

904     void write(int pos, byte[] buf, int off, int len) {
905       first_write_position = Math.min(pos, first_write_position);
906       last_write_position = Math.max(pos + len, last_write_position);
907
908       System.arraycopy(buf, off, buffer, pos, len);
909     }
910
911     public boolean equals(Object JavaDoc ob) {
912       BMPage dest_page = (BMPage) ob;
913       return isPage(dest_page.getID(), dest_page.page);
914     }
915     
916   }
917
918   /**
919    * A data resource that is being buffered.
920    */

921   private static class BResource {
922
923     /**
924      * The id assigned to the resource.
925      */

926     private final long id;
927
928     /**
929      * The unique name of the resource within the store.
930      */

931     private final String JavaDoc name;
932
933     /**
934      * Constructs the resource.
935      */

936     BResource(long id, String JavaDoc name) {
937       this.id = id;
938       this.name = name;
939     }
940
941     /**
942      * Returns the id assigned to this resource.
943      */

944     long getID() {
945       return id;
946     }
947
948     /**
949      * Returns the name of this resource.
950      */

951     String JavaDoc getName() {
952       return name;
953     }
954
955   }
956
957   /**
958    * A Comparator used to sort cache entries.
959    */

960   private final Comparator JavaDoc PAGE_CACHE_COMPARATOR = new Comparator JavaDoc() {
961
962     /**
963      * The calculation for finding the 'weight' of a page in the cache. A
964      * heavier page is sorted lower and is therefore cleared from the cache
965      * faster.
966      */

967     private final float pageEnumValue(BMPage page) {
968       // We fix the access counter so it can not exceed 10000 accesses. I'm
969
// a little unsure if we should put this constant in the equation but it
970
// ensures that some old but highly accessed page will not stay in the
971
// cache forever.
972
final long bounded_page_count = Math.min(page.access_count, 10000);
973       final float v = (1f / bounded_page_count) * ( current_T - page.t );
974       return v;
975     }
976
977     public int compare(Object JavaDoc ob1, Object JavaDoc ob2) {
978       float v1 = pageEnumValue((BMPage) ob1);
979       float v2 = pageEnumValue((BMPage) ob2);
980       if (v1 > v2) {
981         return 1;
982       }
983       else if (v1 < v2) {
984         return -1;
985       }
986       return 0;
987     }
988
989   };
990
991   /**
992    * A factory interface for creating StoreDataAccessor objects from resource
993    * names.
994    */

995   public static interface StoreDataAccessorFactory {
996     
997     /**
998      * Returns a StoreDataAccessor object for the given resource name.
999      */

1000    public StoreDataAccessor createStoreDataAccessor(String JavaDoc resource_name);
1001    
1002  }
1003  
1004  
1005}
1006
1007
Popular Tags