KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > daffodilwoods > daffodildb > server > datasystem > persistentsystem > ClusterManager


1 package com.daffodilwoods.daffodildb.server.datasystem.persistentsystem;
2
3 import java.util.*;
4 import java.io.*;
5 import com.daffodilwoods.database.resource.DException;
6 import com.daffodilwoods.database.general._MemoryHandler;
7 import com.daffodilwoods.daffodildb.server.datasystem.interfaces.*;
8 import com.daffodilwoods.database.utility.P;
9 import com.daffodilwoods.daffodildb.server.sql99.utils._Reference;
10 import com.daffodilwoods.daffodildb.server.datasystem.indexsystem.FixedBTreeCluster;
11 import com.daffodilwoods.daffodildb.server.serversystem.ServerSystem;
12 import java.util.RandomAccess JavaDoc;
13 import com.daffodilwoods.daffodildb.server.datasystem.persistentsystem.versioninfo.VersionHandler;
14 import java.lang.ref.WeakReference JavaDoc;
15
16 /**
17  * The smallest entity in Persistent System is Cluster which is frequently used to
18  * perform it?s operations (read or write) on database file.Persistent System
19  * defines a cluster as collection of fixed number of consecutive bytes.
20  * It is obvious that there are so many clusters involved with a database,so to
21  * manage these clusters and to maintain the locking while writing on a cluster
22  * PersistentSystem has a ClusterManager.Cluster manager has a Map
23  * which is used to maintain the cluster bytes in memory.This map has so much
24  * intelligence that it can work within it?s limit, means it assures the server
25  * that it is not consuming a lot of memory.
26  *
27  *
28  * Important : we take lock on cluster adress to restrain the users to get the
29  * same cluster and use synchronize block on cluster adress. but this could create
30  * a dead lock because we use same type of locking on Session Table for rowId's.
31  * Process would be on dead lock if cluster adress and rowid will have the same
32  * value. Solution ::: to ignore this type of cases we are taking lock on negative
33  * value of cluster adress.
34  *
35  */

