1 package com.knowgate.cache; 2 3 import java.util.HashMap ; 4 import com.knowgate.debug.DebugFile; 5 6 12 13 public final class LRUCachePolicy { 14 15 17 20 21 protected HashMap m_map; 22 23 26 27 protected LRUList m_list; 28 29 32 33 protected int m_maxCapacity; 34 35 38 39 protected int m_minCapacity; 40 41 43 48 49 public LRUCachePolicy() {} 50 51 56 57 public LRUCachePolicy(int min, int max) { 58 if (min < 2 || min > max) { 59 throw new IllegalArgumentException ("Illegal cache capacities"); 60 } 61 m_minCapacity = min; 62 m_maxCapacity = max; 63 64 create(); 65 } 66 67 69 75 76 private void create() { 77 78 m_map = new HashMap (211); 79 m_list = createList(); 80 m_list.m_maxCapacity = m_maxCapacity; 81 m_list.m_minCapacity = m_minCapacity; 82 m_list.m_capacity = m_maxCapacity; 83 } 84 85 90 91 public void start() {} 92 93 99 100 public void stop() { 101 if (m_list != null) { 102 flush(); 103 } 104 } 105 106 112 113 public void destroy() { 114 115 if (m_map != null) { 116 m_map.clear(); 117 118 } 119 if (m_list != null) { 120 m_list.clear(); 121 } 122 } 123 124 public java.util.Set keySet() { 125 return m_map.keySet(); 126 } 127 128 public long last(Object key) { 129 LRUCacheEntry value = (LRUCacheEntry) m_map.get(key); 130 return value.m_last; 131 } 132 133 public Object get(Object key) { 134 Object oRetVal; 135 136 if (DebugFile.trace) { 137 DebugFile.writeln("Begin LRUCachePolicy.get(" + key + ")"); 138 DebugFile.incIdent(); 139 } 140 141 if (key == null) { 142 throw new IllegalArgumentException ( 143 "Requesting an object using a null key"); 144 } 145 146 Object value = m_map.get(key); 147 LRUCacheEntry entry; 148 149 if (value != null) { 150 entry = (LRUCacheEntry)value; 151 m_list.promote(entry); 152 oRetVal = entry.m_object; 153 } 154 else { 155 if (DebugFile.trace) DebugFile.writeln("LRUCachePolicy.cacheMiss()"); 156 cacheMiss(); 157 oRetVal = null; 158 } 159 160 if (DebugFile.trace) { 161 DebugFile.decIdent(); 162 DebugFile.writeln("End LRUCachePolicy.get() : " + (oRetVal!=null ? "[Object]" : "null") ); 163 } 164 return oRetVal; 165 } 167 public Object peek(Object key) { 168 if (key == null) 169 throw new IllegalArgumentException ("Requesting an object using a null key"); 170 171 172 LRUCacheEntry value = (LRUCacheEntry) m_map.get(key); 173 174 if (value == null) 175 return null; 176 else 177 return value.m_object; 178 } 180 public void insert(Object key, Object o, long t) { 181 182 if (o == null) 183 throw new IllegalArgumentException ("Cannot insert a null object in the cache"); 184 185 if (key == null) 186 throw new IllegalArgumentException ("Cannot insert an object in the cache with null key"); 187 188 Object obj = m_map.get(key); 189 190 if (obj == null) { 191 m_list.demote(); 192 LRUCacheEntry entry = createCacheEntry(key, o, t); 193 m_list.promote(entry); 194 m_map.put(key, entry); 195 } 196 else 197 { 198 throw new IllegalStateException ("Attempt to put in the cache an object that is already there"); 199 } 200 } 202 public void remove(Object key) { 203 204 if (key == null) 205 throw new IllegalArgumentException ("Removing an object using a null key"); 206 207 Object value = m_map.get(key); 208 209 if (value != null) { 210 m_list.remove( (LRUCacheEntry) value); 211 m_map.remove(key); 212 } 213 214 } 216 public void flush() { 217 218 LRUCacheEntry entry = null; 219 220 while ( (entry = m_list.m_tail) != null) 221 ageOut(entry); 222 } 224 public int size() { 225 return m_list.m_count; 226 } 228 229 231 234 235 protected LRUList createList() { 236 return new LRUList(); 237 } 238 239 244 245 protected void ageOut(LRUCacheEntry entry) { 246 remove(entry.m_key); 247 } 248 249 252 253 protected void cacheMiss() { 254 } 255 256 259 260 protected LRUCacheEntry createCacheEntry(Object key, Object value, long t) { 261 262 return new LRUCacheEntry(key, value, t); 263 } 264 265 267 269 272 273 public class LRUList { 274 275 276 277 public int m_maxCapacity; 278 279 280 281 public int m_minCapacity; 282 283 284 285 public int m_capacity; 286 287 288 289 public int m_count; 290 291 292 293 public LRUCacheEntry m_head; 294 295 296 297 public LRUCacheEntry m_tail; 298 299 300 301 public int m_cacheMiss; 302 303 306 307 protected LRUList() { 308 309 m_head = null; 310 311 m_tail = null; 312 313 m_count = 0; 314 } 315 316 324 325 protected void promote(LRUCacheEntry entry) { 326 327 if (entry == null) { 328 throw new IllegalArgumentException ("Trying to promote a null object"); 329 } 330 331 if (m_capacity < 1) { 332 throw new IllegalStateException ("Can't work with capacity < 1"); 333 } 334 335 entry.m_time = System.currentTimeMillis(); 336 337 if (entry.m_prev == null) 338 339 { 340 341 if (entry.m_next == null) 342 343 { 344 345 347 if (m_count == 0) 349 { 350 351 m_head = entry; 352 353 m_tail = entry; 354 355 ++m_count; 356 357 entryAdded(entry); 358 359 } 360 361 else if (m_count == 1 && m_head == entry) {} 363 else if (m_count < m_capacity) 364 365 { 366 367 entry.m_prev = null; 368 369 entry.m_next = m_head; 370 371 m_head.m_prev = entry; 372 373 m_head = entry; 374 375 ++m_count; 376 377 entryAdded(entry); 378 379 } 380 381 else if (m_count < m_maxCapacity) 382 383 { 384 385 entry.m_prev = null; 386 387 entry.m_next = m_head; 388 389 m_head.m_prev = entry; 390 391 m_head = entry; 392 393 ++m_count; 394 395 int oldCapacity = m_capacity; 396 397 ++m_capacity; 398 399 entryAdded(entry); 400 401 capacityChanged(oldCapacity); 402 403 } 404 405 else { 406 throw new IllegalStateException ( 407 "Attempt to put a new cache entry on a full cache"); 408 } 409 410 } 411 412 else {} 414 } 415 416 else 417 418 { 419 420 if (entry.m_next == null) 422 { 423 424 LRUCacheEntry beforeLast = entry.m_prev; 425 426 beforeLast.m_next = null; 427 428 entry.m_prev = null; 429 430 entry.m_next = m_head; 431 432 m_head.m_prev = entry; 433 434 m_head = entry; 435 436 m_tail = beforeLast; 437 438 } 439 440 else 442 { 443 444 LRUCacheEntry previous = entry.m_prev; 445 446 previous.m_next = entry.m_next; 447 448 entry.m_next.m_prev = previous; 449 450 entry.m_prev = null; 451 452 entry.m_next = m_head; 453 454 m_head.m_prev = entry; 455 456 m_head = entry; 457 458 } 459 460 } 461 } 462 463 468 469 protected void demote() { 470 471 if (m_capacity < 1) 472 throw new IllegalStateException ("Can't work with capacity < 1"); 473 474 if (m_count > m_maxCapacity) 475 throw new IllegalStateException ("Cache list entries number (" + m_count + 476 ") > than the maximum allowed (" + 477 m_maxCapacity + ")"); 478 479 if (m_count == m_maxCapacity) { 480 481 LRUCacheEntry entry = m_tail; 482 483 485 ageOut(entry); 486 } 487 } 488 489 492 493 protected void remove(LRUCacheEntry entry) throws IllegalArgumentException ,IllegalStateException { 494 495 if (entry == null) 496 throw new IllegalArgumentException ("LRUList.remove() Cannot remove a null entry from the cache"); 497 498 if (m_count < 1) 499 throw new IllegalStateException ("LRUList.remove() Trying to remove an entry from an empty cache"); 500 501 entry.m_key = entry.m_object = null; 502 503 if (m_count == 1) { 504 505 m_head = m_tail = null; 506 } 507 else { 508 if (entry.m_prev == null) { 510 m_head = entry.m_next; 511 512 if (null!=m_head) m_head.m_prev = null; 513 514 entry.m_next = null; 515 } 516 else if (entry.m_next == null) { 518 m_tail = entry.m_prev; 519 520 m_tail.m_next = null; 521 522 entry.m_prev = null; 523 } 524 else { 526 entry.m_next.m_prev = entry.m_prev; 527 528 entry.m_prev.m_next = entry.m_next; 529 530 entry.m_prev = null; 531 532 entry.m_next = null; 533 } 534 } 535 536 --m_count; 537 538 entryRemoved(entry); 539 } 541 544 545 protected void entryAdded(LRUCacheEntry entry) {} 546 547 550 551 protected void entryRemoved(LRUCacheEntry entry) {} 552 553 557 558 protected void capacityChanged(int oldCapacity) {} 559 560 protected void clear() { 561 562 m_head = null; 563 564 m_tail = null; 565 566 m_count = 0; 567 } 568 569 public String toString() { 570 571 String s = Integer.toHexString(super.hashCode()); 572 573 s += " size: " + m_count; 574 575 for (LRUCacheEntry entry = m_head; entry != null; entry = entry.m_next) 576 s += "\n" + entry; 577 578 return s; 579 } 580 } 581 582 585 586 public final class LRUCacheEntry { 587 588 589 590 public LRUCacheEntry m_next; 591 592 593 594 public LRUCacheEntry m_prev; 595 596 597 598 public Object m_key; 599 600 601 602 public Object m_object; 603 604 605 606 public long m_time; 607 608 609 610 public long m_last; 611 612 616 617 protected LRUCacheEntry(Object key, Object object, long t) { 618 619 m_key = key; 620 621 m_object = object; 622 623 m_next = null; 624 625 m_prev = null; 626 627 m_time = 0; 629 m_last = t; 630 } 631 632 public String toString() { 633 return "key: " + m_key + ", object: " + 634 (m_object == null ? "null" : Integer.toHexString(m_object.hashCode())) + 635 ", entry: " + Integer.toHexString(super.hashCode()); 636 } 637 } } | Popular Tags |