1 5 package org.h2.store; 6 7 import java.sql.SQLException ; 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 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 { 58 return file.getRecord(pos, reader, id); 59 } 60 61 public Record getRecordIfStored(int pos) throws SQLException { 62 return file.getRecordIfStored(pos, reader, id); 63 } 64 65 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 { 113 record.setDeleted(false); 114 file.updateRecord(session, record); 115 } 116 117 public void addRecord(Session session, Record record, int pos) throws SQLException { 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 { 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 { 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 { 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 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 { 195 truncate(session); 196 database.removeStorage(id, file); 197 } 198 199 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 { 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 { 231 file.writeBack(rec); 232 } 233 234 public void flushFile() throws SQLException { 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 |