1 29 30 package com.caucho.db.store; 31 32 import com.caucho.log.Log; 33 import com.caucho.util.FreeList; 34 import com.caucho.util.L10N; 35 import com.caucho.util.SyncCacheListener; 36 37 import java.io.IOException ; 38 import java.util.logging.Level ; 39 import java.util.logging.Logger ; 40 41 44 abstract public class Block implements SyncCacheListener { 45 private static final Logger log = Log.open(Block.class); 46 private static final L10N L = new L10N(Block.class); 47 48 protected static final FreeList<byte[]> _freeBuffers 49 = new FreeList<byte[]>(4); 50 51 private final Store _store; 52 private final long _blockId; 53 54 private final Lock _lock; 55 56 private int _useCount = 1; 57 58 private boolean _isFlushDirtyOnCommit; 59 private boolean _isValid; 60 61 private int _dirtyMin = Store.BLOCK_SIZE; 62 private int _dirtyMax; 63 64 Block(Store store, long blockId) 65 { 66 store.validateBlockId(blockId); 67 68 _store = store; 69 _blockId = blockId; 70 71 _lock = new Lock("block:" + store.getName() + ":" + _blockId); 72 73 _isFlushDirtyOnCommit = _store.isFlushDirtyBlocksOnCommit(); 74 75 if (log.isLoggable(Level.FINER)) 76 log.finer(this + " create"); 77 78 } 80 81 84 public boolean isFlushDirtyOnCommit() 85 { 86 return _isFlushDirtyOnCommit; 87 } 88 89 92 public void setFlushDirtyOnCommit(boolean isFlush) 93 { 94 _isFlushDirtyOnCommit = isFlush; 95 } 96 97 100 boolean allocate() 101 { 102 synchronized (this) { 103 if (getBuffer() == null) 104 return false; 105 106 _useCount++; 107 108 if (log.isLoggable(Level.FINEST)) 109 log.finest(this + " allocate"); 110 111 113 if (_useCount > 32 && log.isLoggable(Level.FINE)) { 114 Thread.dumpStack(); 115 log.fine("using " + this + " " + _useCount + " times"); 116 } 117 } 118 119 return true; 120 } 121 122 125 Store getStore() 126 { 127 return _store; 128 } 129 130 133 public long getBlockId() 134 { 135 return _blockId; 136 } 137 138 public Lock getLock() 139 { 140 return _lock; 141 } 142 143 146 abstract public byte []getBuffer(); 147 148 151 public void read() 152 throws IOException 153 { 154 synchronized (this) { 155 if (! _isValid) { 156 if (log.isLoggable(Level.FINER)) 157 log.finer("read db-block " + this); 158 159 _store.readBlock(_blockId & Store.BLOCK_MASK, 160 getBuffer(), 0, Store.BLOCK_SIZE); 161 _isValid = true; 162 163 _dirtyMin = Store.BLOCK_SIZE; 164 _dirtyMax = 0; 165 } 166 } 167 } 168 169 174 public void commit() 175 throws IOException 176 { 177 if (! _isFlushDirtyOnCommit) 178 return; 179 else 180 write(); 181 } 182 183 186 public void write() 187 throws IOException 188 { 189 synchronized (this) { 190 int dirtyMin = _dirtyMin; 191 _dirtyMin = Store.BLOCK_SIZE; 192 193 int dirtyMax = _dirtyMax; 194 _dirtyMax = 0; 195 196 if (dirtyMin < dirtyMax) { 197 if (log.isLoggable(Level.FINER)) 198 log.finer("write db-block " + this + " [" + dirtyMin + ", " + dirtyMax + "]"); 199 200 writeImpl(dirtyMin, dirtyMax - dirtyMin); 202 } 204 else { 205 if (log.isLoggable(Level.FINER)) 206 log.finer("not-dirty db-block " + this); 207 } 208 209 _isValid = true; 210 } 211 } 212 213 216 protected void writeImpl(int offset, int length) 217 throws IOException 218 { 219 _store.writeBlock((_blockId & Store.BLOCK_MASK) + offset, 220 getBuffer(), offset, length); 221 } 222 223 226 public void invalidate() 227 { 228 if (_dirtyMin < _dirtyMax) 229 throw new IllegalStateException (); 230 231 _isValid = false; 232 _dirtyMin = Store.BLOCK_SIZE; 233 _dirtyMax = 0; 234 } 235 236 239 void validate() 240 { 241 _isValid = true; 242 } 243 244 247 public void setDirty(int min, int max) 248 { 249 if (Store.BLOCK_SIZE < max) 250 Thread.dumpStack(); 251 252 _isValid = true; 253 254 if (min < _dirtyMin) 255 _dirtyMin = min; 256 257 if (_dirtyMax < max) 258 _dirtyMax = max; 259 } 260 261 264 public boolean isDirty() 265 { 266 return _dirtyMin < _dirtyMax; 267 } 268 269 272 public boolean isFree() 273 { 274 return _useCount == 0; 275 } 276 277 280 public final void free() 281 { 282 synchronized (this) { 283 if (log.isLoggable(Level.FINEST)) 284 log.finest(this + " free"); 285 286 _useCount--; 287 288 290 if (_useCount > 0) 291 return; 292 293 if (_dirtyMax <= _dirtyMin) { 295 freeImpl(); 296 297 return; 298 } 299 } 300 301 BlockManager.getBlockManager().addLruDirtyWriteBlock(this); 303 } 304 305 308 public final void syncRemoveEvent() 309 { 310 free(); 311 } 312 313 316 void close() 318 { 319 synchronized (this) { 320 if (_dirtyMin < _dirtyMax) { 321 try { 322 write(); 323 } catch (Throwable e) { 324 log.log(Level.FINER, e.toString(), e); 325 } 326 } 327 328 if (_useCount <= 0) 329 freeImpl(); 330 331 if (log.isLoggable(Level.FINER)) 332 log.finer("db-block remove " + this); 333 } 334 } 335 336 339 protected void freeImpl() 340 { 341 } 342 343 public String toString() 344 { 345 return "Block[" + _store + "," + _blockId / Store.BLOCK_SIZE + "]"; 346 } 347 } 348 | Popular Tags |