2 * Copyright (c) 2007, Solido Systems
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
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.
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.
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.
32 package com.solidosystems.tuplesoup.core;
34 import TransactionalIO.core.TransactionalFile;
35 import dstm2.AtomicSuperClass;
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;
46 public @atomic interface TableIndexPageTSInf{
52 Integer getStarthash();
55 TableIndexPageTransactional getNextpage();
56 TableIndexPageTransactional getLowerpage();
57 PagedIndexTransactional getIndex();
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);
75 public TableIndexPageTransactional(PagedIndexTransactional index,TransactionalFile file) throws IOException{
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());
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);
99 index.atomicfields.setStat_create_page(index.atomicfields.getStat_create_page()+1);
100 return new TableIndexPageTransactional(index,file);
103 public void setFirst(){
104 this.atomicfields.setFirst(true);
107 public long getLocation(){
108 return atomicfields.getLocation();
110 public long getEndLocation(){
111 return this.atomicfields.getLocation()+atomicfields.getSize()+BASEOFFSET;
114 public String toString(){
115 StringBuffer buf=new StringBuffer();
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");
125 return buf.toString();
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());
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));
143 this.atomicfields.getLowerpage().addEntriesToList(lst);
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));
150 this.atomicfields.getNextpage().addEntriesToList(lst);
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);
157 if(entry.getLocation()!=Table.DELETE)lst.add(entry);
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));
170 atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
171 return this.atomicfields.getLowerpage().scanIndex(id,hashcode);
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));
180 atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
181 return this.atomicfields.getNextpage().scanIndex(id,hashcode);
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;
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));
194 atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
195 return this.atomicfields.getNextpage().scanIndex(id,hashcode);
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));
205 atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
206 return this.atomicfields.getLowerpage().getOffset(id,hashcode);
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));
215 atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
216 return this.atomicfields.getNextpage().getOffset(id,hashcode);
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;
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));
230 atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
231 return this.atomicfields.getNextpage().getOffset(id,hashcode);
234 protected TableIndexPageTransactional getFirstFreePage(String id,int hashcode) throws IOException{
235 // Is this an empty page?
236 if(this.atomicfields.getOffset()==0){
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());
245 return createNewPage(this.atomicfields.getIndex(),file,PagedIndexTransactional.PAGESIZE);
247 if(this.atomicfields.getLowerpage()==null){
248 file.seek(this.atomicfields.getLower());
249 this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
251 atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
252 return this.atomicfields.getLowerpage().getFirstFreePage(id,hashcode);
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;
258 if(this.atomicfields.getNext()==-1){
259 this.atomicfields.setNext(file.length());
261 return createNewPage(this.atomicfields.getIndex(),file,PagedIndexTransactional.PAGESIZE);
263 if(this.atomicfields.getNextpage()==null){
264 file.seek(this.atomicfields.getNext());
265 this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
267 atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
268 return this.atomicfields.getNextpage().getFirstFreePage(id,hashcode);
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());