001 package edu.harvard.deas.hyperenc.vsat; 002 003 import java.io.Serializable; 004 import java.security.SecureRandom; 005 006 import edu.harvard.deas.hyperenc.util.NNLookup; 007 008 // TODO:Fix the collision detection 009 // TODO:Sync access to the database 010 011 /** Contains an index of the pages we will provide. Does the 012 book-keeping to make sure that each page is only accessed twice, 013 returns pages based on the Nearest Neighbor lookup */ 014 public class NNPageDatabase 015 extends Thread 016 implements Serializable, PageDatabase 017 { 018 private static final long serialVersionUID = 1L; 019 020 /** Controls debugging output. */ 021 private static final boolean DEBUG = false; 022 023 /** 024 * The number of pages this database will contain 025 */ 026 public static final int MAX_NUM_PAGES = 50; 027 028 /** 029 * Strong pseudo-random number generator for creating page id's 030 */ 031 private SecureRandom securePRNG; 032 033 /** 034 * Our database of pages is a NNLookup table. Each page is a VSatPage object 035 **/ 036 private NNLookup<VSatPage> pageDB; 037 038 /** 039 * Creates a new NNPageDatabase. Generates MAX_NUM_PAGES and inserts them 040 * into the database. 041 */ 042 public NNPageDatabase() 043 { 044 pageDB = new NNLookup<VSatPage>(); 045 securePRNG = new SecureRandom(); 046 047 // generate our initial complement of pages 048 for ( int i = 0; i < MAX_NUM_PAGES; i++ ) { 049 if (DEBUG) System.out.println("Creating page " + i + " of " + MAX_NUM_PAGES); 050 generateNewPage(); 051 } 052 } 053 054 /** 055 * @return Number of pages currently stored in the page database. 056 */ 057 public int getNumPages() { 058 return pageDB.size(); 059 } 060 061 /** 062 * @return Maximum number of pages that can be stored in the page database. 063 */ 064 public int getMaxPages() { 065 return MAX_NUM_PAGES; 066 } 067 068 /** 069 * Equivalent to <code>getPage</code>. 070 */ 071 public byte[] getClosestPage(int key) { 072 return getPage(key); 073 } 074 075 /** Use the key to return the closest available page. 076 @param key The key we are trying to match. 077 @return The page whose key was closest to the request, or 078 <code>null</code> if the database is empty. 079 */ 080 public byte[] getPage(int key) 081 { 082 VSatPage thisPage; 083 084 //get closest page 085 synchronized (pageDB) { 086 thisPage = pageDB.get(key); 087 } 088 089 if (thisPage == null) { return null; } 090 091 // increment the counter for that page 092 thisPage.increment(); 093 094 //if this page has been accessed twice, delete it from the db 095 int count = thisPage.getCount(); 096 if ( count == 2 ) { 097 synchronized (pageDB) { 098 pageDB.delete(key); 099 } 100 // Generate a new page to replace the old one 101 this.generateNewPage(); 102 } else if (count > 2) { 103 throw new IllegalStateException("Page access count is " + count 104 + ", which is greater than 2."); 105 } 106 107 return thisPage.getData(); 108 } 109 110 /** Generate a new page and put it into the database */ 111 private void generateNewPage() 112 { 113 // Spawn a thread to collect the page 114 PageCreator pc = new PageCreator(); 115 pc.start(); 116 } 117 118 private class PageCreator extends Thread { 119 public void run() { 120 boolean keepGoing; 121 122 //call a new TrueRandomSource to get file data 123 TrueRandomSource myFRS; 124 // XXX coerce into using DevRandomSource... (undo me later) 125 if (true && DevRandomSource.randomDevice() != null) { 126 myFRS = new DevRandomSource(); 127 if (DEBUG) 128 System.out.println("Node: getting randomness from "+ 129 DevRandomSource.randomDevice()); 130 } else { 131 //System.out.println("Node: getting randomness from FileRandomSource"); 132 myFRS = new FileRandomSource(); 133 if (DEBUG) 134 System.out.println("Node: getting randomness from FileRandomSource"); 135 //myFRS = new DevRandomSource(); 136 } 137 138 VSatPage newPage = null; 139 int key; 140 141 do { 142 byte[] fileRandom = null; // Hold the random file data 143 144 do { 145 fileRandom = myFRS.genRandomness(); 146 } while (fileRandom == null); 147 148 //create a new VSatPage with this data 149 newPage = new VSatPage(fileRandom); 150 151 //we cannot permit collisions; that is, 152 //two pages cannot have the same key value 153 //so we need to find a unique key or just 154 //replace the existing key-page pair 155 //Rather than waste pages, or cause page collection 156 // to fail for the client, we check for uniqueness 157 // make a new key using our strong prng 158 key = securePRNG.nextInt(); 159 synchronized (pageDB) { 160 keepGoing = pageDB.getExact(key) != null; 161 } 162 } while (keepGoing); 163 164 synchronized (pageDB) { 165 pageDB.add(key, newPage); 166 if (DEBUG) System.out.println("Added a page"); 167 } 168 } 169 } 170 171 172 } 173