9385902d4c160d0a583d00c4eb851d121b32fc45
[IRC.git] /
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 java.io.*;
35 import java.util.*;
36
37 public class TableIndexPageTransactional{
38     public @atomic interface TableIndexPageTSInf{
39         Long getLocation();
40         Integer getSize();
41         Long getNext();
42         Long getLower();
43         Integer getOffset();
44         Integer getStarthash();
45         Integer getEndhash();
46         Boolean getFirst();
47         TableIndexPageTSInf getNextpage();
48         TableIndexPageTSInf getLowerpage();
49         
50      
51         void setLowerpage(TableIndexPageTSInf lowerpage);   
52         void setNextpage(TableIndexPageTSInf nextpage);
53         void setFirst(Boolean val);
54         void setEndhash();
55         void setStarthash();
56         void setOffset(Integer offset);
57         void setNext(Long next);
58         void setSize(Integer size);
59         void setLocation(Long location);
60         void setLower(Long val);
61     }
62     private final static int BASEOFFSET=4+8+8+4+4;
63     private RandomAccessFile file=null;
64     
65     private long location=-1;
66     private int size=-1;
67     private long next=-1;
68     private long lower=-1;
69     private int offset=0;
70     
71     private int starthash=-1;
72     private int endhash=-1;
73     private boolean first=false;
74     
75     private TableIndexPage nextpage=null;
76     private TableIndexPage lowerpage=null;
77     
78     private PagedIndex index=null;
79     
80     public TableIndexPageTransactional(PagedIndex index,RandomAccessFile file) throws IOException{
81         this.file=file;
82         this.index=index;
83         first=false;
84         location=file.getFilePointer();
85         size=file.readInt();
86         next=file.readLong();
87         lower=file.readLong();
88         offset=file.readInt();
89         endhash=file.readInt();
90         if(offset>0)starthash=file.readInt();
91     }
92     
93     public static TableIndexPage createNewPage(PagedIndex index,RandomAccessFile file,int size) throws IOException{
94         long pre=file.length();
95         file.setLength(file.length()+size+BASEOFFSET);
96         file.seek(pre);
97         file.writeInt(size);
98         file.writeLong(-1l);
99         file.writeLong(-1l);
100         file.writeInt(0);
101         file.writeInt(-1);
102         file.seek(pre);
103         index.stat_create_page++;
104         return new TableIndexPage(index,file);
105     }
106     
107     public void setFirst(){
108         first=true;
109     }
110     
111     public long getLocation(){
112         return location;
113     }
114     public long getEndLocation(){
115         return location+size+BASEOFFSET;
116     }
117     
118     public String toString(){
119         StringBuffer buf=new StringBuffer();
120         buf.append("{\n");
121         buf.append("  location  "+location+"\n");
122         buf.append("  size      "+size+"\n");
123         buf.append("  next      "+next+"\n");
124         buf.append("  lower     "+lower+"\n");
125         buf.append("  offset    "+offset+"\n");
126         buf.append("  starthash "+starthash+"\n");
127         buf.append("  endhash "+endhash+"\n");
128         buf.append("}\n");
129         return buf.toString();
130     }
131     
132     private void updateMeta() throws IOException{
133         file.seek(location);
134         file.writeInt(size);
135         file.writeLong(next);
136         file.writeLong(lower);
137         file.writeInt(offset);
138         file.writeInt(endhash);
139     }
140     
141     public void addEntriesToList(List<TableIndexEntry> lst) throws IOException{
142         if(lower>-1){
143             if(lowerpage==null){
144                 file.seek(lower);
145                 lowerpage=new TableIndexPage(index,file);
146             }
147             lowerpage.addEntriesToList(lst);
148         }
149         if(next>-1){
150             if(nextpage==null){
151                 file.seek(next);
152                 nextpage=new TableIndexPage(index,file);
153             }
154             nextpage.addEntriesToList(lst);
155         }
156         file.seek(location+BASEOFFSET);
157         long pre=file.getFilePointer();
158         while(file.getFilePointer()<pre+offset){
159             TableIndexEntry entry=TableIndexEntry.readData(file);
160             if(entry!=null){
161                 if(entry.getLocation()!=Table.DELETE)lst.add(entry);
162             }
163         }
164     }
165     
166     public TableIndexEntry scanIndex(String id,int hashcode) throws IOException{
167         if(!first){
168             if(hashcode<starthash){
169                 if(lower==-1)return null;
170                 if(lowerpage==null){
171                     file.seek(lower);
172                     lowerpage=new TableIndexPage(index,file);
173                 }
174                 index.stat_page_branch++;
175                 return lowerpage.scanIndex(id,hashcode);
176             }
177         }
178         if(hashcode>endhash){
179             if(next==-1)return null;
180             if(nextpage==null){
181                 file.seek(next);
182                 nextpage=new TableIndexPage(index,file);
183             }
184             index.stat_page_next++;
185             return nextpage.scanIndex(id,hashcode);
186         }
187         file.seek(location+BASEOFFSET);
188         long pre=file.getFilePointer();
189         while(file.getFilePointer()<pre+offset){
190             TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
191             if(entry!=null)return entry;
192         }
193         if(next==-1)return null;
194         if(nextpage==null){
195             file.seek(next);
196             nextpage=new TableIndexPage(index,file);
197         }
198         index.stat_page_next++;
199         return nextpage.scanIndex(id,hashcode);
200     }
201     protected long getOffset(String id,int hashcode) throws IOException{
202         if(!first){
203             if(hashcode<starthash){
204                 if(lower==-1)return -1;
205                 if(lowerpage==null){
206                     file.seek(lower);
207                     lowerpage=new TableIndexPage(index,file);
208                 }
209                 index.stat_page_branch++;
210                 return lowerpage.getOffset(id,hashcode);
211             }
212         }
213         if(hashcode>endhash){
214             if(next==-1)return -1;
215             if(nextpage==null){
216                 file.seek(next);
217                 nextpage=new TableIndexPage(index,file);
218             }
219             index.stat_page_next++;
220             return nextpage.getOffset(id,hashcode);
221         }
222         file.seek(location+BASEOFFSET);
223         long pre=file.getFilePointer();
224         while(file.getFilePointer()<pre+offset){
225             long prescan=file.getFilePointer();
226             TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
227             if(entry!=null)return prescan;
228         }
229         if(next==-1)return -1;
230         if(nextpage==null){
231             file.seek(next);
232             nextpage=new TableIndexPage(index,file);
233         }
234         index.stat_page_next++;
235         return nextpage.getOffset(id,hashcode);
236     }
237     
238     protected TableIndexPage getFirstFreePage(String id,int hashcode) throws IOException{
239         // Is this an empty page?
240         if(offset==0){
241             return this;
242         }
243         // Is this hash lower than the starthash
244         if(!first){
245             if(hashcode<starthash){
246                 if(lower==-1){
247                     lower=file.length();
248                     updateMeta();
249                     return createNewPage(index,file,PagedIndex.PAGESIZE);
250                 }
251                 if(lowerpage==null){
252                     file.seek(lower);
253                     lowerpage=new TableIndexPage(index,file);
254                 }
255                 index.stat_page_branch++;
256                 return lowerpage.getFirstFreePage(id,hashcode);
257             }
258         }
259         // Do we have space in this page
260         if(size-offset>id.length()*2+4+4+8+1+2)return this;
261         // Check next
262         if(next==-1){
263             next=file.length();
264             updateMeta();
265             return createNewPage(index,file,PagedIndex.PAGESIZE);
266         }
267         if(nextpage==null){
268             file.seek(next);
269             nextpage=new TableIndexPage(index,file);
270         }
271         index.stat_page_next++;
272         return nextpage.getFirstFreePage(id,hashcode);
273     }
274     
275     public void addEntry(String id,int rowsize,int location,long position) throws IOException{
276         if(offset==0)starthash=id.hashCode();
277         file.seek(this.location+BASEOFFSET+offset);
278         TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
279         entry.writeData(file);
280         offset+=entry.getSize();
281         if(id.hashCode()>endhash)endhash=id.hashCode();
282         updateMeta();
283     }
284 }