1 28 29 package com.caucho.vfs; 30 31 import com.caucho.util.CacheListener; 32 import com.caucho.util.LruCache; 33 34 import java.io.IOException ; 35 import java.io.OutputStream ; 36 import java.util.Map ; 37 38 58 public class CachePath extends FilesystemPath { 59 private final static int BLOCK_SIZE = 1024; 60 61 private Path _backingRoot; 62 private LruCache<String ,Cache> _cache; 63 private long _maxSize; 64 private long _maxEntrySize; 65 private long _size; 66 67 private Path _file; 68 private Cache _item; 69 private boolean _removeOnRelease; 70 71 private long _readTotalCount; 73 private long _readHitCount; 74 75 82 public CachePath(Path root, int entries, long capacity) 83 { 84 super(null, "/", "/"); 85 _root = this; 86 87 _backingRoot = root.createRoot(); 88 _cache = new LruCache<String ,Cache>(entries); 89 _maxSize = capacity; 90 _maxEntrySize = _maxSize / 64; 91 _maxEntrySize += BLOCK_SIZE - 1; 92 _maxEntrySize -= _maxEntrySize % BLOCK_SIZE; 93 94 if (_maxEntrySize > 1024 * 1024) 95 _maxEntrySize = 1024 * 1024; 96 97 clear(); 98 } 99 100 107 protected CachePath(FilesystemPath root, String userPath, String path) 108 { 109 super(root, userPath, path); 110 } 111 112 118 public void setRemoveOnRelease(boolean remove) 119 { 120 ((CachePath) _root)._removeOnRelease = remove; 121 } 122 123 132 public Path fsWalk(String userPath, 133 Map <String ,Object > attributes, 134 String path) 135 { 136 return new CachePath(_root, userPath, path); 137 } 138 139 142 public String getScheme() 143 { 144 return "cache"; 145 } 146 147 150 public void clear() 151 { 152 CachePath cRoot = (CachePath) _root; 153 154 synchronized (cRoot) { 155 cRoot._cache.clear(); 156 cRoot._size = 0; 157 } 158 } 159 160 163 public boolean exists() 164 { 165 return getFile().exists(); 166 } 167 168 public boolean isDirectory() 169 { 170 return getFile().isDirectory(); 171 } 172 173 public boolean isFile() 174 { 175 return getFile().isFile(); 176 } 177 178 public long getLength() 179 { 180 return getFile().getLength(); 181 } 182 183 public long getLastModified() 184 { 185 return getFile().getLastModified(); 186 } 187 188 public void setLastModified(long time) 189 { 190 getFile().setLastModified(time); 191 } 192 193 public boolean canRead() 194 { 195 return getFile().canRead(); 196 } 197 198 public boolean canWrite() 199 { 200 return getFile().canWrite(); 201 } 202 203 public String []list() throws IOException 204 { 205 return getFile().list(); 206 } 207 208 public boolean mkdir() 209 throws IOException 210 { 211 return getFile().mkdir(); 212 } 213 214 public boolean mkdirs() 215 throws IOException 216 { 217 return getFile().mkdirs(); 218 } 219 220 public boolean remove() 221 throws IOException 222 { 223 if (getFile().remove()) { 224 CachePath root = (CachePath) _root; 225 root._cache.remove(getPath()); 226 227 return true; 228 } 229 else 230 return false; 231 } 232 233 public boolean renameTo(Path path) 234 throws IOException 235 { 236 if (getFile().renameTo(path)) { 237 CachePath root = (CachePath) _root; 238 root._cache.remove(getPath()); 239 240 return true; 241 } 242 else 243 return false; 244 } 245 246 251 public void writeToStream(OutputStream os) throws IOException 252 { 253 CachePath root = (CachePath) _root; 254 LruCache<String ,Cache> cache = root._cache; 255 256 String path = getPath(); 257 258 if (_item == null) 259 _item = cache.get(path); 260 261 if (_item != null) { 262 TempBuffer head = _item.getHead(); 263 264 if (head != null) { 265 for (; head != null; head = head.getNext()) 266 os.write(head.getBuffer(), 0, head.getLength()); 267 return; 268 } 269 } 270 271 Path file = getFile(); 272 long length = file.getLength(); 273 274 if (length <= root._maxEntrySize && length > 0) { 275 ReadStream is = file.openRead(); 276 TempBuffer head; 277 278 try { 279 head = copyFromStream(is, os, length); 280 } finally { 281 is.close(); 282 } 283 284 _item = new Cache(root, file, head); 285 286 synchronized (root) { 287 long size = _item.getSize(); 288 root._size += _item.getSize(); 289 cache.put(path, _item); 290 } 291 292 int i = 16; 293 while (root._maxSize < root._size && i-- > 0) { 294 root._cache.removeTail(); 295 } 296 } 297 else 298 getFile().writeToStream(os); 299 } 300 301 306 public StreamImpl openReadImpl() throws IOException 307 { 308 CachePath root = (CachePath) _root; 309 LruCache<String ,Cache> cache = root._cache; 310 311 String path = getPath(); 312 Cache item = cache.get(path); 313 314 root._readTotalCount++; 315 if (item != null) { 316 root._readHitCount++; 317 TempReadStream rs = new TempReadStream(item.getHead()); 318 rs.setFreeWhenDone(false); 319 return rs; 320 } 321 322 Path file = getFile(); 323 long length = file.getLength(); 324 325 if (length <= root._maxEntrySize && length > 0) { 326 try { 327 ReadStream is = file.openRead(); 328 TempBuffer head = null; 329 try { 330 head = copyFromStream(is, null, length); 331 } finally { 332 is.close(); 333 } 334 335 item = new Cache((CachePath) root, file, head); 336 337 synchronized (root) { 338 root._size += item.getSize(); 339 root._cache.put(path, item); 340 } 341 342 while (root._size > root._maxSize) { 343 root._cache.removeTail(); 344 } 345 346 TempReadStream rs = new TempReadStream(head); 347 rs.setFreeWhenDone(false); 348 return rs; 349 } catch (IOException e) { 350 } 351 } 352 353 return file.openReadImpl(); 354 } 355 356 private TempBuffer copyFromStream(ReadStream is, OutputStream os, 357 long length) 358 throws IOException 359 { 360 TempBuffer head = new TempBuffer(BLOCK_SIZE); 361 TempBuffer tail = head; 362 int len; 363 364 while ((len = is.readAll(tail.getBuffer(), 0, tail.getCapacity())) > 0) { 365 length -= len; 366 367 tail.setLength(len); 368 if (os != null) 369 os.write(tail.getBuffer(), 0, len); 370 371 if (length > 0) { 372 tail.setNext(new TempBuffer(BLOCK_SIZE)); 373 tail = tail.getNext(); 374 } 375 else 376 break; 377 } 378 379 return head; 380 } 381 382 public StreamImpl openWriteImpl() throws IOException 383 { 384 String path = getPath(); 385 LruCache<String ,Cache> cache = ((CachePath) _root)._cache; 386 cache.remove(path); 387 return getFile().openWriteImpl(); 388 } 389 390 public StreamImpl openAppendImpl() throws IOException 391 { 392 return getFile().openAppendImpl(); 393 } 394 395 public StreamImpl openReadWriteImpl() throws IOException 396 { 397 return getFile().openReadWriteImpl(); 398 } 399 400 403 public int hashCode() 404 { 405 return getFile().hashCode(); 406 } 407 408 public boolean equals(Object b) 409 { 410 if (b instanceof CachePath) { 411 CachePath test = (CachePath) b; 412 413 return getFile().equals(test.getFile()); 414 } 415 else 416 return getFile().equals(b); 417 } 418 419 422 private Path getFile() 423 { 424 if (_file == null) 425 _file = ((CachePath) _root)._backingRoot.lookup(getPath()); 426 427 return _file; 428 } 429 430 static class Cache implements CacheListener { 431 private CachePath _root; 432 private Path _path; 433 private TempBuffer _head; 434 private long _size; 435 436 Cache(CachePath root, Path path, TempBuffer head) 437 { 438 _root = root; 439 _path = path; 440 _head = head; 441 442 for (TempBuffer ptr = head; ptr != null; ptr = ptr.getNext()) 443 _size += ptr.getCapacity(); 444 } 445 446 TempBuffer getHead() 447 { 448 return _head; 449 } 450 451 long getSize() 452 { 453 return _size; 454 } 455 456 public void removeEvent() 457 { 458 synchronized (_root) { 459 _root._size -= _size; 460 _size = 0; 461 } 462 463 _head = null; 465 466 if (_root._removeOnRelease) { 467 try { 468 _path.remove(); 469 } catch (IOException e) { 470 } 471 } 472 } 473 } 474 } 475 | Popular Tags |