KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > store > Storage


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.store;
6
7 import java.sql.SQLException JavaDoc;
8
9 import org.h2.engine.Constants;
10 import org.h2.engine.Database;
11 import org.h2.engine.Session;
12 import org.h2.message.Message;
13 import org.h2.util.BitField;
14 import org.h2.util.IntArray;
15 import org.h2.util.MathUtils;
16
17 /**
18  * File format:
19  * intfixed block size
20  * intfixed storage id
21  * record data
22  * byte checksum
23  * [bytes * fillerLength]
24  *
25  * @author Thomas
26  */

27
28 public class Storage {
29
30     public static final int ALLOCATE_POS = -1;
31     private static final int FREE_LIST_SIZE = Math.max(1024, DiskFile.BLOCKS_PER_PAGE * 4);
32     private DiskFile file;
33     private int recordCount;
34     private RecordReader reader;
35     private IntArray freeList = new IntArray();
36     private IntArray pages = new IntArray();
37     private int id;
38     private Database database;
39     private DataPage dummy;
40
41     public Storage(Database database, DiskFile file, RecordReader reader, int id) {
42         this.database = database;
43         this.file = file;
44         this.reader = reader;
45         this.id = id;
46         dummy = DataPage.create(database, 0);
47     }
48
49     public RecordReader getRecordReader() {
50         return reader;
51     }
52
53     void incrementRecordCount() {
54         recordCount++;
55     }
56
57     public Record getRecord(int pos) throws SQLException JavaDoc {
58         return file.getRecord(pos, reader, id);
59     }
60
61     public Record getRecordIfStored(int pos) throws SQLException JavaDoc {
62         return file.getRecordIfStored(pos, reader, id);
63     }
64
65     /**
66      * Gets the position of the next record.
67      * @param record the last record (null to get the first record)
68      * @return -1 if no record is found, otherwise the position
69      */

70     public int getNext(Record record) {
71         int next;
72         int lastCheckedPage;
73         int pageIndex = -1;
74         if (record == null) {
75             if(pages.size() == 0) {
76                 return -1;
77             }
78             pageIndex = 0;
79             lastCheckedPage = pages.get(0);
80             next = lastCheckedPage * DiskFile.BLOCKS_PER_PAGE;
81         } else {
82             int blockCount = record.getBlockCount();
83             lastCheckedPage = file.getPage(record.getPos());
84             next = record.getPos() + blockCount;
85         }
86         BitField used = file.getUsed();
87         while (true) {
88             int page = file.getPage(next);
89             if(lastCheckedPage != page) {
90                 if(pageIndex < 0) {
91                     pageIndex = pages.findNextValueIndex(page);
92                 } else {
93                     pageIndex++;
94                 }
95                 if(pageIndex >= pages.size()) {
96                     return -1;
97                 }
98                 lastCheckedPage = pages.get(pageIndex);
99                 next = Math.max(next, DiskFile.BLOCKS_PER_PAGE * lastCheckedPage);
100             }
101             if (used.get(next)) {
102                 return next;
103             }
104             if(used.getLong(next) == 0) {
105                 next = MathUtils.roundUp(next+1, 64);
106             } else {
107                 next++;
108             }
109         }
110     }
111
112     public void updateRecord(Session session, Record record) throws SQLException JavaDoc {
113         record.setDeleted(false);
114         file.updateRecord(session, record);
115     }
116
117     public void addRecord(Session session, Record record, int pos) throws SQLException JavaDoc {
118         record.setStorageId(id);
119         int size = file.getRecordOverhead() + record.getByteCount(dummy);
120         size = MathUtils.roundUp(size, DiskFile.BLOCK_SIZE);
121         record.setDeleted(false);
122         int blockCount = size / DiskFile.BLOCK_SIZE;
123         if(pos == ALLOCATE_POS) {
124             pos = allocate(blockCount);
125         } else {
126             file.setUsed(pos, blockCount);
127         }
128         record.setPos(pos);
129         record.setBlockCount(blockCount);
130         record.setChanged(true);
131         recordCount++;
132         file.addRecord(session, record);
133     }
134
135     public void removeRecord(Session session, int pos) throws SQLException JavaDoc {
136         Record record = getRecord(pos);
137         if(Constants.CHECK && record.getDeleted()) {
138             throw Message.getInternalError("duplicate delete " + pos);
139         }
140         record.setDeleted(true);
141         int blockCount = record.getBlockCount();
142         free(pos, blockCount);
143         recordCount--;
144         file.removeRecord(session, pos, record, blockCount);
145     }
146
147     public void removeRecord(Session session, int pos, int blockCount) throws SQLException JavaDoc {
148
149     }
150
151     private boolean isFreeAndMine(int pos, int blocks) {
152         BitField used = file.getUsed();
153         for(int i=blocks + pos -1; i>=pos; i--) {
154             if(file.getPageOwner(file.getPage(i)) != id || used.get(i)) {
155                 return false;
156             }
157         }
158         return true;
159     }
160
161     public int allocate(int blockCount) throws SQLException JavaDoc {
162         if (freeList.size() > 0) {
163             synchronized(file) {
164                 BitField used = file.getUsed();
165                 for (int i = 0; i < freeList.size(); i++) {
166                     int px = freeList.get(i);
167                     if (used.get(px)) {
168                         // sometime there may stay some entries in the freeList that are not free (free 2, free 1, allocate 1+2)
169
// these entries are removed right here
170
freeList.remove(i--);
171                     } else {
172                         if (isFreeAndMine(px, blockCount)) {
173                             int pos = px;
174                             freeList.remove(i--);
175                             file.setUsed(pos, blockCount);
176                             return pos;
177                         }
178                     }
179                 }
180             }
181         }
182         int pos = file.allocate(this, blockCount);
183         file.setUsed(pos, blockCount);
184         return pos;
185     }
186
187     void free(int pos, int blockCount) {
188         file.free(pos, blockCount);
189         if (freeList.size() < FREE_LIST_SIZE) {
190             freeList.add(pos);
191         }
192     }
193
194     public void delete(Session session) throws SQLException JavaDoc {
195         truncate(session);
196         database.removeStorage(id, file);
197     }
198
199     // private int allocateBest(int start, int blocks) {
200
// while (true) {
201
// int p = getLastUsedPlusOne(start, blocks);
202
// if (p == start) {
203
// start = p;
204
// break;
205
// }
206
// start = p;
207
// }
208
// allocate(start, blocks);
209
// return start;
210
// }
211

212     public int getId() {
213         return id;
214     }
215
216     public int getRecordCount() {
217         return recordCount;
218     }
219
220     public void truncate(Session session) throws SQLException JavaDoc {
221         freeList = new IntArray();
222         recordCount = 0;
223         file.truncateStorage(session, this, pages);
224     }
225
226     public void setReader(RecordReader reader) {
227         this.reader = reader;
228     }
229
230     public void flushRecord(Record rec) throws SQLException JavaDoc {
231         file.writeBack(rec);
232     }
233
234     public void flushFile() throws SQLException JavaDoc {
235         file.flush();
236     }
237
238     public int getRecordOverhead() {
239         return file.getRecordOverhead();
240     }
241
242     public DiskFile getDiskFile() {
243         return file;
244     }
245
246     public void setRecordCount(int recordCount) {
247         this.recordCount = recordCount;
248     }
249
250     public void addPage(int i) {
251         pages.addValueSorted(i);
252     }
253
254     public void removePage(int i) {
255         pages.removeValue(i);
256     }
257
258 }
259
Popular Tags