package com.sleepycat.bdb;
import com.sleepycat.bdb.bind.DataFormat;
import com.sleepycat.bdb.bind.KeyExtractor;
import com.sleepycat.db.Db;
import com.sleepycat.db.Dbc;
import com.sleepycat.db.DbException;
import java.io.FileNotFoundException;
import java.io.IOException;
public class DataIndex {
DataDb db;
DataStore store;
DataFormat keyFormat;
KeyExtractor keyExtractor;
public DataIndex(DataStore store, Db db,
DataFormat keyFormat, KeyExtractor keyExtractor) {
this.store = store;
this.keyFormat = keyFormat;
this.keyExtractor = keyExtractor;
this.db = new DataDb(db);
if (store.db.isTransactional() != this.db.isTransactional()) {
throw new IllegalArgumentException(
this.db + " and " + store.db +
" must must both be transactional or non-transactional");
}
if (this.db.areDuplicatesAllowed() &&
!this.db.areDuplicatesOrdered()) {
throw new IllegalArgumentException(
this.db + " must use sorted duplicates for index");
}
if (!keyFormat.equals(keyExtractor.getIndexKeyFormat())) {
throw new IllegalArgumentException(
this.db + " extractor index key format mismatch");
}
if (keyExtractor.getPrimaryKeyFormat() != null &&
!store.keyFormat.equals(keyExtractor.getPrimaryKeyFormat())) {
throw new IllegalArgumentException(
this.db + " extractor primary key format mismatch");
}
if (keyExtractor.getValueFormat() != null &&
!store.valueFormat.equals(keyExtractor.getValueFormat())) {
throw new IllegalArgumentException(
this.db + " extractor value format mismatch");
}
if (keyFormat instanceof RecordNumberFormat &&
!this.db.hasRecNumAccess()) {
throw new IllegalArgumentException(
this.db + " RecordNumberFormat is only allowed when the" +
" access method has record number keys");
}
store.addIndex(this);
}
public final DataStore getStore() {
return store;
}
public final DataFormat getKeyFormat() {
return keyFormat;
}
public final KeyExtractor getKeyExtractor() {
return keyExtractor;
}
public String toString() {
return db.toString();
}
void applyChange(DataThang keyThang,
DataThang oldValueThang,
DataThang newValueThang)
throws DbException, IOException {
DataThang oldIndexKey = null;
if (oldValueThang != null) {
oldIndexKey = new DataThang();
keyExtractor.extractIndexKey(
(keyExtractor.getPrimaryKeyFormat() != null)
? keyThang : null,
(keyExtractor.getValueFormat() != null)
? oldValueThang : null,
oldIndexKey);
if (oldIndexKey.getDataLength() == 0) oldIndexKey = null;
}
DataThang newIndexKey = null;
if (newValueThang != null) {
newIndexKey = new DataThang();
keyExtractor.extractIndexKey(
(keyExtractor.getPrimaryKeyFormat() != null)
? keyThang : null,
(keyExtractor.getValueFormat() != null)
? newValueThang : null,
newIndexKey);
if (newIndexKey.getDataLength() == 0) newIndexKey = null;
}
if (oldIndexKey == null && newIndexKey == null) {
return;
}
if (oldIndexKey != null && newIndexKey != null &&
oldIndexKey.compareTo(newIndexKey) == 0) {
return;
}
if (oldIndexKey != null) {
applyIndexDelete(keyThang, oldIndexKey);
}
if (newIndexKey != null) {
applyIndexInsert(keyThang, newIndexKey);
}
}
void applyIndexDelete(DataThang keyThang, DataThang oldIndexKey)
throws DbException, IOException {
Dbc cursor = db.openCursor(true);
try {
int err = cursor.get(oldIndexKey, keyThang,
Db.DB_GET_BOTH |
store.db.env.getWriteLockFlag());
if (err == 0) {
cursor.delete(0);
} else {
throw new IntegrityConstraintException(
"Index entry not found");
}
} finally {
db.closeCursor(cursor);
}
}
void applyIndexInsert(DataThang keyThang, DataThang newIndexKey)
throws DbException, IOException {
int err = db.put(newIndexKey, keyThang, Db.DB_NODUPDATA);
if (err != 0) {
throw new IntegrityConstraintException(
"Index entry already exists");
}
}
}