diff options
Diffstat (limited to 'qpid/cpp/src')
| -rw-r--r-- | qpid/cpp/src/qpid/broker/AsyncCommandCallback.cpp | 11 | ||||
| -rw-r--r-- | qpid/cpp/src/qpid/broker/AsyncCommandCallback.h | 7 | ||||
| -rw-r--r-- | qpid/cpp/src/qpid/broker/SemanticState.cpp | 4 | ||||
| -rw-r--r-- | qpid/cpp/src/qpid/broker/SessionContext.h | 2 | ||||
| -rw-r--r-- | qpid/cpp/src/qpid/broker/SessionState.cpp | 32 | ||||
| -rw-r--r-- | qpid/cpp/src/qpid/broker/SessionState.h | 16 | ||||
| -rw-r--r-- | qpid/cpp/src/tests/AsyncCompletion.cpp | 35 |
7 files changed, 86 insertions, 21 deletions
diff --git a/qpid/cpp/src/qpid/broker/AsyncCommandCallback.cpp b/qpid/cpp/src/qpid/broker/AsyncCommandCallback.cpp index 2b1f3ad8e4..52dab42948 100644 --- a/qpid/cpp/src/qpid/broker/AsyncCommandCallback.cpp +++ b/qpid/cpp/src/qpid/broker/AsyncCommandCallback.cpp @@ -28,8 +28,8 @@ namespace broker { using namespace framing; -AsyncCommandCallback::AsyncCommandCallback(SessionState& ss, Command f) : - AsyncCommandContext(ss), command(f), channel(ss.getChannel()) +AsyncCommandCallback::AsyncCommandCallback(SessionState& ss, Command f, bool sync) : + AsyncCommandContext(ss), command(f), channel(ss.getChannel()), syncPoint(sync) {} void AsyncCommandCallback::completed(bool sync) { @@ -57,8 +57,11 @@ void AsyncCommandCallback::complete() { void AsyncCommandCallback::doCommand() { SessionState* session = completerContext->getSession(); - if (session && session->isAttached()) - session->completeCommand(id, false, requiresSync, command()); + if (session && session->isAttached()) { + // Complete now unless this is a syncPoint and there are incomplete commands. + if (!(syncPoint && session->addPendingExecutionSync(id))) + session->completeCommand(id, false, requiresSync, command()); + } else throw InternalErrorException("Cannot complete command, no session"); } diff --git a/qpid/cpp/src/qpid/broker/AsyncCommandCallback.h b/qpid/cpp/src/qpid/broker/AsyncCommandCallback.h index dd8214683a..15884ae8d9 100644 --- a/qpid/cpp/src/qpid/broker/AsyncCommandCallback.h +++ b/qpid/cpp/src/qpid/broker/AsyncCommandCallback.h @@ -45,7 +45,11 @@ class AsyncCommandCallback : public SessionState::AsyncCommandContext { */ typedef boost::function<std::string ()> Command; - AsyncCommandCallback(SessionState& ss, Command f); + /** + * @param syncPoint: if true have this command complete only when all + * preceeding commands are complete, like execution.sync. + */ + AsyncCommandCallback(SessionState& ss, Command f, bool syncPoint=false); void completed(bool sync); @@ -57,6 +61,7 @@ class AsyncCommandCallback : public SessionState::AsyncCommandContext { Command command; uint16_t channel; + bool syncPoint; }; }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp index 83405229ed..1b3823c845 100644 --- a/qpid/cpp/src/qpid/broker/SemanticState.cpp +++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp @@ -198,7 +198,9 @@ void SemanticState::commit(MessageStore* const store) txBuffer->startCommit(store); AsyncCommandCallback callback( session, - boost::bind(&TxBuffer::endCommit, txBuffer, store)); + boost::bind(&TxBuffer::endCommit, txBuffer, store), + true // This is a sync point + ); txBuffer->end(callback); } diff --git a/qpid/cpp/src/qpid/broker/SessionContext.h b/qpid/cpp/src/qpid/broker/SessionContext.h index 92a3dcecc2..53f3e1bab3 100644 --- a/qpid/cpp/src/qpid/broker/SessionContext.h +++ b/qpid/cpp/src/qpid/broker/SessionContext.h @@ -50,7 +50,7 @@ class SessionContext : public OwnershipToken virtual Broker& getBroker() = 0; virtual uint16_t getChannel() const = 0; virtual const SessionId& getSessionId() const = 0; - virtual void addPendingExecutionSync() = 0; + virtual bool addPendingExecutionSync() = 0; virtual void setUnackedCount(uint64_t) {} }; diff --git a/qpid/cpp/src/qpid/broker/SessionState.cpp b/qpid/cpp/src/qpid/broker/SessionState.cpp index 186bf77c64..c509ae7c14 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.cpp +++ b/qpid/cpp/src/qpid/broker/SessionState.cpp @@ -266,11 +266,14 @@ void SessionState::completeCommand(SequenceNumber id, // Are there any outstanding Execution.Sync commands pending the // completion of this cmd? If so, complete them. while (!pendingExecutionSyncs.empty() && - receiverGetIncomplete().front() >= pendingExecutionSyncs.front()) { - const SequenceNumber id = pendingExecutionSyncs.front(); + (receiverGetIncomplete().empty() || + receiverGetIncomplete().front() >= pendingExecutionSyncs.front())) + { + const SequenceNumber syncId = pendingExecutionSyncs.front(); pendingExecutionSyncs.pop(); - QPID_LOG(debug, getId() << ": delayed execution.sync " << id << " is completed."); - receiverCompleted(id); + QPID_LOG(debug, getId() << ": delayed execution.sync " << syncId << " is completed."); + if (receiverGetIncomplete().contains(syncId)) + receiverCompleted(syncId); callSendCompletion = true; // likely peer is pending for this completion. } @@ -348,15 +351,24 @@ void SessionState::setTimeout(uint32_t) { } // Current received command is an execution.sync command. // Complete this command only when all preceding commands have completed. // (called via the invoker() in handleCommand() above) -void SessionState::addPendingExecutionSync() -{ - SequenceNumber syncCommandId = currentCommand.getId(); - if (receiverGetIncomplete().front() < syncCommandId) { +bool SessionState::addPendingExecutionSync() { + SequenceNumber id = currentCommand.getId(); + if (addPendingExecutionSync(id)) { currentCommand.setCompleteSync(false); - pendingExecutionSyncs.push(syncCommandId); + QPID_LOG(debug, getId() << ": delaying completion of execution.sync " << id); + return true; + } + return false; +} + +bool SessionState::addPendingExecutionSync(SequenceNumber id) +{ + if (receiverGetIncomplete().front() < id) { + pendingExecutionSyncs.push(id); asyncCommandCompleter->flushPendingMessages(); - QPID_LOG(debug, getId() << ": delaying completion of execution.sync " << syncCommandId); + return true; } + return false; } /** factory for creating a reference-counted IncompleteIngressMsgXfer object diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h index ca6d6bf530..c71c520f9c 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.h +++ b/qpid/cpp/src/qpid/broker/SessionState.h @@ -116,9 +116,19 @@ class SessionState : public qpid::SessionState, const SessionId& getSessionId() const { return getId(); } - // Used by ExecutionHandler sync command processing. Notifies - // the SessionState of a received Execution.Sync command. - void addPendingExecutionSync(); + /** + * Used by ExecutionHandler sync command processing. Notifies + * the SessionState of a received Execution.Sync command. + * Return true if there are incomplete commands before the execution sync. + */ + bool addPendingExecutionSync(); + + /** + * Mark commannd ID as an execution sync point, completions will be sent + * when all commands up to that point are completed. + */ + bool addPendingExecutionSync(SequenceNumber id); + void setUnackedCount(uint64_t count) { if (mgmtObject) diff --git a/qpid/cpp/src/tests/AsyncCompletion.cpp b/qpid/cpp/src/tests/AsyncCompletion.cpp index e32097106f..dc43f10156 100644 --- a/qpid/cpp/src/tests/AsyncCompletion.cpp +++ b/qpid/cpp/src/tests/AsyncCompletion.cpp @@ -44,7 +44,8 @@ using broker::PersistableQueue; using sys::TIME_SEC; using boost::intrusive_ptr; -/** @file Unit tests for async completion. +/** @file + * Unit tests for async completion. * Using a dummy store, verify that the broker indicates async completion of * message enqueues at the correct time. */ @@ -69,6 +70,10 @@ class AsyncCompletionMessageStore : public NullMessageStore { QPID_AUTO_TEST_SUITE(AsyncCompletionTestSuite) +/** + * Send a sync after a bunch of incomplete messages, verify the sync completes + * only when all the messages are complete. + */ QPID_AUTO_TEST_CASE(testWaitTillComplete) { SessionFixture fix; AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore; @@ -104,6 +109,34 @@ QPID_AUTO_TEST_CASE(testWaitTillComplete) { sync.wait(); // Should complete now, all messages are completed. } +/** + * Send a sync after all messages are complete, verify it completes immediately. + */ +QPID_AUTO_TEST_CASE(testSyncAfterComplete) { + SessionFixture fix; + AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore; + boost::shared_ptr<qpid::broker::MessageStore> p; + p.reset(store); + fix.broker->setStore(p); + AsyncSession s = fix.session; + + static const int count = 3; + + s.queueDeclare("q", arg::durable=true); + // Transfer and complete all the messages + for (int i = 0; i < count; ++i) { + Message msg(boost::lexical_cast<string>(i), "q"); + msg.getDeliveryProperties().setDeliveryMode(PERSISTENT); + Completion transfer = s.messageTransfer(arg::content=msg, arg::sync=true); + intrusive_ptr<PersistableMessage> enqueued = store->enqueued.pop(TIME_SEC); + enqueued->enqueueComplete(); + transfer.wait(); + } + // Send a sync, make sure it completes immediately + Completion sync = s.executionSync(arg::sync=true); + sync.wait(); // Should complete now, all messages are completed. +} + QPID_AUTO_TEST_CASE(testGetResult) { SessionFixture fix; AsyncSession s = fix.session; |
