Bugfix: store() should never throw a DuplicateKeyException.
It would be extremely rare, but if two nodes were trying to simultaneously store() the same record with the same Key, one could fail with a DKE. Attempt a second 'update' if the insert fails.
This commit is contained in:
@@ -553,43 +553,67 @@ public abstract class DepotRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
final boolean[] created = new boolean[1];
|
final boolean[] created = new boolean[1];
|
||||||
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
try {
|
||||||
@Override
|
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
@Override
|
||||||
if (_key != null) {
|
protected int invoke (Connection conn, DatabaseLiaison liaison)
|
||||||
// run the update
|
throws SQLException
|
||||||
int mods = builder.prepare(conn).executeUpdate();
|
{
|
||||||
if (mods > 0) {
|
if (_key != null) {
|
||||||
// if it succeeded, we're done
|
// run the update
|
||||||
return mods;
|
int mods = builder.prepare(conn).executeUpdate();
|
||||||
|
if (mods > 0) {
|
||||||
|
// if it succeeded, we're done
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if the update modified zero rows or the primary key was unset, insert
|
// if the update modified zero rows or the primary key was unset, insert
|
||||||
Set<String> identityFields = Collections.emptySet();
|
Set<String> identityFields = Collections.emptySet();
|
||||||
if (_key == null) {
|
if (_key == null) {
|
||||||
// first, set any auto-generated column values
|
// first, set any auto-generated column values
|
||||||
identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
|
identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
|
||||||
// update our modifier's key so that it can cache our results
|
// update our modifier's key so that it can cache our results
|
||||||
updateKey(marsh.getPrimaryKey(_result, false));
|
updateKey(marsh.getPrimaryKey(_result, false));
|
||||||
}
|
}
|
||||||
builder.newQuery(new InsertClause(pClass, _result, identityFields));
|
builder.newQuery(new InsertClause(pClass, _result, identityFields));
|
||||||
|
|
||||||
int mods = builder.prepare(conn).executeUpdate();
|
int mods = builder.prepare(conn).executeUpdate();
|
||||||
|
|
||||||
// run any post-factum value generators and potentially generate our key
|
// run any post-factum value generators and potentially generate our key
|
||||||
if (_key == null) {
|
if (_key == null) {
|
||||||
marsh.generateFieldValues(conn, liaison, _result, true);
|
marsh.generateFieldValues(conn, liaison, _result, true);
|
||||||
updateKey(marsh.getPrimaryKey(_result, false));
|
updateKey(marsh.getPrimaryKey(_result, false));
|
||||||
|
}
|
||||||
|
created[0] = true;
|
||||||
|
return mods;
|
||||||
}
|
}
|
||||||
created[0] = true;
|
@Override
|
||||||
return mods;
|
public void updateStats (Stats stats) {
|
||||||
|
stats.noteModification(pClass);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (DuplicateKeyException dke) {
|
||||||
|
if (key == null) {
|
||||||
|
throw dke; // how would this even happen?
|
||||||
}
|
}
|
||||||
@Override
|
// this should be very rare: the insert failed. Retry one more update.
|
||||||
public void updateStats (Stats stats) {
|
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
stats.noteModification(pClass);
|
@Override
|
||||||
}
|
protected int invoke (Connection conn, DatabaseLiaison liaison)
|
||||||
});
|
throws SQLException
|
||||||
|
{
|
||||||
|
builder.newQuery(update);
|
||||||
|
return builder.prepare(conn).executeUpdate();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void updateStats (Stats stats) {
|
||||||
|
stats.noteModification(pClass);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return created[0];
|
return created[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user