use of org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord in project zookeeper by apache.
the class PrepRequestProcessor method getPendingChanges.
/**
* Grab current pending change records for each op in a multi-op.
*
* This is used inside MultiOp error code path to rollback in the event
* of a failed multi-op.
*
* @param multiRequest
* @return a map that contains previously existed records that probably need to be
* rolled back in any failure.
*/
private Map<String, ChangeRecord> getPendingChanges(MultiTransactionRecord multiRequest) {
Map<String, ChangeRecord> pendingChangeRecords = new HashMap<String, ChangeRecord>();
for (Op op : multiRequest) {
String path = op.getPath();
ChangeRecord cr = getOutstandingChange(path);
// only previously existing records need to be rolled back.
if (cr != null) {
pendingChangeRecords.put(path, cr);
}
/*
* ZOOKEEPER-1624 - We need to store for parent's ChangeRecord
* of the parent node of a request. So that if this is a
* sequential node creation request, rollbackPendingChanges()
* can restore previous parent's ChangeRecord correctly.
*
* Otherwise, sequential node name generation will be incorrect
* for a subsequent request.
*/
int lastSlash = path.lastIndexOf('/');
if (lastSlash == -1 || path.indexOf('\0') != -1) {
continue;
}
String parentPath = path.substring(0, lastSlash);
ChangeRecord parentCr = getOutstandingChange(parentPath);
if (parentCr != null) {
pendingChangeRecords.put(parentPath, parentCr);
}
}
return pendingChangeRecords;
}
use of org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord in project fabric8 by jboss-fuse.
the class PrepRequestProcessor method getPendingChanges.
/**
* Grab current pending change records for each op in a multi-op.
*
* This is used inside MultiOp error code path to rollback in the event
* of a failed multi-op.
*
* @param multiRequest
* @return a map that contains previously existed records that probably need to be
* rolled back in any failure.
*/
HashMap<String, ChangeRecord> getPendingChanges(MultiTransactionRecord multiRequest) {
HashMap<String, ChangeRecord> pendingChangeRecords = new HashMap<String, ChangeRecord>();
for (Op op : multiRequest) {
String path = op.getPath();
ChangeRecord cr = getOutstandingChange(path);
// only previously existing records need to be rolled back.
if (cr != null) {
pendingChangeRecords.put(path, cr);
}
/*
* ZOOKEEPER-1624 - We need to store for parent's ChangeRecord
* of the parent node of a request. So that if this is a
* sequential node creation request, rollbackPendingChanges()
* can restore previous parent's ChangeRecord correctly.
*
* Otherwise, sequential node name generation will be incorrect
* for a subsequent request.
*/
int lastSlash = path.lastIndexOf('/');
if (lastSlash == -1 || path.indexOf('\0') != -1) {
continue;
}
String parentPath = path.substring(0, lastSlash);
ChangeRecord parentCr = getOutstandingChange(parentPath);
if (parentCr != null) {
pendingChangeRecords.put(parentPath, parentCr);
}
}
return pendingChangeRecords;
}
use of org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord in project fabric8 by jboss-fuse.
the class PrepRequestProcessor method pRequest.
/**
* This method will be called inside the ProcessRequestThread, which is a
* singleton, so there will be a single thread calling this code.
*
* @param request
*/
@SuppressWarnings("unchecked")
protected void pRequest(Request request) throws RequestProcessorException {
// LOG.info("Prep>>> cxid = " + request.cxid + " type = " +
// request.type + " id = 0x" + Long.toHexString(request.sessionId));
request.hdr = null;
request.txn = null;
try {
switch(request.type) {
case OpCode.create:
CreateRequest createRequest = new CreateRequest();
pRequest2Txn(request.type, zks.getNextZxid(), request, createRequest, true);
break;
case OpCode.delete:
DeleteRequest deleteRequest = new DeleteRequest();
pRequest2Txn(request.type, zks.getNextZxid(), request, deleteRequest, true);
break;
case OpCode.setData:
SetDataRequest setDataRequest = new SetDataRequest();
pRequest2Txn(request.type, zks.getNextZxid(), request, setDataRequest, true);
break;
case OpCode.setACL:
SetACLRequest setAclRequest = new SetACLRequest();
pRequest2Txn(request.type, zks.getNextZxid(), request, setAclRequest, true);
break;
case OpCode.check:
CheckVersionRequest checkRequest = new CheckVersionRequest();
pRequest2Txn(request.type, zks.getNextZxid(), request, checkRequest, true);
break;
case OpCode.multi:
MultiTransactionRecord multiRequest = new MultiTransactionRecord();
try {
ByteBufferInputStream.byteBuffer2Record(request.request, multiRequest);
} catch (IOException e) {
request.hdr = new TxnHeader(request.sessionId, request.cxid, zks.getNextZxid(), zks.getTime(), OpCode.multi);
throw e;
}
List<Txn> txns = new ArrayList<Txn>();
// Each op in a multi-op must have the same zxid!
long zxid = zks.getNextZxid();
KeeperException ke = null;
// Store off current pending change records in case we need to rollback
HashMap<String, ChangeRecord> pendingChanges = getPendingChanges(multiRequest);
int index = 0;
for (Op op : multiRequest) {
Record subrequest = op.toRequestRecord();
/* If we've already failed one of the ops, don't bother
* trying the rest as we know it's going to fail and it
* would be confusing in the logfiles.
*/
if (ke != null) {
request.hdr.setType(OpCode.error);
request.txn = new ErrorTxn(Code.RUNTIMEINCONSISTENCY.intValue());
} else /* Prep the request and convert to a Txn */
{
try {
pRequest2Txn(op.getType(), zxid, request, subrequest, false);
} catch (KeeperException e) {
if (ke == null) {
ke = e;
}
request.hdr.setType(OpCode.error);
request.txn = new ErrorTxn(e.code().intValue());
if (!(request.type == OpCode.exists)) {
// INFO log only if we're not asking for existence of a node
// as this is absolutely normal to ask if a node exists and it doesn't exist
LOG.info("Got user-level KeeperException when processing " + request.toString() + " aborting remaining multi ops." + " Error Path:" + e.getPath() + " Error:" + e.getMessage());
}
request.setException(e);
/* Rollback change records from failed multi-op */
rollbackPendingChanges(zxid, pendingChanges);
}
}
// FIXME: I don't want to have to serialize it here and then
// immediately deserialize in next processor. But I'm
// not sure how else to get the txn stored into our list.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
request.txn.serialize(boa, "request");
ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
txns.add(new Txn(request.hdr.getType(), bb.array()));
index++;
}
request.hdr = new TxnHeader(request.sessionId, request.cxid, zxid, zks.getTime(), request.type);
request.txn = new MultiTxn(txns);
break;
// create/close session don't require request record
case OpCode.createSession:
case OpCode.closeSession:
pRequest2Txn(request.type, zks.getNextZxid(), request, null, true);
break;
// All the rest don't need to create a Txn - just verify session
case OpCode.sync:
case OpCode.exists:
case OpCode.getData:
case OpCode.getACL:
case OpCode.getChildren:
case OpCode.getChildren2:
case OpCode.ping:
case OpCode.setWatches:
zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
break;
}
} catch (KeeperException e) {
if (request.hdr != null) {
request.hdr.setType(OpCode.error);
request.txn = new ErrorTxn(e.code().intValue());
}
LOG.info("Got user-level KeeperException when processing " + request.toString() + " Error Path:" + e.getPath() + " Error:" + e.getMessage());
request.setException(e);
} catch (Exception e) {
// log at error level as we are returning a marshalling
// error to the user
LOG.error("Failed to process " + request, e);
StringBuilder sb = new StringBuilder();
ByteBuffer bb = request.request;
if (bb != null) {
bb.rewind();
while (bb.hasRemaining()) {
sb.append(Integer.toHexString(bb.get() & 0xff));
}
} else {
sb.append("request buffer is null");
}
LOG.error("Dumping request buffer: 0x" + sb.toString());
if (request.hdr != null) {
request.hdr.setType(OpCode.error);
request.txn = new ErrorTxn(Code.MARSHALLINGERROR.intValue());
}
}
request.zxid = zks.getZxid();
nextProcessor.processRequest(request);
}
use of org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord in project zookeeper by apache.
the class PrepRequestProcessor method rollbackPendingChanges.
/**
* Rollback pending changes records from a failed multi-op.
*
* If a multi-op fails, we can't leave any invalid change records we created
* around. We also need to restore their prior value (if any) if their prior
* value is still valid.
*
* @param zxid
* @param pendingChangeRecords
*/
void rollbackPendingChanges(long zxid, Map<String, ChangeRecord> pendingChangeRecords) {
synchronized (zks.outstandingChanges) {
// Grab a list iterator starting at the END of the list so we can iterate in reverse
Iterator<ChangeRecord> iter = zks.outstandingChanges.descendingIterator();
while (iter.hasNext()) {
ChangeRecord c = iter.next();
if (c.zxid == zxid) {
iter.remove();
// Remove all outstanding changes for paths of this multi.
// Previous records will be added back later.
zks.outstandingChangesForPath.remove(c.path);
} else {
break;
}
}
// we don't need to roll back any records because there is nothing left.
if (zks.outstandingChanges.isEmpty()) {
return;
}
long firstZxid = zks.outstandingChanges.peek().zxid;
for (ChangeRecord c : pendingChangeRecords.values()) {
// once they are completed.
if (c.zxid < firstZxid) {
continue;
}
// add previously existing records back.
zks.outstandingChangesForPath.put(c.path, c);
}
}
}
use of org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord in project zookeeper by apache.
the class PrepRequestProcessor method getRecordForPath.
private ChangeRecord getRecordForPath(String path) throws KeeperException.NoNodeException {
ChangeRecord lastChange = null;
synchronized (zks.outstandingChanges) {
lastChange = zks.outstandingChangesForPath.get(path);
if (lastChange == null) {
DataNode n = zks.getZKDatabase().getNode(path);
if (n != null) {
Set<String> children;
synchronized (n) {
children = n.getChildren();
}
lastChange = new ChangeRecord(-1, path, n.stat, children.size(), zks.getZKDatabase().aclForNode(n));
if (digestEnabled) {
lastChange.precalculatedDigest = new PrecalculatedDigest(digestCalculator.calculateDigest(path, n), 0);
}
lastChange.data = n.getData();
}
}
}
if (lastChange == null || lastChange.stat == null) {
throw new KeeperException.NoNodeException(path);
}
return lastChange;
}
Aggregations