001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: BasicIndex.java,v 1.9.2.3 2008/01/07 15:14:18 cwl Exp $
007: */
008:
009: package com.sleepycat.persist;
010:
011: import com.sleepycat.bind.EntryBinding;
012: import com.sleepycat.compat.DbCompat;
013: import com.sleepycat.je.Cursor;
014: import com.sleepycat.je.CursorConfig;
015: import com.sleepycat.je.Database;
016: import com.sleepycat.je.DatabaseConfig;
017: import com.sleepycat.je.DatabaseEntry;
018: import com.sleepycat.je.DatabaseException;
019: import com.sleepycat.je.LockMode;
020: import com.sleepycat.je.OperationStatus;
021: import com.sleepycat.je.SecondaryDatabase;
022: import com.sleepycat.je.Transaction;
023: import com.sleepycat.util.keyrange.KeyRange;
024: import com.sleepycat.util.keyrange.RangeCursor;
025:
026: /**
027: * Implements EntityIndex using a ValueAdapter. This class is abstract and
028: * does not implement get()/map()/sortedMap() because it doesn't have access
029: * to the entity binding.
030: *
031: * @author Mark Hayes
032: */
033: abstract class BasicIndex<K, E> implements EntityIndex<K, E> {
034:
035: static final DatabaseEntry NO_RETURN_ENTRY;
036: static {
037: NO_RETURN_ENTRY = new DatabaseEntry();
038: NO_RETURN_ENTRY.setPartial(0, 0, true);
039: }
040:
041: Database db;
042: boolean transactional;
043: Class<K> keyClass;
044: EntryBinding keyBinding;
045: KeyRange emptyRange;
046: ValueAdapter<K> keyAdapter;
047: ValueAdapter<E> entityAdapter;
048:
049: BasicIndex(Database db, Class<K> keyClass, EntryBinding keyBinding,
050: ValueAdapter<E> entityAdapter) throws DatabaseException {
051:
052: this .db = db;
053: DatabaseConfig config = db.getConfig();
054: transactional = config.getTransactional();
055:
056: this .keyClass = keyClass;
057: this .keyBinding = keyBinding;
058: this .entityAdapter = entityAdapter;
059:
060: emptyRange = new KeyRange(config.getBtreeComparator());
061: keyAdapter = new KeyValueAdapter(keyClass, keyBinding);
062: }
063:
064: /*
065: * Of the EntityIndex methods only get()/map()/sortedMap() are not
066: * implemented here and therefore must be implemented by subclasses.
067: */
068:
069: public boolean contains(K key) throws DatabaseException {
070:
071: return contains(null, key, null);
072: }
073:
074: public boolean contains(Transaction txn, K key, LockMode lockMode)
075: throws DatabaseException {
076:
077: DatabaseEntry keyEntry = new DatabaseEntry();
078: DatabaseEntry dataEntry = NO_RETURN_ENTRY;
079: keyBinding.objectToEntry(key, keyEntry);
080:
081: OperationStatus status = db.get(txn, keyEntry, dataEntry,
082: lockMode);
083: return (status == OperationStatus.SUCCESS);
084: }
085:
086: public long count() throws DatabaseException {
087:
088: if (DbCompat.DATABASE_COUNT) {
089: return DbCompat.getDatabaseCount(db);
090: } else {
091: long count = 0;
092: boolean countDups = db instanceof SecondaryDatabase;
093: DatabaseEntry key = NO_RETURN_ENTRY;
094: DatabaseEntry data = NO_RETURN_ENTRY;
095: CursorConfig cursorConfig = CursorConfig.READ_UNCOMMITTED;
096: Cursor cursor = db.openCursor(null, cursorConfig);
097: try {
098: OperationStatus status = cursor.getFirst(key, data,
099: null);
100: while (status == OperationStatus.SUCCESS) {
101: if (countDups) {
102: count += cursor.count();
103: } else {
104: count += 1;
105: }
106: status = cursor.getNextNoDup(key, data, null);
107: }
108: } finally {
109: cursor.close();
110: }
111: return count;
112: }
113: }
114:
115: public boolean delete(K key) throws DatabaseException {
116:
117: return delete(null, key);
118: }
119:
120: public boolean delete(Transaction txn, K key)
121: throws DatabaseException {
122:
123: DatabaseEntry keyEntry = new DatabaseEntry();
124: keyBinding.objectToEntry(key, keyEntry);
125:
126: OperationStatus status = db.delete(txn, keyEntry);
127: return (status == OperationStatus.SUCCESS);
128: }
129:
130: public EntityCursor<K> keys() throws DatabaseException {
131:
132: return keys(null, null);
133: }
134:
135: public EntityCursor<K> keys(Transaction txn, CursorConfig config)
136: throws DatabaseException {
137:
138: return cursor(txn, emptyRange, keyAdapter, config);
139: }
140:
141: public EntityCursor<E> entities() throws DatabaseException {
142:
143: return cursor(null, emptyRange, entityAdapter, null);
144: }
145:
146: public EntityCursor<E> entities(Transaction txn, CursorConfig config)
147: throws DatabaseException {
148:
149: return cursor(txn, emptyRange, entityAdapter, config);
150: }
151:
152: public EntityCursor<K> keys(K fromKey, boolean fromInclusive,
153: K toKey, boolean toInclusive) throws DatabaseException {
154:
155: return cursor(null, fromKey, fromInclusive, toKey, toInclusive,
156: keyAdapter, null);
157: }
158:
159: public EntityCursor<K> keys(Transaction txn, K fromKey,
160: boolean fromInclusive, K toKey, boolean toInclusive,
161: CursorConfig config) throws DatabaseException {
162:
163: return cursor(txn, fromKey, fromInclusive, toKey, toInclusive,
164: keyAdapter, config);
165: }
166:
167: public EntityCursor<E> entities(K fromKey, boolean fromInclusive,
168: K toKey, boolean toInclusive) throws DatabaseException {
169:
170: return cursor(null, fromKey, fromInclusive, toKey, toInclusive,
171: entityAdapter, null);
172: }
173:
174: public EntityCursor<E> entities(Transaction txn, K fromKey,
175: boolean fromInclusive, K toKey, boolean toInclusive,
176: CursorConfig config) throws DatabaseException {
177:
178: return cursor(txn, fromKey, fromInclusive, toKey, toInclusive,
179: entityAdapter, config);
180: }
181:
182: /*
183: public ForwardCursor<K> unsortedKeys(KeySelector<K> selector)
184: throws DatabaseException {
185:
186: return unsortedKeys(null, selector, null);
187: }
188:
189: public ForwardCursor<K> unsortedKeys(Transaction txn,
190: KeySelector<K> selector,
191: CursorConfig config)
192: throws DatabaseException {
193:
194: throw new UnsupportedOperationException();
195: }
196:
197: public ForwardCursor<E> unsortedEntities(KeySelector<K> selector)
198: throws DatabaseException {
199:
200: return unsortedEntities(null, selector, null);
201: }
202:
203: public ForwardCursor<E> unsortedEntities(Transaction txn,
204: KeySelector<K> selector,
205: CursorConfig config)
206: throws DatabaseException {
207:
208: throw new UnsupportedOperationException();
209: }
210: */
211:
212: private <V> EntityCursor<V> cursor(Transaction txn, K fromKey,
213: boolean fromInclusive, K toKey, boolean toInclusive,
214: ValueAdapter<V> adapter, CursorConfig config)
215: throws DatabaseException {
216:
217: DatabaseEntry fromEntry = null;
218: if (fromKey != null) {
219: fromEntry = new DatabaseEntry();
220: keyBinding.objectToEntry(fromKey, fromEntry);
221: }
222: DatabaseEntry toEntry = null;
223: if (toKey != null) {
224: toEntry = new DatabaseEntry();
225: keyBinding.objectToEntry(toKey, toEntry);
226: }
227: KeyRange range = emptyRange.subRange(fromEntry, fromInclusive,
228: toEntry, toInclusive);
229: return cursor(txn, range, adapter, config);
230: }
231:
232: private <V> EntityCursor<V> cursor(Transaction txn, KeyRange range,
233: ValueAdapter<V> adapter, CursorConfig config)
234: throws DatabaseException {
235:
236: Cursor cursor = db.openCursor(txn, config);
237: RangeCursor rangeCursor = new RangeCursor(range, cursor);
238: return new BasicCursor<V>(rangeCursor, adapter);
239: }
240: }
|