1 4 package com.tc.objectserver.persistence.sleepycat; 5 6 import com.sleepycat.je.Cursor; 7 import com.sleepycat.je.CursorConfig; 8 import com.sleepycat.je.Database; 9 import com.sleepycat.je.DatabaseEntry; 10 import com.sleepycat.je.DatabaseException; 11 import com.sleepycat.je.LockMode; 12 import com.sleepycat.je.OperationStatus; 13 import com.tc.object.ObjectID; 14 import com.tc.objectserver.persistence.api.PersistenceTransaction; 15 import com.tc.util.Conversion; 16 17 import gnu.trove.THashMap; 18 19 import java.io.IOException ; 20 import java.util.Collection ; 21 import java.util.Iterator ; 22 import java.util.Map ; 23 import java.util.Set ; 24 25 public class SleepycatPersistableMap implements Map { 26 27 private static final Object REMOVED = new Object (); 28 29 32 private final Map map = new THashMap(0); 33 34 37 private final Map delta = new THashMap(0); 38 39 private final long id; 40 private int removeCount = 0; 41 private boolean clear = false; 42 43 public SleepycatPersistableMap(ObjectID id) { 44 this.id = id.toLong(); 45 } 46 47 public int size() { 48 return map.size() + delta.size() - removeCount; 49 } 50 51 public boolean isEmpty() { 52 return size() == 0; 53 } 54 55 public boolean containsKey(Object key) { 56 Object value; 57 return delta.containsKey(key) || ((value = map.get(key)) != null && value != REMOVED); 59 } 60 61 public boolean containsValue(Object value) { 62 return delta.containsValue(value) || map.containsValue(value); 63 } 64 65 public Object get(Object key) { 66 Object value = delta.get(key); 67 if (value == null) { 68 value = map.get(key); 69 if (value == REMOVED) value = null; 70 } 71 return value; 72 } 73 74 public Object put(Object key, Object value) { 75 Object returnVal = delta.put(key, value); 76 if (returnVal != null) { return returnVal; } 77 if (map.containsKey(key)) { 78 returnVal = map.put(key, REMOVED); 79 if (returnVal == REMOVED) { return null; } 80 removeCount++; 81 } 82 return returnVal; 83 } 84 85 public Object remove(Object key) { 86 Object returnVal = delta.remove(key); 87 if (returnVal != null) { return returnVal; } 88 if (map.containsKey(key)) { 89 returnVal = map.put(key, REMOVED); 90 if (returnVal == REMOVED) { return null; } 91 removeCount++; 92 } 93 return returnVal; 94 } 95 96 public void putAll(Map m) { 97 for (Iterator i = m.entrySet().iterator(); i.hasNext();) { 98 Map.Entry entry = (Map.Entry) i.next(); 99 put(entry.getKey(), entry.getValue()); 100 } 101 } 102 103 public void clear() { 104 clear = true; 105 delta.clear(); 108 map.clear(); 109 removeCount = 0; 110 } 111 112 public Set keySet() { 113 return new KeyView(); 114 } 115 116 public Collection values() { 117 return new ValuesView(); 118 } 119 120 public Set entrySet() { 121 return new EntryView(); 122 } 123 124 public void commit(SleepycatCollectionsPersistor persistor, PersistenceTransaction tx, Database db) 125 throws IOException , DatabaseException { 126 129 if (clear) { 131 basicClear(persistor, tx, db); 132 clear = false; 133 } 136 137 if (delta.size() > 0) { 139 basicPut(persistor, tx, db); 140 delta.clear(); 144 } 145 146 if (removeCount > 0) { 149 basicRemove(persistor, tx, db); 150 removeCount = 0; 153 } 154 } 156 157 private void basicRemove(SleepycatCollectionsPersistor persistor, PersistenceTransaction tx, Database db) 158 throws IOException , DatabaseException { 159 for (Iterator i = map.entrySet().iterator(); i.hasNext();) { 160 Map.Entry e = (Entry) i.next(); 161 Object k = e.getKey(); 162 Object v = e.getValue(); 163 if (v == REMOVED) { 164 DatabaseEntry key = new DatabaseEntry(); 165 key.setData(persistor.serialize(id, k)); 166 OperationStatus status = db.delete(persistor.pt2nt(tx), key); 167 if (!(OperationStatus.NOTFOUND.equals(status) || OperationStatus.SUCCESS.equals(status))) { 168 throw new DBException("Unable to remove Map Entry for object id: " + id + ", status: " + status + ", key: " 170 + key); 171 } 172 i.remove(); 173 } 174 } 175 176 } 177 178 private void basicPut(SleepycatCollectionsPersistor persistor, PersistenceTransaction tx, Database db) 179 throws IOException , DatabaseException { 180 for (Iterator i = delta.entrySet().iterator(); i.hasNext();) { 181 Map.Entry e = (Entry) i.next(); 182 Object k = e.getKey(); 183 Object v = e.getValue(); 184 DatabaseEntry key = new DatabaseEntry(); 185 key.setData(persistor.serialize(id, k)); 186 DatabaseEntry value = new DatabaseEntry(); 187 value.setData(persistor.serialize(v)); 188 OperationStatus status = db.put(persistor.pt2nt(tx), key, value); 189 if (!OperationStatus.SUCCESS.equals(status)) { throw new DBException("Unable to update Map table : " + id 190 + " status : " + status); } 191 map.put(k, v); 192 } 193 } 194 195 private void basicClear(SleepycatCollectionsPersistor persistor, PersistenceTransaction tx, Database db) 196 throws DatabaseException { 197 Cursor c = db.openCursor(persistor.pt2nt(tx), CursorConfig.READ_COMMITTED); 202 byte idb[] = Conversion.long2Bytes(id); 203 DatabaseEntry key = new DatabaseEntry(); 204 key.setData(idb); 205 DatabaseEntry value = new DatabaseEntry(); 206 value.setPartial(0, 0, true); 207 if (c.getSearchKeyRange(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) { 208 do { 209 if (partialMatch(idb, key.getData())) { 210 c.delete(); 211 } else { 212 break; 213 } 214 } while (c.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS); 215 } 216 c.close(); 217 } 218 219 233 private boolean partialMatch(byte[] idbytes, byte[] key) { 234 if (key.length < idbytes.length) return false; 235 for (int i = 0; i < idbytes.length; i++) { 236 if (idbytes[i] != key[i]) return false; 237 } 238 return true; 239 } 240 241 public boolean equals(Object other) { 242 if (!(other instanceof Map)) { return false; } 243 Map that = (Map) other; 244 if (that.size() != this.size()) { return false; } 245 return entrySet().containsAll(that.entrySet()); 246 } 247 248 public int hashCode() { 249 int h = 0; 250 for (Iterator i = entrySet().iterator(); i.hasNext();) { 251 h += i.next().hashCode(); 252 } 253 return h; 254 } 255 256 public String toString() { 257 return "SleepycatPersistableMap(" + id + ")={ Map.size() = " + map.size() + ", delta.size() = " + delta.size() 258 + ", removeCount = " + removeCount + " }"; 259 } 260 261 public void load(SleepycatCollectionsPersistor persistor, PersistenceTransaction tx, Database db) throws IOException , 262 ClassNotFoundException , DatabaseException { 263 Cursor c = db.openCursor(persistor.pt2nt(tx), CursorConfig.READ_COMMITTED); 266 byte idb[] = Conversion.long2Bytes(id); 267 DatabaseEntry key = new DatabaseEntry(); 268 key.setData(idb); 269 DatabaseEntry value = new DatabaseEntry(); 270 if (c.getSearchKeyRange(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) { 271 do { 272 if (false) System.err.println("MapDB " + toString(key) + " , " + toString(value)); 273 if (partialMatch(idb, key.getData())) { 274 Object mkey = persistor.deserialize(idb.length, key.getData()); 275 Object mvalue = persistor.deserialize(value.getData()); 276 map.put(mkey, mvalue); 277 } else { 279 break; 280 } 281 } while (c.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS); 282 } 283 c.close(); 284 } 285 286 private String toString(DatabaseEntry entry) { 287 StringBuffer sb = new StringBuffer (); 288 sb.append("<DatabaseEntry "); 289 byte b[] = entry.getData(); 290 if (b == null) { 291 sb.append(" NULL Data>"); 292 } else if (b.length == 0) { 293 sb.append(" ZERO bytes>"); 294 } else { 295 for (int i = 0; i < b.length; i++) { 296 sb.append(b[i]).append(' '); 297 } 298 sb.append(">"); 299 } 300 return sb.toString(); 301 } 302 303 private abstract class BaseView implements Set { 304 305 public int size() { 306 return SleepycatPersistableMap.this.size(); 307 } 308 309 public boolean isEmpty() { 310 return SleepycatPersistableMap.this.isEmpty(); 311 } 312 313 public Object [] toArray() { 314 Object [] result = new Object [size()]; 315 Iterator e = iterator(); 316 for (int i = 0; e.hasNext(); i++) 317 result[i] = e.next(); 318 return result; 319 } 320 321 public Object [] toArray(Object [] a) { 322 int size = size(); 323 if (a.length < size) a = (Object []) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); 324 325 Iterator it = iterator(); 326 for (int i = 0; i < size; i++) { 327 a[i] = it.next(); 328 } 329 330 if (a.length > size) { 331 a[size] = null; 332 } 333 334 return a; 335 } 336 337 public boolean add(Object arg0) { 338 throw new UnsupportedOperationException (); 339 } 340 341 public boolean remove(Object o) { 342 throw new UnsupportedOperationException (); 343 } 344 345 public boolean containsAll(Collection collection) { 346 for (Iterator i = collection.iterator(); i.hasNext();) { 347 if (!contains(i.next())) { return false; } 348 } 349 return true; 350 } 351 352 public boolean addAll(Collection arg0) { 353 throw new UnsupportedOperationException (); 354 } 355 356 public boolean retainAll(Collection arg0) { 357 throw new UnsupportedOperationException (); 358 } 359 360 public boolean removeAll(Collection arg0) { 361 throw new UnsupportedOperationException (); 362 } 363 364 public void clear() { 365 throw new UnsupportedOperationException (); 366 } 367 } 368 369 private class KeyView extends BaseView { 370 371 public boolean contains(Object key) { 372 return SleepycatPersistableMap.this.containsKey(key); 373 } 374 375 public Iterator iterator() { 376 return new KeyIterator(); 377 } 378 } 379 380 private class ValuesView extends BaseView { 381 382 public boolean contains(Object value) { 383 return SleepycatPersistableMap.this.containsValue(value); 384 } 385 386 public Iterator iterator() { 387 return new ValuesIterator(); 388 } 389 } 390 391 private class EntryView extends BaseView { 392 393 public boolean contains(Object o) { 394 Map.Entry entry = (Entry) o; 395 Object val = get(entry.getKey()); 396 Object entryValue = entry.getValue(); 397 return entryValue == val || (null != val && val.equals(entryValue)); 398 } 399 400 public Iterator iterator() { 401 return new EntryIterator(); 402 } 403 } 404 405 private abstract class BaseIterator implements Iterator { 406 407 boolean isDelta = false; 408 Iterator current = map.entrySet().iterator(); 409 Map.Entry next; 410 411 BaseIterator() { 412 moveToNext(); 413 } 414 415 private void moveToNext() { 416 while (current.hasNext()) { 417 next = (Entry) current.next(); 418 if (next.getValue() != REMOVED) { return; } 419 } 420 if (isDelta) { 421 next = null; 422 } else { 423 current = delta.entrySet().iterator(); 424 isDelta = true; 425 moveToNext(); 426 } 427 } 428 429 public boolean hasNext() { 430 return (next != null); 431 } 432 433 public Object next() { 434 Object key = getNext(); 435 moveToNext(); 436 return key; 437 } 438 439 public void remove() { 440 throw new UnsupportedOperationException (); 441 } 442 443 protected abstract Object getNext(); 444 445 } 446 447 private class KeyIterator extends BaseIterator { 448 protected Object getNext() { 449 return next.getKey(); 450 } 451 } 452 453 private class ValuesIterator extends BaseIterator { 454 protected Object getNext() { 455 return next.getValue(); 456 } 457 } 458 459 private class EntryIterator extends BaseIterator { 460 protected Object getNext() { 461 return next; 462 } 463 } 464 } 465 | Popular Tags |