1 10 package org.mmbase.util; 11 12 import org.mmbase.cache.CacheImplementationInterface; 13 import java.util.*; 14 15 26 public class LRUHashtable extends Hashtable implements Cloneable , CacheImplementationInterface, SizeMeasurable { 27 28 private static final String ROOT = "root"; 29 private static final String DANGLING = "dangling"; 30 35 private final LRUEntry root = new LRUEntry(ROOT, ROOT); 36 40 private final LRUEntry dangling = new LRUEntry(DANGLING, DANGLING); 41 42 45 private int size = 0; 46 49 private int currentSize = 0; 50 51 57 public LRUHashtable(int size, int cap, float lf) { 58 super(cap, lf); 59 root.next = dangling; 60 dangling.prev = root; 61 this.size = size; 62 } 63 64 69 public LRUHashtable(int size, int cap) { 70 this(size, cap, 0.75f); 71 } 72 73 78 public LRUHashtable(int size) { 79 this(size, 101, 0.75f); 80 } 81 82 86 public LRUHashtable() { 87 this(100, 101, 0.75f); 88 } 89 90 96 public synchronized Object put(Object key, Object value) { 97 LRUEntry work = (LRUEntry) super.get(key); 98 Object rtn; 99 if (work != null) { 100 rtn = work.value; 101 work.value = value; 102 removeEntry(work); 103 appendEntry(work); 104 } else { 105 rtn = null; 106 work = new LRUEntry(key, value); 107 super.put(key, work); 108 appendEntry(work); 109 currentSize++; 110 if (currentSize > size) { 111 remove(root.next.key); 112 } 113 } 114 return rtn; 115 } 116 117 122 public int getCount(Object key) { 123 LRUEntry work = (LRUEntry) super.get(key); 124 if (work != null) { 125 return work.requestCount; 126 } else { 127 return -1; 128 } 129 } 130 131 136 public synchronized Object get(Object key) { 137 LRUEntry work = (LRUEntry) super.get(key); 138 if (work != null) { 139 work.requestCount++; 140 Object rtn = work.value; 141 removeEntry(work); 142 appendEntry(work); 143 return rtn; 144 } else { 145 return null; 146 } 147 } 148 149 154 public synchronized Object remove(Object key) { 155 LRUEntry work = (LRUEntry) super.remove(key); 156 if (work != null) { 157 Object rtn = work.value; 158 removeEntry(work); 159 currentSize--; 160 return rtn; 161 } else { 162 return null; 163 } 164 } 165 166 167 173 public Set keySet() { 174 return Collections.unmodifiableSet(super.keySet()); 175 } 176 177 182 public Set entrySet() { 183 return new LRUEntrySet(); 184 } 185 186 190 public Collection values() { 191 return Collections.unmodifiableCollection(super.values()); 192 } 193 194 197 public int size() { 198 return currentSize; 199 } 200 201 206 public void setMaxSize(int size) { 207 if (size < 0 ) throw new IllegalArgumentException ("Cannot set size of LRUHashtable to negative value"); 208 if (size < this.size) { 209 while(currentSize > size) { 210 remove(root.next.key); 211 } 212 } 213 this.size = size; 214 } 215 216 219 public int maxSize() { 220 return size; 221 } 222 223 226 private void appendEntry(LRUEntry wrk) { 227 dangling.prev.next = wrk; 228 wrk.prev = dangling.prev; 229 wrk.next = dangling; 230 dangling.prev = wrk; 231 } 232 233 236 private void removeEntry(LRUEntry wrk) { 237 wrk.next.prev = wrk.prev; 238 wrk.prev.next = wrk.next; 239 wrk.next = null; 240 wrk.prev = null; 241 } 242 243 248 public String toString() { 249 return "Size=" + currentSize + ", Max=" + size; 250 } 251 252 259 public String toString(boolean which) { 260 if (which) { 261 StringBuffer b = new StringBuffer (); 262 b.append("Size " + currentSize + ", Max " + size + " : "); 263 b.append(super.toString()); 264 return b.toString(); 265 } else { 266 return toString(); 267 } 268 } 269 270 273 public synchronized void clear() { 274 while (root.next != dangling) removeEntry(root.next); 275 super.clear(); 276 currentSize = 0; 277 } 278 279 282 public synchronized Object clone() { 283 throw new UnsupportedOperationException (); 284 } 285 286 289 public synchronized Enumeration elements() { 290 return new LRUHashtableEnumeration(); 291 } 292 293 294 295 298 public Enumeration getOrderedElements() { 299 return getOrderedElements(-1); 300 } 301 302 305 public Enumeration getOrderedElements(int maxnumber) { 306 List results = new ArrayList(); 307 LRUEntry current = root.next; 308 if (maxnumber != -1) { 309 int i = 0; 310 while (current!=null && current!=dangling && i<maxnumber) { 311 results.add(0, current.value); 312 current = current.next; 313 i++; 314 } 315 } else { 316 while (current!=null && current!=dangling) { 317 results.add(0, current.value); 318 current = current.next; 319 } 320 } 321 return Collections.enumeration(results); 322 } 323 324 329 330 public List getOrderedEntries() { 331 return getOrderedEntries(-1); 332 } 333 334 340 341 public List getOrderedEntries(int maxNumber) { 342 List results = new ArrayList(); 343 LRUEntry current = root.next; 344 int i = 0; 345 while (current != null && current != dangling && (maxNumber < 0 || i < maxNumber)) { 346 results.add(0, current); 347 current = current.next; 348 i++; 349 } 350 return Collections.unmodifiableList(results); 351 } 352 353 354 public void config(Map map) { 355 } 357 358 public int getByteSize() { 359 return getByteSize(new SizeOf()); 360 } 361 public int getByteSize(SizeOf sizeof) { 362 int len = 4 * SizeOf.SZ_REF + (30 + 5 * SizeOf.SZ_REF) * currentSize; LRUEntry current = root.next; 364 while (current != null && current != dangling) { 365 current = current.next; 366 len += sizeof.sizeof(current.key); 367 len += sizeof.sizeof(current.value); 368 } 369 return len; 370 } 371 372 375 private class LRUHashtableEnumeration implements Enumeration { 376 private Enumeration superior; 377 378 LRUHashtableEnumeration() { 379 superior = LRUHashtable.this.elements(); 380 } 381 382 public boolean hasMoreElements() { 383 return superior.hasMoreElements(); 384 } 385 386 public Object nextElement() { 387 LRUEntry entry = (LRUEntry) superior.nextElement(); 388 return entry.value; 389 } 390 } 391 392 393 396 public class LRUEntry implements Map.Entry, SizeMeasurable { 397 400 protected Object value; 401 404 protected LRUEntry next; 405 408 protected LRUEntry prev; 409 412 protected Object key; 413 417 protected int requestCount = 0; 418 419 LRUEntry(Object key, Object val) { 420 this(key, val, null, null); 421 } 422 423 LRUEntry(Object key, Object value, LRUEntry prev, LRUEntry next) { 424 this.value = value; 425 this.next = next; 426 this.prev = prev; 427 this.key = key; 428 } 429 430 public Object getKey() { 431 return key; 432 } 433 434 public Object getValue() { 435 return value; 436 } 437 438 public Object setValue(Object o) { 439 throw new UnsupportedOperationException ("Cannot change values in LRU Hashtable"); 440 } 441 442 public int getByteSize() { 443 return new SizeOf().sizeof(value); 444 } 445 public int getByteSize(SizeOf sizeof) { 446 return 20 + sizeof.sizeof(value); 448 } 449 public String toString() { 450 return value == LRUHashtable.this ? "[this lru]" : String.valueOf(value); 451 } 452 453 } 454 458 protected class LRUEntrySet extends AbstractSet { 459 Set set; 460 LRUEntrySet() { 461 set = LRUHashtable.super.entrySet(); 462 } 463 public int size() { 464 return set.size(); 465 } 466 public Iterator iterator() { 467 return new LRUEntrySetIterator(set.iterator()); 468 } 469 } 470 471 475 protected class LRUEntrySetIterator implements Iterator { 476 Iterator it; 477 LRUEntry work; 478 LRUEntrySetIterator(Iterator i ) { 479 it = i; 480 } 481 public boolean hasNext() { 482 return it.hasNext(); 483 } 484 public Object next() { 485 Map.Entry entry = (Map.Entry) it.next(); 486 work = (LRUEntry) entry.getValue(); 487 return work; 488 } 489 public void remove() { 490 it.remove(); 491 if (work != null) { 492 LRUHashtable.this.removeEntry(work); 493 LRUHashtable.this.currentSize--; 494 } 495 } 496 } 497 498 public static void main(String argv[]) { 499 int treesiz = 1024; 500 int opers = 1000000; 501 int thrds = 1; 502 503 try { 504 if (argv.length > 0) { 505 treesiz = Integer.parseInt(argv[0]); 506 } 507 if (argv.length > 1) { 508 opers = Integer.parseInt(argv[1]); 509 } 510 if (argv.length > 2) { 511 thrds = Integer.parseInt(argv[2]); 512 } 513 } catch (Exception e) { 514 System.out.println("Usage: java org.mmbase.util.LRUHashtable <size of table> <number of operation to do> <threads>"); 515 return; 516 } 517 518 final int TREESIZ = treesiz; 519 final int OPERS = opers; 520 final int THREADS = thrds; 521 522 final LRUHashtable treap = new LRUHashtable(TREESIZ); 523 long ll1 = System.currentTimeMillis(); 524 525 for (int i = 0; i < TREESIZ; i++) { 527 treap.put(""+i,""+i); 528 } 529 long ll2=System.currentTimeMillis(); 530 System.out.println("Size "+treap.size()); 531 532 if (TREESIZ <= 1024) { 533 System.out.println("LRUHashtable initaly " + treap.toString(true)); 534 } 535 536 final int score[][] = new int[TREESIZ][THREADS]; 537 long ll3 = System.currentTimeMillis(); 538 539 Thread [] threads = new Thread [THREADS]; 540 for (int t = 0; t < THREADS; t++) { 541 final int threadnr = t; 542 Runnable runnable = new Runnable () { 543 public void run() { 544 if (THREADS > 1) { 545 System.out.println("Thread " + threadnr + " started"); 546 } 547 Random rnd = new Random(); 548 for (int i = 0;i<OPERS;i++) { 549 int j = Math.abs(rnd.nextInt())%(TREESIZ/2)+(TREESIZ/4); 551 int k = Math.abs(rnd.nextInt())%2; 552 Object rtn; 553 switch (k) { 554 case 0: 555 rtn=treap.put(""+j,""+j); 556 score[j][threadnr]++; 557 break; 558 case 1: 559 rtn=treap.get(""+j); 560 score[j][threadnr]++; 561 break; 562 } 563 j = Math.abs(rnd.nextInt())%(TREESIZ); 565 rtn = treap.get(""+j); 566 score[j][threadnr]++; 567 } 568 if (THREADS > 1) { 569 System.out.println("Thread " + threadnr + " ready"); 570 } 571 } 572 }; 573 threads[t] = new Thread (runnable); 574 threads[t].start(); 575 } 576 long ll4 = System.currentTimeMillis(); 577 for (int i = 0; i < THREADS; i++) { 578 try { 579 threads[i].join(); 580 } catch (InterruptedException ie) { 581 System.err.println("Interrupted"); 582 } 583 } 584 585 long ll5 = System.currentTimeMillis(); 586 if (TREESIZ <= 1024) { 587 System.out.println("LRUHashtable afterwards " + treap.toString(true)); 588 589 for (int i = 0; i <TREESIZ; i++) { 590 int totscore = 0; 591 for (int j = 0; j < THREADS; j++) { 592 totscore += score[i][j]; 593 } 594 System.out.println("" + i + " score " + totscore); 595 } 596 } 597 System.out.println("Creation " + (ll2-ll1) + " ms"); 598 System.out.println("Thread starting " + (ll4-ll3) + " ms"); 599 if (TREESIZ <= 1024) { 600 System.out.println("Print " + (ll3-ll2) + " ms"); 601 } else { 602 System.out.println("Not printed (too huge)"); 603 } 604 long timePerKop = (ll5 - ll3) * 1000 / (OPERS); 605 System.out.println("Run " + (ll5-ll3) + " ms (" + timePerKop + " ms/koperation, " + (timePerKop / THREADS) + " ms/koperation total from " + THREADS + " threads)"); 606 } 607 } 608 609 610 611 | Popular Tags |