System.exit(ExitCode.SERVER_EXCEPTION);
}
}
public void processPacket(ByteBuffer packet, Cnxn src) {
PacketHeader h = PacketHeader.fromInt(packet.getInt());
boolean success = false;
int statType = BKStats.STATS_UNKNOWN;
long startTime = 0;
if (isStatsEnabled) {
startTime = MathUtils.now();
}
// packet format is different between ADDENTRY and READENTRY
long ledgerId = -1;
long entryId = BookieProtocol.INVALID_ENTRY_ID;
byte[] masterKey = null;
switch (h.getOpCode()) {
case BookieProtocol.ADDENTRY:
// first read master key
masterKey = new byte[BookieProtocol.MASTER_KEY_LENGTH];
packet.get(masterKey, 0, BookieProtocol.MASTER_KEY_LENGTH);
ByteBuffer bb = packet.duplicate();
ledgerId = bb.getLong();
entryId = bb.getLong();
break;
case BookieProtocol.READENTRY:
ledgerId = packet.getLong();
entryId = packet.getLong();
break;
}
if (h.getVersion() < BookieProtocol.LOWEST_COMPAT_PROTOCOL_VERSION
|| h.getVersion() > BookieProtocol.CURRENT_PROTOCOL_VERSION) {
LOG.error("Invalid protocol version, expected something between "
+ BookieProtocol.LOWEST_COMPAT_PROTOCOL_VERSION
+ " & " + BookieProtocol.CURRENT_PROTOCOL_VERSION
+ ". got " + h.getVersion());
src.sendResponse(buildResponse(BookieProtocol.EBADVERSION,
h.getVersion(), h.getOpCode(), ledgerId, entryId));
return;
}
short flags = h.getFlags();
switch (h.getOpCode()) {
case BookieProtocol.ADDENTRY:
statType = BKStats.STATS_ADD;
if (bookie.isReadOnly()) {
LOG.warn("BookieServer is running as readonly mode,"
+ " so rejecting the request from the client!");
src.sendResponse(buildResponse(BookieProtocol.EREADONLY,
h.getVersion(), h.getOpCode(), ledgerId, entryId));
break;
}
try {
TimedCnxn tsrc = new TimedCnxn(src, startTime);
if ((flags & BookieProtocol.FLAG_RECOVERY_ADD) == BookieProtocol.FLAG_RECOVERY_ADD) {
bookie.recoveryAddEntry(packet.slice(), this, tsrc, masterKey);
} else {
bookie.addEntry(packet.slice(), this, tsrc, masterKey);
}
success = true;
} catch (IOException e) {
LOG.error("Error writing " + entryId + "@" + ledgerId, e);
src.sendResponse(buildResponse(BookieProtocol.EIO, h.getVersion(), h.getOpCode(), ledgerId, entryId));
} catch (BookieException.LedgerFencedException lfe) {
LOG.error("Attempt to write to fenced ledger", lfe);
src.sendResponse(buildResponse(BookieProtocol.EFENCED, h.getVersion(), h.getOpCode(), ledgerId, entryId));
} catch (BookieException e) {
LOG.error("Unauthorized access to ledger " + ledgerId, e);
src.sendResponse(buildResponse(BookieProtocol.EUA, h.getVersion(), h.getOpCode(), ledgerId, entryId));
}
break;
case BookieProtocol.READENTRY:
statType = BKStats.STATS_READ;
ByteBuffer[] rsp = new ByteBuffer[2];
LOG.debug("Received new read request: {}, {}", ledgerId, entryId);
int errorCode = BookieProtocol.EIO;
try {
Future<Boolean> fenceResult = null;
if ((flags & BookieProtocol.FLAG_DO_FENCING) == BookieProtocol.FLAG_DO_FENCING) {
LOG.warn("Ledger " + ledgerId + " fenced by " + src.getPeerName());
if (h.getVersion() >= 2) {
masterKey = new byte[BookieProtocol.MASTER_KEY_LENGTH];
packet.get(masterKey, 0, BookieProtocol.MASTER_KEY_LENGTH);
fenceResult = bookie.fenceLedger(ledgerId, masterKey);
} else {
LOG.error("Password not provided, Not safe to fence {}", ledgerId);
throw BookieException.create(BookieException.Code.UnauthorizedAccessException);
}
}
rsp[1] = bookie.readEntry(ledgerId, entryId);
LOG.debug("##### Read entry ##### {}", rsp[1].remaining());
if (null != fenceResult) {
// TODO:
// currently we don't have readCallback to run in separated read
// threads. after BOOKKEEPER-429 is complete, we could improve
// following code to make it not wait here
//
// For now, since we only try to wait after read entry. so writing
// to journal and read entry are executed in different thread
// it would be fine.
try {
Boolean fenced = fenceResult.get(1000, TimeUnit.MILLISECONDS);
if (null == fenced || !fenced) {
// if failed to fence, fail the read request to make it retry.
errorCode = BookieProtocol.EIO;
success = false;
rsp[1] = null;
} else {
errorCode = BookieProtocol.EOK;
success = true;
}
} catch (InterruptedException ie) {
LOG.error("Interrupting fence read entry (lid:" + ledgerId
+ ", eid:" + entryId + ") :", ie);
errorCode = BookieProtocol.EIO;
success = false;
rsp[1] = null;
} catch (ExecutionException ee) {
LOG.error("Failed to fence read entry (lid:" + ledgerId
+ ", eid:" + entryId + ") :", ee);
errorCode = BookieProtocol.EIO;
success = false;
rsp[1] = null;
} catch (TimeoutException te) {
LOG.error("Timeout to fence read entry (lid:" + ledgerId
+ ", eid:" + entryId + ") :", te);
errorCode = BookieProtocol.EIO;
success = false;
rsp[1] = null;
}
} else {
errorCode = BookieProtocol.EOK;
success = true;
}
} catch (Bookie.NoLedgerException e) {
if (LOG.isTraceEnabled()) {
LOG.error("Error reading " + entryId + "@" + ledgerId, e);
}
errorCode = BookieProtocol.ENOLEDGER;
} catch (Bookie.NoEntryException e) {
if (LOG.isTraceEnabled()) {
LOG.error("Error reading " + entryId + "@" + ledgerId, e);
}
errorCode = BookieProtocol.ENOENTRY;
} catch (IOException e) {
if (LOG.isTraceEnabled()) {
LOG.error("Error reading " + entryId + "@" + ledgerId, e);
}
errorCode = BookieProtocol.EIO;
} catch (BookieException e) {
LOG.error("Unauthorized access to ledger " + ledgerId, e);
errorCode = BookieProtocol.EUA;
}
rsp[0] = buildResponse(errorCode, h.getVersion(), h.getOpCode(), ledgerId, entryId);
if (LOG.isTraceEnabled()) {
LOG.trace("Read entry rc = " + errorCode + " for " + entryId + "@" + ledgerId);
}
if (rsp[1] == null) {
// We haven't filled in entry data, so we have to send back
// the ledger and entry ids here
rsp[1] = ByteBuffer.allocate(16);
rsp[1].putLong(ledgerId);
rsp[1].putLong(entryId);
rsp[1].flip();
}
if (LOG.isTraceEnabled()) {
byte[] content = new byte[rsp[1].remaining()];
rsp[1].duplicate().get(content);
LOG.trace("Sending response for: {}, content: {}", entryId, Hex.encodeHexString(content));
} else {
LOG.debug("Sending response for: {}, length: {}", entryId, rsp[1].remaining());
}
src.sendResponse(rsp);
break;
default:
src.sendResponse(buildResponse(BookieProtocol.EBADREQ, h.getVersion(), h.getOpCode(), ledgerId, entryId));
}
if (isStatsEnabled) {
if (success) {
// for add operations, we compute latency in writeComplete callbacks.
if (statType != BKStats.STATS_ADD) {