1 package com.quadcap.sql.file; 2 3 40 41 import java.io.File ; 42 import java.io.FileDescriptor ; 43 import java.io.IOException ; 44 import java.io.RandomAccessFile ; 45 46 import java.util.BitSet ; 47 48 import com.quadcap.util.Debug; 49 import com.quadcap.util.Util; 50 51 import com.quadcap.sql.Version; 52 53 59 public class BlockStore { 60 File file; 61 FileRandomAccess fra; 62 boolean readOnly; 63 Log log; 64 int blockSize; 65 BitSet modified = new BitSet (); 66 Object lock; 67 boolean encrypted = false; 68 boolean isTempFile = false; 69 70 79 public BlockStore() { 80 } 81 82 public String getName() { 83 return file == null ? "null" : file.getName(); 84 } 85 86 public void init(File file, String mode, int blockSize, Object lock) 87 throws IOException 88 { 89 this.file = file; 90 boolean exists = file.exists(); 91 RandomAccessFile ra = new RandomAccessFile (file.getAbsolutePath(), mode); 92 this.fra = new FileRandomAccess(ra, 1024L * 1024L * 1024L * 1024L); 93 this.readOnly = mode.equalsIgnoreCase("r"); 94 this.lock = lock; 95 if (!exists) { 96 createHeader(blockSize); 97 } else { 98 readHeader(); 99 } 100 isTempFile = !(file.getPath().endsWith("datafile")); 101 } 102 103 106 public void setLog(Log log) { this.log = log; } 107 108 111 public Log getLog() { return log; } 112 113 116 public int blockSize() { return blockSize; } 117 118 121 public File getFile() { return file; } 122 123 130 public void read(long blockNum, byte[] buf) throws IOException { 131 read(blockNum, buf, 0); 132 } 133 134 public void read(long blockNum, byte[] buf, int off) 135 throws IOException 136 { 137 synchronized (lock) { 138 readCount++; 139 fra.read(blockNum * blockSize, buf, off, blockSize); 140 } 141 } 142 143 public static int writeCount = 0; 144 public static int readCount = 0; 145 152 public void write(long blockNum, byte[] buf) 153 throws IOException 154 { 155 synchronized (lock) { 156 writeCount++; 157 if (readOnly) { 158 throw new IOException ("Attempt to write readonly file: " + 159 file.getName()); 160 } 161 long pos = blockNum * blockSize; 162 if (log != null && !modified.get((int)blockNum)) { 163 modified.set((int)blockNum); 164 if (pos < fra.size()) { 165 log.saveBlock(blockNum); 166 } 167 } 168 if (Trace.bit(20)) { 170 Debug.println(toString() + ".write(" + blockNum + "," + 171 Block.signature(buf) + ") " + Util.stackTrace()); 172 } 173 fra.write(blockNum * blockSize, buf, 0, buf.length); 175 } 176 } 177 178 181 public void restore(long blockNum, byte[] buf, int off) 182 throws IOException 183 { 184 synchronized (lock) { 185 if (Trace.bit(20)) { 187 Debug.println(toString() + ".restore(" + blockNum + "," + 188 Block.signature(buf, off, blockSize) + ")"); 189 } 190 fra.write(blockNum * blockSize, buf, off, blockSize); 192 } 193 194 } 195 196 public void clearModified() throws IOException { 197 modified = new BitSet (); 198 if (log != null) log.resetBlocks(); 199 } 200 201 202 public void setLength(long length) throws IOException { 203 if (readOnly) { 204 throw new IOException ("Attempt to write readonly file: " + 205 file.getName()); 206 } 207 fra.resize(length); 208 } 209 210 public boolean isEncrypted() { 211 return encrypted; 212 } 213 214 private void readHeader() throws IOException { 215 byte[] buf = new byte[32]; 216 fra.read(0, buf, 0, buf.length); 217 int v = ((buf[0] & 0xff) << 8) + (buf[1] & 0xff); 218 switch (v) { 219 case 0x040c: encrypted = false; 221 break; 222 case 0x0e0c: encrypted = true; 224 break; 225 default: 226 throw new IOException ("BlockFile: bad magic"); 227 } 228 if (buf[2] != Version.majorVersion) { 233 throw new IOException ("BlockFile: bad version (" + 234 (int)buf[2] + "." + (int)buf[3] + 235 " vs " + 236 Version.majorVersion + "." + 237 Version.minorVersion + ")"); 238 } 239 this.blockSize = ByteUtil.getInt(buf, BlockFile.oBLOCKSIZE); 240 } 241 242 private void createHeader(int blockSize) throws IOException { 243 this.blockSize = blockSize; 244 byte[] buf = newHeader(blockSize, 2); 245 fra.write(0, buf, 0, buf.length); 246 } 247 248 protected final byte[] newHeader(int blockSize, long lastBlock) { 249 byte[] buf = new byte[blockSize]; 250 for (int i = 0; i < blockSize; i++) buf[i] = (byte)0; 251 buf[0] = 0x4; buf[1] = 0xc; buf[2] = Version.majorVersion; 253 buf[3] = Version.minorVersion; 254 ByteUtil.putInt(buf, BlockFile.oBLOCKSIZE, blockSize); 255 ByteUtil.putLong(buf, BlockFile.oLASTBLOCK, lastBlock); return buf; 257 } 258 259 public void close() throws IOException { 260 try { 261 if (fra != null) fra.close(); 262 } finally { 263 fra = null; 264 } 265 } 266 267 public void flush() throws IOException { 268 try { 269 fra.flush(); 270 readCount = writeCount = 0; 271 } catch (Throwable t) {} 272 } 273 274 public void setKey(com.quadcap.crypto.SymmetricKey key) 276 throws IOException 277 { 278 throw new IOException ("Not encrypted"); 279 } 280 282 public String toString() { 284 return "BlockStore(" + file.getPath() + ")"; 285 } 286 287 public static String rw() { 288 return "(r=" + BlockStore.readCount + 289 " w=" + BlockStore.writeCount + ")"; 290 } 291 292 294 } 295 | Popular Tags |