1 5 package org.h2.util; 6 7 import java.sql.SQLException ; 8 9 import org.h2.engine.Constants; 10 import org.h2.message.Message; 11 12 18 public class CacheLRU implements Cache { 19 20 public static final String TYPE_NAME = "LRU"; 21 22 private int len; 23 private int maxSize; 24 private CacheObject[] values; 25 private int mask; 26 private CacheWriter writer; 27 private int sizeRecords; 28 private int sizeBlocks; 29 private CacheObject head = new CacheHead(); 30 31 public CacheLRU(CacheWriter writer, int maxSize) { 32 this.writer = writer; 33 this.len = maxSize / 2; 34 this.mask = len - 1; 35 MathUtils.checkPowerOf2(len); 36 this.maxSize = maxSize; 37 clear(); 38 } 39 40 public void put(CacheObject rec) throws SQLException { 41 if(Constants.CHECK) { 42 for(int i=0; i<rec.getBlockCount(); i++) { 43 CacheObject old = find(rec.getPos() + i); 44 if(old != null) { 45 throw Message.getInternalError("try to add a record twice i="+i); 46 } 47 } 48 } 49 int index = rec.getPos() & mask; 50 rec.chained = values[index]; 51 values[index] = rec; 52 sizeRecords++; 53 sizeBlocks += rec.getBlockCount(); 54 addToFront(rec); 55 removeOld(); 56 } 57 58 public CacheObject update(int pos, CacheObject rec) throws SQLException { 59 CacheObject old = find(pos); 60 if(old == null) { 61 put(rec); 62 } else { 63 if(Constants.CHECK) { 64 if(old!=rec) { 65 throw Message.getInternalError("old != record old="+old+" new="+rec); 66 } 67 } 68 removeFromLinkedList(rec); 69 addToFront(rec); 70 } 71 return old; 72 } 73 74 private void removeOld() throws SQLException { 75 if(sizeBlocks < maxSize) { 76 return; 77 } 78 int i=0; 79 ObjectArray changed = new ObjectArray(); 80 while (sizeBlocks*4 > maxSize*3 && sizeRecords > Constants.CACHE_MIN_RECORDS) { 81 CacheObject last = head.next; 82 if(i++ >= sizeRecords) { 83 break; 87 } 88 if(Constants.CHECK && last == head) { 89 throw Message.getInternalError("try to remove head"); 90 } 91 if(!last.canRemove()) { 95 removeFromLinkedList(last); 96 addToFront(last); 97 continue; 98 } 99 remove(last.getPos()); 100 if (last.isChanged()) { 101 changed.add(last); 102 } 103 } 104 if(changed.size() > 0) { 105 CacheObject.sort(changed); 106 for(i=0; i<changed.size(); i++) { 107 CacheObject rec = (CacheObject) changed.get(i); 108 writer.writeBack(rec); 109 } 110 } 111 } 112 113 private void addToFront(CacheObject rec) { 114 if(Constants.CHECK && rec == head) { 115 throw Message.getInternalError("try to move head"); 116 } 117 rec.next = head; 118 rec.previous = head.previous; 119 rec.previous.next = rec; 120 head.previous = rec; 121 } 122 123 private void removeFromLinkedList(CacheObject rec) { 124 if(Constants.CHECK && rec == head) { 125 throw Message.getInternalError("try to remove head"); 126 } 127 rec.previous.next = rec.next; 128 rec.next.previous = rec.previous; 129 rec.next = null; 131 rec.previous = null; 132 } 133 134 public void remove(int pos) { 135 int index = pos & mask; 136 CacheObject rec = values[index]; 137 if(rec == null) { 138 return; 139 } 140 if(rec.getPos() == pos) { 141 values[index] = rec.chained; 142 } else { 143 CacheObject last; 144 do { 145 last = rec; 146 rec = rec.chained; 147 if(rec == null) { 148 return; 149 } 150 } while(rec.getPos() != pos); 151 last.chained = rec.chained; 152 } 153 sizeRecords--; 154 sizeBlocks -= rec.getBlockCount(); 155 removeFromLinkedList(rec); 156 if(Constants.CHECK) { 157 rec.chained = null; 158 if(find(pos) != null) { 159 throw Message.getInternalError("not removed!"); 160 } 161 } 162 } 163 164 public CacheObject find(int pos) { 165 CacheObject rec = values[pos & mask]; 166 while(rec != null && rec.getPos() != pos) { 167 rec = rec.chained; 168 } 169 return rec; 170 } 171 172 public CacheObject get(int pos) { 173 CacheObject rec = find(pos); 174 if(rec != null) { 175 removeFromLinkedList(rec); 176 addToFront(rec); 177 } 178 return rec; 179 } 180 181 210 public ObjectArray getAllChanged() { 211 ObjectArray list = new ObjectArray(); 216 for (int i = 0; i < len; i++) { 217 CacheObject rec = values[i]; 218 while (rec != null) { 219 if(rec.isChanged()) { 220 list.add(rec); 221 if(list.size() >= sizeRecords) { 222 if(Constants.CHECK) { 223 if(list.size() > sizeRecords) { 224 throw Message.getInternalError("cache chain error"); 225 } 226 } else { 227 break; 228 } 229 } 230 } 231 rec = rec.chained; 232 } 233 } 234 return list; 235 } 236 237 public void clear() { 238 head.next = head.previous = head; 239 values = new CacheObject[len]; 240 sizeRecords = 0; 241 sizeBlocks = 0; 242 } 243 244 public void setMaxSize(int newSize) throws SQLException { 245 maxSize = newSize < 0 ? 0 : newSize; 246 removeOld(); 247 } 248 249 public String getTypeName() { 250 return TYPE_NAME; 251 } 252 253 } 254 255 315 | Popular Tags |