*** empty log message ***
[IRC.git] / Robust / Transactions / mytuplesoup / src / com / solidosystems / tuplesoup / core / TableIndexPageTransactional.java
1 /*
2  * Copyright (c) 2007, Solido Systems
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * Neither the name of Solido Systems nor the names of its contributors may be
16  * used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31  
32 package com.solidosystems.tuplesoup.core;
33
34 import TransactionalIO.core.TransactionalFile;
35 import dstm2.AtomicSuperClass;
36 import dstm2.atomic;
37 import java.io.*;
38 import java.util.*;
39
40 public class TableIndexPageTransactional implements AtomicSuperClass{
41     TableIndexPageTSInf atomicfields = null;
42     private final static int BASEOFFSET=4+8+8+4+4;
43     //private RandomAccessFile file=null;
44     private TransactionalFile file = null;
45     
46     public @atomic interface TableIndexPageTSInf{
47         Long getLocation();
48         Integer getSize();
49         Long getNext();
50         Long getLower();
51         Integer getOffset();
52         Integer getStarthash();
53         Integer getEndhash();
54         Boolean getFirst();
55         TableIndexPageTransactional getNextpage();
56         TableIndexPageTransactional getLowerpage();
57         PagedIndexTransactional getIndex(); 
58         
59      
60         void setLowerpage(TableIndexPageTransactional lowerpage);   
61         void setNextpage(TableIndexPageTransactional nextpage);
62         void setFirst(Boolean val);
63         void setEndhash(int val);
64         void setStarthash(int val);
65         void setOffset(Integer offset);
66         void setNext(Long next);
67         void setSize(Integer size);
68         void setLocation(Long location);
69         void setLower(Long val);
70         void setIndex(PagedIndexTransactional val);
71     }
72   
73     
74     
75     public TableIndexPageTransactional(PagedIndexTransactional index,TransactionalFile file) throws IOException{
76         this.file=file;
77         this.atomicfields.setIndex(index);
78         this.atomicfields.setFirst(false);
79         this.atomicfields.setLocation(file.getFilePointer());
80         this.atomicfields.setSize(file.readInt());
81         this.atomicfields.setNext(file.readLong());
82         this.atomicfields.setLower(file.readLong());
83         this.atomicfields.setOffset(file.readInt());
84         this.atomicfields.setEndhash(file.readInt());
85         if(this.atomicfields.getOffset()>0)
86             this.atomicfields.setStarthash(file.readInt());
87     }
88     
89     public static TableIndexPageTransactional createNewPage(PagedIndexTransactional index,TransactionalFile file,int size) throws IOException{
90         long pre=file.length();
91 //        file.setLength(file.length()+size+BASEOFFSET);
92         file.seek(pre);
93         file.writeInt(size);
94         file.writeLong(-1l);
95         file.writeLong(-1l);
96         file.writeInt(0);
97         file.writeInt(-1);
98         file.seek(pre);
99         index.atomicfields.setStat_create_page(index.atomicfields.getStat_create_page()+1);
100         return new TableIndexPageTransactional(index,file);
101     }
102     
103     public void setFirst(){
104         this.atomicfields.setFirst(true);
105     }
106     
107     public long getLocation(){
108         return atomicfields.getLocation();
109     }
110     public long getEndLocation(){
111         return this.atomicfields.getLocation()+atomicfields.getSize()+BASEOFFSET;
112     }
113     
114     public String toString(){
115         StringBuffer buf=new StringBuffer();
116         buf.append("{\n");
117         buf.append("  location  "+this.atomicfields.getLocation()+"\n");
118         buf.append("  size      "+this.atomicfields.getSize()+"\n");
119         buf.append("  next      "+this.atomicfields.getNext()+"\n");
120         buf.append("  lower     "+this.atomicfields.getLower()+"\n");
121         buf.append("  offset    "+this.atomicfields.getOffset()+"\n");
122         buf.append("  starthash "+this.atomicfields.getStarthash()+"\n");
123         buf.append("  endhash "+this.atomicfields.getEndhash()+"\n");
124         buf.append("}\n");
125         return buf.toString();
126     }
127     
128     private void updateMeta() throws IOException{
129         file.seek(this.atomicfields.getLocation());
130         file.writeInt(this.atomicfields.getSize());
131         file.writeLong(this.atomicfields.getNext());
132         file.writeLong(this.atomicfields.getLower());
133         file.writeInt(this.atomicfields.getOffset());
134         file.writeInt(this.atomicfields.getEndhash());
135     }
136     
137     public void addEntriesToList(List<TableIndexEntryTransactional> lst) throws IOException{
138         if(this.atomicfields.getLower()>-1){
139             if(this.atomicfields.getLowerpage()==null){
140                 file.seek(this.atomicfields.getLower());
141                 this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
142             }
143             this.atomicfields.getLowerpage().addEntriesToList(lst);
144         }
145         if(this.atomicfields.getNext()>-1){
146             if(this.atomicfields.getNextpage()==null){
147                 file.seek(this.atomicfields.getNext());
148                 this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
149             }
150             this.atomicfields.getNextpage().addEntriesToList(lst);
151         }
152         file.seek(this.atomicfields.getLocation()+BASEOFFSET);
153         long pre=file.getFilePointer();
154         while(file.getFilePointer()<pre+this.atomicfields.getOffset()){
155             TableIndexEntryTransactional entry=TableIndexEntryTransactional.readData(file);
156             if(entry!=null){
157                 if(entry.getLocation()!=Table.DELETE)lst.add(entry);
158             }
159         }
160     }
161     
162     public TableIndexEntryTransactional scanIndex(String id,int hashcode) throws IOException{
163         if(!atomicfields.getFirst()){
164             if(hashcode<atomicfields.getStarthash()){
165                 if(atomicfields.getLower()==-1) return null;
166                 if(this.atomicfields.getLowerpage()==null){
167                     file.seek(this.atomicfields.getLower());
168                     this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
169                 }
170                 atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
171                 return this.atomicfields.getLowerpage().scanIndex(id,hashcode);
172             }
173         }
174         if(hashcode>this.atomicfields.getEndhash()){
175             if(this.atomicfields.getNext()==-1)return null;
176             if(this.atomicfields.getNextpage()==null){
177                 file.seek(this.atomicfields.getNext());
178                 this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
179             }
180             atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
181             return this.atomicfields.getNextpage().scanIndex(id,hashcode);
182         }
183         file.seek(this.atomicfields.getLocation()+BASEOFFSET);
184         long pre=file.getFilePointer();
185         while(file.getFilePointer()<pre+this.atomicfields.getOffset()){
186             TableIndexEntryTransactional entry=TableIndexEntryTransactional.lookForData(id,file);
187             if(entry!=null)return entry;
188         }
189         if(this.atomicfields.getNext()==-1)return null;
190         if(this.atomicfields.getNextpage()==null){
191             file.seek(this.atomicfields.getNext());
192             this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
193         }
194         atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
195         return this.atomicfields.getNextpage().scanIndex(id,hashcode);
196     }
197     protected long getOffset(String id,int hashcode) throws IOException{
198         if(!this.atomicfields.getFirst()){
199             if(hashcode<this.atomicfields.getStarthash()){
200                 if(this.atomicfields.getLower()==-1)return -1;
201                 if(this.atomicfields.getLowerpage()==null){
202                     file.seek(atomicfields.getLower());
203                     this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
204                 }
205                 atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
206                 return this.atomicfields.getLowerpage().getOffset(id,hashcode);
207             }
208         }
209         if(hashcode>this.atomicfields.getEndhash()){
210             if(this.atomicfields.getNext()==-1)return -1;
211             if(this.atomicfields.getNextpage()==null){
212                 file.seek(this.atomicfields.getNext());
213                 this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
214             }
215             atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
216             return this.atomicfields.getNextpage().getOffset(id,hashcode);
217         }
218         file.seek(this.atomicfields.getLocation()+BASEOFFSET);
219         long pre=file.getFilePointer();
220         while(file.getFilePointer()<pre+this.atomicfields.getOffset()){
221             long prescan=file.getFilePointer();
222             TableIndexEntryTransactional entry=TableIndexEntryTransactional.lookForData(id,file);
223             if(entry!=null)return prescan;
224         }
225         if(this.atomicfields.getNext()==-1)return -1;
226         if(this.atomicfields.getNextpage()==null){
227             file.seek(this.atomicfields.getNext());
228             this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
229         }
230         atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
231         return this.atomicfields.getNextpage().getOffset(id,hashcode);
232     }
233     
234     protected TableIndexPageTransactional getFirstFreePage(String id,int hashcode) throws IOException{
235         // Is this an empty page?
236         if(this.atomicfields.getOffset()==0){
237             return this;
238         }
239         // Is this hash lower than the starthash
240         if(!this.atomicfields.getFirst()){
241             if(hashcode<this.atomicfields.getStarthash()){
242                 if(this.atomicfields.getLower()==-1){
243                     this.atomicfields.setLower(file.length());
244                     updateMeta();
245                     return createNewPage(this.atomicfields.getIndex(),file,PagedIndexTransactional.PAGESIZE);
246                 }
247                 if(this.atomicfields.getLowerpage()==null){
248                     file.seek(this.atomicfields.getLower());
249                     this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
250                 }
251                 atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
252                 return this.atomicfields.getLowerpage().getFirstFreePage(id,hashcode);
253             }
254         }
255         // Do we have space in this page
256         if(this.atomicfields.getSize()-this.atomicfields.getOffset()>id.length()*2+4+4+8+1+2)return this;
257         // Check next
258         if(this.atomicfields.getNext()==-1){
259             this.atomicfields.setNext(file.length());
260             updateMeta();
261             return createNewPage(this.atomicfields.getIndex(),file,PagedIndexTransactional.PAGESIZE);
262         }
263         if(this.atomicfields.getNextpage()==null){
264             file.seek(this.atomicfields.getNext());
265             this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
266         }
267         atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
268         return this.atomicfields.getNextpage().getFirstFreePage(id,hashcode);
269     }
270     
271     public void addEntry(String id,int rowsize,int location,long position) throws IOException{
272         if(atomicfields.getOffset()==0)this.atomicfields.setStarthash(id.hashCode());
273         file.seek(this.atomicfields.getLocation()+BASEOFFSET+this.atomicfields.getOffset());
274         TableIndexEntryTransactional entry=new TableIndexEntryTransactional(id,rowsize,location,position);
275         entry.writeData(file);
276         this.atomicfields.setOffset(this.atomicfields.getOffset()+entry.getSize());
277         if(id.hashCode()>this.atomicfields.getEndhash()) this.atomicfields.setEndhash(id.hashCode());
278         updateMeta();
279     }
280 }