use of ca.nrc.cadc.net.PreconditionFailedException in project caom2db by opencadc.
the class AbstractObservationDAOTest method testConditionalUpdate.
@Test
public void testConditionalUpdate() {
try {
SimpleObservation orig = new SimpleObservation("FOO", "bar");
dao.put(orig);
Observation c = dao.get(orig.getURI());
Assert.assertNotNull("found", c);
testEqual(orig, c);
URI cs1 = c.getAccMetaChecksum();
c.sequenceNumber = 1;
dao.put(c, cs1);
Observation c2 = dao.get(c.getURI());
Assert.assertNotNull("found", c2);
URI cs2 = c.getAccMetaChecksum();
// conditional update fails when expected checksum does not match
c.type = "OBJECT";
try {
dao.put(c, cs1);
} catch (PreconditionFailedException expected) {
log.info("caught expected exception: " + expected);
}
// conditional update succeeds when expected checksum does match
dao.put(c, cs2);
Observation c3 = dao.get(c.getURI());
Assert.assertNotNull("found", c3);
URI cs3 = c.getAccMetaChecksum();
dao.delete(orig.getID());
// copnditional update fails when not found
try {
dao.put(c, cs3);
} catch (PreconditionFailedException expected) {
log.info("caught expected exception: " + expected);
}
} catch (Exception unexpected) {
log.error("unexpected exception", unexpected);
if (txnManager.isOpen())
try {
txnManager.rollbackTransaction();
} catch (Throwable t) {
log.error("failed to rollback transaction", t);
}
Assert.fail("unexpected exception: " + unexpected);
}
}
use of ca.nrc.cadc.net.PreconditionFailedException in project caom2db by opencadc.
the class ObservationDAO method put.
/**
* Store an observation. If the optional accMetaChecksum argument is not null and does not
* match the accMetaChecksum of the currently observation, the update is rejected.
*
* @param obs the observation
* @param expectedMetaChecksum optional metadata checksum
* @throws PreconditionFailedException if the accMetaChecksum does not match
*/
public void put(Observation obs, URI expectedMetaChecksum) throws PreconditionFailedException {
if (readOnly) {
throw new UnsupportedOperationException("put in readOnly mode");
}
checkInit();
if (obs == null) {
throw new IllegalArgumentException("arg cannot be null");
}
log.debug("PUT: " + obs.getURI() + ", planes: " + obs.getPlanes().size());
long t = System.currentTimeMillis();
boolean txnOpen = false;
try {
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
// get current timestamp from server so that lastModified is closer to
// monatonically increasing than if we use client machine clock
Date now = getCurrentTime(jdbc);
DateFormat df = DateUtil.getDateFormat(DateUtil.IVOA_DATE_FORMAT, DateUtil.UTC);
log.debug("current time: " + df.format(now));
// NOTE: this is by ID which means to update the caller must get(uri) then put(o)
// and if they do not get(uri) they can get a duplicate observation error
// if they violate unique keys
String sql = gen.getSelectSQL(obs.getID(), SQLGenerator.MAX_DEPTH, true);
log.debug("PUT: " + sql);
final ObservationSkeleton dirtyRead = (ObservationSkeleton) jdbc.query(sql, new ObservationSkeletonExtractor());
log.debug("starting transaction");
getTransactionManager().startTransaction();
txnOpen = true;
// obtain row lock on observation update
ObservationSkeleton cur = null;
if (dirtyRead != null) {
String lock = gen.getUpdateLockSQL(obs.getID());
log.debug("LOCK SQL: " + lock);
jdbc.update(lock);
// req-acquire current state after obtaining lock
cur = (ObservationSkeleton) jdbc.query(sql, new ObservationSkeletonExtractor());
// check conditional update
if (expectedMetaChecksum != null) {
if (cur == null) {
// deleted by another actor since dirtyRead
throw new PreconditionFailedException("update blocked: current entity does not exist");
} else if (!expectedMetaChecksum.equals(cur.accMetaChecksum)) {
throw new PreconditionFailedException("update blocked: current entity is : " + cur.accMetaChecksum);
}
}
} else if (expectedMetaChecksum != null) {
throw new PreconditionFailedException("update blocked: current entity does not exist");
}
// update metadata checksums, maybe modified timestamps
updateEntity(obs, cur, now);
// delete obsolete children
List<Pair<Plane>> pairs = new ArrayList<Pair<Plane>>();
if (cur != null) {
// delete the skeletons that are not in obs.getPlanes()
for (PlaneSkeleton ps : cur.planes) {
Plane p = Util.findPlane(obs.getPlanes(), ps.id);
if (p == null) {
log.debug("PUT: caused delete: " + ps.id);
planeDAO.delete(ps, jdbc);
}
}
// pair up planes and skeletons for insert/update
for (Plane p : obs.getPlanes()) {
PlaneSkeleton ps = Util.findPlaneSkel(cur.planes, p.getID());
// null ok
pairs.add(new Pair<Plane>(ps, p));
}
} else {
for (Plane p : obs.getPlanes()) {
pairs.add(new Pair<Plane>(null, p));
}
}
super.put(cur, obs, null, jdbc);
// insert/update children
LinkedList<CaomEntity> parents = new LinkedList<CaomEntity>();
parents.push(obs);
for (Pair<Plane> p : pairs) {
planeDAO.put(p.cur, p.val, parents, jdbc);
}
log.debug("committing transaction");
getTransactionManager().commitTransaction();
log.debug("commit: OK");
txnOpen = false;
} catch (DataIntegrityViolationException e) {
log.debug("failed to insert " + obs + ": ", e);
getTransactionManager().rollbackTransaction();
log.debug("rollback: OK");
txnOpen = false;
throw e;
} catch (PreconditionFailedException ex) {
log.debug("failed to update " + obs + ": ", ex);
getTransactionManager().rollbackTransaction();
log.debug("rollback: OK");
txnOpen = false;
throw ex;
} catch (Exception e) {
log.error("failed to insert " + obs + ": ", e);
getTransactionManager().rollbackTransaction();
log.debug("rollback: OK");
txnOpen = false;
throw e;
} finally {
if (txnOpen) {
log.error("BUG - open transaction in finally");
getTransactionManager().rollbackTransaction();
log.error("rollback: OK");
}
long dt = System.currentTimeMillis() - t;
log.debug("PUT: " + obs.getURI() + " " + dt + "ms");
}
}
Aggregations