36 public class ClusterManager {
37
38   /**
39    * HashMap To Have listing of Clusters in Memory having mapping with their
40    * address and Read/Write Status
41    */

42   TableHashMap usedClusters;
43
44   /**
45    * Used to store the cluster bytes of those clusters which have uncommitted bytes, but can't reside in Map
46    * to reduce memory consumption.
47    */

48
49   private RandomAccessFile tempFile;
50
51   /**
52    * For reading from main database file.
53    */

54
55   private PersistentDatabase database;
56
57   /**
58    * for reading and writting in Temporary File ( swap file).
59    */

60
61   private TempFileHandler handler ;
62
63   /**
64    * It has the list of those address in Temp file which can be re-used
65    */

66
67   private Vector freeAddresses;
68
69   /**
70    * It is used while making new cluster instances and for accessig number
71    * of Read - Write clusters and cluster size etc.
72    */

73   DatabaseProperties databaseProperties;
74
75   /**
76    * It is used while creating new instance of a cluster.
77    */

78   VersionHandler versionHandler;
79   /**
80    * It is used to lock ClusterCharacteristics of a cluster
81    * while we are making new instance of a cluster or
82    * while we are removing a cluster fromo used cluster map.
83    */

84   ClusterLock clusterLock;
85
86   public ClusterManager(RandomAccessFile tempFile0, PersistentDatabase database0,DatabaseProperties databaseProperties0,VersionHandler versionHandler0,String JavaDoc daffodilHome) {
87     versionHandler = versionHandler0;
88     clusterLock = new ClusterLock();
89     databaseProperties = databaseProperties0;
90     tempFile = tempFile0;
91     handler = new TempFileHandler(this);
92     usedClusters = new TableHashMap(handler, database0.getDatabaseName(),databaseProperties);
93     freeAddresses = new Vector();
94     database = database0;
95
96   }
97 /*
98   private void init(RandomAccessFile tempFile0, PersistentDatabase database0,DatabaseProperties databaseProperties0){
99     databaseProperties = databaseProperties0;
100     tempFile = tempFile0;
101     handler = new TempFileHandler(this);
102     usedClusters = new TableHashMap(handler, database0.getDatabaseName(),databaseProperties);
103     freeAddresses = new ArrayList();
104     database = database0;
105   }
106 */

107
108   /**
109    * There are two types of clusters defined in DaffodilDB.One is ClusterForRead and an other is
110    * ClusterForWrite.If user wants only reading then it demands for clusterForRead otherwise
111    * clusterForWrite.If any user changes the bytes of cluster after taking the cluster for read then
112    * user can?t persistent their changes.PersistentDatabase provides both type of clusters.
113    *
114    *
115    * @param cc clustercharacteristics of cluster which is required for read
116    * @return cluster having staus as read
117    */

118
119
120
121   final Cluster getClusterForWrite(_DatabaseUser user,ClusterCharacteristics cc ) throws DException{
122   return getClusterForWrite(user,cc,false);
123   }
124
125   /**
126    * Used to get a cluster for read.
127    * Firstly we check it in map if we get it than we updtae mapping of read clusters and return it.
128    * otherwise we get null from map than we take lock on clusterCharacteristics whose cluster is to be geted
129    * now we get it form tempFileHandler's clusterMap
130    * if we get it than we make a instance of keyValue by passing cluster and its mode
131    * and we get address for these clusterCharacteristics in tempFile and if we find it than we
132    * add into freeAddressList which is used for temp file free adresses.
133    * else we make a new cluster if IsBtreeCluster true tahn we creat instance of fixedBtreeCluster otherwise cluster
134    * now making keyValue instance by passing cluster and null for indicating read mode of cluster
135    * now we try to get adddress from temp file corresponding to its clusterCharacteristics if we found it
136    * than we get bytes from temp file for this cluster and otherwise we read from database file.
137    * and set them in new cluster instance and if we readed bytes from tempfile than we add its adddress in freeAddressList.
138    * and set its key for write(by passing "") also set cluster as dirty because we readed bytes from temp file which are ot committed yet.
139    *
140    * @param cc ClusterCharacteristics - of whcih cluster is t be returned.
141    * @param isBTreeCluster boolean - is cluster used in btree or not.
142    * @throws DException
143    * @return Cluster - cluster corresponding to passed ClusterCharateristics.
144    */

145
146   final Cluster getClusterForRead(ClusterCharacteristics cc ,boolean isBTreeCluster ) throws DException{
147     KeyValue dbcl = (KeyValue)usedClusters.get(cc);
148     if(dbcl == null){
149       clusterLock.lock(cc.getStartAddress());
150       try{
151         dbcl = (KeyValue) usedClusters.get(cc);
152         if (dbcl == null) {
153           Cluster cls = handler.getClusterFromClustersMap(cc);
154           if (cls == null) {
155             Cluster newCluster = isBTreeCluster ?
156                 new FixedBTreeCluster(cc, databaseProperties, versionHandler) :
157                 new Cluster(cc, databaseProperties, versionHandler);
158             dbcl = new KeyValue(newCluster, null);
159             long add = handler.getAddressOfTempFile(cc);
160             byte[] bytes = (add == -1) ?
161                 database.getBytes(newCluster.clusterCharacteristics.
162                                   getStartAddress())
163                 : readFromTempFile(add);
164             newCluster.setBytesWithInitializeParameters(bytes);
165             if (add != -1) {
166               addInFreeAddressList(new Long JavaDoc(add));
167               dbcl.setKey("");
168               dbcl.cluster.setDirty(true);
169             }
170           }
171           else {
172             dbcl = new KeyValue(cls, cls.readMode ? null : "");
173             long add = handler.getAddressOfTempFile(cc);
174             if (add != -1) {
175               addInFreeAddressList(new Long JavaDoc(add));
176             }
177           }
178         }
179         usedClusters.updateClusterMappingForRead(cc, dbcl);
180       }finally{
181           clusterLock.unLock(cc.getStartAddress());
182       }
183     }
184     else{
185        usedClusters.updateClusterMappingForRead();
186     }
187     return dbcl.cluster;
188   }
189   /**
190     * Used to get a cluster for write.
191     * Firstly we check it in map if we get it than we updtae mapping of clusters and return it.
192     * otherwise we get null from map than we take lock on clusterCharacteristics whose cluster is to be geted
193     * now we get it form tempFileHandler's clusterMap
194     * if we get it than we get address for these clusterCharacteristics in tempFile and if we find it than we
195     * add into freeAddressList which is used for temp file free adresses.
196     * else we make a new cluster if IsBtreeCluster true tahn we creat instance of fixedBtreeCluster otherwise cluster
197     * now making keyValue instance by passing cluster and null for indicating read mode of cluster
198     * now we try to get adddress from temp file corresponding to its clusterCharacteristics if we found it
199     * than we get bytes from temp file for this cluster and otherwise we read from database file.
200     * and set them in new cluster instance and if we readed bytes from tempfile than we add its adddress in freeAddressList.
201     * and set cluster as dirty because we readed bytes from temp file which are ot committed yet.
202     * now we make a instance of keyValue by passing cluster and its mode for write by passing ""
203     * unlock clusterCharcteristics.
204     *
205     * @param cc ClusterCharacteristics - of whcih cluster is t be returned.
206     * @param isBTreeCluster boolean - is cluster used in btree or not.
207     * @throws DException
208     * @return Cluster - cluster corresponding to passed ClusterCharateristics.
209     */

210
211
212   final Cluster getClusterForWrite(_DatabaseUser user,ClusterCharacteristics cc,boolean isBTreeCluster ) throws DException{
213
214      KeyValue dbcl = (KeyValue)usedClusters.get(cc);
215     if(dbcl == null){
216       clusterLock.lock(cc.getStartAddress());
217       try {
218         dbcl = (KeyValue) usedClusters.get(cc);
219         if (dbcl == null) {
220           Cluster cls = handler.getClusterFromClustersMap(cc);
221           if (cls == null) {
222             cls = isBTreeCluster ?
223                 new FixedBTreeCluster(cc, databaseProperties, versionHandler) :
224                 new Cluster(cc, databaseProperties, versionHandler);
225             long add = handler.getAddressOfTempFile(cc);
226             byte[] bytes = (add == -1) ?
227                 database.getBytes(cls.clusterCharacteristics.getStartAddress())
228                 : readFromTempFile(add);
229             cls.setBytesWithInitializeParameters(bytes);
230             if (add != -1) {
231               addInFreeAddressList(new Long JavaDoc(add));
232               cls.setDirty(true);
233             }
234           }
235           else {
236             long add = handler.getAddressOfTempFile(cc);
237             if (add != -1) {
238               addInFreeAddressList(new Long JavaDoc(add));
239             }
240
241           }
242
243           dbcl = new KeyValue(cls, "");
244           usedClusters.updateClusterMappingForRead(cc, dbcl);
245         }
246         else {
247           dbcl.setKey("");
248           usedClusters.updateClusterMappingForRead(cc, dbcl);
249         }
250
251       }finally{
252         clusterLock.unLock(cc.getStartAddress());
253       }
254     }
255     else{
256       dbcl.setKey("");
257       usedClusters.updateClusterMappingForRead();
258     }
259     Cluster cluster = dbcl.cluster;
260     user.addCluster(cluster);
261     return cluster;
262   }
263
264   /**
265    * Not Used Now
266    */

267
268
269 /**
270  * returns the cluster bytes which is written in TemporaryFile at the address passed.
271  */

272
273   private byte[] readFromTempFile(long address) throws DException{
274     try{
275       byte[] bytes = new byte[databaseProperties.CLUSTERSIZE];
276       synchronized(tempFile){
277         tempFile.seek(address);
278         tempFile.read(bytes);
279       }
280       return bytes;
281     }
282     catch(IOException ioe) {
283       throw new DException("DSE2025",new Object JavaDoc[] {ioe.getMessage()});
284     }
285   }
286
287   /**
288    * write the cluster bytes in temp file at the appropriate location.
289    *
290    */

291
292   void writeInTempFile(Cluster cluster,byte[] bytes) throws DException{
293     synchronized(tempFile){
294       try {
295         long address = tempFile.length();
296         int size = freeAddresses.size();
297         if(size > 0){
298           address = ((Long JavaDoc)freeAddresses.get(size - 1)).longValue();
299           tempFile.seek(address);
300           tempFile.write(bytes);
301           freeAddresses.remove(size-1);
302           size--;
303         }
304         else{
305           tempFile.seek(address);
306           tempFile.write(bytes);
307         }
308         handler.addAddressOfTempFile(cluster.clusterCharacteristics,address);
309         handler.addCluster(cluster);
310       }
311       catch (IOException ex) {
312         throw new DException("DSE2025",new Object JavaDoc[] {ex.getMessage()});
313       }
314     }
315   }
316   /**
317    * It is used to check that number of used clusters in memory exceeds
318    * cluster's limit for write than we remove those clusters which are loaded
319    * with read status and after it we again check that now clusters exceeds limit
320    * if still limit is exceeds than we write cluster which is passed into temp file
321    * and remove it from used clusters map Here after limit exceeds than we write all after
322    * it into temp file(swap file).
323    * @param cluster Cluster
324    * @throws DException
325    */

326   void updateWriteClusters(Cluster cluster) throws DException{
327     if(usedClusters.size() > databaseProperties.CLUSTERS_IN_MEMORY_FOR_WRITE){
328       usedClusters.updateClusterMappingForReadWrite();
329
330       if(usedClusters.size() > databaseProperties.CLUSTERS_IN_MEMORY_FOR_WRITE){
331         writeInTempFile(cluster, cluster.getBytes());
332         removeCluster(cluster.getClusterCharacteristics());
333       }
334     }
335   }
336
337   final void addInFreeAddressList(Long JavaDoc ll) throws DException{
338     if(!freeAddresses.contains(ll)){
339       freeAddresses.add(ll);
340     }
341   }
342   /**
343      * Returns the appropriate cluster with bytes without decryption.It is called by PersistentDatabase at the time of creation
344      * of new cluster charactersitics.
345      *
346      * @param cc Cluster Characteristics of required cluster.
347      * @param flag true if cluster is BtreeCluster
348      * @return desired cluster
349      */

350   final Cluster getNewClusterForWrite(_DatabaseUser user,ClusterCharacteristics cc,boolean flag ) throws DException{
351         clusterLock.lock(cc.getStartAddress());
352         try{
353           Cluster cls = flag ?
354               new FixedBTreeCluster(cc, databaseProperties, versionHandler) :
355               new Cluster(cc, databaseProperties, versionHandler);
356           byte[] bytes = new byte[databaseProperties.CLUSTERSIZE];
357           Arrays.fill(bytes, (byte) 0);
358           cls.setBytes(bytes);
359           cls.setDirty(true);
360           KeyValue dbcl = new KeyValue(cls, "");
361           usedClusters.updateClusterMappingForRead(cc, dbcl);
362           Cluster cluster = dbcl.cluster;
363           user.addCluster(cluster);
364           return cluster;
365         }finally{
366            clusterLock.unLock(cc.getStartAddress());
367         }
368
369   }
370
371   /**
372    * Returns the appropriate cluster with bytes without decryption.It is called by PersistentDatabase at the time of creation
373    * of new cluster charactersitics.
374    *
375    * @param cc Cluster Characteristics of required cluster.
376    * @param flag true if cluster is BtreeCluster
377    * @return desired cluster
378    */

379
380   final Cluster getStartClusterForWriteFirst(_DatabaseUser user,ClusterCharacteristics cc,boolean flag ) throws DException{
381
382      KeyValue dbcl = (KeyValue)usedClusters.get(cc);
383     if(dbcl == null){
384       clusterLock.lock(cc.getStartAddress());
385       try{
386       dbcl = (KeyValue) usedClusters.get(cc);
387       if (dbcl == null) {
388         Cluster cls = handler.getClusterFromClustersMap(cc);
389         if (cls == null) {
390           cls = flag ? new FixedBTreeCluster(cc, databaseProperties,versionHandler) :
391                 new Cluster(cc, databaseProperties,versionHandler);
392           long add = handler.getAddressOfTempFile(cc);
393           byte[] bytes = (add == -1) ?
394                          database.getBytesFirst(cls.clusterCharacteristics.
395                          getStartAddress())
396                          : readFromTempFile(add);
397           cls.setBytes(bytes);
398           if (add != -1) {
399             addInFreeAddressList(new Long JavaDoc(add));
400             cls.setDirty(true);
401           }
402         }else{
403           long add = handler.getAddressOfTempFile(cc);
404           if (add != -1){
405              addInFreeAddressList(new Long JavaDoc(add));
406           }
407
408         }
409
410         dbcl = new KeyValue(cls, "");
411         usedClusters.updateClusterMappingForRead(cc, dbcl);
412       }
413       else{
414         dbcl.setKey("");
415         usedClusters.updateClusterMappingForRead(cc,dbcl);
416       }
417
418      }finally{
419        clusterLock.unLock(cc.getStartAddress());
420             }
421     }
422     else{
423       dbcl.setKey("");
424       usedClusters.updateClusterMappingForRead();
425     }
426     Cluster cluster = dbcl.cluster;
427     user.addCluster(cluster);
428     return cluster;
429   }
430
431   /**
432    * Returns the appropriate cluster with bytes without decryption.It is called by PersistentDatabase when the very first cluster of our
433    * Database file is needed.
434    *
435    * @param cc Cluster Characteristics of desired cluster
436    */

437   final Cluster getClusterForReadFirst(ClusterCharacteristics cc ) throws DException{
438
439     KeyValue dbcl = (KeyValue)usedClusters.get(cc);
440     if(dbcl == null){
441       clusterLock.lock(cc.getStartAddress());
442       try{
443       dbcl = (KeyValue)usedClusters.get(cc);
444       if( dbcl == null ){
445         Cluster cls = handler.getClusterFromClustersMap(cc);
446         if(cls == null){
447           Cluster newCluster = new Cluster(cc,databaseProperties,versionHandler);
448           dbcl = new KeyValue(newCluster, null);
449           long add = handler.getAddressOfTempFile(cc);
450           byte[] bytes = (add == -1) ? database.getBytesFirst(newCluster.clusterCharacteristics.getStartAddress())
451                          : readFromTempFile(add);
452           newCluster.setBytesWithInitializeParameters(bytes);
453           if(add != -1 ){
454             addInFreeAddressList(new Long JavaDoc(add));
455             dbcl.setKey("");
456           }
457         }
458         else{
459           dbcl = new KeyValue(cls, cls.readMode ? null : "");
460           long add = handler.getAddressOfTempFile(cc);
461           if (add != -1)
462             addInFreeAddressList(new Long JavaDoc(add));
463
464         }
465       }
466       usedClusters.updateClusterMappingForRead(cc,dbcl);
467
468       } finally{
469       clusterLock.unLock(cc.getStartAddress());
470       }
471     }
472     else
473       usedClusters.updateClusterMappingForRead();
474     return dbcl.cluster;
475   }
476   /**
477    * It is called from persistent database closeFile called and from finalize
478    * it closes temp file.
479    * @throws IOException
480    */

481   void closeFile()throws IOException{
482     if(tempFile!= null)
483       tempFile.close();
484   }
485   /**
486    * It remove cluster from used cluster map.
487    * @param cc ClusterCharacteristics of cluster which is to be removed.
488    * @throws DException
489    */

490   public void removeCluster(ClusterCharacteristics cc) throws DException {
491     clusterLock.lock(cc.getStartAddress());
492     try{
493       synchronized (usedClusters) {
494         usedClusters.remove(cc);
495       }
496     }finally{
497       clusterLock.unLock(cc.getStartAddress());
498     }
499   }
500   /**
501    * It is used to get cluster for power file
502    * difference between other method to get cluster and this is that
503    * In this case we doesn't add address in freeAddresslist whcih is used for temp file
504    * @param cc ClusterCharacteristics -- cluster to be geted corresponding to these clusterCharacteristics
505    * @param isBTreeCluster boolean -- is cluster for btree or not.
506    * @throws DException
507    * @return Cluster
508    */

509   final Cluster getClusterForPowerFile(ClusterCharacteristics cc ,boolean isBTreeCluster ) throws DException{
510     KeyValue dbcl = (KeyValue)usedClusters.get(cc);
511     if(dbcl == null){
512       clusterLock.lock(cc.getStartAddress());
513       try{
514       dbcl = (KeyValue)usedClusters.get(cc);
515       if( dbcl == null ){
516         Cluster cls = handler.getClusterFromClustersMap(cc);
517         if(cls == null){
518           Cluster newCluster = isBTreeCluster ? new FixedBTreeCluster(cc,databaseProperties,versionHandler): new Cluster(cc,databaseProperties,versionHandler);
519           dbcl = new KeyValue(newCluster, null);
520           long add = handler.getAddressOfTempFileForPowerFile(cc);
521           byte[] bytes = (add == -1) ? database.getBytes(newCluster.clusterCharacteristics.getStartAddress())
522                          : readFromTempFile(add);
523           newCluster.setBytesWithInitializeParameters(bytes);
524           if(add != -1 ){
525             dbcl.setKey("");
526             dbcl.cluster.setDirty(true);
527           }
528         }
529         else{
530           dbcl = new KeyValue(cls, cls.readMode ? null : "");
531         }
532       }
533       usedClusters.updateClusterMappingForRead();
534
535      }finally{
536       clusterLock.unLock(cc.getStartAddress());
537      }
538     }
539     else
540       usedClusters.updateClusterMappingForRead();
541     return dbcl.cluster;
542   }
543
544   /**
545    * For Testing Purpose
546    */

547
548   boolean checkInMap(ClusterCharacteristics cc) {
549     return usedClusters.get(cc) != null;
550   }
551   /**
552    * it is called from TempFileHandler
553    * @return RandomAccessFile temp.swp file
554    */

555   public RandomAccessFile getTempFile() {
556     return tempFile;
557   }
558   /**
559    * it is also called from TempFileHandler
560    * @return ArrayList free address list which contains free addresses for temp file.
561    */

562   public Vector getFreeAddresses(){
563     return freeAddresses;
564   }
565   /**
566    * It is called from persitentDatabase while adding a cluster into free list.
567    * We remove it from usedClusters map and now get it from temp file handler's cluster map
568    * now we get it's address from temp file and if isn't -1 then we add it into
569    * freeAddressList.
570    * @param cc ClusterCharacteristics
571    * @throws DException
572    */

573   public void removeClusterBeforeAddingInFreeList(ClusterCharacteristics cc) throws DException{
574     clusterLock.lock(cc.getStartAddress());
575     try{
576     synchronized (usedClusters) {
577       usedClusters.remove(cc);
578     }
579     Cluster cls = handler.getClusterFromClustersMap(cc);
580     /* check commented because it can be possible that a after a cluster is written into temp file
581      and added into clusterMap which holds a soft reference of cluster so while we are geting it from map
582      than it is also possble that it can't be garbage collected so we also need to get its address and
583      add it into free list so that we can use it again. */

584       long add = handler.getAddressOfTempFile(cc);
585       if(add != -1 )
586         addInFreeAddressList(new Long JavaDoc(add));
587     }finally{
588     clusterLock.unLock(cc.getStartAddress());
589     }
590   }
591 }
592
Popular Tags