1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002,2008 Oracle. All rights reserved. 5 * 6 * $Id: BasicIndex.java,v 1.2 2008/02/08 20:12:37 mark Exp $ 7 */ 8 9package com.sleepycat.persist; 10 11import com.sleepycat.bind.EntryBinding; 12import com.sleepycat.compat.DbCompat; 13import com.sleepycat.db.Cursor; 14import com.sleepycat.db.CursorConfig; 15import com.sleepycat.db.Database; 16import com.sleepycat.db.DatabaseConfig; 17import com.sleepycat.db.DatabaseEntry; 18import com.sleepycat.db.DatabaseException; 19import com.sleepycat.db.LockMode; 20import com.sleepycat.db.OperationStatus; 21import com.sleepycat.db.Transaction; 22import com.sleepycat.util.keyrange.KeyRange; 23import com.sleepycat.util.keyrange.RangeCursor; 24 25/** 26 * Implements EntityIndex using a ValueAdapter. This class is abstract and 27 * does not implement get()/map()/sortedMap() because it doesn't have access 28 * to the entity binding. 29 * 30 * @author Mark Hayes 31 */ 32abstract class BasicIndex<K,E> implements EntityIndex<K,E> { 33 34 static final DatabaseEntry NO_RETURN_ENTRY; 35 static { 36 NO_RETURN_ENTRY = new DatabaseEntry(); 37 NO_RETURN_ENTRY.setPartial(0, 0, true); 38 } 39 40 Database db; 41 boolean transactional; 42 boolean sortedDups; 43 boolean locking; 44 Class<K> keyClass; 45 EntryBinding keyBinding; 46 KeyRange emptyRange; 47 ValueAdapter<K> keyAdapter; 48 ValueAdapter<E> entityAdapter; 49 50 BasicIndex(Database db, 51 Class<K> keyClass, 52 EntryBinding keyBinding, 53 ValueAdapter<E> entityAdapter) 54 throws DatabaseException { 55 56 this.db = db; 57 DatabaseConfig config = db.getConfig(); 58 transactional = config.getTransactional(); 59 sortedDups = config.getSortedDuplicates(); 60 locking = 61 DbCompat.getInitializeLocking(db.getEnvironment().getConfig()); 62 63 this.keyClass = keyClass; 64 this.keyBinding = keyBinding; 65 this.entityAdapter = entityAdapter; 66 67 emptyRange = new KeyRange(config.getBtreeComparator()); 68 keyAdapter = new KeyValueAdapter(keyClass, keyBinding); 69 } 70 71 /* 72 * Of the EntityIndex methods only get()/map()/sortedMap() are not 73 * implemented here and therefore must be implemented by subclasses. 74 */ 75 76 public boolean contains(K key) 77 throws DatabaseException { 78 79 return contains(null, key, null); 80 } 81 82 public boolean contains(Transaction txn, K key, LockMode lockMode) 83 throws DatabaseException { 84 85 DatabaseEntry keyEntry = new DatabaseEntry(); 86 DatabaseEntry dataEntry = NO_RETURN_ENTRY; 87 keyBinding.objectToEntry(key, keyEntry); 88 89 OperationStatus status = db.get(txn, keyEntry, dataEntry, lockMode); 90 return (status == OperationStatus.SUCCESS); 91 } 92 93 public long count() 94 throws DatabaseException { 95 96 if (DbCompat.DATABASE_COUNT) { 97 return DbCompat.getDatabaseCount(db); 98 } else { 99 long count = 0; 100 DatabaseEntry key = NO_RETURN_ENTRY; 101 DatabaseEntry data = NO_RETURN_ENTRY; 102 CursorConfig cursorConfig = locking ? 103 CursorConfig.READ_UNCOMMITTED : null; 104 Cursor cursor = db.openCursor(null, cursorConfig); 105 try { 106 OperationStatus status = cursor.getFirst(key, data, null); 107 while (status == OperationStatus.SUCCESS) { 108 if (sortedDups) { 109 count += cursor.count(); 110 } else { 111 count += 1; 112 } 113 status = cursor.getNextNoDup(key, data, null); 114 } 115 } finally { 116 cursor.close(); 117 } 118 return count; 119 } 120 } 121 122 public boolean delete(K key) 123 throws DatabaseException { 124 125 return delete(null, key); 126 } 127 128 public boolean delete(Transaction txn, K key) 129 throws DatabaseException { 130 131 DatabaseEntry keyEntry = new DatabaseEntry(); 132 keyBinding.objectToEntry(key, keyEntry); 133 134 OperationStatus status = db.delete(txn, keyEntry); 135 return (status == OperationStatus.SUCCESS); 136 } 137 138 public EntityCursor<K> keys() 139 throws DatabaseException { 140 141 return keys(null, null); 142 } 143 144 public EntityCursor<K> keys(Transaction txn, CursorConfig config) 145 throws DatabaseException { 146 147 return cursor(txn, emptyRange, keyAdapter, config); 148 } 149 150 public EntityCursor<E> entities() 151 throws DatabaseException { 152 153 return cursor(null, emptyRange, entityAdapter, null); 154 } 155 156 public EntityCursor<E> entities(Transaction txn, 157 CursorConfig config) 158 throws DatabaseException { 159 160 return cursor(txn, emptyRange, entityAdapter, config); 161 } 162 163 public EntityCursor<K> keys(K fromKey, boolean fromInclusive, 164 K toKey, boolean toInclusive) 165 throws DatabaseException { 166 167 return cursor(null, fromKey, fromInclusive, toKey, toInclusive, 168 keyAdapter, null); 169 } 170 171 public EntityCursor<K> keys(Transaction txn, 172 K fromKey, 173 boolean fromInclusive, 174 K toKey, 175 boolean toInclusive, 176 CursorConfig config) 177 throws DatabaseException { 178 179 return cursor(txn, fromKey, fromInclusive, toKey, toInclusive, 180 keyAdapter, config); 181 } 182 183 public EntityCursor<E> entities(K fromKey, boolean fromInclusive, 184 K toKey, boolean toInclusive) 185 throws DatabaseException { 186 187 return cursor(null, fromKey, fromInclusive, toKey, toInclusive, 188 entityAdapter, null); 189 } 190 191 public EntityCursor<E> entities(Transaction txn, 192 K fromKey, 193 boolean fromInclusive, 194 K toKey, 195 boolean toInclusive, 196 CursorConfig config) 197 throws DatabaseException { 198 199 return cursor(txn, fromKey, fromInclusive, toKey, toInclusive, 200 entityAdapter, config); 201 } 202 203 /* 204 public ForwardCursor<K> unsortedKeys(KeySelector<K> selector) 205 throws DatabaseException { 206 207 return unsortedKeys(null, selector, null); 208 } 209 210 public ForwardCursor<K> unsortedKeys(Transaction txn, 211 KeySelector<K> selector, 212 CursorConfig config) 213 throws DatabaseException { 214 215 throw new UnsupportedOperationException(); 216 } 217 218 public ForwardCursor<E> unsortedEntities(KeySelector<K> selector) 219 throws DatabaseException { 220 221 return unsortedEntities(null, selector, null); 222 } 223 224 public ForwardCursor<E> unsortedEntities(Transaction txn, 225 KeySelector<K> selector, 226 CursorConfig config) 227 throws DatabaseException { 228 229 throw new UnsupportedOperationException(); 230 } 231 */ 232 233 private <V> EntityCursor<V> cursor(Transaction txn, 234 K fromKey, 235 boolean fromInclusive, 236 K toKey, 237 boolean toInclusive, 238 ValueAdapter<V> adapter, 239 CursorConfig config) 240 throws DatabaseException { 241 242 DatabaseEntry fromEntry = null; 243 if (fromKey != null) { 244 fromEntry = new DatabaseEntry(); 245 keyBinding.objectToEntry(fromKey, fromEntry); 246 } 247 DatabaseEntry toEntry = null; 248 if (toKey != null) { 249 toEntry = new DatabaseEntry(); 250 keyBinding.objectToEntry(toKey, toEntry); 251 } 252 KeyRange range = emptyRange.subRange 253 (fromEntry, fromInclusive, toEntry, toInclusive); 254 return cursor(txn, range, adapter, config); 255 } 256 257 private <V> EntityCursor<V> cursor(Transaction txn, 258 KeyRange range, 259 ValueAdapter<V> adapter, 260 CursorConfig config) 261 throws DatabaseException { 262 263 Cursor cursor = db.openCursor(txn, config); 264 RangeCursor rangeCursor = 265 new RangeCursor(range, null/*pkRange*/, sortedDups, cursor); 266 return new BasicCursor<V>(rangeCursor, adapter, isUpdateAllowed()); 267 } 268 269 abstract boolean isUpdateAllowed(); 270} 271