Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Index triggers only use "for update" mode when the strict option is s…
Browse files Browse the repository at this point in the history
…upplied.
  • Loading branch information
broneill committed Apr 13, 2013
1 parent f54bb91 commit b926a08
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 31 deletions.
Expand Up @@ -75,13 +75,7 @@ public void afterUpdate(S storable, Object state) throws PersistException {
}

@Override
public Object beforeTryDelete(Transaction txn, S storable) throws PersistException {
return beforeDelete(txn, storable);
}

@Override
public Object beforeDelete(Transaction txn, S storable) throws PersistException {
txn.setForUpdate(true);
public Object beforeDelete(S storable) throws PersistException {
try {
if (storable.copy().tryLoad()) {
return createDependentIndexEntries(storable);
Expand Down Expand Up @@ -175,4 +169,30 @@ private void updateValues(S storable, Object state) throws PersistException {
newIndexEntry.tryInsert();
}
}

/**
* Ensure old storable instance is loaded with an upgradable lock, allowing change to
* proceed without deadlock.
*/
final static class Strict<S extends Storable, D extends Storable>
extends DerivedIndexesTrigger<S, D>
{
Strict(IndexedRepository repository,
Class<S> sType, ChainedProperty<D> derivedTo)
throws RepositoryException
{
super(repository, sType, derivedTo);
}

@Override
public Object beforeTryDelete(Transaction txn, S storable) throws PersistException {
return beforeDelete(txn, storable);
}

@Override
public Object beforeDelete(Transaction txn, S storable) throws PersistException {
txn.setForUpdate(true);
return super.beforeDelete(storable);
}
}
}
Expand Up @@ -278,7 +278,11 @@ public IndexAnalysis(IndexedRepository repository, Storage<S> masterStorage)
managedIndexes[i++] = managedIndex;
}

indexesTrigger = new IndexesTrigger<S>(managedIndexes);
if (repository.isStrictTriggers()) {
indexesTrigger = new IndexesTrigger.Strict<S>(managedIndexes);
} else {
indexesTrigger = new IndexesTrigger<S>(managedIndexes);
}
}

derivedToDependencies = gatherDerivedToDependencies(info);
Expand Down
Expand Up @@ -64,14 +64,16 @@ class IndexedRepository implements Repository,
private final boolean mIndexRepairEnabled;
private final double mIndexThrottle;
private final boolean mAllClustered;
private final boolean mStrictTriggers;
private final StoragePool mStoragePool;
private final IndexAnalysisPool mIndexAnalysisPool;

IndexedRepository(AtomicReference<Repository> rootRef, String name,
Repository repository,
boolean indexRepairEnabled,
double indexThrottle,
boolean allClustered)
boolean allClustered,
boolean strictTriggers)
{
if (repository.getCapability(IndexInfoCapability.class) == null) {
throw new UnsupportedOperationException
Expand All @@ -85,6 +87,7 @@ class IndexedRepository implements Repository,
mIndexRepairEnabled = indexRepairEnabled;
mIndexThrottle = indexThrottle;
mAllClustered = allClustered;
mStrictTriggers = strictTriggers;
mIndexAnalysisPool = new IndexAnalysisPool(this);

mStoragePool = new StoragePool() {
Expand Down Expand Up @@ -264,4 +267,8 @@ boolean isIndexRepairEnabled() {
boolean isAllClustered() {
return mAllClustered;
}

boolean isStrictTriggers() {
return mStrictTriggers;
}
}
Expand Up @@ -50,6 +50,7 @@ public class IndexedRepositoryBuilder extends AbstractRepositoryBuilder {
private boolean mIndexRepairEnabled = true;
private double mIndexThrottle = 1.0;
private boolean mAllClustered;
private boolean mStrictTriggers;

public IndexedRepositoryBuilder() {
}
Expand Down Expand Up @@ -77,7 +78,8 @@ public Repository build(AtomicReference<Repository> rootRef) throws RepositoryEx
Repository repo = new IndexedRepository(rootRef, getName(), wrapped,
isIndexRepairEnabled(),
getIndexRepairThrottle(),
isAllClustered());
isAllClustered(),
mStrictTriggers);
rootRef.set(repo);
return repo;
}
Expand Down Expand Up @@ -190,6 +192,14 @@ public void setAllClustered(boolean clustered) {
mAllClustered = clustered;
}

/**
* Set to true to require that index maintenance triggers use a "for update" transaction,
* avoiding deadlocks and lock upgrade failures.
*/
public void setStrictTriggers(boolean strict) {
mStrictTriggers = strict;
}

@Override
public void errorCheck(Collection<String> messages) throws ConfigurationException {
super.errorCheck(messages);
Expand Down
Expand Up @@ -112,7 +112,15 @@ class IndexedStorage<S extends Storable> implements Storage<S>, StorageAccess<S>
// Install triggers to manage derived properties in external Storables.
if (analysis.derivedToDependencies != null) {
for (ChainedProperty<?> derivedTo : analysis.derivedToDependencies) {
addTrigger(new DerivedIndexesTrigger(mRepository, getStorableType(), derivedTo));
Trigger<? super S> trigger;
if (mRepository.isStrictTriggers()) {
trigger = new DerivedIndexesTrigger.Strict
(mRepository, getStorableType(), derivedTo);
} else {
trigger = new DerivedIndexesTrigger
(mRepository, getStorableType(), derivedTo);
}
addTrigger(trigger);
}
}
}
Expand Down
54 changes: 34 additions & 20 deletions src/main/java/com/amazon/carbonado/repo/indexed/IndexesTrigger.java
Expand Up @@ -64,16 +64,7 @@ public void afterTryInsert(S storable, Object state) throws PersistException {
}

@Override
public Object beforeTryUpdate(Transaction txn, S storable) throws PersistException {
return beforeUpdate(txn, storable);
}

@Override
public Object beforeUpdate(Transaction txn, S storable) throws PersistException {
// Ensure old storable is loaded with an upgradable lock, allowing
// update to proceed without deadlock.
txn.setForUpdate(true);

public Object beforeUpdate(S storable) throws PersistException {
// Return old storable for afterUpdate.
S copy = (S) storable.copy();
try {
Expand All @@ -98,16 +89,7 @@ public void afterUpdate(S storable, Object state) throws PersistException {
}

@Override
public Object beforeTryDelete(Transaction txn, S storable) throws PersistException {
return beforeDelete(txn, storable);
}

@Override
public Object beforeDelete(Transaction txn, S storable) throws PersistException {
// Ensure old storable is loaded with an upgradable lock, allowing
// delete to proceed without deadlock.
txn.setForUpdate(true);

public Object beforeDelete(S storable) throws PersistException {
// Delete index entries referenced by existing storable.
S copy = (S) storable.copy();
try {
Expand All @@ -130,4 +112,36 @@ public Object beforeDelete(Transaction txn, S storable) throws PersistException
}
return null;
}

/**
* Ensure old storable instance is loaded with an upgradable lock, allowing change to
* proceed without deadlock.
*/
final static class Strict<S extends Storable> extends IndexesTrigger<S> {
Strict(ManagedIndex<S>[] managedIndexes) {
super(managedIndexes);
}

@Override
public Object beforeTryUpdate(Transaction txn, S storable) throws PersistException {
return beforeUpdate(txn, storable);
}

@Override
public Object beforeUpdate(Transaction txn, S storable) throws PersistException {
txn.setForUpdate(true);
return super.beforeUpdate(storable);
}

@Override
public Object beforeTryDelete(Transaction txn, S storable) throws PersistException {
return beforeDelete(txn, storable);
}

@Override
public Object beforeDelete(Transaction txn, S storable) throws PersistException {
txn.setForUpdate(true);
return super.beforeDelete(storable);
}
}
}

0 comments on commit b926a08

Please sign in to comment.