diff options
117 files changed, 5779 insertions, 5537 deletions
diff --git a/cpp/include/Ice/AsyncResult.h b/cpp/include/Ice/AsyncResult.h new file mode 100644 index 00000000000..5452c5de970 --- /dev/null +++ b/cpp/include/Ice/AsyncResult.h @@ -0,0 +1,353 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef ICE_ASYNC_RESULT_H +#define ICE_ASYNC_RESULT_H + +#include <IceUtil/Monitor.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/UniquePtr.h> +#include <Ice/LocalObject.h> +#include <Ice/CommunicatorF.h> +#include <Ice/ConnectionF.h> +#include <Ice/ProxyF.h> +#include <Ice/InstanceF.h> +#include <Ice/RequestHandlerF.h> +#include <Ice/AsyncResultF.h> +#include <Ice/ObserverHelper.h> +#include <Ice/BasicStream.h> + +#ifdef ICE_CPP11 +# include <functional> // for std::function +#endif + +namespace IceInternal +{ + +class CallbackBase; +typedef IceUtil::Handle<CallbackBase> CallbackBasePtr; + +} + +namespace Ice +{ + +class ICE_API AsyncResult : public Ice::LocalObject, private IceUtil::noncopyable +{ +public: + + void cancel(); + + Int getHash() const; + + CommunicatorPtr getCommunicator() const; + virtual ConnectionPtr getConnection() const; + virtual ObjectPrx getProxy() const; + + bool isCompleted() const; + void waitForCompleted(); + + bool isSent() const; + void waitForSent(); + + void throwLocalException() const; + + bool sentSynchronously() const; + LocalObjectPtr getCookie() const; + const std::string& getOperation() const; + + ::IceInternal::BasicStream* __startReadParams() + { + _is.startReadEncaps(); + return &_is; + } + void __endReadParams() + { + _is.endReadEncaps(); + } + void __readEmptyParams() + { + _is.skipEmptyEncaps(); + } + void __readParamEncaps(const ::Ice::Byte*& encaps, ::Ice::Int& sz) + { + _is.readEncaps(encaps, sz); + } + void __throwUserException(); + + bool __wait(); + + static void __check(const AsyncResultPtr&, const ::IceProxy::Ice::Object*, const ::std::string&); + static void __check(const AsyncResultPtr&, const Connection*, const ::std::string&); + static void __check(const AsyncResultPtr&, const Communicator*, const ::std::string&); + +protected: + + static void __check(const AsyncResultPtr&, const ::std::string&); + + AsyncResult(const CommunicatorPtr&, const IceInternal::InstancePtr&, const std::string&, + const IceInternal::CallbackBasePtr&, const LocalObjectPtr&); + virtual ~AsyncResult(); // Must be heap-allocated + + bool sent(bool); + bool finished(bool); + bool finished(const Exception&); + + void invokeSentAsync(); + void invokeCompletedAsync(); + + void invokeSent(); + void invokeCompleted(); + + void cancel(const LocalException&); + void cancelable(const IceInternal::CancellationHandlerPtr&); + void checkCanceled(); + + void warning(const std::exception&) const; + void warning() const; + + // + // This virtual method is necessary for the communicator flush + // batch requests implementation. + // + virtual IceInternal::InvocationObserver& getObserver() + { + return _observer; + } + + const IceInternal::InstancePtr _instance; + IceInternal::InvocationObserver _observer; + Ice::ConnectionPtr _cachedConnection; + bool _sentSynchronously; + + IceInternal::BasicStream _is; + + IceUtil::Monitor<IceUtil::Mutex> _monitor; + +private: + + const CommunicatorPtr _communicator; + const std::string& _operation; + const IceInternal::CallbackBasePtr _callback; + const LocalObjectPtr _cookie; + IceUtil::UniquePtr<Exception> _exception; + + IceInternal::CancellationHandlerPtr _cancellationHandler; + IceUtil::UniquePtr<Ice::LocalException> _cancellationException; + + static const unsigned char OK; + static const unsigned char Done; + static const unsigned char Sent; + static const unsigned char EndCalled; + static const unsigned char Canceled; + unsigned char _state; +}; + +} + +namespace IceInternal +{ + +// +// Base class for all callbacks. +// +class ICE_API CallbackBase : public IceUtil::Shared +{ +public: + + void checkCallback(bool, bool); + + virtual void completed(const ::Ice::AsyncResultPtr&) const = 0; + virtual CallbackBasePtr verify(const ::Ice::LocalObjectPtr&) = 0; + virtual void sent(const ::Ice::AsyncResultPtr&) const = 0; + virtual bool hasSentCallback() const = 0; +}; + +// +// Base class for generic callbacks. +// +class ICE_API GenericCallbackBase : virtual public CallbackBase +{ +}; + +// +// See comments in OutgoingAsync.cpp +// +extern ICE_API CallbackBasePtr __dummyCallback; + +// +// Generic callback template that requires the caller to down-cast the +// proxy and the cookie that are obtained from the AsyncResult. +// +template<class T> +class AsyncCallback : public GenericCallbackBase +{ +public: + + typedef T callback_type; + typedef IceUtil::Handle<T> TPtr; + + typedef void (T::*Callback)(const ::Ice::AsyncResultPtr&); + + AsyncCallback(const TPtr& instance, Callback cb, Callback sentcb = 0) : + _callback(instance), _completed(cb), _sent(sentcb) + { + checkCallback(instance, cb != 0); + } + + virtual void completed(const ::Ice::AsyncResultPtr& result) const + { + (_callback.get()->*_completed)(result); + } + + virtual CallbackBasePtr verify(const ::Ice::LocalObjectPtr&) + { + return this; // Nothing to do, the cookie is not type-safe. + } + + virtual void sent(const ::Ice::AsyncResultPtr& result) const + { + if(_sent) + { + (_callback.get()->*_sent)(result); + } + } + + virtual bool hasSentCallback() const + { + return _sent != 0; + } + +private: + + TPtr _callback; + Callback _completed; + Callback _sent; +}; + +#ifdef ICE_CPP11 + +template<typename T> struct callback_type +{ + static const int value = 1; +}; + +template<> struct callback_type<void(const ::Ice::AsyncResultPtr&)> +{ + static const int value = 2; +}; + +template<> struct callback_type<void(const ::Ice::Exception&)> +{ + static const int value = 3; +}; + +template<typename Callable, typename = void> struct callable_type +{ + static const int value = 1; +}; + +template<class Callable> struct callable_type<Callable, typename ::std::enable_if< + ::std::is_class<Callable>::value && + !::std::is_bind_expression<Callable>::value>::type> +{ + template<typename T, T> struct TypeCheck; + template<typename T> struct AsyncResultCallback + { + typedef void (T::*ok)(const ::Ice::AsyncResultPtr&) const; + }; + template<typename T> struct ExceptionCallback + { + typedef void (T::*ok)(const ::Ice::Exception&) const; + }; + + typedef char (&other)[1]; + typedef char (&asyncResult)[2]; + typedef char (&exception)[3]; + + template<typename T> static other check(...); + template<typename T> static asyncResult check(TypeCheck<typename AsyncResultCallback<T>::ok, &T::operator()>*); + template<typename T> static exception check(TypeCheck<typename ExceptionCallback<T>::ok, &T::operator()>*); + + enum { value = sizeof(check<Callable>(0)) }; +}; + +template<> struct callable_type<void(*)(const ::Ice::AsyncResultPtr&)> +{ + static const int value = 2; +}; + +template<> struct callable_type<void(*)(const ::Ice::Exception&)> +{ + static const int value = 3; +}; + +template<typename Callable, typename Callback> struct is_callable +{ + static const bool value = callable_type<Callable>::value == callback_type<Callback>::value; +}; + +template<class S> class Function : public std::function<S> +{ + +public: + + template<typename T> Function(T f, typename ::std::enable_if<is_callable<T, S>::value>::type* = 0) + : std::function<S>(f) + { + } + + Function() + { + } + + Function(::std::nullptr_t) : ::std::function<S>(nullptr) + { + } +}; + +#endif + +} + +namespace Ice +{ + +typedef IceUtil::Handle< ::IceInternal::GenericCallbackBase> CallbackPtr; + +template<class T> CallbackPtr +newCallback(const IceUtil::Handle<T>& instance, + void (T::*cb)(const AsyncResultPtr&), + void (T::*sentcb)(const AsyncResultPtr&) = 0) +{ + return new ::IceInternal::AsyncCallback<T>(instance, cb, sentcb); +} + +template<class T> CallbackPtr +newCallback(T* instance, + void (T::*cb)(const AsyncResultPtr&), + void (T::*sentcb)(const AsyncResultPtr&) = 0) +{ + return new ::IceInternal::AsyncCallback<T>(instance, cb, sentcb); +} + +#ifdef ICE_CPP11 + +ICE_API CallbackPtr +newCallback(const ::IceInternal::Function<void (const AsyncResultPtr&)>&, + const ::IceInternal::Function<void (const AsyncResultPtr&)>& = + ::IceInternal::Function<void (const AsyncResultPtr&)>()); +#endif + +// +// Operation callbacks are specified in Proxy.h +// +} + +#endif diff --git a/cpp/include/Ice/AsyncResultF.h b/cpp/include/Ice/AsyncResultF.h new file mode 100644 index 00000000000..dac5f9b68cf --- /dev/null +++ b/cpp/include/Ice/AsyncResultF.h @@ -0,0 +1,26 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef ICE_ASYNC_RESULT_F_H +#define ICE_ASYNC_RESULT_F_H + +#include <IceUtil/Shared.h> + +#include <Ice/Handle.h> + +namespace Ice +{ + +class AsyncResult; +ICE_API IceUtil::Shared* upCast(::Ice::AsyncResult*); +typedef IceInternal::Handle<AsyncResult> AsyncResultPtr; + +} + +#endif diff --git a/cpp/include/Ice/Initialize.h b/cpp/include/Ice/Initialize.h index 04271017221..7331d12dae5 100644 --- a/cpp/include/Ice/Initialize.h +++ b/cpp/include/Ice/Initialize.h @@ -10,6 +10,7 @@ #ifndef ICE_INITIALIZE_H #define ICE_INITIALIZE_H +#include <IceUtil/Timer.h> #include <Ice/CommunicatorF.h> #include <Ice/PropertiesF.h> #include <Ice/InstanceF.h> diff --git a/cpp/include/Ice/Outgoing.h b/cpp/include/Ice/Outgoing.h index e6697387603..c50b0a28aae 100644 --- a/cpp/include/Ice/Outgoing.h +++ b/cpp/include/Ice/Outgoing.h @@ -35,38 +35,63 @@ namespace IceInternal class CollocatedRequestHandler; // Forward declaration -class ICE_API OutgoingMessageCallback : private IceUtil::noncopyable +class ICE_API OutgoingBase : private IceUtil::noncopyable { public: - virtual ~OutgoingMessageCallback() { } + virtual ~OutgoingBase() { } virtual bool send(const Ice::ConnectionIPtr&, bool, bool) = 0; virtual void invokeCollocated(CollocatedRequestHandler*) = 0; virtual void sent() = 0; - virtual void finished(const Ice::Exception&) = 0; + virtual void completed(const Ice::Exception&) = 0; + + BasicStream* os() { return &_os; } + + void attachRemoteObserver(const Ice::ConnectionInfoPtr& c, const Ice::EndpointPtr& endpt, Ice::Int requestId) + { + const Ice::Int size = static_cast<Ice::Int>(_os.b.size() - IceInternal::headerSize - 4); + _childObserver.attach(_observer.getRemoteObserver(c, endpt, requestId, size)); + } + + void attachCollocatedObserver(const Ice::ObjectAdapterPtr& adapter, Ice::Int requestId) + { + const Ice::Int size = static_cast<Ice::Int>(_os.b.size() - IceInternal::headerSize - 4); + _childObserver.attach(_observer.getCollocatedObserver(adapter, requestId, size)); + } + +protected: + + OutgoingBase(Instance*, const std::string&); + + BasicStream _os; + IceUtil::UniquePtr<Ice::Exception> _exception; + bool _sent; + InvocationObserver _observer; + ObserverHelperT<Ice::Instrumentation::ChildInvocationObserver> _childObserver; + + IceUtil::Monitor<IceUtil::Mutex> _monitor; }; -class ICE_API Outgoing : public OutgoingMessageCallback +class ICE_API Outgoing : public OutgoingBase { public: Outgoing(IceProxy::Ice::Object*, const std::string&, Ice::OperationMode, const Ice::Context*); ~Outgoing(); - bool invoke(); // Returns true if ok, false if user exception. - void abort(const Ice::LocalException&); - virtual bool send(const Ice::ConnectionIPtr&, bool, bool); virtual void invokeCollocated(CollocatedRequestHandler*); + virtual void sent(); - virtual void finished(const Ice::Exception&); + virtual void completed(const Ice::Exception&); - void finished(BasicStream&); + bool invoke(); // Returns true if ok, false if user exception. + void abort(const Ice::LocalException&); + void completed(BasicStream&); // Inlined for speed optimization. - BasicStream* os() { return &_os; } BasicStream* startReadParams() { _is.startReadEncaps(); @@ -117,20 +142,6 @@ public: void throwUserException(); - void attachRemoteObserver(const Ice::ConnectionInfoPtr& c, const Ice::EndpointPtr& endpt, - Ice::Int requestId, Ice::Int size) - { - _childObserver.attach(_observer.getRemoteObserver(c, endpt, requestId, size)); - } - - void attachCollocatedObserver(const Ice::ObjectAdapterPtr& adapter, Ice::Int requestId) - { - _childObserver.attach(_observer.getCollocatedObserver(adapter, - requestId, - static_cast<Ice::Int>(_os.b.size() - - IceInternal::headerSize - 4))); - } - private: // @@ -140,9 +151,7 @@ private: IceProxy::Ice::Object* _proxy; Ice::OperationMode _mode; RequestHandlerPtr _handler; - IceUtil::UniquePtr<Ice::Exception> _exception; - InvocationObserver _observer; - ObserverHelperT<Ice::Instrumentation::ChildInvocationObserver> _childObserver; + IceUtil::Time _invocationTimeoutDeadline; enum { @@ -156,60 +165,27 @@ private: Ice::EncodingVersion _encoding; BasicStream _is; - BasicStream _os; - bool _sent; - - // - // NOTE: we use an attribute for the monitor instead of inheriting - // from the monitor template. Otherwise, the template would be - // exported from the DLL on Windows and could cause linker errors - // because of multiple definition of IceUtil::Monitor<IceUtil::Mutex>, - // see bug 1541. - // - IceUtil::Monitor<IceUtil::Mutex> _monitor; }; -class BatchOutgoing : public OutgoingMessageCallback +class FlushBatch : public OutgoingBase { public: - BatchOutgoing(IceProxy::Ice::Object*, const std::string&); - BatchOutgoing(Ice::ConnectionI*, Instance*, const std::string&); + FlushBatch(IceProxy::Ice::Object*, const std::string&); + FlushBatch(Ice::ConnectionI*, Instance*, const std::string&); void invoke(); virtual bool send(const Ice::ConnectionIPtr&, bool, bool); virtual void invokeCollocated(CollocatedRequestHandler*); - virtual void sent(); - virtual void finished(const Ice::Exception&); - - BasicStream* os() { return &_os; } - void attachRemoteObserver(const Ice::ConnectionInfoPtr& connection, const Ice::EndpointPtr& endpt, Ice::Int sz) - { - _childObserver.attach(_observer.getRemoteObserver(connection, endpt, 0, sz)); - } - - void attachCollocatedObserver(const Ice::ObjectAdapterPtr& adapter, Ice::Int requestId) - { - _childObserver.attach(_observer.getCollocatedObserver(adapter, - requestId, - static_cast<Ice::Int>(_os.b.size() - - IceInternal::headerSize - 4))); - } + virtual void sent(); + virtual void completed(const Ice::Exception&); private: - IceUtil::Monitor<IceUtil::Mutex> _monitor; IceProxy::Ice::Object* _proxy; Ice::ConnectionI* _connection; - bool _sent; - IceUtil::UniquePtr<Ice::Exception> _exception; - - BasicStream _os; - - InvocationObserver _observer; - ObserverHelperT<Ice::Instrumentation::ChildInvocationObserver> _childObserver; }; } diff --git a/cpp/include/Ice/OutgoingAsync.h b/cpp/include/Ice/OutgoingAsync.h index 422ad6d65db..a81419465fa 100644 --- a/cpp/include/Ice/OutgoingAsync.h +++ b/cpp/include/Ice/OutgoingAsync.h @@ -10,276 +10,151 @@ #ifndef ICE_OUTGOING_ASYNC_H #define ICE_OUTGOING_ASYNC_H -#include <IceUtil/Monitor.h> -#include <IceUtil/Mutex.h> #include <IceUtil/Timer.h> -#include <IceUtil/Exception.h> -#include <IceUtil/UniquePtr.h> #include <Ice/OutgoingAsyncF.h> -#include <Ice/RequestHandlerF.h> -#include <Ice/InstanceF.h> -#include <Ice/ReferenceF.h> +#include <Ice/AsyncResult.h> #include <Ice/CommunicatorF.h> #include <Ice/ConnectionIF.h> -#include <Ice/Current.h> -#include <Ice/BasicStream.h> -#include <Ice/ObserverHelper.h> #include <Ice/ObjectAdapterF.h> -#include <Ice/ThreadPoolF.h> - -#ifdef ICE_CPP11 -# include <functional> // for std::function -#endif namespace IceInternal { -class CallbackBase; -typedef IceUtil::Handle<CallbackBase> CallbackBasePtr; - -} - -namespace Ice -{ +class RetryException; +class CollocatedRequestHandler; -class ICE_API AsyncResult : virtual public Ice::LocalObject, protected IceUtil::TimerTask, private IceUtil::noncopyable +// +// Base class for handling asynchronous invocations. This class is +// responsible for the handling of the output stream and the child +// invocation observer. +// +class ICE_API OutgoingAsyncBase : public Ice::AsyncResult { public: - virtual Int getHash() const; - - virtual CommunicatorPtr getCommunicator() const - { - return _communicator; - } - - virtual ConnectionPtr getConnection() const - { - return 0; - } - - virtual ObjectPrx getProxy() const - { - return 0; - } - - bool isCompleted() const; - void waitForCompleted(); + // + // Those methods must be overriden if the invocation is sent + // through a request handler. + // + virtual AsyncStatus send(const Ice::ConnectionIPtr&, bool, bool) { assert(false); return AsyncStatusQueued; } + virtual AsyncStatus invokeCollocated(CollocatedRequestHandler*) { assert(false); return AsyncStatusQueued; } - bool isSent() const; - void waitForSent(); + virtual bool sent(); + virtual bool completed(const Ice::Exception&); - void throwLocalException() const; + // Those methods are public when called from an OutgoingAsyncBase reference. + using Ice::AsyncResult::cancelable; + using Ice::AsyncResult::invokeSent; + using Ice::AsyncResult::invokeCompleted; + using Ice::AsyncResult::invokeCompletedAsync; - bool sentSynchronously() const + void attachRemoteObserver(const Ice::ConnectionInfoPtr& c, const Ice::EndpointPtr& endpt, Ice::Int requestId) { - return _sentSynchronously; // No lock needed, immutable once __send() is called + const Ice::Int size = static_cast<Ice::Int>(_os.b.size() - headerSize - 4); + _childObserver.attach(getObserver().getRemoteObserver(c, endpt, requestId, size)); } - - LocalObjectPtr getCookie() const + + void attachCollocatedObserver(const Ice::ObjectAdapterPtr& adapter, Ice::Int requestId) { - return _cookie; // No lock needed, cookie is immutable + const Ice::Int size = static_cast<Ice::Int>(_os.b.size() - headerSize - 4); + _childObserver.attach(getObserver().getCollocatedObserver(adapter, requestId, size)); } - const std::string& getOperation() const - { - return _operation; - } - - ::IceInternal::BasicStream* - __getOs() + BasicStream* getOs() { return &_os; } - ::IceInternal::BasicStream* __startReadParams() - { - _is.startReadEncaps(); - return &_is; - } - void __endReadParams() - { - _is.endReadEncaps(); - } - void __readEmptyParams() - { - _is.skipEmptyEncaps(); - } - void __readParamEncaps(const ::Ice::Byte*& encaps, ::Ice::Int& sz) - { - _is.readEncaps(encaps, sz); - } - - bool __wait(); - void __throwUserException(); - virtual void __invokeExceptionAsync(const Exception&); - void __invokeCompleted(); - - static void __check(const AsyncResultPtr&, const ::IceProxy::Ice::Object*, const ::std::string&); - static void __check(const AsyncResultPtr&, const Connection*, const ::std::string&); - static void __check(const AsyncResultPtr&, const Communicator*, const ::std::string&); - - virtual void __invokeException(const Exception&); // Required to be public for AsynchronousException - void __invokeSent(); // Required to be public for AsynchronousSent - - void __attachRemoteObserver(const Ice::ConnectionInfoPtr& c, const Ice::EndpointPtr& endpt, - Ice::Int requestId, Ice::Int sz) - { - _childObserver.attach(_observer.getRemoteObserver(c, endpt, requestId, sz)); - } - - void __attachCollocatedObserver(const Ice::ObjectAdapterPtr& adapter, Ice::Int requestId) - { - _childObserver.attach(_observer.getCollocatedObserver(adapter, - requestId, - static_cast<Ice::Int>(_os.b.size() - - IceInternal::headerSize - 4))); - } - - // - // Called by the retry queue to process retry. - // - virtual void __processRetry() = 0; - protected: - static void __check(const AsyncResultPtr&, const ::std::string&); - - AsyncResult(const CommunicatorPtr&, const IceInternal::InstancePtr&, const std::string&, - const IceInternal::CallbackBasePtr&, const LocalObjectPtr&); - - void __invokeSentAsync(); - - void runTimerTask(); // Implementation of TimerTask::runTimerTask() - - void __warning(const std::exception&) const; - void __warning() const; - - virtual ~AsyncResult(); // Must be heap-allocated. - - const CommunicatorPtr _communicator; - const IceInternal::InstancePtr _instance; - const std::string& _operation; - Ice::ConnectionPtr _cachedConnection; - const IceInternal::CallbackBasePtr _callback; - const LocalObjectPtr _cookie; + OutgoingAsyncBase(const Ice::CommunicatorPtr&, const InstancePtr&, const std::string&, const CallbackBasePtr&, + const Ice::LocalObjectPtr&); - IceUtil::Monitor<IceUtil::Mutex> _monitor; - IceInternal::BasicStream _is; - IceInternal::BasicStream _os; + bool sent(bool); + bool finished(const Ice::Exception&); - IceInternal::RequestHandlerPtr _timeoutRequestHandler; + ObserverHelperT<Ice::Instrumentation::ChildInvocationObserver> _childObserver; - static const unsigned char OK; - static const unsigned char Done; - static const unsigned char Sent; - static const unsigned char EndCalled; - - unsigned char _state; - bool _sentSynchronously; - IceUtil::UniquePtr<Exception> _exception; - IceInternal::InvocationObserver _observer; - IceInternal::ObserverHelperT<Ice::Instrumentation::ChildInvocationObserver> _childObserver; + BasicStream _os; }; -} - -namespace IceInternal -{ - // -// See comments in OutgoingAsync.cpp +// Base class for proxy based invocations. This class handles the +// retry for proxy invocations. It also ensures the child observer is +// correct notified of failures and make sure the retry task is +// correctly canceled when the invocation completes. // -extern ICE_API CallbackBasePtr __dummyCallback; - -class CollocatedRequestHandler; - -// -// This interface is used by the connection to handle OutgoingAsync -// and BatchOutgoingAsync messages. -// -class ICE_API OutgoingAsyncMessageCallback : virtual public Ice::LocalObject +class ICE_API ProxyOutgoingAsyncBase : public OutgoingAsyncBase, protected IceUtil::TimerTask { public: - virtual ~OutgoingAsyncMessageCallback() - { - } + virtual Ice::ObjectPrx getProxy() const; - // - // Called by the request handler to send the request over the connection. - // - virtual IceInternal::AsyncStatus __send(const Ice::ConnectionIPtr&, bool, bool) = 0; + virtual bool sent(); + virtual bool completed(const Ice::Exception&); - // - // Called by the collocated request handler to invoke the request. - // - virtual IceInternal::AsyncStatus __invokeCollocated(CollocatedRequestHandler*) = 0; + void retry(); + void abort(const Ice::Exception&); - // - // Called by the connection when the message is confirmed sent. The connection is locked - // when this is called so this method can't call the sent callback. Instead, this method - // returns true if there's a sent callback and false otherwise. If true is returned, the - // connection will call the __invokeSentCallback() method bellow (which in turn should - // call the sent callback). - // - virtual bool __sent() = 0; +protected: - // - // Called by the connection to call the user sent callback. - // - virtual void __invokeSent() = 0; + ProxyOutgoingAsyncBase(const Ice::ObjectPrx&, const std::string&, const CallbackBasePtr&, + const Ice::LocalObjectPtr&); - // - // Called by the connection when the request failed. - // - virtual void __finished(const Ice::Exception&) = 0; + void invokeImpl(bool); - // - // Helper to dispatch invocation timeout. - // - void __dispatchInvocationTimeout(const ThreadPoolPtr&, const Ice::ConnectionPtr&); + bool sent(bool); + bool finished(const Ice::Exception&); + bool finished(bool); + + virtual void handleRetryException(const RetryException&); + virtual int handleException(const Ice::Exception&); + virtual void runTimerTask(); + + const Ice::ObjectPrx _proxy; + RequestHandlerPtr _handler; + Ice::OperationMode _mode; + +private: + + int _cnt; + bool _sent; }; -class ICE_API OutgoingAsync : public OutgoingAsyncMessageCallback, public Ice::AsyncResult +// +// Class for handling Slice operation invocations +// +class ICE_API OutgoingAsync : public ProxyOutgoingAsyncBase { public: OutgoingAsync(const Ice::ObjectPrx&, const std::string&, const CallbackBasePtr&, const Ice::LocalObjectPtr&); - void __prepare(const std::string&, Ice::OperationMode, const Ice::Context*); + void prepare(const std::string&, Ice::OperationMode, const Ice::Context*); - virtual Ice::ObjectPrx - getProxy() const - { - return _proxy; - } + virtual AsyncStatus send(const Ice::ConnectionIPtr&, bool, bool); + virtual AsyncStatus invokeCollocated(CollocatedRequestHandler*); - virtual IceInternal::AsyncStatus __send(const Ice::ConnectionIPtr&, bool, bool); - virtual IceInternal::AsyncStatus __invokeCollocated(CollocatedRequestHandler*); - virtual bool __sent(); - virtual void __invokeSent(); - virtual void __finished(const Ice::Exception&); - virtual void __invokeExceptionAsync(const Ice::Exception&); - virtual void __processRetry(); + void abort(const Ice::Exception&); - bool __finished(); - bool __invoke(bool); + void invoke(); + using ProxyOutgoingAsyncBase::completed; + bool completed(); - BasicStream* __startWriteParams(Ice::FormatType format) + BasicStream* startWriteParams(Ice::FormatType format) { _os.startWriteEncaps(_encoding, format); return &_os; } - void __endWriteParams() + void endWriteParams() { _os.endWriteEncaps(); } - void __writeEmptyParams() + void writeEmptyParams() { _os.writeEmptyEncaps(_encoding); } - void __writeParamEncaps(const ::Ice::Byte* encaps, ::Ice::Int size) + void writeParamEncaps(const ::Ice::Byte* encaps, ::Ice::Int size) { if(size == 0) { @@ -291,315 +166,95 @@ public: } } - ::IceInternal::BasicStream* - __getIs() + BasicStream* getIs() { return &_is; } private: - void handleException(const Ice::Exception&); - - const Ice::ObjectPrx _proxy; const Ice::EncodingVersion _encoding; - - RequestHandlerPtr _handler; - int _cnt; - bool _sent; - Ice::OperationMode _mode; -}; - -class ICE_API BatchOutgoingAsync : public OutgoingAsyncMessageCallback, public Ice::AsyncResult -{ -public: - - BatchOutgoingAsync(const Ice::CommunicatorPtr&, const InstancePtr&, const std::string&, const CallbackBasePtr&, - const Ice::LocalObjectPtr&); - - virtual IceInternal::AsyncStatus __send(const Ice::ConnectionIPtr&, bool, bool); - virtual IceInternal::AsyncStatus __invokeCollocated(CollocatedRequestHandler*); - virtual bool __sent(); - virtual void __invokeSent(); - virtual void __finished(const Ice::Exception&); - virtual void __processRetry(); -}; - -class ICE_API ProxyBatchOutgoingAsync : public BatchOutgoingAsync -{ -public: - - ProxyBatchOutgoingAsync(const Ice::ObjectPrx&, const std::string&, const CallbackBasePtr&, - const Ice::LocalObjectPtr&); - - void __invoke(); - - virtual Ice::ObjectPrx - getProxy() const - { - return _proxy; - } - -private: - - const Ice::ObjectPrx _proxy; }; -class ICE_API ConnectionBatchOutgoingAsync : public BatchOutgoingAsync -{ -public: - - ConnectionBatchOutgoingAsync(const Ice::ConnectionIPtr&, const Ice::CommunicatorPtr&, const InstancePtr&, - const std::string&, const CallbackBasePtr&, const Ice::LocalObjectPtr&); - - void __invoke(); - - virtual Ice::ConnectionPtr getConnection() const; - -private: - - const Ice::ConnectionIPtr _connection; -}; - -class ICE_API CommunicatorBatchOutgoingAsync : public Ice::AsyncResult -{ -public: - - CommunicatorBatchOutgoingAsync(const Ice::CommunicatorPtr&, const InstancePtr&, const std::string&, - const CallbackBasePtr&, const Ice::LocalObjectPtr&); - - void flushConnection(const Ice::ConnectionIPtr&); - void ready(); - - virtual void __processRetry(); - -private: - - void check(bool); - - int _useCount; -}; - -class ICE_API GetConnectionOutgoingAsync : public OutgoingAsyncMessageCallback, public Ice::AsyncResult +// +// Class for handling the proxy's begin_ice_flushBatchRequest request. +// +class ICE_API ProxyFlushBatch : public ProxyOutgoingAsyncBase { public: - GetConnectionOutgoingAsync(const Ice::ObjectPrx&, const std::string&, const CallbackBasePtr&, - const Ice::LocalObjectPtr&); + ProxyFlushBatch(const Ice::ObjectPrx&, const std::string&, const CallbackBasePtr&, const Ice::LocalObjectPtr&); - void __invoke(); + virtual bool sent(); - virtual Ice::ObjectPrx - getProxy() const - { - return _proxy; - } + virtual AsyncStatus send(const Ice::ConnectionIPtr&, bool, bool); + virtual AsyncStatus invokeCollocated(CollocatedRequestHandler*); - virtual AsyncStatus __send(const Ice::ConnectionIPtr&, bool, bool); - virtual AsyncStatus __invokeCollocated(CollocatedRequestHandler*); - virtual bool __sent(); - virtual void __invokeSent(); - virtual void __finished(const Ice::Exception&); - virtual void __processRetry(); + void invoke(); private: - void handleException(const Ice::Exception&); - - Ice::ObjectPrx _proxy; - RequestHandlerPtr _handler; - int _cnt; + virtual void handleRetryException(const RetryException&); + virtual int handleException(const Ice::Exception&); }; +typedef IceUtil::Handle<ProxyFlushBatch> ProxyFlushBatchPtr; // -// Base class for all callbacks. +// Class for handling the proxy's begin_ice_getConnection request. // -class ICE_API CallbackBase : public IceUtil::Shared +class ICE_API ProxyGetConnection : public ProxyOutgoingAsyncBase { public: - void checkCallback(bool, bool); + ProxyGetConnection(const Ice::ObjectPrx&, const std::string&, const CallbackBasePtr&, const Ice::LocalObjectPtr&); - virtual void completed(const ::Ice::AsyncResultPtr&) const = 0; - virtual CallbackBasePtr verify(const ::Ice::LocalObjectPtr&) = 0; - virtual void sent(const ::Ice::AsyncResultPtr&) const = 0; - virtual bool hasSentCallback() const = 0; -}; + virtual AsyncStatus send(const Ice::ConnectionIPtr&, bool, bool); + virtual AsyncStatus invokeCollocated(CollocatedRequestHandler*); -// -// Base class for generic callbacks. -// -class ICE_API GenericCallbackBase : virtual public CallbackBase -{ + void invoke(); }; +typedef IceUtil::Handle<ProxyGetConnection> ProxyGetConnectionPtr; // -// Generic callback template that requires the caller to down-cast the -// proxy and the cookie that are obtained from the AsyncResult. +// Class for handling Ice::Connection::begin_flushBatchRequests // -template<class T> -class AsyncCallback : public GenericCallbackBase +class ICE_API ConnectionFlushBatch : public OutgoingAsyncBase { public: - typedef T callback_type; - typedef IceUtil::Handle<T> TPtr; - - typedef void (T::*Callback)(const ::Ice::AsyncResultPtr&); - - AsyncCallback(const TPtr& instance, Callback cb, Callback sentcb = 0) : - _callback(instance), _completed(cb), _sent(sentcb) - { - checkCallback(instance, cb != 0); - } - - virtual void completed(const ::Ice::AsyncResultPtr& result) const - { - (_callback.get()->*_completed)(result); - } - - virtual CallbackBasePtr verify(const ::Ice::LocalObjectPtr&) - { - return this; // Nothing to do, the cookie is not type-safe. - } - - virtual void sent(const ::Ice::AsyncResultPtr& result) const - { - if(_sent) - { - (_callback.get()->*_sent)(result); - } - } + ConnectionFlushBatch(const Ice::ConnectionIPtr&, const Ice::CommunicatorPtr&, const InstancePtr&, + const std::string&, const CallbackBasePtr&, const Ice::LocalObjectPtr&); + + virtual Ice::ConnectionPtr getConnection() const; - virtual bool hasSentCallback() const - { - return _sent != 0; - } + void invoke(); private: - TPtr _callback; - Callback _completed; - Callback _sent; -}; - -#ifdef ICE_CPP11 - -template<typename T> struct callback_type -{ - static const int value = 1; -}; - -template<> struct callback_type<void(const ::Ice::AsyncResultPtr&)> -{ - static const int value = 2; -}; - -template<> struct callback_type<void(const ::Ice::Exception&)> -{ - static const int value = 3; -}; - -template<typename Callable, typename = void> struct callable_type -{ - static const int value = 1; -}; - -template<class Callable> struct callable_type<Callable, typename ::std::enable_if< - ::std::is_class<Callable>::value && - !::std::is_bind_expression<Callable>::value>::type> -{ - template<typename T, T> struct TypeCheck; - template<typename T> struct AsyncResultCallback - { - typedef void (T::*ok)(const ::Ice::AsyncResultPtr&) const; - }; - template<typename T> struct ExceptionCallback - { - typedef void (T::*ok)(const ::Ice::Exception&) const; - }; - - typedef char (&other)[1]; - typedef char (&asyncResult)[2]; - typedef char (&exception)[3]; - - template<typename T> static other check(...); - template<typename T> static asyncResult check(TypeCheck<typename AsyncResultCallback<T>::ok, &T::operator()>*); - template<typename T> static exception check(TypeCheck<typename ExceptionCallback<T>::ok, &T::operator()>*); - - enum { value = sizeof(check<Callable>(0)) }; -}; - -template<> struct callable_type<void(*)(const ::Ice::AsyncResultPtr&)> -{ - static const int value = 2; -}; - -template<> struct callable_type<void(*)(const ::Ice::Exception&)> -{ - static const int value = 3; -}; - -template<typename Callable, typename Callback> struct is_callable -{ - static const bool value = callable_type<Callable>::value == callback_type<Callback>::value; + const Ice::ConnectionIPtr _connection; }; +typedef IceUtil::Handle<ConnectionFlushBatch> ConnectionFlushBatchPtr; -template<class S> class Function : public std::function<S> +// +// Class for handling Ice::Communicator::begin_flushBatchRequests +// +class ICE_API CommunicatorFlushBatch : public Ice::AsyncResult { - public: - template<typename T> Function(T f, typename ::std::enable_if<is_callable<T, S>::value>::type* = 0) - : std::function<S>(f) - { - } - - Function() - { - } - - Function(::std::nullptr_t) : ::std::function<S>(nullptr) - { - } -}; - -#endif - -} - -namespace Ice -{ + CommunicatorFlushBatch(const Ice::CommunicatorPtr&, const InstancePtr&, const std::string&, + const CallbackBasePtr&, const Ice::LocalObjectPtr&); -typedef IceUtil::Handle< ::IceInternal::GenericCallbackBase> CallbackPtr; - -template<class T> CallbackPtr -newCallback(const IceUtil::Handle<T>& instance, - void (T::*cb)(const AsyncResultPtr&), - void (T::*sentcb)(const AsyncResultPtr&) = 0) -{ - return new ::IceInternal::AsyncCallback<T>(instance, cb, sentcb); -} + void flushConnection(const Ice::ConnectionIPtr&); + void ready(); -template<class T> CallbackPtr -newCallback(T* instance, - void (T::*cb)(const AsyncResultPtr&), - void (T::*sentcb)(const AsyncResultPtr&) = 0) -{ - return new ::IceInternal::AsyncCallback<T>(instance, cb, sentcb); -} +private: -#ifdef ICE_CPP11 + void check(bool); -ICE_API CallbackPtr -newCallback(const ::IceInternal::Function<void (const AsyncResultPtr&)>&, - const ::IceInternal::Function<void (const AsyncResultPtr&)>& = - ::IceInternal::Function<void (const AsyncResultPtr&)>()); -#endif + int _useCount; +}; -// -// Operation callbacks are specified in Proxy.h -// } #endif diff --git a/cpp/include/Ice/OutgoingAsyncF.h b/cpp/include/Ice/OutgoingAsyncF.h index 9675fa6c468..811a588e0b3 100644 --- a/cpp/include/Ice/OutgoingAsyncF.h +++ b/cpp/include/Ice/OutgoingAsyncF.h @@ -14,45 +14,24 @@ #include <Ice/Handle.h> -namespace Ice -{ - -class AsyncResult; -ICE_API IceUtil::Shared* upCast(::Ice::AsyncResult*); -typedef IceInternal::Handle<AsyncResult> AsyncResultPtr; - -} - namespace IceInternal { +class OutgoingAsyncBase; +ICE_API IceUtil::Shared* upCast(OutgoingAsyncBase*); +typedef IceInternal::Handle<OutgoingAsyncBase> OutgoingAsyncBasePtr; + class OutgoingAsync; ICE_API IceUtil::Shared* upCast(OutgoingAsync*); typedef IceInternal::Handle<OutgoingAsync> OutgoingAsyncPtr; -class OutgoingAsyncMessageCallback; -ICE_API IceUtil::Shared* upCast(OutgoingAsyncMessageCallback*); -typedef IceInternal::Handle<OutgoingAsyncMessageCallback> OutgoingAsyncMessageCallbackPtr; - -class BatchOutgoingAsync; -ICE_API IceUtil::Shared* upCast(BatchOutgoingAsync*); -typedef IceInternal::Handle<BatchOutgoingAsync> BatchOutgoingAsyncPtr; - -class ProxyBatchOutgoingAsync; -ICE_API IceUtil::Shared* upCast(ProxyBatchOutgoingAsync*); -typedef IceInternal::Handle<ProxyBatchOutgoingAsync> ProxyBatchOutgoingAsyncPtr; - -class ConnectionBatchOutgoingAsync; -ICE_API IceUtil::Shared* upCast(ConnectionBatchOutgoingAsync*); -typedef IceInternal::Handle<ConnectionBatchOutgoingAsync> ConnectionBatchOutgoingAsyncPtr; - -class CommunicatorBatchOutgoingAsync; -ICE_API IceUtil::Shared* upCast(CommunicatorBatchOutgoingAsync*); -typedef IceInternal::Handle<CommunicatorBatchOutgoingAsync> CommunicatorBatchOutgoingAsyncPtr; +class ProxyOutgoingAsyncBase; +ICE_API IceUtil::Shared* upCast(ProxyOutgoingAsyncBase*); +typedef IceInternal::Handle<ProxyOutgoingAsyncBase> ProxyOutgoingAsyncBasePtr; -class GetConnectionOutgoingAsync; -ICE_API IceUtil::Shared* upCast(GetConnectionOutgoingAsync*); -typedef IceInternal::Handle<GetConnectionOutgoingAsync> GetConnectionOutgoingAsyncPtr; +class CommunicatorFlushBatch; +ICE_API IceUtil::Shared* upCast(CommunicatorFlushBatch*); +typedef IceInternal::Handle<CommunicatorFlushBatch> CommunicatorFlushBatchPtr; } diff --git a/cpp/include/Ice/Proxy.h b/cpp/include/Ice/Proxy.h index 6bbd1c7ffe7..0600916d324 100644 --- a/cpp/include/Ice/Proxy.h +++ b/cpp/include/Ice/Proxy.h @@ -21,7 +21,7 @@ #include <Ice/ObjectF.h> #include <Ice/ObjectAdapterF.h> #include <Ice/ReferenceF.h> -#include <Ice/OutgoingAsync.h> +#include <Ice/AsyncResult.h> //#include <Ice/RouterF.h> // Can't include RouterF.h here, otherwise we have cyclic includes //#include <Ice/LocatorF.h> // Can't include RouterF.h here, otherwise we have cyclic includes #include <Ice/Current.h> @@ -1378,8 +1378,6 @@ public: } }; - - template<class T, typename CT> class TwowayCallback : public Callback<T, CT> { diff --git a/cpp/include/Ice/RequestHandlerF.h b/cpp/include/Ice/RequestHandlerF.h index 09013ba6fc8..3d63656edc5 100644 --- a/cpp/include/Ice/RequestHandlerF.h +++ b/cpp/include/Ice/RequestHandlerF.h @@ -20,6 +20,10 @@ class RequestHandler; ICE_API IceUtil::Shared* upCast(RequestHandler*); typedef IceInternal::Handle<RequestHandler> RequestHandlerPtr; +class CancellationHandler; +ICE_API IceUtil::Shared* upCast(CancellationHandler*); +typedef IceInternal::Handle<CancellationHandler> CancellationHandlerPtr; + } #endif diff --git a/cpp/src/Ice/AsyncResult.cpp b/cpp/src/Ice/AsyncResult.cpp new file mode 100644 index 00000000000..03abc55e020 --- /dev/null +++ b/cpp/src/Ice/AsyncResult.cpp @@ -0,0 +1,602 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/DisableWarnings.h> +#include <Ice/AsyncResult.h> +#include <Ice/ThreadPool.h> +#include <Ice/Instance.h> +#include <Ice/LoggerUtil.h> +#include <Ice/Properties.h> +#include <Ice/RequestHandler.h> +#include <Ice/OutgoingAsync.h> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +IceUtil::Shared* Ice::upCast(AsyncResult* p) { return p; } + +const unsigned char Ice::AsyncResult::OK = 0x1; +const unsigned char Ice::AsyncResult::Done = 0x2; +const unsigned char Ice::AsyncResult::Sent = 0x4; +const unsigned char Ice::AsyncResult::EndCalled = 0x8; + +void +AsyncResult::cancel() +{ + cancel(InvocationCanceledException(__FILE__, __LINE__)); +} + +Int +AsyncResult::getHash() const +{ + return static_cast<Int>(reinterpret_cast<Long>(this) >> 4); +} + +CommunicatorPtr +AsyncResult::getCommunicator() const +{ + return _communicator; +} + +ConnectionPtr +AsyncResult::getConnection() const +{ + return 0; +} + +ObjectPrx +AsyncResult::getProxy() const +{ + return 0; +} + +bool +AsyncResult::isCompleted() const +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + return _state & Done; +} + +void +AsyncResult::waitForCompleted() +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + while(!(_state & Done)) + { + _monitor.wait(); + } +} + +bool +AsyncResult::isSent() const +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + return _state & Sent; +} + +void +AsyncResult::waitForSent() +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + while(!(_state & Sent) && !_exception.get()) + { + _monitor.wait(); + } +} + +void +AsyncResult::throwLocalException() const +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_exception.get()) + { + _exception.get()->ice_throw(); + } +} + +bool +AsyncResult::sentSynchronously() const +{ + return _sentSynchronously; +} + +LocalObjectPtr +AsyncResult::getCookie() const +{ + return _cookie; +} + +const std::string& +AsyncResult::getOperation() const +{ + return _operation; +} + +void +AsyncResult::__throwUserException() +{ + try + { + _is.startReadEncaps(); + _is.throwException(); + } + catch(const Ice::UserException&) + { + _is.endReadEncaps(); + throw; + } +} + +bool +AsyncResult::__wait() +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_state & EndCalled) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "end_ method called more than once"); + } + _state |= EndCalled; + while(!(_state & Done)) + { + _monitor.wait(); + } + if(_exception.get()) + { + _exception.get()->ice_throw(); + } + return _state & OK; +} + +void +AsyncResult::__check(const AsyncResultPtr& r, const IceProxy::Ice::Object* prx, const string& operation) +{ + __check(r, operation); + if(r->getProxy().get() != prx) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Proxy for call to end_" + operation + + " does not match proxy that was used to call corresponding begin_" + + operation + " method"); + } +} + +void +AsyncResult::__check(const AsyncResultPtr& r, const Ice::Communicator* com, const string& operation) +{ + __check(r, operation); + if(r->getCommunicator().get() != com) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Communicator for call to end_" + operation + + " does not match communicator that was used to call corresponding " + + "begin_" + operation + " method"); + } +} + +void +AsyncResult::__check(const AsyncResultPtr& r, const Ice::Connection* con, const string& operation) +{ + __check(r, operation); + if(r->getConnection().get() != con) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Connection for call to end_" + operation + + " does not match connection that was used to call corresponding " + + "begin_" + operation + " method"); + } +} + +void +AsyncResult::__check(const AsyncResultPtr& r, const string& operation) +{ + if(!r) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "AsyncResult == null"); + } + else if(&r->_operation != &operation) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Incorrect operation for end_" + operation + + " method: " + r->_operation); + } +} + +AsyncResult::AsyncResult(const CommunicatorPtr& communicator, + const IceInternal::InstancePtr& instance, + const string& op, + const CallbackBasePtr& del, + const LocalObjectPtr& cookie) : + _instance(instance), + _sentSynchronously(false), + _is(instance.get(), Ice::currentProtocolEncoding), + _communicator(communicator), + _operation(op), + _callback(del), + _cookie(cookie), + _state(0) +{ + if(!_callback) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__); + } + const_cast<CallbackBasePtr&>(_callback) = _callback->verify(_cookie); +} + +AsyncResult::~AsyncResult() +{ +} + +bool +AsyncResult::sent(bool done) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + assert(!_exception.get()); + + bool alreadySent = _state & Sent; + _state |= Sent; + if(done) + { + _state |= Done | OK; + _cancellationHandler = 0; + if(!_callback || !_callback->hasSentCallback()) + { + _observer.detach(); + } + } + + _monitor.notifyAll(); + return !alreadySent && _callback && _callback->hasSentCallback(); +} + +bool +AsyncResult::finished(bool ok) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + _state |= Done; + if(ok) + { + _state |= OK; + } + _cancellationHandler = 0; + if(!_callback) + { + _observer.detach(); + } + _monitor.notifyAll(); + return _callback; +} + +bool +AsyncResult::finished(const Ice::Exception& ex) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + _state |= Done; + _exception.reset(ex.ice_clone()); + _cancellationHandler = 0; + _observer.failed(ex.ice_name()); + if(!_callback) + { + _observer.detach(); + } + _monitor.notifyAll(); + return _callback; +} + +void +AsyncResult::invokeSentAsync() +{ + class AsynchronousSent : public DispatchWorkItem + { + public: + + AsynchronousSent(const ConnectionPtr& connection, const AsyncResultPtr& result) : + DispatchWorkItem(connection), _result(result) + { + } + + virtual void + run() + { + _result->invokeSent(); + } + + private: + + const AsyncResultPtr _result; + }; + + // + // This is called when it's not safe to call the sent callback + // synchronously from this thread. Instead the exception callback + // is called asynchronously from the client thread pool. + // + try + { + _instance->clientThreadPool()->dispatch(new AsynchronousSent(_cachedConnection, this)); + } + catch(const Ice::CommunicatorDestroyedException&) + { + } +} + +void +AsyncResult::invokeCompletedAsync() +{ + class AsynchronousCompleted : public DispatchWorkItem + { + public: + + AsynchronousCompleted(const ConnectionPtr& connection, const AsyncResultPtr& result) : + DispatchWorkItem(connection), _result(result) + { + } + + virtual void + run() + { + _result->invokeCompleted(); + } + + private: + + const AsyncResultPtr _result; + }; + + // + // CommunicatorDestroyedCompleted is the only exception that can propagate directly + // from this method. + // + _instance->clientThreadPool()->dispatch(new AsynchronousCompleted(_cachedConnection, this)); +} + +void +AsyncResult::invokeSent() +{ + assert(_callback); + + try + { + AsyncResultPtr self(this); + _callback->sent(self); + } + catch(const std::exception& ex) + { + warning(ex); + } + catch(...) + { + warning(); + } + + if(_observer) + { + ObjectPrx proxy = getProxy(); + if(!proxy || !proxy->ice_isTwoway()) + { + _observer.detach(); + } + } +} + +void +AsyncResult::invokeCompleted() +{ + assert(_callback); + + try + { + AsyncResultPtr self(this); + _callback->completed(self); + } + catch(const std::exception& ex) + { + warning(ex); + } + catch(...) + { + warning(); + } + + _observer.detach(); +} + +void +AsyncResult::cancel(const Ice::LocalException& ex) +{ + { + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + _cancellationException.reset(ex.ice_clone()); + if(!_cancellationHandler) + { + return; + } + } + _cancellationHandler->asyncRequestCanceled(OutgoingAsyncBasePtr::dynamicCast(this), ex); +} + +void +AsyncResult::cancelable(const CancellationHandlerPtr& handler) +{ + { + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(!_cancellationException.get()) + { + _cancellationHandler = handler; + return; + } + } + handler->asyncRequestCanceled(OutgoingAsyncBasePtr::dynamicCast(this), *_cancellationException.get()); +} + +void +AsyncResult::checkCanceled() +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_cancellationException.get()) + { + _cancellationException->ice_throw(); + } +} + +void +AsyncResult::warning(const std::exception& exc) const +{ + if(_instance->initializationData().properties->getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + { + Warning out(_instance->initializationData().logger); + const Exception* ex = dynamic_cast<const Exception*>(&exc); + if(ex) + { + out << "Ice::Exception raised by AMI callback:\n" << *ex; + } + else + { + out << "std::exception raised by AMI callback:\n" << exc.what(); + } + } +} + +void +AsyncResult::warning() const +{ + if(_instance->initializationData().properties->getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + { + Warning out(_instance->initializationData().logger); + out << "unknown exception raised by AMI callback"; + } +} + + +namespace +{ + +// +// Dummy class derived from CallbackBase +// We use this class for the __dummyCallback extern pointer in OutgoingAsync. In turn, +// this allows us to test whether the user supplied a null delegate instance to the +// generated begin_ method without having to generate a separate test to throw IllegalArgumentException +// in the inlined versions of the begin_ method. In other words, this reduces the amount of generated +// object code. +// +class DummyCallback : public CallbackBase +{ +public: + + DummyCallback() + { + } + + virtual void + completed(const Ice::AsyncResultPtr&) const + { + assert(false); + } + + virtual CallbackBasePtr + verify(const Ice::LocalObjectPtr&) + { + // + // Called by the AsyncResult constructor to verify the delegate. The dummy + // delegate is passed when the user used a begin_ method without delegate. + // By returning 0 here, we tell the AsyncResult that no delegates was + // provided. + // + return 0; + } + + virtual void + sent(const AsyncResultPtr&) const + { + assert(false); + } + + virtual bool + hasSentCallback() const + { + assert(false); + return false; + } +}; + +} + +// +// This gives a pointer value to compare against in the generated +// begin_ method to decide whether the caller passed a null pointer +// versus the generated inline version of the begin_ method having +// passed a pointer to the dummy delegate. +// +CallbackBasePtr IceInternal::__dummyCallback = new DummyCallback; + +#ifdef ICE_CPP11 + +Ice::CallbackPtr +Ice::newCallback(const ::IceInternal::Function<void (const AsyncResultPtr&)>& completed, + const ::IceInternal::Function<void (const AsyncResultPtr&)>& sent) +{ + class Cpp11CB : public GenericCallbackBase + { + public: + + Cpp11CB(const ::std::function<void (const AsyncResultPtr&)>& completed, + const ::std::function<void (const AsyncResultPtr&)>& sent) : + _completed(completed), + _sent(sent) + { + checkCallback(true, completed != nullptr); + } + + virtual void + completed(const AsyncResultPtr& result) const + { + _completed(result); + } + + virtual CallbackBasePtr + verify(const LocalObjectPtr&) + { + return this; // Nothing to do, the cookie is not type-safe. + } + + virtual void + sent(const AsyncResultPtr& result) const + { + if(_sent != nullptr) + { + _sent(result); + } + } + + virtual bool + hasSentCallback() const + { + return _sent != nullptr; + } + + private: + + ::std::function< void (const AsyncResultPtr&)> _completed; + ::std::function< void (const AsyncResultPtr&)> _sent; + }; + + return new Cpp11CB(completed, sent); +} +#endif + +void +IceInternal::CallbackBase::checkCallback(bool obj, bool cb) +{ + if(!obj) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "callback object cannot be null"); + } + if(!cb) + { + throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "callback cannot be null"); + } +} + + diff --git a/cpp/src/Ice/CollocatedRequestHandler.cpp b/cpp/src/Ice/CollocatedRequestHandler.cpp index 0b08198726a..3fc321735cb 100644 --- a/cpp/src/Ice/CollocatedRequestHandler.cpp +++ b/cpp/src/Ice/CollocatedRequestHandler.cpp @@ -14,6 +14,8 @@ #include <Ice/Reference.h> #include <Ice/Instance.h> #include <Ice/TraceLevels.h> +#include <Ice/Outgoing.h> +#include <Ice/OutgoingAsync.h> #include <Ice/TraceUtil.h> @@ -28,7 +30,7 @@ class InvokeAll : public DispatchWorkItem { public: - InvokeAll(OutgoingMessageCallback* out, + InvokeAll(OutgoingBase* out, BasicStream* os, CollocatedRequestHandler* handler, Int requestId, @@ -49,7 +51,7 @@ public: private: - OutgoingMessageCallback* _out; + OutgoingBase* _out; BasicStream* _os; CollocatedRequestHandlerPtr _handler; Int _requestId; @@ -61,7 +63,7 @@ class InvokeAllAsync : public DispatchWorkItem { public: - InvokeAllAsync(const OutgoingAsyncMessageCallbackPtr& outAsync, + InvokeAllAsync(const OutgoingAsyncBasePtr& outAsync, BasicStream* os, CollocatedRequestHandler* handler, Int requestId, @@ -82,7 +84,7 @@ public: private: - OutgoingAsyncMessageCallbackPtr _outAsync; + OutgoingAsyncBasePtr _outAsync; BasicStream* _os; CollocatedRequestHandlerPtr _handler; Int _requestId; @@ -113,7 +115,7 @@ public: private: const CollocatedRequestHandlerPtr _handler; - const OutgoingAsyncMessageCallbackPtr _outAsync; + const OutgoingAsyncBasePtr _outAsync; BasicStream _stream; Int _invokeNum; }; @@ -261,24 +263,24 @@ CollocatedRequestHandler::abortBatchRequest() } bool -CollocatedRequestHandler::sendRequest(OutgoingMessageCallback* out) +CollocatedRequestHandler::sendRequest(OutgoingBase* out) { out->invokeCollocated(this); return !_response && _reference->getInvocationTimeout() == 0; } AsyncStatus -CollocatedRequestHandler::sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr& outAsync) +CollocatedRequestHandler::sendAsyncRequest(const OutgoingAsyncBasePtr& outAsync) { - return outAsync->__invokeCollocated(this); + return outAsync->invokeCollocated(this); } void -CollocatedRequestHandler::requestTimedOut(OutgoingMessageCallback* out) +CollocatedRequestHandler::requestCanceled(OutgoingBase* out, const LocalException& ex) { Lock sync(*this); - map<OutgoingMessageCallback*, Int>::iterator p = _sendRequests.find(out); + map<OutgoingBase*, Int>::iterator p = _sendRequests.find(out); if(p != _sendRequests.end()) { if(p->second > 0) @@ -286,7 +288,7 @@ CollocatedRequestHandler::requestTimedOut(OutgoingMessageCallback* out) _requests.erase(p->second); } InvocationTimeoutException ex(__FILE__, __LINE__); - out->finished(ex); + out->completed(ex); _sendRequests.erase(p); return; } @@ -299,7 +301,7 @@ CollocatedRequestHandler::requestTimedOut(OutgoingMessageCallback* out) if(q->second == o) { InvocationTimeoutException ex(__FILE__, __LINE__); - o->finished(ex); + o->completed(ex); _requests.erase(q); return; // We're done. } @@ -307,12 +309,12 @@ CollocatedRequestHandler::requestTimedOut(OutgoingMessageCallback* out) } } -void -CollocatedRequestHandler::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr& outAsync) +void +CollocatedRequestHandler::asyncRequestCanceled(const OutgoingAsyncBasePtr& outAsync, const LocalException& ex) { Lock sync(*this); - - map<OutgoingAsyncMessageCallbackPtr, Int>::iterator p = _sendAsyncRequests.find(outAsync); + + map<OutgoingAsyncBasePtr, Int>::iterator p = _sendAsyncRequests.find(outAsync); if(p != _sendAsyncRequests.end()) { if(p->second > 0) @@ -320,7 +322,10 @@ CollocatedRequestHandler::asyncRequestTimedOut(const OutgoingAsyncMessageCallbac _asyncRequests.erase(p->second); } _sendAsyncRequests.erase(p); - outAsync->__dispatchInvocationTimeout(_reference->getInstance()->clientThreadPool(), 0); + if(outAsync->completed(ex)) + { + outAsync->invokeCompletedAsync(); + } return; } @@ -332,7 +337,10 @@ CollocatedRequestHandler::asyncRequestTimedOut(const OutgoingAsyncMessageCallbac if(q->second.get() == o.get()) { _asyncRequests.erase(q); - outAsync->__dispatchInvocationTimeout(_reference->getInstance()->clientThreadPool(), 0); + if(outAsync->completed(ex)) + { + outAsync->invokeCompletedAsync(); + } return; } } @@ -391,16 +399,17 @@ CollocatedRequestHandler::invokeAsyncRequest(OutgoingAsync* outAsync) { _sendAsyncRequests.insert(make_pair(outAsync, requestId)); } + outAsync->cancelable(this); } - outAsync->__attachCollocatedObserver(_adapter, requestId); + outAsync->attachCollocatedObserver(_adapter, requestId); - _adapter->getThreadPool()->dispatch(new InvokeAllAsync(outAsync, outAsync->__getOs(), this, requestId, 1, false)); + _adapter->getThreadPool()->dispatch(new InvokeAllAsync(outAsync, outAsync->getOs(), this, requestId, 1, false)); return AsyncStatusQueued; } void -CollocatedRequestHandler::invokeBatchRequests(BatchOutgoing* out) +CollocatedRequestHandler::invokeBatchRequests(OutgoingBase* out) { Int invokeNum; { @@ -457,7 +466,7 @@ CollocatedRequestHandler::invokeBatchRequests(BatchOutgoing* out) } AsyncStatus -CollocatedRequestHandler::invokeAsyncBatchRequests(BatchOutgoingAsync* outAsync) +CollocatedRequestHandler::invokeAsyncBatchRequests(OutgoingAsyncBase* outAsync) { Int invokeNum; { @@ -473,10 +482,12 @@ CollocatedRequestHandler::invokeAsyncBatchRequests(BatchOutgoingAsync* outAsync) if(_reference->getInvocationTimeout() > 0) { _sendAsyncRequests.insert(make_pair(outAsync, 0)); + + outAsync->cancelable(this); } assert(!_batchStream.b.empty()); - _batchStream.swap(*outAsync->__getOs()); + _batchStream.swap(*outAsync->getOs()); // // Reset the batch stream. @@ -488,14 +499,14 @@ CollocatedRequestHandler::invokeAsyncBatchRequests(BatchOutgoingAsync* outAsync) } } - outAsync->__attachCollocatedObserver(_adapter, 0); + outAsync->attachCollocatedObserver(_adapter, 0); if(invokeNum > 0) { - _adapter->getThreadPool()->dispatch(new InvokeAllAsync(outAsync, outAsync->__getOs(), this, 0, invokeNum,true)); + _adapter->getThreadPool()->dispatch(new InvokeAllAsync(outAsync, outAsync->getOs(), this, 0, invokeNum,true)); return AsyncStatusQueued; } - else if(outAsync->__sent()) + else if(outAsync->sent()) { return static_cast<AsyncStatus>(AsyncStatusSent | AsyncStatusInvokeSentCallback); } @@ -512,7 +523,7 @@ CollocatedRequestHandler::sendResponse(Int requestId, BasicStream* os, Byte) { Lock sync(*this); assert(_response); - + os->i = os->b.begin() + sizeof(replyHdr) + 4; if(_traceLevels->protocol >= 1) @@ -524,7 +535,7 @@ CollocatedRequestHandler::sendResponse(Int requestId, BasicStream* os, Byte) map<int, Outgoing*>::iterator p = _requests.find(requestId); if(p != _requests.end()) { - p->second->finished(*os); + p->second->completed(*os); _requests.erase(p); } else @@ -532,17 +543,21 @@ CollocatedRequestHandler::sendResponse(Int requestId, BasicStream* os, Byte) map<int, OutgoingAsyncPtr>::iterator q = _asyncRequests.find(requestId); if(q != _asyncRequests.end()) { - os->swap(*q->second->__getIs()); - outAsync = q->second; + os->swap(*q->second->getIs()); + if(q->second->completed()) + { + outAsync = q->second; + } _asyncRequests.erase(q); } } } - if(outAsync && outAsync->__finished()) + if(outAsync) { - outAsync->__invokeCompleted(); + outAsync->invokeCompleted(); } + _adapter->decDirectCount(); } @@ -563,12 +578,7 @@ CollocatedRequestHandler::systemException(Int requestId, const SystemException& void CollocatedRequestHandler::invokeException(Int requestId, const LocalException& ex, int invokeNum) { - if(requestId > 0) - { - Lock sync(*this); - _requests.erase(requestId); - _asyncRequests.erase(requestId); - } + handleException(requestId, ex); _adapter->decDirectCount(); } @@ -585,7 +595,7 @@ CollocatedRequestHandler::waitForConnection() } bool -CollocatedRequestHandler::sent(OutgoingMessageCallback* out) +CollocatedRequestHandler::sent(OutgoingBase* out) { if(_reference->getInvocationTimeout() > 0) { @@ -600,7 +610,7 @@ CollocatedRequestHandler::sent(OutgoingMessageCallback* out) } bool -CollocatedRequestHandler::sentAsync(OutgoingAsyncMessageCallback* outAsync) +CollocatedRequestHandler::sentAsync(OutgoingAsyncBase* outAsync) { if(_reference->getInvocationTimeout() > 0) { @@ -610,9 +620,9 @@ CollocatedRequestHandler::sentAsync(OutgoingAsyncMessageCallback* outAsync) return false; // The request timed-out. } } - if(outAsync->__sent()) + if(outAsync->sent()) { - outAsync->__invokeSent(); + outAsync->invokeSent(); } return true; } @@ -684,7 +694,7 @@ CollocatedRequestHandler::handleException(int requestId, const Exception& ex) map<int, Outgoing*>::iterator p = _requests.find(requestId); if(p != _requests.end()) { - p->second->finished(ex); + p->second->completed(ex); _requests.erase(p); } else @@ -692,13 +702,17 @@ CollocatedRequestHandler::handleException(int requestId, const Exception& ex) map<int, OutgoingAsyncPtr>::iterator q = _asyncRequests.find(requestId); if(q != _asyncRequests.end()) { - outAsync = q->second; + if(q->second->completed(ex)) + { + outAsync = q->second; + } _asyncRequests.erase(q); } } } + if(outAsync) { - outAsync->__finished(ex); + outAsync->invokeCompleted(); } } diff --git a/cpp/src/Ice/CollocatedRequestHandler.h b/cpp/src/Ice/CollocatedRequestHandler.h index a3ac1387045..3930c12ce1c 100644 --- a/cpp/src/Ice/CollocatedRequestHandler.h +++ b/cpp/src/Ice/CollocatedRequestHandler.h @@ -31,10 +31,10 @@ typedef IceUtil::Handle<ObjectAdapterI> ObjectAdapterIPtr; namespace IceInternal { +class OutgoingBase; class Outgoing; -class BatchOutgoing; +class OutgoingAsyncBase; class OutgoingAsync; -class BatchOutgoingAsync; class CollocatedRequestHandler : public RequestHandler, public ResponseHandler, private IceUtil::Monitor<IceUtil::Mutex> { @@ -50,11 +50,11 @@ public: virtual void finishBatchRequest(BasicStream*); virtual void abortBatchRequest(); - virtual bool sendRequest(OutgoingMessageCallback*); - virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr&); + virtual bool sendRequest(OutgoingBase*); + virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncBasePtr&); - virtual void requestTimedOut(OutgoingMessageCallback*); - virtual void asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr&); + virtual void requestCanceled(OutgoingBase*, const Ice::LocalException&); + virtual void asyncRequestCanceled(const OutgoingAsyncBasePtr&, const Ice::LocalException&); virtual void sendResponse(Ice::Int, BasicStream*, Ice::Byte); virtual void sendNoResponse(); @@ -68,11 +68,11 @@ public: void invokeRequest(Outgoing*); AsyncStatus invokeAsyncRequest(OutgoingAsync*); - void invokeBatchRequests(BatchOutgoing*); - AsyncStatus invokeAsyncBatchRequests(BatchOutgoingAsync*); + void invokeBatchRequests(OutgoingBase*); + AsyncStatus invokeAsyncBatchRequests(OutgoingAsyncBase*); - bool sent(OutgoingMessageCallback*); - bool sentAsync(OutgoingAsyncMessageCallback*); + bool sent(OutgoingBase*); + bool sentAsync(OutgoingAsyncBase*); void invokeAll(BasicStream*, Ice::Int, Ice::Int, bool); @@ -88,8 +88,8 @@ private: int _requestId; - std::map<OutgoingMessageCallback*, Ice::Int> _sendRequests; - std::map<OutgoingAsyncMessageCallbackPtr, Ice::Int> _sendAsyncRequests; + std::map<OutgoingBase*, Ice::Int> _sendRequests; + std::map<OutgoingAsyncBasePtr, Ice::Int> _sendAsyncRequests; std::map<Ice::Int, Outgoing*> _requests; std::map<Ice::Int, OutgoingAsyncPtr> _asyncRequests; diff --git a/cpp/src/Ice/CommunicatorI.cpp b/cpp/src/Ice/CommunicatorI.cpp index 9b7ce8b8cd8..a7c2aee35d2 100644 --- a/cpp/src/Ice/CommunicatorI.cpp +++ b/cpp/src/Ice/CommunicatorI.cpp @@ -21,6 +21,7 @@ #include <Ice/DefaultsAndOverrides.h> #include <Ice/TraceLevels.h> #include <Ice/Router.h> +#include <Ice/OutgoingAsync.h> #include <IceUtil/Mutex.h> #include <IceUtil/MutexPtrLock.h> #include <IceUtil/UUID.h> @@ -198,8 +199,7 @@ Ice::CommunicatorI::getPluginManager() const void Ice::CommunicatorI::flushBatchRequests() { - AsyncResultPtr r = begin_flushBatchRequests(); - end_flushBatchRequests(r); + end_flushBatchRequests(begin_flushBatchRequests()); } AsyncResultPtr @@ -223,9 +223,8 @@ Ice::CommunicatorI::begin_flushBatchRequests(const Callback_Communicator_flushBa #ifdef ICE_CPP11 AsyncResultPtr -Ice::CommunicatorI::begin_flushBatchRequests( - const IceInternal::Function<void (const Exception&)>& exception, - const IceInternal::Function<void (bool)>& sent) +Ice::CommunicatorI::begin_flushBatchRequests(const IceInternal::Function<void (const Exception&)>& exception, + const IceInternal::Function<void (bool)>& sent) { class Cpp11CB : public IceInternal::Cpp11FnCallbackNC { @@ -268,8 +267,7 @@ const ::std::string __flushBatchRequests_name = "flushBatchRequests"; } AsyncResultPtr -Ice::CommunicatorI::__begin_flushBatchRequests(const IceInternal::CallbackBasePtr& cb, - const LocalObjectPtr& cookie) +Ice::CommunicatorI::__begin_flushBatchRequests(const IceInternal::CallbackBasePtr& cb, const LocalObjectPtr& cookie) { OutgoingConnectionFactoryPtr connectionFactory = _instance->outgoingConnectionFactory(); ObjectAdapterFactoryPtr adapterFactory = _instance->objectAdapterFactory(); @@ -278,8 +276,11 @@ Ice::CommunicatorI::__begin_flushBatchRequests(const IceInternal::CallbackBasePt // This callback object receives the results of all invocations // of Connection::begin_flushBatchRequests. // - CommunicatorBatchOutgoingAsyncPtr result = - new CommunicatorBatchOutgoingAsync(this, _instance, __flushBatchRequests_name, cb, cookie); + CommunicatorFlushBatchPtr result = new CommunicatorFlushBatch(this, + _instance, + __flushBatchRequests_name, + cb, + cookie); connectionFactory->flushAsyncBatchRequests(result); adapterFactory->flushAsyncBatchRequests(result); diff --git a/cpp/src/Ice/ConnectRequestHandler.cpp b/cpp/src/Ice/ConnectRequestHandler.cpp index 5a9a84c83b1..7d7f4a9291c 100644 --- a/cpp/src/Ice/ConnectRequestHandler.cpp +++ b/cpp/src/Ice/ConnectRequestHandler.cpp @@ -49,7 +49,7 @@ class FlushSentRequests : public DispatchWorkItem { public: - FlushSentRequests(const Ice::ConnectionPtr& connection, const vector<OutgoingAsyncMessageCallbackPtr>& callbacks) : + FlushSentRequests(const Ice::ConnectionPtr& connection, const vector<OutgoingAsyncBasePtr>& callbacks) : DispatchWorkItem(connection), _callbacks(callbacks) { } @@ -57,15 +57,15 @@ public: virtual void run() { - for(vector<OutgoingAsyncMessageCallbackPtr>::const_iterator p = _callbacks.begin(); p != _callbacks.end(); ++p) + for(vector<OutgoingAsyncBasePtr>::const_iterator p = _callbacks.begin(); p != _callbacks.end(); ++p) { - (*p)->__invokeSent(); + (*p)->invokeSent(); } } private: - vector<OutgoingAsyncMessageCallbackPtr> _callbacks; + vector<OutgoingAsyncBasePtr> _callbacks; }; }; @@ -202,7 +202,7 @@ ConnectRequestHandler::abortBatchRequest() } bool -ConnectRequestHandler::sendRequest(OutgoingMessageCallback* out) +ConnectRequestHandler::sendRequest(OutgoingBase* out) { { Lock sync(*this); @@ -225,7 +225,7 @@ ConnectRequestHandler::sendRequest(OutgoingMessageCallback* out) } AsyncStatus -ConnectRequestHandler::sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr& out) +ConnectRequestHandler::sendAsyncRequest(const OutgoingAsyncBasePtr& out) { { Lock sync(*this); @@ -236,6 +236,7 @@ ConnectRequestHandler::sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr& o Request req; req.outAsync = out; _requests.push_back(req); + out->cancelable(this); return AsyncStatusQueued; } } @@ -244,11 +245,11 @@ ConnectRequestHandler::sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr& o throw RetryException(ex); } } - return out->__send(_connection, _compress, _response); + return out->send(_connection, _compress, _response); } void -ConnectRequestHandler::requestTimedOut(OutgoingMessageCallback* out) +ConnectRequestHandler::requestCanceled(OutgoingBase* out, const Ice::LocalException& ex) { { Lock sync(*this); @@ -263,8 +264,7 @@ ConnectRequestHandler::requestTimedOut(OutgoingMessageCallback* out) { if(p->out == out) { - Ice::InvocationTimeoutException ex(__FILE__, __LINE__); - out->finished(ex); + out->completed(ex); _requests.erase(p); return; } @@ -272,11 +272,11 @@ ConnectRequestHandler::requestTimedOut(OutgoingMessageCallback* out) assert(false); // The request has to be queued if it timed out and we're not initialized yet. } } - _connection->requestTimedOut(out); + _connection->requestCanceled(out, ex); } void -ConnectRequestHandler::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr& outAsync) +ConnectRequestHandler::asyncRequestCanceled(const OutgoingAsyncBasePtr& outAsync, const Ice::LocalException& ex) { { Lock sync(*this); @@ -292,14 +292,16 @@ ConnectRequestHandler::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPt if(p->outAsync.get() == outAsync.get()) { _requests.erase(p); - outAsync->__dispatchInvocationTimeout(_reference->getInstance()->clientThreadPool(), 0); + if(outAsync->completed(ex)) + { + outAsync->invokeCompletedAsync(); + } return; } } - assert(false); // The request has to be queued if it timed out and we're not initialized yet. } } - _connection->asyncRequestTimedOut(outAsync); + _connection->asyncRequestCanceled(outAsync, ex); } Ice::ConnectionIPtr @@ -451,7 +453,7 @@ ConnectRequestHandler::flushRequests() _flushing = true; } - vector<OutgoingAsyncMessageCallbackPtr> sentCallbacks; + vector<OutgoingAsyncBasePtr> sentCallbacks; try { while(!_requests.empty()) // _requests is immutable when _flushing = true @@ -463,7 +465,7 @@ ConnectRequestHandler::flushRequests() } else if(req.outAsync) { - if(req.outAsync->__send(_connection, _compress, _response) & AsyncStatusInvokeSentCallback) + if(req.outAsync->send(_connection, _compress, _response) & AsyncStatusInvokeSentCallback) { sentCallbacks.push_back(req.outAsync); } @@ -551,11 +553,14 @@ ConnectRequestHandler::flushRequestsWithException() { if(p->out) { - p->out->finished(*_exception.get()); + p->out->completed(*_exception.get()); } else if(p->outAsync) { - p->outAsync->__finished(*_exception.get()); + if(p->outAsync->completed(*_exception.get())) + { + p->outAsync->invokeCompleted(); + } } else { diff --git a/cpp/src/Ice/ConnectRequestHandler.h b/cpp/src/Ice/ConnectRequestHandler.h index 095edda6123..c5bc6602766 100644 --- a/cpp/src/Ice/ConnectRequestHandler.h +++ b/cpp/src/Ice/ConnectRequestHandler.h @@ -42,11 +42,11 @@ public: virtual void finishBatchRequest(BasicStream*); virtual void abortBatchRequest(); - virtual bool sendRequest(OutgoingMessageCallback*); - virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr&); + virtual bool sendRequest(OutgoingBase*); + virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncBasePtr&); - virtual void requestTimedOut(OutgoingMessageCallback*); - virtual void asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr&); + virtual void requestCanceled(OutgoingBase*, const Ice::LocalException&); + virtual void asyncRequestCanceled(const OutgoingAsyncBasePtr&, const Ice::LocalException&); virtual Ice::ConnectionIPtr getConnection(); virtual Ice::ConnectionIPtr waitForConnection(); @@ -69,8 +69,8 @@ private: { } - OutgoingMessageCallback* out; - OutgoingAsyncMessageCallbackPtr outAsync; + OutgoingBase* out; + OutgoingAsyncBasePtr outAsync; BasicStream* os; }; diff --git a/cpp/src/Ice/ConnectionFactory.cpp b/cpp/src/Ice/ConnectionFactory.cpp index f859ac3fa58..f1fc0380727 100644 --- a/cpp/src/Ice/ConnectionFactory.cpp +++ b/cpp/src/Ice/ConnectionFactory.cpp @@ -24,6 +24,7 @@ #include <Ice/RouterInfo.h> #include <Ice/LocalException.h> #include <Ice/Functional.h> +#include <Ice/OutgoingAsync.h> #include <IceUtil/Random.h> #include <iterator> @@ -432,7 +433,7 @@ IceInternal::OutgoingConnectionFactory::removeAdapter(const ObjectAdapterPtr& ad } void -IceInternal::OutgoingConnectionFactory::flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr& outAsync) +IceInternal::OutgoingConnectionFactory::flushAsyncBatchRequests(const CommunicatorFlushBatchPtr& outAsync) { list<ConnectionIPtr> c; @@ -1357,7 +1358,7 @@ IceInternal::IncomingConnectionFactory::connections() const } void -IceInternal::IncomingConnectionFactory::flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr& outAsync) +IceInternal::IncomingConnectionFactory::flushAsyncBatchRequests(const CommunicatorFlushBatchPtr& outAsync) { list<ConnectionIPtr> c = connections(); // connections() is synchronized, so no need to synchronize here. diff --git a/cpp/src/Ice/ConnectionFactory.h b/cpp/src/Ice/ConnectionFactory.h index bd0bbe30804..92603a55b04 100644 --- a/cpp/src/Ice/ConnectionFactory.h +++ b/cpp/src/Ice/ConnectionFactory.h @@ -66,7 +66,7 @@ public: const CreateConnectionCallbackPtr&); void setRouterInfo(const RouterInfoPtr&); void removeAdapter(const Ice::ObjectAdapterPtr&); - void flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr&); + void flushAsyncBatchRequests(const CommunicatorFlushBatchPtr&); private: @@ -178,7 +178,7 @@ public: EndpointIPtr endpoint() const; std::list<Ice::ConnectionIPtr> connections() const; - void flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr&); + void flushAsyncBatchRequests(const CommunicatorFlushBatchPtr&); // // Operations from EventHandler diff --git a/cpp/src/Ice/ConnectionI.cpp b/cpp/src/Ice/ConnectionI.cpp index 1bdbeb12448..92dc4a1693d 100644 --- a/cpp/src/Ice/ConnectionI.cpp +++ b/cpp/src/Ice/ConnectionI.cpp @@ -242,7 +242,7 @@ Ice::ConnectionI::OutgoingMessage::adopt(BasicStream* str) } void -Ice::ConnectionI::OutgoingMessage::timedOut(bool adoptStream) +Ice::ConnectionI::OutgoingMessage::canceled(bool adoptStream) { assert((out || outAsync)); // Only requests can timeout. out = 0; @@ -253,7 +253,7 @@ Ice::ConnectionI::OutgoingMessage::timedOut(bool adoptStream) } else { - assert(!adopted && !stream); + assert(!adopted); } } @@ -273,25 +273,28 @@ Ice::ConnectionI::OutgoingMessage::sent() else if(outAsync) { #if defined(ICE_USE_IOCP) || defined(ICE_OS_WINRT) - invokeSent = outAsync->__sent(); + invokeSent = outAsync->sent(); return invokeSent || receivedReply; #else - return outAsync->__sent(); + return outAsync->sent(); #endif } return false; } void -Ice::ConnectionI::OutgoingMessage::finished(const Ice::LocalException& ex) +Ice::ConnectionI::OutgoingMessage::completed(const Ice::LocalException& ex) { if(out) { - out->finished(ex); + out->completed(ex); } else if(outAsync) { - outAsync->__finished(ex); + if(outAsync->completed(ex)) + { + outAsync->invokeCompleted(); + } } if(adopted) @@ -651,8 +654,7 @@ Ice::ConnectionI::sendRequest(Outgoing* out, bool compress, bool response) #endif } - out->attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, - static_cast<Int>(os->b.size() - headerSize - 4)); + out->attachRemoteObserver(initConnectionInfo(), _endpoint, requestId); // // Send the message. If it can't be sent without blocking the message is added @@ -685,7 +687,7 @@ Ice::ConnectionI::sendRequest(Outgoing* out, bool compress, bool response) AsyncStatus Ice::ConnectionI::sendAsyncRequest(const OutgoingAsyncPtr& out, bool compress, bool response) { - BasicStream* os = out->__getOs(); + BasicStream* os = out->getOs(); IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); if(_exception.get()) @@ -731,8 +733,7 @@ Ice::ConnectionI::sendAsyncRequest(const OutgoingAsyncPtr& out, bool compress, b #endif } - out->__attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, - static_cast<Int>(os->b.size() - headerSize - 4)); + out->attachRemoteObserver(initConnectionInfo(), _endpoint, requestId); AsyncStatus status = AsyncStatusQueued; try @@ -747,6 +748,11 @@ Ice::ConnectionI::sendAsyncRequest(const OutgoingAsyncPtr& out, bool compress, b _exception->ice_throw(); } + if(response || status & AsyncStatusQueued) + { + out->cancelable(this); // Notify the request that it's cancelable + } + if(response) { // @@ -961,7 +967,7 @@ Ice::ConnectionI::abortBatchRequest() void Ice::ConnectionI::flushBatchRequests() { - BatchOutgoing out(this, _instance.get(), __flushBatchRequests_name); + FlushBatch out(this, _instance.get(), __flushBatchRequests_name); out.invoke(); } @@ -986,9 +992,8 @@ Ice::ConnectionI::begin_flushBatchRequests(const Callback_Connection_flushBatchR #ifdef ICE_CPP11 AsyncResultPtr -Ice::ConnectionI::begin_flushBatchRequests( - const IceInternal::Function<void (const Exception&)>& exception, - const IceInternal::Function<void (bool)>& sent) +Ice::ConnectionI::begin_flushBatchRequests(const IceInternal::Function<void (const Exception&)>& exception, + const IceInternal::Function<void (bool)>& sent) { class Cpp11CB : public IceInternal::Cpp11FnCallbackNC @@ -1026,16 +1031,13 @@ Ice::ConnectionI::begin_flushBatchRequests( AsyncResultPtr Ice::ConnectionI::__begin_flushBatchRequests(const CallbackBasePtr& cb, const LocalObjectPtr& cookie) { - ConnectionBatchOutgoingAsyncPtr result = - new ConnectionBatchOutgoingAsync(this, _communicator, _instance, __flushBatchRequests_name, cb, cookie); - try - { - result->__invoke(); - } - catch(const LocalException& __ex) - { - result->__invokeExceptionAsync(__ex); - } + ConnectionFlushBatchPtr result = new ConnectionFlushBatch(this, + _communicator, + _instance, + __flushBatchRequests_name, + cb, + cookie); + result->invoke(); return result; } @@ -1047,7 +1049,7 @@ Ice::ConnectionI::end_flushBatchRequests(const AsyncResultPtr& r) } bool -Ice::ConnectionI::flushBatchRequests(BatchOutgoing* out) +Ice::ConnectionI::flushBatchRequests(OutgoingBase* out) { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); while(_batchStreamInUse && !_exception.get()) @@ -1075,12 +1077,10 @@ Ice::ConnectionI::flushBatchRequests(BatchOutgoing* out) #else copy(p, p + sizeof(Int), _batchStream.b.begin() + headerSize); #endif - - out->attachRemoteObserver(initConnectionInfo(), _endpoint, - static_cast<Int>(_batchStream.b.size() - headerSize - 4)); - _batchStream.swap(*out->os()); + out->attachRemoteObserver(initConnectionInfo(), _endpoint, 0); + // // Send the batch stream. // @@ -1109,7 +1109,7 @@ Ice::ConnectionI::flushBatchRequests(BatchOutgoing* out) } AsyncStatus -Ice::ConnectionI::flushAsyncBatchRequests(const BatchOutgoingAsyncPtr& outAsync) +Ice::ConnectionI::flushAsyncBatchRequests(const OutgoingAsyncBasePtr& outAsync) { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); while(_batchStreamInUse && !_exception.get()) @@ -1125,7 +1125,7 @@ Ice::ConnectionI::flushAsyncBatchRequests(const BatchOutgoingAsyncPtr& outAsync) if(_batchRequestNum == 0) { AsyncStatus status = AsyncStatusSent; - if(outAsync->__sent()) + if(outAsync->sent()) { status = static_cast<AsyncStatus>(status | AsyncStatusInvokeSentCallback); } @@ -1141,11 +1141,9 @@ Ice::ConnectionI::flushAsyncBatchRequests(const BatchOutgoingAsyncPtr& outAsync) #else copy(p, p + sizeof(Int), _batchStream.b.begin() + headerSize); #endif + _batchStream.swap(*outAsync->getOs()); - outAsync->__attachRemoteObserver(initConnectionInfo(), _endpoint, 0, - static_cast<Int>(_batchStream.b.size() - headerSize - 4)); - - _batchStream.swap(*outAsync->__getOs()); + outAsync->attachRemoteObserver(initConnectionInfo(), _endpoint, 0); // // Send the batch stream. @@ -1153,7 +1151,7 @@ Ice::ConnectionI::flushAsyncBatchRequests(const BatchOutgoingAsyncPtr& outAsync) AsyncStatus status = AsyncStatusQueued; try { - OutgoingMessage message(outAsync, outAsync->__getOs(), _batchRequestCompress, 0); + OutgoingMessage message(outAsync, outAsync->getOs(), _batchRequestCompress, 0); status = sendMessage(message); } catch(const Ice::LocalException& ex) @@ -1163,6 +1161,11 @@ Ice::ConnectionI::flushAsyncBatchRequests(const BatchOutgoingAsyncPtr& outAsync) _exception->ice_throw(); } + if(status & AsyncStatusQueued) + { + outAsync->cancelable(this); // Notify the request that it's cancelable. + } + // // Reset the batch stream. // @@ -1276,9 +1279,14 @@ Ice::ConnectionI::getACM() } void -Ice::ConnectionI::requestTimedOut(OutgoingMessageCallback* out) +Ice::ConnectionI::requestCanceled(OutgoingBase* out, const Ice::LocalException& ex) { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); + if(_state >= StateClosed) + { + return; // The request has already been or will be shortly notified of the failure. + } + for(deque<OutgoingMessage>::iterator o = _sendStreams.begin(); o != _sendStreams.end(); ++o) { if(o->out == out) @@ -1302,16 +1310,15 @@ Ice::ConnectionI::requestTimedOut(OutgoingMessageCallback* out) // if(o == _sendStreams.begin()) { - o->timedOut(true); // true = adopt the stream. + o->canceled(true); // true = adopt the stream. } else { - o->timedOut(false); + o->canceled(false); _sendStreams.erase(o); } - InvocationTimeoutException ex(__FILE__, __LINE__); - out->finished(ex); + out->completed(ex); return; } } @@ -1321,8 +1328,7 @@ Ice::ConnectionI::requestTimedOut(OutgoingMessageCallback* out) { if(_requestsHint != _requests.end() && _requestsHint->second == o) { - InvocationTimeoutException ex(__FILE__, __LINE__); - o->finished(ex); + o->completed(ex); _requests.erase(_requestsHint); _requestsHint = _requests.end(); } @@ -1332,8 +1338,7 @@ Ice::ConnectionI::requestTimedOut(OutgoingMessageCallback* out) { if(p->second == o) { - InvocationTimeoutException ex(__FILE__, __LINE__); - o->finished(ex); + o->completed(ex); assert(p != _requestsHint); _requests.erase(p); return; // We're done. @@ -1344,10 +1349,18 @@ Ice::ConnectionI::requestTimedOut(OutgoingMessageCallback* out) } void -Ice::ConnectionI::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr& outAsync) +Ice::ConnectionI::asyncRequestCanceled(const OutgoingAsyncBasePtr& outAsync, const LocalException& ex) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); + // + // NOTE: This isn't called from a thread pool thread. + // + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(*this); + if(_state >= StateClosed) + { + return; // The request has already been or will be shortly notified of the failure. + } + for(deque<OutgoingMessage>::iterator o = _sendStreams.begin(); o != _sendStreams.end(); ++o) { if(o->outAsync.get() == outAsync.get()) @@ -1365,25 +1378,29 @@ Ice::ConnectionI::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr& ou _asyncRequests.erase(o->requestId); } } - + // // If the request is being sent, don't remove it from the send streams, // it will be removed once the sending is finished. // if(o == _sendStreams.begin()) { - o->timedOut(true); // true = adopt the stream + o->canceled(true); // true = adopt the stream } else { - o->timedOut(false); + o->canceled(false); _sendStreams.erase(o); } - outAsync->__dispatchInvocationTimeout(_threadPool, this); - return; // We're done + if(outAsync->completed(ex)) + { + sync.release(); + outAsync->invokeCompleted(); + } + return; } } - + OutgoingAsyncPtr o = OutgoingAsyncPtr::dynamicCast(outAsync); if(o) { @@ -1393,19 +1410,25 @@ Ice::ConnectionI::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr& ou { _asyncRequests.erase(_asyncRequestsHint); _asyncRequestsHint = _asyncRequests.end(); - outAsync->__dispatchInvocationTimeout(_threadPool, this); - return; // We're done + if(outAsync->completed(ex)) + { + outAsync->invokeCompletedAsync(); + } + return; } } - + for(map<Int, OutgoingAsyncPtr>::iterator p = _asyncRequests.begin(); p != _asyncRequests.end(); ++p) { if(p->second.get() == o.get()) { assert(p != _asyncRequestsHint); _asyncRequests.erase(p); - outAsync->__dispatchInvocationTimeout(_threadPool, this); - return; // We're done + if(outAsync->completed(ex)) + { + outAsync->invokeCompletedAsync(); + } + return; } } } @@ -1972,18 +1995,18 @@ ConnectionI::dispatch(const StartCallbackPtr& startCB, const vector<OutgoingMess #if defined(ICE_USE_IOCP) || defined(ICE_OS_WINRT) if(p->invokeSent) { - p->outAsync->__invokeSent(); + p->outAsync->invokeSent(); } if(p->receivedReply) { OutgoingAsyncPtr outAsync = OutgoingAsyncPtr::dynamicCast(p->outAsync); - if(outAsync->__finished()) + if(outAsync->completed()) { - outAsync->__invokeCompleted(); + outAsync->invokeCompleted(); } } #else - p->outAsync->__invokeSent(); + p->outAsync->invokeSent(); #endif } ++dispatchedCount; @@ -1995,7 +2018,7 @@ ConnectionI::dispatch(const StartCallbackPtr& startCB, const vector<OutgoingMess // if(outAsync) { - outAsync->__invokeCompleted(); + outAsync->invokeCompleted(); ++dispatchedCount; } @@ -2147,14 +2170,14 @@ Ice::ConnectionI::finish() { if(message->sent() && message->invokeSent) { - message->outAsync->__invokeSent(); + message->outAsync->invokeSent(); } if(message->receivedReply) { OutgoingAsyncPtr outAsync = OutgoingAsyncPtr::dynamicCast(message->outAsync); - if(outAsync->__finished()) + if(outAsync->completed()) { - outAsync->__invokeCompleted(); + outAsync->invokeCompleted(); } } _sendStreams.pop_front(); @@ -2164,7 +2187,7 @@ Ice::ConnectionI::finish() for(deque<OutgoingMessage>::iterator o = _sendStreams.begin(); o != _sendStreams.end(); ++o) { - o->finished(*_exception.get()); + o->completed(*_exception.get()); if(o->requestId) // Make sure finished isn't called twice. { if(o->out) @@ -2182,13 +2205,16 @@ Ice::ConnectionI::finish() for(map<Int, Outgoing*>::const_iterator p = _requests.begin(); p != _requests.end(); ++p) { - p->second->finished(*_exception.get()); + p->second->completed(*_exception.get()); } _requests.clear(); for(map<Int, OutgoingAsyncPtr>::const_iterator q = _asyncRequests.begin(); q != _asyncRequests.end(); ++q) { - q->second->__finished(*_exception.get()); + if(q->second->completed(*_exception.get())) + { + q->second->invokeCompleted(); + } } _asyncRequests.clear(); @@ -3481,7 +3507,7 @@ Ice::ConnectionI::parseMessage(BasicStream& stream, Int& invokeNum, Int& request if(p != _requests.end()) { - p->second->finished(stream); + p->second->completed(stream); if(p == _requestsHint) { @@ -3508,7 +3534,7 @@ Ice::ConnectionI::parseMessage(BasicStream& stream, Int& invokeNum, Int& request _asyncRequests.erase(q); } - stream.swap(*outAsync->__getIs()); + stream.swap(*outAsync->getIs()); #if defined(ICE_USE_IOCP) || defined(ICE_OS_WINRT) // @@ -3522,7 +3548,7 @@ Ice::ConnectionI::parseMessage(BasicStream& stream, Int& invokeNum, Int& request message->receivedReply = true; outAsync = 0; } - else if(outAsync->__finished()) + else if(outAsync->completed()) { ++dispatchCount; } @@ -3531,7 +3557,7 @@ Ice::ConnectionI::parseMessage(BasicStream& stream, Int& invokeNum, Int& request outAsync = 0; } #else - if(outAsync->__finished()) + if(outAsync->completed()) { ++dispatchCount; } diff --git a/cpp/src/Ice/ConnectionI.h b/cpp/src/Ice/ConnectionI.h index 32c474d20da..3ecec79a247 100644 --- a/cpp/src/Ice/ConnectionI.h +++ b/cpp/src/Ice/ConnectionI.h @@ -30,6 +30,7 @@ #include <Ice/TraceLevelsF.h> #include <Ice/OutgoingAsyncF.h> #include <Ice/EventHandler.h> +#include <Ice/RequestHandler.h> #include <Ice/ResponseHandler.h> #include <Ice/Dispatcher.h> #include <Ice/ObserverHelper.h> @@ -43,8 +44,7 @@ namespace IceInternal { class Outgoing; -class BatchOutgoing; -class OutgoingMessageCallback; +class OutgoingBase; } @@ -56,6 +56,7 @@ class LocalException; class ConnectionI : public Connection, public IceInternal::EventHandler, public IceInternal::ResponseHandler, + public IceInternal::CancellationHandler, public IceUtil::Monitor<IceUtil::Mutex> { class Observer : public IceInternal::ObserverHelperT<Ice::Instrumentation::ConnectionObserver> @@ -89,7 +90,7 @@ public: { } - OutgoingMessage(IceInternal::OutgoingMessageCallback* o, IceInternal::BasicStream* str, bool comp, int rid) : + OutgoingMessage(IceInternal::OutgoingBase* o, IceInternal::BasicStream* str, bool comp, int rid) : stream(str), out(o), compress(comp), requestId(rid), adopted(false) #if defined(ICE_USE_IOCP) || defined(ICE_OS_WINRT) , isSent(false), invokeSent(false), receivedReply(false) @@ -97,7 +98,7 @@ public: { } - OutgoingMessage(const IceInternal::OutgoingAsyncMessageCallbackPtr& o, IceInternal::BasicStream* str, + OutgoingMessage(const IceInternal::OutgoingAsyncBasePtr& o, IceInternal::BasicStream* str, bool comp, int rid) : stream(str), out(0), outAsync(o), compress(comp), requestId(rid), adopted(false) #if defined(ICE_USE_IOCP) || defined(ICE_OS_WINRT) @@ -107,13 +108,13 @@ public: } void adopt(IceInternal::BasicStream*); - void timedOut(bool); + void canceled(bool); bool sent(); - void finished(const Ice::LocalException&); + void completed(const Ice::LocalException&); IceInternal::BasicStream* stream; - IceInternal::OutgoingMessageCallback* out; - IceInternal::OutgoingAsyncMessageCallbackPtr outAsync; + IceInternal::OutgoingBase* out; + IceInternal::OutgoingAsyncBasePtr outAsync; bool compress; int requestId; bool adopted; @@ -178,8 +179,8 @@ public: virtual void end_flushBatchRequests(const AsyncResultPtr&); - bool flushBatchRequests(IceInternal::BatchOutgoing*); - IceInternal::AsyncStatus flushAsyncBatchRequests(const IceInternal::BatchOutgoingAsyncPtr&); + bool flushBatchRequests(IceInternal::OutgoingBase*); + IceInternal::AsyncStatus flushAsyncBatchRequests(const IceInternal::OutgoingAsyncBasePtr&); virtual void setCallback(const ConnectionCallbackPtr&); virtual void setACM(const IceUtil::Optional<int>&, @@ -187,8 +188,8 @@ public: const IceUtil::Optional<ACMHeartbeat>&); virtual ACM getACM(); - void requestTimedOut(IceInternal::OutgoingMessageCallback*); - void asyncRequestTimedOut(const IceInternal::OutgoingAsyncMessageCallbackPtr&); + virtual void requestCanceled(IceInternal::OutgoingBase*, const LocalException&); + virtual void asyncRequestCanceled(const IceInternal::OutgoingAsyncBasePtr&, const LocalException&); virtual void sendResponse(Int, IceInternal::BasicStream*, Byte); virtual void sendNoResponse(); diff --git a/cpp/src/Ice/ConnectionRequestHandler.cpp b/cpp/src/Ice/ConnectionRequestHandler.cpp index 43dda1b88ed..a94d3e7180a 100644 --- a/cpp/src/Ice/ConnectionRequestHandler.cpp +++ b/cpp/src/Ice/ConnectionRequestHandler.cpp @@ -91,27 +91,27 @@ ConnectionRequestHandler::abortBatchRequest() } bool -ConnectionRequestHandler::sendRequest(OutgoingMessageCallback* out) +ConnectionRequestHandler::sendRequest(OutgoingBase* out) { return out->send(_connection, _compress, _response) && !_response; // Finished if sent and no response } AsyncStatus -ConnectionRequestHandler::sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr& out) +ConnectionRequestHandler::sendAsyncRequest(const OutgoingAsyncBasePtr& out) { - return out->__send(_connection, _compress, _response); + return out->send(_connection, _compress, _response); } void -ConnectionRequestHandler::requestTimedOut(OutgoingMessageCallback* out) +ConnectionRequestHandler::requestCanceled(OutgoingBase* out, const Ice::LocalException& ex) { - _connection->requestTimedOut(out); + _connection->requestCanceled(out, ex); } void -ConnectionRequestHandler::asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr& outAsync) +ConnectionRequestHandler::asyncRequestCanceled(const OutgoingAsyncBasePtr& outAsync, const Ice::LocalException& ex) { - _connection->asyncRequestTimedOut(outAsync); + _connection->asyncRequestCanceled(outAsync, ex); } Ice::ConnectionIPtr diff --git a/cpp/src/Ice/ConnectionRequestHandler.h b/cpp/src/Ice/ConnectionRequestHandler.h index 5ab5a4c9ea7..211e8f02819 100644 --- a/cpp/src/Ice/ConnectionRequestHandler.h +++ b/cpp/src/Ice/ConnectionRequestHandler.h @@ -31,11 +31,11 @@ public: virtual void finishBatchRequest(BasicStream*); virtual void abortBatchRequest(); - virtual bool sendRequest(OutgoingMessageCallback*); - virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr&); + virtual bool sendRequest(OutgoingBase*); + virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncBasePtr&); - virtual void requestTimedOut(OutgoingMessageCallback*); - virtual void asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr&); + virtual void requestCanceled(OutgoingBase*, const Ice::LocalException&); + virtual void asyncRequestCanceled(const OutgoingAsyncBasePtr&, const Ice::LocalException&); virtual Ice::ConnectionIPtr getConnection(); virtual Ice::ConnectionIPtr waitForConnection(); diff --git a/cpp/src/Ice/Exception.cpp b/cpp/src/Ice/Exception.cpp index a8bb8c6f81a..e5a3aed5b9f 100644 --- a/cpp/src/Ice/Exception.cpp +++ b/cpp/src/Ice/Exception.cpp @@ -502,6 +502,13 @@ Ice::InvocationTimeoutException::ice_print(ostream& out) const } void +Ice::InvocationCanceledException::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ":\ninvocation canceled"; +} + +void Ice::ProtocolException::ice_print(ostream& out) const { Exception::ice_print(out); diff --git a/cpp/src/Ice/Makefile b/cpp/src/Ice/Makefile index 1398ab5d07a..f44e0c977a8 100644 --- a/cpp/src/Ice/Makefile +++ b/cpp/src/Ice/Makefile @@ -57,6 +57,7 @@ SLICE_OBJS = BuiltinSequences.o \ OBJS = Acceptor.o \ ACM.o \ Application.o \ + AsyncResult.o \ Base64.o \ BasicStream.o \ Buffer.o \ diff --git a/cpp/src/Ice/Makefile.mak b/cpp/src/Ice/Makefile.mak index 75cf8c26a68..fcc4d3eb3e9 100644 --- a/cpp/src/Ice/Makefile.mak +++ b/cpp/src/Ice/Makefile.mak @@ -59,6 +59,7 @@ WINDOWS_OBJS = .\DLLMain.obj OBJS = .\Acceptor.obj \ .\ACM.obj \ .\Application.obj \ + .\AsyncResult.obj \ .\Base64.obj \ .\BasicStream.obj \ .\Buffer.obj \ diff --git a/cpp/src/Ice/ObjectAdapterFactory.cpp b/cpp/src/Ice/ObjectAdapterFactory.cpp index ca7938bcc55..35ca16ea03e 100644 --- a/cpp/src/Ice/ObjectAdapterFactory.cpp +++ b/cpp/src/Ice/ObjectAdapterFactory.cpp @@ -211,7 +211,7 @@ IceInternal::ObjectAdapterFactory::removeObjectAdapter(const ObjectAdapterPtr& a } void -IceInternal::ObjectAdapterFactory::flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr& outAsync) const +IceInternal::ObjectAdapterFactory::flushAsyncBatchRequests(const CommunicatorFlushBatchPtr& outAsync) const { list<ObjectAdapterIPtr> adapters; { diff --git a/cpp/src/Ice/ObjectAdapterFactory.h b/cpp/src/Ice/ObjectAdapterFactory.h index 7faa8ef73f4..37b3853497c 100644 --- a/cpp/src/Ice/ObjectAdapterFactory.h +++ b/cpp/src/Ice/ObjectAdapterFactory.h @@ -33,7 +33,7 @@ public: ::Ice::ObjectAdapterPtr createObjectAdapter(const std::string&, const Ice::RouterPrx&); ::Ice::ObjectAdapterPtr findObjectAdapter(const ::Ice::ObjectPrx&); void removeObjectAdapter(const ::Ice::ObjectAdapterPtr&); - void flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr&) const; + void flushAsyncBatchRequests(const CommunicatorFlushBatchPtr&) const; private: diff --git a/cpp/src/Ice/ObjectAdapterI.cpp b/cpp/src/Ice/ObjectAdapterI.cpp index 422cdb8fd01..c9a05c091ca 100644 --- a/cpp/src/Ice/ObjectAdapterI.cpp +++ b/cpp/src/Ice/ObjectAdapterI.cpp @@ -743,7 +743,7 @@ Ice::ObjectAdapterI::isLocal(const ObjectPrx& proxy) const } void -Ice::ObjectAdapterI::flushAsyncBatchRequests(const CommunicatorBatchOutgoingAsyncPtr& outAsync) +Ice::ObjectAdapterI::flushAsyncBatchRequests(const CommunicatorFlushBatchPtr& outAsync) { vector<IncomingConnectionFactoryPtr> f; { diff --git a/cpp/src/Ice/ObjectAdapterI.h b/cpp/src/Ice/ObjectAdapterI.h index 3897c0ef557..30f499d96c0 100644 --- a/cpp/src/Ice/ObjectAdapterI.h +++ b/cpp/src/Ice/ObjectAdapterI.h @@ -87,7 +87,7 @@ public: bool isLocal(const ObjectPrx&) const; - void flushAsyncBatchRequests(const IceInternal::CommunicatorBatchOutgoingAsyncPtr&); + void flushAsyncBatchRequests(const IceInternal::CommunicatorFlushBatchPtr&); void updateConnectionObservers(); void updateThreadObservers(); diff --git a/cpp/src/Ice/Outgoing.cpp b/cpp/src/Ice/Outgoing.cpp index 66509a2bedc..4815b9796fb 100644 --- a/cpp/src/Ice/Outgoing.cpp +++ b/cpp/src/Ice/Outgoing.cpp @@ -7,36 +7,44 @@ // // ********************************************************************** +#include <IceUtil/DisableWarnings.h> #include <Ice/Outgoing.h> -#include <Ice/Object.h> -#include <Ice/CollocatedRequestHandler.h> #include <Ice/ConnectionI.h> +#include <Ice/CollocatedRequestHandler.h> #include <Ice/Reference.h> -#include <Ice/Endpoint.h> -#include <Ice/LocalException.h> -#include <Ice/Protocol.h> #include <Ice/Instance.h> +#include <Ice/LocalException.h> #include <Ice/ReplyStatus.h> -#include <Ice/ProxyFactory.h> +#include <Ice/ImplicitContextI.h> using namespace std; using namespace Ice; using namespace Ice::Instrumentation; using namespace IceInternal; -IceInternal::Outgoing::Outgoing(IceProxy::Ice::Object* proxy, const string& operation, OperationMode mode, - const Context* context) : +OutgoingBase::OutgoingBase(Instance* instance, const string& operation) : + _os(instance, Ice::currentProtocolEncoding), _sent(false) +{ +} + +Outgoing::Outgoing(IceProxy::Ice::Object* proxy, const string& operation, OperationMode mode, const Context* context) : + OutgoingBase(proxy->__reference()->getInstance().get(), operation), _proxy(proxy), _mode(mode), - _observer(proxy, operation, context), _state(StateUnsent), _encoding(getCompatibleEncoding(proxy->__reference()->getEncoding())), - _is(proxy->__reference()->getInstance().get(), Ice::currentProtocolEncoding), - _os(proxy->__reference()->getInstance().get(), Ice::currentProtocolEncoding), - _sent(false) + _is(proxy->__reference()->getInstance().get(), Ice::currentProtocolEncoding) { checkSupportedProtocol(getCompatibleProtocol(proxy->__reference()->getProtocol())); + _observer.attach(proxy, operation, context); + + int invocationTimeout = _proxy->__reference()->getInvocationTimeout(); + if(invocationTimeout > 0) + { + _invocationTimeoutDeadline = IceUtil::Time::now() + IceUtil::Time::milliSeconds(invocationTimeout); + } + switch(_proxy->__reference()->getMode()) { case Reference::ModeTwoway: @@ -129,7 +137,66 @@ Outgoing::~Outgoing() } bool -IceInternal::Outgoing::invoke() +Outgoing::send(const Ice::ConnectionIPtr& connection, bool compress, bool response) +{ + return connection->sendRequest(this, compress, response); +} + +void +Outgoing::invokeCollocated(CollocatedRequestHandler* handler) +{ + handler->invokeRequest(this); +} + +void +Outgoing::sent() +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + if(_proxy->__reference()->getMode() != Reference::ModeTwoway) + { + _childObserver.detach(); + _state = StateOK; + } + _sent = true; + _monitor.notify(); + + // + // NOTE: At this point the stack allocated Outgoing object can be destroyed + // since the notify() on the monitor will release the thread waiting on the + // synchronous Ice call. + // +} + +void +Outgoing::completed(const Exception& ex) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); + //assert(_state <= StateInProgress); + if(_state > StateInProgress) + { + // + // Response was already received but message + // didn't get removed first from the connection + // send message queue so it's possible we can be + // notified of failures. In this case, ignore the + // failure and assume the outgoing has been sent. + // + assert(_state != StateFailed); + _sent = true; + _monitor.notify(); + return; + } + + _childObserver.failed(ex.ice_name()); + _childObserver.detach(); + + _state = StateFailed; + _exception.reset(ex.ice_clone()); + _monitor.notify(); +} + +bool +Outgoing::invoke() { assert(_state == StateUnsent); @@ -146,6 +213,11 @@ IceInternal::Outgoing::invoke() { try { + if(_invocationTimeoutDeadline != IceUtil::Time() && _invocationTimeoutDeadline <= IceUtil::Time::now()) + { + throw Ice::InvocationTimeoutException(__FILE__, __LINE__); + } + _state = StateInProgress; _exception.reset(0); _sent = false; @@ -164,19 +236,18 @@ IceInternal::Outgoing::invoke() // // If the handler says it's not finished, we wait until we're done. // - int invocationTimeout = _proxy->__reference()->getInvocationTimeout(); - if(invocationTimeout > 0) + if(_invocationTimeoutDeadline != IceUtil::Time()) { IceUtil::Time now = IceUtil::Time::now(); - IceUtil::Time deadline = now + IceUtil::Time::milliSeconds(invocationTimeout); + timedOut = now >= _invocationTimeoutDeadline; while((_state == StateInProgress || !_sent) && _state != StateFailed && !timedOut) { - _monitor.timedWait(deadline - now); + _monitor.timedWait(_invocationTimeoutDeadline - now); if((_state == StateInProgress || !_sent) && _state != StateFailed) { now = IceUtil::Time::now(); - timedOut = now >= deadline; + timedOut = now >= _invocationTimeoutDeadline; } } } @@ -191,15 +262,15 @@ IceInternal::Outgoing::invoke() if(timedOut) { - _handler->requestTimedOut(this); + _handler->requestCanceled(this, InvocationTimeoutException(__FILE__, __LINE__)); // // Wait for the exception to propagate. It's possible the request handler ignores - // the timeout if there was a failure shortly before requestTimedOut got called. + // the timeout if there was a failure shortly before requestCanceled got called. // In this case, the exception should be set on the Outgoing. // IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - while(!_exception.get()) + while(_state == StateInProgress) { _monitor.wait(); } @@ -223,11 +294,23 @@ IceInternal::Outgoing::invoke() { try { - int interval = _proxy->__handleException(ex, _handler, _mode, _sent, cnt); - _observer.retried(); // Invocation is being retried. - if(interval > 0) + IceUtil::Time interval; + interval = IceUtil::Time::milliSeconds(_proxy->__handleException(ex, _handler, _mode, _sent, cnt)); + if(interval > IceUtil::Time()) + { + if(_invocationTimeoutDeadline != IceUtil::Time()) + { + IceUtil::Time deadline = _invocationTimeoutDeadline - IceUtil::Time::now(); + if(deadline < interval) + { + interval = deadline; + } + } + IceUtil::ThreadControl::sleep(interval); + } + if(_invocationTimeoutDeadline == IceUtil::Time() || _invocationTimeoutDeadline > IceUtil::Time::now()) { - IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(interval)); + _observer.retried(); } } catch(const Ice::Exception& ex) @@ -243,7 +326,7 @@ IceInternal::Outgoing::invoke() } void -IceInternal::Outgoing::abort(const LocalException& ex) +Outgoing::abort(const LocalException& ex) { assert(_state == StateUnsent); @@ -261,67 +344,8 @@ IceInternal::Outgoing::abort(const LocalException& ex) ex.ice_throw(); } -bool -IceInternal::Outgoing::send(const Ice::ConnectionIPtr& connection, bool compress, bool response) -{ - return connection->sendRequest(this, compress, response); -} - -void -IceInternal::Outgoing::invokeCollocated(CollocatedRequestHandler* handler) -{ - handler->invokeRequest(this); -} - -void -IceInternal::Outgoing::sent() -{ - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - if(_proxy->__reference()->getMode() != Reference::ModeTwoway) - { - _childObserver.detach(); - _state = StateOK; - } - _sent = true; - _monitor.notify(); - - // - // NOTE: At this point the stack allocated Outgoing object can be destroyed - // since the notify() on the monitor will release the thread waiting on the - // synchronous Ice call. - // -} - void -IceInternal::Outgoing::finished(const Exception& ex) -{ - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - //assert(_state <= StateInProgress); - if(_state > StateInProgress) - { - // - // Response was already received but message - // didn't get removed first from the connection - // send message queue so it's possible we can be - // notified of failures. In this case, ignore the - // failure and assume the outgoing has been sent. - // - assert(_state != StateFailed); - _sent = true; - _monitor.notify(); - return; - } - - _childObserver.failed(ex.ice_name()); - _childObserver.detach(); - - _state = StateFailed; - _exception.reset(ex.ice_clone()); - _monitor.notify(); -} - -void -IceInternal::Outgoing::finished(BasicStream& is) +Outgoing::completed(BasicStream& is) { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); @@ -482,7 +506,7 @@ IceInternal::Outgoing::finished(BasicStream& is) } void -IceInternal::Outgoing::throwUserException() +Outgoing::throwUserException() { try { @@ -496,27 +520,22 @@ IceInternal::Outgoing::throwUserException() } } -IceInternal::BatchOutgoing::BatchOutgoing(IceProxy::Ice::Object* proxy, const string& name) : - _proxy(proxy), - _connection(0), - _sent(false), - _os(proxy->__reference()->getInstance().get(), Ice::currentProtocolEncoding), - _observer(proxy, name, 0) +FlushBatch::FlushBatch(IceProxy::Ice::Object* proxy, const string& operation) : + OutgoingBase(proxy->__reference()->getInstance().get(), operation), _proxy(proxy), _connection(0) { checkSupportedProtocol(proxy->__reference()->getProtocol()); + + _observer.attach(proxy->__reference()->getInstance().get(), operation); } -IceInternal::BatchOutgoing::BatchOutgoing(ConnectionI* connection, Instance* instance, const string& name) : - _proxy(0), - _connection(connection), - _sent(false), - _os(instance, Ice::currentProtocolEncoding), - _observer(instance, name) +FlushBatch::FlushBatch(ConnectionI* connection, Instance* instance, const string& operation) : + OutgoingBase(instance, operation), _proxy(0), _connection(connection) { + _observer.attach(instance, operation); } void -IceInternal::BatchOutgoing::invoke() +FlushBatch::invoke() { assert(_proxy || _connection); @@ -577,7 +596,8 @@ IceInternal::BatchOutgoing::invoke() if(timedOut) { - handler->requestTimedOut(this); + Ice::InvocationTimeoutException ex(__FILE__, __LINE__); + handler->requestCanceled(this, ex); // // Wait for the exception to propagate. It's possible the request handler ignores @@ -614,19 +634,19 @@ IceInternal::BatchOutgoing::invoke() } bool -IceInternal::BatchOutgoing::send(const Ice::ConnectionIPtr& connection, bool, bool) +FlushBatch::send(const Ice::ConnectionIPtr& connection, bool, bool) { return connection->flushBatchRequests(this); } void -IceInternal::BatchOutgoing::invokeCollocated(CollocatedRequestHandler* handler) +FlushBatch::invokeCollocated(CollocatedRequestHandler* handler) { handler->invokeBatchRequests(this); } void -IceInternal::BatchOutgoing::sent() +FlushBatch::sent() { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); _childObserver.detach(); @@ -635,14 +655,14 @@ IceInternal::BatchOutgoing::sent() _monitor.notify(); // - // NOTE: At this point the stack allocated BatchOutgoing object + // NOTE: At this point the stack allocated FlushBatch object // can be destroyed since the notify() on the monitor will release // the thread waiting on the synchronous Ice call. // } void -IceInternal::BatchOutgoing::finished(const Ice::Exception& ex) +FlushBatch::completed(const Ice::Exception& ex) { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); _childObserver.failed(ex.ice_name()); diff --git a/cpp/src/Ice/OutgoingAsync.cpp b/cpp/src/Ice/OutgoingAsync.cpp index fb57965b60f..b348b1c8cc8 100644 --- a/cpp/src/Ice/OutgoingAsync.cpp +++ b/cpp/src/Ice/OutgoingAsync.cpp @@ -9,18 +9,11 @@ #include <IceUtil/DisableWarnings.h> #include <Ice/OutgoingAsync.h> -#include <Ice/Object.h> #include <Ice/ConnectionI.h> #include <Ice/CollocatedRequestHandler.h> #include <Ice/Reference.h> #include <Ice/Instance.h> #include <Ice/LocalException.h> -#include <Ice/Properties.h> -#include <Ice/LoggerUtil.h> -#include <Ice/LocatorInfo.h> -#include <Ice/ProxyFactory.h> -#include <Ice/RouterInfo.h> -#include <Ice/Protocol.h> #include <Ice/ReplyStatus.h> #include <Ice/ImplicitContextI.h> #include <Ice/ThreadPool.h> @@ -30,431 +23,289 @@ using namespace std; using namespace Ice; using namespace IceInternal; -IceUtil::Shared* Ice::upCast(AsyncResult* p) { return p; } - -IceUtil::Shared* IceInternal::upCast(OutgoingAsyncMessageCallback* p) { return p; } +IceUtil::Shared* IceInternal::upCast(OutgoingAsyncBase* p) { return p; } +IceUtil::Shared* IceInternal::upCast(ProxyOutgoingAsyncBase* p) { return p; } IceUtil::Shared* IceInternal::upCast(OutgoingAsync* p) { return p; } -IceUtil::Shared* IceInternal::upCast(BatchOutgoingAsync* p) { return p; } -IceUtil::Shared* IceInternal::upCast(ProxyBatchOutgoingAsync* p) { return p; } -IceUtil::Shared* IceInternal::upCast(ConnectionBatchOutgoingAsync* p) { return p; } -IceUtil::Shared* IceInternal::upCast(CommunicatorBatchOutgoingAsync* p) { return p; } -IceUtil::Shared* IceInternal::upCast(GetConnectionOutgoingAsync* p) { return p; } - -const unsigned char Ice::AsyncResult::OK = 0x1; -const unsigned char Ice::AsyncResult::Done = 0x2; -const unsigned char Ice::AsyncResult::Sent = 0x4; -const unsigned char Ice::AsyncResult::EndCalled = 0x8; - -namespace -{ - -class AsynchronousException : public DispatchWorkItem -{ -public: - - AsynchronousException(const Ice::ConnectionPtr& connection, const Ice::AsyncResultPtr& result, - const Ice::Exception& ex) : - DispatchWorkItem(connection), _result(result), _exception(ex.ice_clone()) - { - } - - virtual void - run() - { - _result->__invokeException(*_exception.get()); - } - -private: - - const Ice::AsyncResultPtr _result; - const IceUtil::UniquePtr<Ice::Exception> _exception; -}; - -class AsynchronousSent : public DispatchWorkItem -{ -public: - - AsynchronousSent(const Ice::ConnectionPtr& connection, const Ice::AsyncResultPtr& result) : - DispatchWorkItem(connection), _result(result) - { - } - - virtual void - run() - { - _result->__invokeSent(); - } +IceUtil::Shared* IceInternal::upCast(CommunicatorFlushBatch* p) { return p; } -private: - - const Ice::AsyncResultPtr _result; -}; - -}; - -Ice::AsyncResult::AsyncResult(const CommunicatorPtr& communicator, - const IceInternal::InstancePtr& instance, - const string& op, - const CallbackBasePtr& del, - const LocalObjectPtr& cookie) : - _communicator(communicator), - _instance(instance), - _operation(op), - _callback(del), - _cookie(cookie), - _is(instance.get(), Ice::currentProtocolEncoding), - _os(instance.get(), Ice::currentProtocolEncoding), - _state(0), - _sentSynchronously(false), - _exception(0) +bool +OutgoingAsyncBase::sent() { - if(!_callback) - { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__); - } - const_cast<CallbackBasePtr&>(_callback) = _callback->verify(_cookie); + return sent(true); } -Ice::AsyncResult::~AsyncResult() +bool +OutgoingAsyncBase::completed(const Exception& ex) { + return finished(ex); } -Int -Ice::AsyncResult::getHash() const +OutgoingAsyncBase::OutgoingAsyncBase(const CommunicatorPtr& communicator, + const InstancePtr& instance, + const string& operation, + const CallbackBasePtr& delegate, + const LocalObjectPtr& cookie) : + AsyncResult(communicator, instance, operation, delegate, cookie), + _os(instance.get(), Ice::currentProtocolEncoding) { - return static_cast<Int>(reinterpret_cast<Long>(this) >> 4); } bool -Ice::AsyncResult::isCompleted() const +OutgoingAsyncBase::sent(bool done) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - return _state & Done; -} - -void -Ice::AsyncResult::waitForCompleted() -{ - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - while(!(_state & Done)) + if(done) { - _monitor.wait(); + _childObserver.detach(); } + return AsyncResult::sent(done); } bool -Ice::AsyncResult::isSent() const -{ - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - return _state & Sent; -} - -void -Ice::AsyncResult::waitForSent() +OutgoingAsyncBase::finished(const Exception& ex) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - while(!(_state & Sent) && !_exception.get()) + if(_childObserver) { - _monitor.wait(); + _childObserver.failed(ex.ice_name()); + _childObserver.detach(); } + return AsyncResult::finished(ex); } -void -Ice::AsyncResult::throwLocalException() const +Ice::ObjectPrx +ProxyOutgoingAsyncBase::getProxy() const { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - if(_exception.get()) - { - _exception.get()->ice_throw(); - } + return _proxy; } bool -Ice::AsyncResult::__wait() +ProxyOutgoingAsyncBase::sent() { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - if(_state & EndCalled) - { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "end_ method called more than once"); - } - _state |= EndCalled; - while(!(_state & Done)) - { - _monitor.wait(); - } - if(_exception.get()) - { - _exception.get()->ice_throw(); - } - return _state & OK; + return sent(!_proxy->ice_isTwoway()); // Done if it's not a two-way proxy (no response expected). } -void -Ice::AsyncResult::__throwUserException() +bool +ProxyOutgoingAsyncBase::completed(const Exception& exc) { - try - { - _is.startReadEncaps(); - _is.throwException(); - } - catch(const Ice::UserException&) + if(_childObserver) { - _is.endReadEncaps(); - throw; + _childObserver.failed(exc.ice_name()); + _childObserver.detach(); } -} -void -Ice::AsyncResult::__invokeSent() -{ // - // Note: no need to change the _state here, specializations are responsible for - // changing the state. + // NOTE: at this point, synchronization isn't needed, no other threads should be + // calling on the callback. // - - if(_callback) + try { - try - { - AsyncResultPtr self(this); - _callback->sent(self); - } - catch(const std::exception& ex) - { - __warning(ex); - } - catch(...) - { - __warning(); - } + _instance->retryQueue()->add(this, handleException(exc)); + return false; } - - if(_observer) + catch(const Exception& ex) { - Ice::ObjectPrx proxy = getProxy(); - if(!proxy || !proxy->ice_isTwoway()) - { - _observer.detach(); - } + return finished(ex); // No retries, we're done } } void -Ice::AsyncResult::__invokeSentAsync() +ProxyOutgoingAsyncBase::retry() { - // - // This is called when it's not safe to call the sent callback synchronously - // from this thread. Instead the exception callback is called asynchronously from - // the client thread pool. - // - try - { - _instance->clientThreadPool()->dispatch(new AsynchronousSent(_cachedConnection, this)); - } - catch(const Ice::CommunicatorDestroyedException&) - { - } + invokeImpl(false); } void -Ice::AsyncResult::__invokeException(const Ice::Exception& ex) +ProxyOutgoingAsyncBase::abort(const Ice::Exception& ex) { + assert(!_childObserver); + + if(finished(ex)) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - _state |= Done; - _os.resize(0); // Clear buffer now, instead of waiting for AsyncResult deallocation - _exception.reset(ex.ice_clone()); - _monitor.notifyAll(); + invokeCompletedAsync(); + } + else if(dynamic_cast<const Ice::CommunicatorDestroyedException*>(&ex)) + { + // + // If it's a communicator destroyed exception, don't swallow + // it but instead notify the user thread. Even if no callback + // was provided. + // + ex.ice_throw(); } - - __invokeCompleted(); } -void -Ice::AsyncResult::__invokeExceptionAsync(const Ice::Exception& ex) +ProxyOutgoingAsyncBase::ProxyOutgoingAsyncBase(const ObjectPrx& prx, + const string& operation, + const CallbackBasePtr& delegate, + const LocalObjectPtr& cookie) : + OutgoingAsyncBase(prx->ice_getCommunicator(), prx->__reference()->getInstance(), operation, delegate, cookie), + _proxy(prx), + _mode(Normal), + _cnt(0), + _sent(false) { - // - // This is called when it's not safe to call the exception callback synchronously - // from this thread. Instead the exception callback is called asynchronously from - // the client thread pool. - // - // CommunicatorDestroyedException is the only exception that can propagate directly - // from this method. - // - _instance->clientThreadPool()->dispatch(new AsynchronousException(_cachedConnection, this, ex)); } void -Ice::AsyncResult::__invokeCompleted() +ProxyOutgoingAsyncBase::invokeImpl(bool userThread) { - // - // Note: no need to change the _state here, specializations are responsible for - // changing the state. - // - - if(_callback) + try { - try + if(userThread) { - AsyncResultPtr self(this); - _callback->completed(self); + int invocationTimeout = _proxy->__reference()->getInvocationTimeout(); + if(invocationTimeout > 0) + { + _instance->timer()->schedule(this, IceUtil::Time::milliSeconds(invocationTimeout)); + } } - catch(const std::exception& ex) + else { - __warning(ex); + checkCanceled(); // Cancellation exception aren't retriable + _observer.retried(); } - catch(...) + + while(true) { - __warning(); + try + { + _sent = false; + _handler = _proxy->__getRequestHandler(); + AsyncStatus status = _handler->sendAsyncRequest(this); + if(status & AsyncStatusSent) + { + if(userThread) + { + _sentSynchronously = true; + if(status & AsyncStatusInvokeSentCallback) + { + invokeSent(); // Call the sent callback from the user thread. + } + } + else + { + if(status & AsyncStatusInvokeSentCallback) + { + invokeSentAsync(); // Call the sent callback from a client thread pool thread. + } + } + } + return; // We're done! + } + catch(const RetryException& ex) + { + handleRetryException(ex); + } + catch(const Exception& ex) + { + if(_childObserver) + { + _childObserver.failed(ex.ice_name()); + _childObserver.detach(); + } + int interval = handleException(ex); + if(interval > 0) + { + _instance->retryQueue()->add(this, interval); + return; + } + else + { + checkCanceled(); // Cancellation exception aren't retriable + _observer.retried(); + } + } } } - - _observer.detach(); -} - -void -Ice::AsyncResult::runTimerTask() // Implementation of TimerTask::runTimerTask() -{ - RequestHandlerPtr handler; + catch(const Exception& ex) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - swap(handler, _timeoutRequestHandler); - } - - if(handler) - { - handler->asyncRequestTimedOut(OutgoingAsyncMessageCallbackPtr::dynamicCast(this)); + // + // If called from the user thread we re-throw, the exception + // will be catch by the caller and abort() will be called. + // + if(userThread) + { + throw; + } + else if(finished(ex)) // No retries, we're done + { + invokeCompletedAsync(); + } } } - -void -Ice::AsyncResult::__check(const AsyncResultPtr& r, const IceProxy::Ice::Object* prx, const string& operation) +bool +ProxyOutgoingAsyncBase::sent(bool done) { - __check(r, operation); - if(r->getProxy().get() != prx) + _sent = true; + if(done) { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Proxy for call to end_" + operation + - " does not match proxy that was used to call corresponding begin_" + - operation + " method"); + if(_proxy->__reference()->getInvocationTimeout() > 0) + { + _instance->timer()->cancel(this); + } } + return OutgoingAsyncBase::sent(done); } -void -Ice::AsyncResult::__check(const AsyncResultPtr& r, const Ice::Communicator* com, const string& operation) +bool +ProxyOutgoingAsyncBase::finished(const Exception& ex) { - __check(r, operation); - if(r->getCommunicator().get() != com) + if(_proxy->__reference()->getInvocationTimeout() > 0) { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Communicator for call to end_" + operation + - " does not match communicator that was used to call corresponding " + - "begin_" + operation + " method"); + _instance->timer()->cancel(this); } + return OutgoingAsyncBase::finished(ex); } -void -Ice::AsyncResult::__check(const AsyncResultPtr& r, const Ice::Connection* con, const string& operation) +bool +ProxyOutgoingAsyncBase::finished(bool ok) { - __check(r, operation); - if(r->getConnection().get() != con) + if(_proxy->__reference()->getInvocationTimeout() > 0) { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Connection for call to end_" + operation + - " does not match connection that was used to call corresponding " + - "begin_" + operation + " method"); + _instance->timer()->cancel(this); } + return AsyncResult::finished(ok); } void -Ice::AsyncResult::__check(const AsyncResultPtr& r, const string& operation) +ProxyOutgoingAsyncBase::handleRetryException(const RetryException& exc) { - if(!r) - { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "AsyncResult == null"); - } - else if(&r->_operation != &operation) - { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Incorrect operation for end_" + operation + - " method: " + r->_operation); - } + _proxy->__setRequestHandler(_handler, 0); // Clear request handler and always retry. } - -void -Ice::AsyncResult::__warning(const std::exception& exc) const +int +ProxyOutgoingAsyncBase::handleException(const Exception& exc) { - if(_instance->initializationData().properties->getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) - { - Warning out(_instance->initializationData().logger); - const Exception* ex = dynamic_cast<const Exception*>(&exc); - if(ex) - { - out << "Ice::Exception raised by AMI callback:\n" << *ex; - } - else - { - out << "std::exception raised by AMI callback:\n" << exc.what(); - } - } + return _proxy->__handleException(exc, _handler, _mode, _sent, _cnt); } void -Ice::AsyncResult::__warning() const +ProxyOutgoingAsyncBase::runTimerTask() { - if(_instance->initializationData().properties->getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + try { - Warning out(_instance->initializationData().logger); - out << "unknown exception raised by AMI callback"; + cancel(InvocationTimeoutException(__FILE__, __LINE__)); } -} - -void -IceInternal::OutgoingAsyncMessageCallback::__dispatchInvocationTimeout(const ThreadPoolPtr& threadPool, - const Ice::ConnectionPtr& connection) -{ - class InvocationTimeoutCall : public DispatchWorkItem + catch(const CommunicatorDestroyedException&) { - public: - - InvocationTimeoutCall(const OutgoingAsyncMessageCallbackPtr& outAsync, const Ice::ConnectionPtr& connection) : - DispatchWorkItem(connection), _outAsync(outAsync) - { - } - - virtual void - run() - { - InvocationTimeoutException ex(__FILE__, __LINE__); - _outAsync->__finished(ex); - } - - private: - - const OutgoingAsyncMessageCallbackPtr _outAsync; - }; - threadPool->dispatch(new InvocationTimeoutCall(this, connection)); + } } -IceInternal::OutgoingAsync::OutgoingAsync(const ObjectPrx& prx, - const std::string& operation, - const CallbackBasePtr& delegate, - const Ice::LocalObjectPtr& cookie) : - AsyncResult(prx->ice_getCommunicator(), prx->__reference()->getInstance(), operation, delegate, cookie), - _proxy(prx), +OutgoingAsync::OutgoingAsync(const ObjectPrx& prx, + const string& operation, + const CallbackBasePtr& delegate, + const LocalObjectPtr& cookie) : + ProxyOutgoingAsyncBase(prx, operation, delegate, cookie), _encoding(getCompatibleEncoding(prx->__reference()->getEncoding())) { } void -IceInternal::OutgoingAsync::__prepare(const std::string& operation, OperationMode mode, const Context* context) +OutgoingAsync::prepare(const string& operation, OperationMode mode, const Context* context) { - _handler = 0; - _cnt = 0; - _sent = false; - _mode = mode; - _sentSynchronously = false; - checkSupportedProtocol(getCompatibleProtocol(_proxy->__reference()->getProtocol())); + _mode = mode; _observer.attach(_proxy.get(), operation, context); switch(_proxy->__reference()->getMode()) @@ -482,7 +333,7 @@ IceInternal::OutgoingAsync::__prepare(const std::string& operation, OperationMod { _proxy->__setRequestHandler(_handler, 0); // Clear request handler and retry. } - catch(const Ice::LocalException& ex) + catch(const LocalException& ex) { _observer.failed(ex.ice_name()); _proxy->__setRequestHandler(_handler, 0); // Clear request handler @@ -541,109 +392,63 @@ IceInternal::OutgoingAsync::__prepare(const std::string& operation, OperationMod } AsyncStatus -IceInternal::OutgoingAsync::__send(const Ice::ConnectionIPtr& connection, bool compress, bool response) +OutgoingAsync::send(const ConnectionIPtr& connection, bool compress, bool response) { _cachedConnection = connection; return connection->sendAsyncRequest(this, compress, response); } AsyncStatus -IceInternal::OutgoingAsync::__invokeCollocated(CollocatedRequestHandler* handler) +OutgoingAsync::invokeCollocated(CollocatedRequestHandler* handler) { return handler->invokeAsyncRequest(this); } -bool -IceInternal::OutgoingAsync::__sent() +void +OutgoingAsync::abort(const Exception& ex) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - - bool alreadySent = _state & Sent; // Expected in case of a retry. - _state |= Sent; - _sent = true; - - assert(!(_state & Done)); - if(!_proxy->ice_isTwoway()) + const Reference::Mode mode = _proxy->__reference()->getMode(); + if(mode == Reference::ModeBatchOneway || mode == Reference::ModeBatchDatagram) { - _childObserver.detach(); - if(!_callback || !_callback->hasSentCallback()) + if(_handler) { - _observer.detach(); - } - if(_timeoutRequestHandler) - { - _instance->timer()->cancel(this); - _timeoutRequestHandler = 0; + // + // If we didn't finish a batch oneway or datagram request, we + // must notify the connection about that we give up ownership + // of the batch stream. + // + _handler->abortBatchRequest(); } - _state |= Done | OK; - //_os.resize(0); // Don't clear the buffer now, it's needed for collocation optimization. } - _monitor.notifyAll(); - return !alreadySent && _callback && _callback->hasSentCallback(); -} - -void -IceInternal::OutgoingAsync::__invokeSent() -{ - ::Ice::AsyncResult::__invokeSent(); + + ProxyOutgoingAsyncBase::abort(ex); } void -IceInternal::OutgoingAsync::__finished(const Ice::Exception& exc) +OutgoingAsync::invoke() { + const Reference::Mode mode = _proxy->__reference()->getMode(); + if(mode == Reference::ModeBatchOneway || mode == Reference::ModeBatchDatagram) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - assert(!(_state & Done)); - _childObserver.failed(exc.ice_name()); - _childObserver.detach(); - if(_timeoutRequestHandler) + if(_handler) { - _instance->timer()->cancel(this); - _timeoutRequestHandler = 0; + _sentSynchronously = true; + _handler->finishBatchRequest(&_os); + finished(true); } + return; // Don't call sent/completed callback for batch AMI requests } // - // NOTE: at this point, synchronization isn't needed, no other threads should be - // calling on the callback. + // NOTE: invokeImpl doesn't throw so this can be called from the + // try block with the catch block calling abort() in case of an + // exception. // - try - { - handleException(exc); - } - catch(const Ice::Exception& ex) - { - __invokeException(ex); - } -} - -void -IceInternal::OutgoingAsync::__invokeExceptionAsync(const Ice::Exception& ex) -{ - if((_state & Done) == 0 && _handler) - { - // - // If we didn't finish a batch oneway or datagram request, we - // must notify the connection about that we give up ownership - // of the batch stream. - // - int mode = _proxy->__reference()->getMode(); - if(mode == Reference::ModeBatchOneway || mode == Reference::ModeBatchDatagram) - { - _handler->abortBatchRequest(); - } - } - AsyncResult::__invokeExceptionAsync(ex); -} - -void -IceInternal::OutgoingAsync::__processRetry() -{ - __invoke(false); + invokeImpl(true); // userThread = true } bool -IceInternal::OutgoingAsync::__finished() +OutgoingAsync::completed() { // // NOTE: this method is called from ConnectionI.parseMessage @@ -652,25 +457,15 @@ IceInternal::OutgoingAsync::__finished() // assert(_proxy->ice_isTwoway()); // Can only be called for twoways. - Ice::Byte replyStatus; - try + if(_childObserver) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - assert(!_exception.get() && !(_state & Done)); - assert(!_is.b.empty()); - - if(_childObserver) - { - _childObserver->reply(static_cast<Int>(_is.b.size() - headerSize - 4)); - } + _childObserver->reply(static_cast<Int>(_is.b.size() - headerSize - 4)); _childObserver.detach(); + } - if(_timeoutRequestHandler) - { - _instance->timer()->cancel(this); - _timeoutRequestHandler = 0; - } - + Byte replyStatus; + try + { _is.read(replyStatus); switch(replyStatus) @@ -789,373 +584,197 @@ IceInternal::OutgoingAsync::__finished() } } - _state |= Done; - _os.resize(0); // Clear buffer now, instead of waiting for AsyncResult deallocation - if(replyStatus == replyOK) - { - _state |= OK; - } - _monitor.notifyAll(); - - if(!_callback) - { - _observer.detach(); - return false; - } - return true; + return finished(replyStatus == replyOK); } - catch(const LocalException& exc) + catch(const Exception& ex) { - // - // We don't call finished(exc) here because we don't want - // to invoke the completion callback. The completion - // callback is invoked by the connection is this method - // returns true. - // - try - { - handleException(exc); - return false; // Invocation will be retried. - } - catch(const Ice::Exception& ex) - { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - _state |= Done; - _os.resize(0); // Clear buffer now, instead of waiting for AsyncResult deallocation - _exception.reset(ex.ice_clone()); - _monitor.notifyAll(); - - if(!_callback) - { - _observer.detach(); - return false; - } - return true; - } + return completed(ex); } } +ProxyFlushBatch::ProxyFlushBatch(const ObjectPrx& proxy, + const string& operation, + const CallbackBasePtr& delegate, + const LocalObjectPtr& cookie) : + ProxyOutgoingAsyncBase(proxy, operation, delegate, cookie) +{ + _observer.attach(proxy.get(), operation, 0); +} + bool -IceInternal::OutgoingAsync::__invoke(bool userThread) +ProxyFlushBatch::sent() { - const Reference::Mode mode = _proxy->__reference()->getMode(); - if(mode == Reference::ModeBatchOneway || mode == Reference::ModeBatchDatagram) - { - _state |= Done | OK; - _handler->finishBatchRequest(&_os); - _observer.detach(); - return true; - } + return ProxyOutgoingAsyncBase::sent(true); // Overriden because the flush is done even if using a two-way proxy. +} - while(true) - { - try - { - _sent = false; - _handler = _proxy->__getRequestHandler(); - AsyncStatus status = _handler->sendAsyncRequest(this); - if(status & AsyncStatusSent) - { - if(userThread) - { - _sentSynchronously = true; - if(status & AsyncStatusInvokeSentCallback) - { - __invokeSent(); // Call the sent callback from the user thread. - } - } - else - { - if(status & AsyncStatusInvokeSentCallback) - { - __invokeSentAsync(); // Call the sent callback from a client thread pool thread. - } - } - } +AsyncStatus +ProxyFlushBatch::send(const ConnectionIPtr& connection, bool, bool) +{ + _cachedConnection = connection; + return connection->flushAsyncBatchRequests(this); +} - if(mode == Reference::ModeTwoway || !(status & AsyncStatusSent)) - { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - if(!(_state & Done)) - { - int invocationTimeout = _handler->getReference()->getInvocationTimeout(); - if(invocationTimeout > 0) - { - _instance->timer()->schedule(this, IceUtil::Time::milliSeconds(invocationTimeout)); - _timeoutRequestHandler = _handler; - } - } - } - } - catch(const RetryException&) - { - _proxy->__setRequestHandler(_handler, 0); // Clear request handler and retry. - continue; - } - catch(const Ice::Exception& ex) - { - handleException(ex); - } - break; - } - return _sentSynchronously; +AsyncStatus +ProxyFlushBatch::invokeCollocated(CollocatedRequestHandler* handler) +{ + return handler->invokeAsyncBatchRequests(this); } void -IceInternal::OutgoingAsync::handleException(const Ice::Exception& exc) +ProxyFlushBatch::invoke() { - try - { - int interval = _proxy->__handleException(exc, _handler, _mode, _sent, _cnt); - _observer.retried(); // Invocation is being retried. - - // - // Schedule the retry. Note that we always schedule the retry - // on the retry queue even if the invocation can be retried - // immediately. This is required because it might not be safe - // to retry from this thread (this is for instance called by - // finished(BasicStream) which is called with the connection - // locked. - // - _instance->retryQueue()->add(this, interval); - } - catch(const Ice::Exception& ex) - { - _observer.failed(ex.ice_name()); - throw; - } + checkSupportedProtocol(getCompatibleProtocol(_proxy->__reference()->getProtocol())); + invokeImpl(true); // userThread = true } -IceInternal::BatchOutgoingAsync::BatchOutgoingAsync(const CommunicatorPtr& communicator, - const InstancePtr& instance, - const std::string& operation, - const CallbackBasePtr& delegate, - const Ice::LocalObjectPtr& cookie) : - AsyncResult(communicator, instance, operation, delegate, cookie) +void +ProxyFlushBatch::handleRetryException(const RetryException& ex) { + _proxy->__setRequestHandler(_handler, 0); // Clear request handler + ex.get()->ice_throw(); // No retries, we want to notify the user of potentially lost batch requests } -AsyncStatus -IceInternal::BatchOutgoingAsync::__send(const Ice::ConnectionIPtr& connection, bool, bool) +int +ProxyFlushBatch::handleException(const Exception& ex) { - _cachedConnection = connection; - return connection->flushAsyncBatchRequests(this); + _proxy->__setRequestHandler(_handler, 0); // Clear request handler + ex.ice_throw(); // No retries, we want to notify the user of potentially lost batch requests + return 0; } -AsyncStatus -IceInternal::BatchOutgoingAsync::__invokeCollocated(CollocatedRequestHandler* handler) +ProxyGetConnection::ProxyGetConnection(const ObjectPrx& prx, + const string& operation, + const CallbackBasePtr& delegate, + const LocalObjectPtr& cookie) : + ProxyOutgoingAsyncBase(prx, operation, delegate, cookie) { - return handler->invokeAsyncBatchRequests(this); + _observer.attach(prx.get(), operation, 0); } -bool -IceInternal::BatchOutgoingAsync::__sent() +AsyncStatus +ProxyGetConnection::send(const ConnectionIPtr& connection, bool, bool) { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - assert(!_exception.get()); - _state |= Done | OK | Sent; - //_os.resize(0); // Don't clear the buffer now, it's needed for collocation optimization. - _childObserver.detach(); - if(_timeoutRequestHandler) - { - _instance->timer()->cancel(this); - _timeoutRequestHandler = 0; - } - _monitor.notifyAll(); - if(!_callback || !_callback->hasSentCallback()) + _cachedConnection = connection; + if(finished(true)) { - _observer.detach(); - return false; + invokeCompletedAsync(); } - return true; + return AsyncStatusSent; } -void -IceInternal::BatchOutgoingAsync::__invokeSent() +AsyncStatus +ProxyGetConnection::invokeCollocated(CollocatedRequestHandler*) { - ::Ice::AsyncResult::__invokeSent(); + if(finished(true)) + { + invokeCompletedAsync(); + } + return AsyncStatusSent; } void -IceInternal::BatchOutgoingAsync::__finished(const Ice::Exception& exc) +ProxyGetConnection::invoke() { - { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - _childObserver.failed(exc.ice_name()); - _childObserver.detach(); - if(_timeoutRequestHandler) - { - _instance->timer()->cancel(this); - _timeoutRequestHandler = 0; - } - } - __invokeException(exc); + invokeImpl(true); // userThread = true } -void -IceInternal::BatchOutgoingAsync::__processRetry() +ConnectionFlushBatch::ConnectionFlushBatch(const ConnectionIPtr& connection, + const CommunicatorPtr& communicator, + const InstancePtr& instance, + const string& operation, + const CallbackBasePtr& delegate, + const LocalObjectPtr& cookie) : + OutgoingAsyncBase(communicator, instance, operation, delegate, cookie), _connection(connection) { - assert(false); // Retries are never scheduled + _observer.attach(instance.get(), operation); } -IceInternal::ProxyBatchOutgoingAsync::ProxyBatchOutgoingAsync(const Ice::ObjectPrx& proxy, - const std::string& operation, - const CallbackBasePtr& delegate, - const Ice::LocalObjectPtr& cookie) : - BatchOutgoingAsync(proxy->ice_getCommunicator(), proxy->__reference()->getInstance(), operation, delegate, cookie), - _proxy(proxy) +ConnectionPtr +ConnectionFlushBatch::getConnection() const { - _observer.attach(proxy.get(), operation, 0); + return _connection; } void -IceInternal::ProxyBatchOutgoingAsync::__invoke() +ConnectionFlushBatch::invoke() { - checkSupportedProtocol(_proxy->__reference()->getProtocol()); - - RequestHandlerPtr handler; try { - handler = _proxy->__getRequestHandler(); - AsyncStatus status = handler->sendAsyncRequest(this); + AsyncStatus status = _connection->flushAsyncBatchRequests(this); if(status & AsyncStatusSent) { _sentSynchronously = true; if(status & AsyncStatusInvokeSentCallback) { - __invokeSent(); - } - } - else - { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - if(!(_state & Done)) - { - int invocationTimeout = handler->getReference()->getInvocationTimeout(); - if(invocationTimeout > 0) - { - _instance->timer()->schedule(this, IceUtil::Time::milliSeconds(invocationTimeout)); - _timeoutRequestHandler = handler; - } + invokeSent(); } } } - catch(const RetryException&) - { - // - // Clear request handler but don't retry or throw. Retrying - // isn't useful, there were no batch requests associated with - // the proxy's request handler. - // - _proxy->__setRequestHandler(handler, 0); - } - catch(const Ice::Exception& ex) + catch(const Exception& ex) { - _observer.failed(ex.ice_name()); - _proxy->__setRequestHandler(handler, 0); // Clear request handler - throw; // Throw to notify the user that batch requests were potentially lost. - } -} - -IceInternal::ConnectionBatchOutgoingAsync::ConnectionBatchOutgoingAsync(const ConnectionIPtr& con, - const CommunicatorPtr& communicator, - const InstancePtr& instance, - const string& operation, - const CallbackBasePtr& delegate, - const Ice::LocalObjectPtr& cookie) : - BatchOutgoingAsync(communicator, instance, operation, delegate, cookie), - _connection(con) -{ - _observer.attach(instance.get(), operation); -} - -void -IceInternal::ConnectionBatchOutgoingAsync::__invoke() -{ - AsyncStatus status = _connection->flushAsyncBatchRequests(this); - if(status & AsyncStatusSent) - { - _sentSynchronously = true; - if(status & AsyncStatusInvokeSentCallback) + if(completed(ex)) { - __invokeSent(); + invokeCompletedAsync(); } } } -Ice::ConnectionPtr -IceInternal::ConnectionBatchOutgoingAsync::getConnection() const +CommunicatorFlushBatch::CommunicatorFlushBatch(const CommunicatorPtr& communicator, + const InstancePtr& instance, + const string& operation, + const CallbackBasePtr& cb, + const LocalObjectPtr& cookie) : + AsyncResult(communicator, instance, operation, cb, cookie) { - return _connection; -} + _observer.attach(instance.get(), operation); -IceInternal::CommunicatorBatchOutgoingAsync::CommunicatorBatchOutgoingAsync(const CommunicatorPtr& communicator, - const InstancePtr& instance, - const string& operation, - const CallbackBasePtr& delegate, - const Ice::LocalObjectPtr& cookie) : - AsyncResult(communicator, instance, operation, delegate, cookie) -{ // // _useCount is initialized to 1 to prevent premature callbacks. // The caller must invoke ready() after all flush requests have // been initiated. // _useCount = 1; - - // - // Assume all connections are flushed synchronously. - // - _sentSynchronously = true; - - // - // Attach observer - // - _observer.attach(instance.get(), operation); } void -IceInternal::CommunicatorBatchOutgoingAsync::flushConnection(const ConnectionIPtr& con) +CommunicatorFlushBatch::flushConnection(const ConnectionIPtr& con) { - class BatchOutgoingAsyncI : public BatchOutgoingAsync + class FlushBatch : public OutgoingAsyncBase { public: - - BatchOutgoingAsyncI(const CommunicatorBatchOutgoingAsyncPtr& outAsync, - const InstancePtr& instance, - InvocationObserver& observer) : - BatchOutgoingAsync(outAsync->getCommunicator(), instance, outAsync->getOperation(), __dummyCallback, 0), - _outAsync(outAsync), _observer(observer) + + FlushBatch(const CommunicatorFlushBatchPtr& outAsync, + const InstancePtr& instance, + InvocationObserver& observer) : + OutgoingAsyncBase(outAsync->getCommunicator(), instance, outAsync->getOperation(), __dummyCallback, 0), + _outAsync(outAsync), + _observer(observer) { } - virtual bool __sent() + virtual bool sent() { _childObserver.detach(); _outAsync->check(false); return false; } -#ifdef __SUNPRO_CC - using BatchOutgoingAsync::__sent; -#endif - - virtual void __finished(const Ice::Exception& ex) + virtual bool completed(const Exception& ex) { _childObserver.failed(ex.ice_name()); _childObserver.detach(); _outAsync->check(false); + return false; } - virtual void __attachRemoteObserver(const Ice::ConnectionInfoPtr& connection, const Ice::EndpointPtr& endpt, - Ice::Int requestId, Ice::Int sz) + private: + + virtual InvocationObserver& getObserver() { - _childObserver.attach(_observer.getRemoteObserver(connection, endpt, requestId, sz)); + return _observer; } - private: - - const CommunicatorBatchOutgoingAsyncPtr _outAsync; + const CommunicatorFlushBatchPtr _outAsync; InvocationObserver& _observer; }; @@ -1166,13 +785,9 @@ IceInternal::CommunicatorBatchOutgoingAsync::flushConnection(const ConnectionIPt try { - AsyncStatus status = con->flushAsyncBatchRequests(new BatchOutgoingAsyncI(this, _instance, _observer)); - if(!(status & AsyncStatusSent)) - { - _sentSynchronously = false; - } + con->flushAsyncBatchRequests(new FlushBatch(this, _instance, _observer)); } - catch(const Ice::LocalException&) + catch(const LocalException&) { check(false); throw; @@ -1180,19 +795,13 @@ IceInternal::CommunicatorBatchOutgoingAsync::flushConnection(const ConnectionIPt } void -IceInternal::CommunicatorBatchOutgoingAsync::ready() +CommunicatorFlushBatch::ready() { check(true); } void -IceInternal::CommunicatorBatchOutgoingAsync::__processRetry() -{ - assert(false); // Retries are never scheduled -} - -void -IceInternal::CommunicatorBatchOutgoingAsync::check(bool userThread) +CommunicatorFlushBatch::check(bool userThread) { { IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); @@ -1201,255 +810,18 @@ IceInternal::CommunicatorBatchOutgoingAsync::check(bool userThread) { return; } - _state |= Done | OK | Sent; - _os.resize(0); // Clear buffer now, instead of waiting for AsyncResult deallocation - _monitor.notifyAll(); } - if(!_callback || !_callback->hasSentCallback()) + if(sent(true)) { - _observer.detach(); - } - else - { - // - // _sentSynchronously is immutable here. - // - if(!_sentSynchronously || !userThread) + if(userThread) { - __invokeSentAsync(); + _sentSynchronously = true; + invokeSent(); } else { - AsyncResult::__invokeSent(); - } - } -} - -IceInternal::GetConnectionOutgoingAsync::GetConnectionOutgoingAsync(const Ice::ObjectPrx& prx, - const std::string& operation, - const CallbackBasePtr& delegate, - const Ice::LocalObjectPtr& cookie) : - AsyncResult(prx->ice_getCommunicator(), prx->__reference()->getInstance(), operation, delegate, cookie), - _proxy(prx), - _cnt(0) -{ - _observer.attach(prx.get(), operation, 0); -} - -void -IceInternal::GetConnectionOutgoingAsync::__invoke() -{ - while(true) - { - try - { - _handler = _proxy->__getRequestHandler(); - _handler->sendAsyncRequest(this); - } - catch(const RetryException&) - { - _proxy->__setRequestHandler(_handler, 0); - } - catch(const Ice::Exception& ex) - { - handleException(ex); + invokeSentAsync(); } - break; - } -} - -AsyncStatus -IceInternal::GetConnectionOutgoingAsync::__send(const Ice::ConnectionIPtr&, bool, bool) -{ - __sent(); - return AsyncStatusSent; -} - -AsyncStatus -IceInternal::GetConnectionOutgoingAsync::__invokeCollocated(CollocatedRequestHandler*) -{ - __sent(); - return AsyncStatusSent; -} - -bool -IceInternal::GetConnectionOutgoingAsync::__sent() -{ - { - IceUtil::Monitor<IceUtil::Mutex>::Lock sync(_monitor); - _state |= Done; - _monitor.notifyAll(); - } - __invokeCompleted(); - return false; -} - -void -IceInternal::GetConnectionOutgoingAsync::__invokeSent() -{ - // No sent callback -} - -void -IceInternal::GetConnectionOutgoingAsync::__finished(const Ice::Exception& exc) -{ - try - { - handleException(exc); - } - catch(const Ice::Exception& ex) - { - __invokeException(ex); - } -} - -void -IceInternal::GetConnectionOutgoingAsync::__processRetry() -{ - __invoke(); -} - -void -IceInternal::GetConnectionOutgoingAsync::handleException(const Ice::Exception& exc) -{ - try - { - _instance->retryQueue()->add(this, _proxy->__handleException(exc, _handler, Ice::Idempotent, false, _cnt)); - _observer.retried(); // Invocation is being retried. - } - catch(const Ice::Exception& ex) - { - _observer.failed(ex.ice_name()); - throw; - } -} - -namespace -{ - -// -// Dummy class derived from CallbackBase -// We use this class for the __dummyCallback extern pointer in OutgoingAsync. In turn, -// this allows us to test whether the user supplied a null delegate instance to the -// generated begin_ method without having to generate a separate test to throw IllegalArgumentException -// in the inlined versions of the begin_ method. In other words, this reduces the amount of generated -// object code. -// -class DummyCallback : public CallbackBase -{ -public: - - DummyCallback() - { - } - - virtual void - completed(const Ice::AsyncResultPtr&) const - { - assert(false); - } - - virtual CallbackBasePtr - verify(const Ice::LocalObjectPtr&) - { - // - // Called by the AsyncResult constructor to verify the delegate. The dummy - // delegate is passed when the user used a begin_ method without delegate. - // By returning 0 here, we tell the AsyncResult that no delegates was - // provided. - // - return 0; - } - - virtual void - sent(const AsyncResultPtr&) const - { - assert(false); - } - - virtual bool - hasSentCallback() const - { - assert(false); - return false; - } -}; - -} - -// -// This gives a pointer value to compare against in the generated -// begin_ method to decide whether the caller passed a null pointer -// versus the generated inline version of the begin_ method having -// passed a pointer to the dummy delegate. -// -CallbackBasePtr IceInternal::__dummyCallback = new DummyCallback; - -#ifdef ICE_CPP11 - -Ice::CallbackPtr -Ice::newCallback(const ::IceInternal::Function<void (const AsyncResultPtr&)>& completed, - const ::IceInternal::Function<void (const AsyncResultPtr&)>& sent) -{ - class Cpp11CB : public GenericCallbackBase - { - public: - - Cpp11CB(const ::std::function<void (const AsyncResultPtr&)>& completed, - const ::std::function<void (const AsyncResultPtr&)>& sent) : - _completed(completed), - _sent(sent) - { - checkCallback(true, completed != nullptr); - } - - virtual void - completed(const AsyncResultPtr& result) const - { - _completed(result); - } - - virtual CallbackBasePtr - verify(const LocalObjectPtr&) - { - return this; // Nothing to do, the cookie is not type-safe. - } - - virtual void - sent(const AsyncResultPtr& result) const - { - if(_sent != nullptr) - { - _sent(result); - } - } - - virtual bool - hasSentCallback() const - { - return _sent != nullptr; - } - - private: - - ::std::function< void (const AsyncResultPtr&)> _completed; - ::std::function< void (const AsyncResultPtr&)> _sent; - }; - - return new Cpp11CB(completed, sent); -} -#endif - -void -IceInternal::CallbackBase::checkCallback(bool obj, bool cb) -{ - if(!obj) - { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "callback object cannot be null"); - } - if(!cb) - { - throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "callback cannot be null"); } } diff --git a/cpp/src/Ice/Proxy.cpp b/cpp/src/Ice/Proxy.cpp index f455f5e6361..13bd0120a8f 100644 --- a/cpp/src/Ice/Proxy.cpp +++ b/cpp/src/Ice/Proxy.cpp @@ -217,15 +217,15 @@ IceProxy::Ice::Object::begin_ice_isA(const string& typeId, OutgoingAsyncPtr __result = new OutgoingAsync(this, ice_isA_name, del, cookie); try { - __result->__prepare(ice_isA_name, Nonmutating, ctx); - IceInternal::BasicStream* __os = __result->__startWriteParams(DefaultFormat); + __result->prepare(ice_isA_name, Nonmutating, ctx); + IceInternal::BasicStream* __os = __result->startWriteParams(DefaultFormat); __os->write(typeId); - __result->__endWriteParams(); - __result->__invoke(true); + __result->endWriteParams(); + __result->invoke(); } catch(const Exception& __ex) { - __result->__invokeExceptionAsync(__ex); + __result->abort(__ex); } return __result; } @@ -233,12 +233,11 @@ IceProxy::Ice::Object::begin_ice_isA(const string& typeId, #ifdef ICE_CPP11 Ice::AsyncResultPtr -IceProxy::Ice::Object::__begin_ice_isA( - const ::std::string& typeId, - const ::Ice::Context* ctx, - const ::IceInternal::Function<void (bool)>& response, - const ::IceInternal::Function<void (const ::Ice::Exception&)>& exception, - const ::IceInternal::Function<void (bool)>& sent) +IceProxy::Ice::Object::__begin_ice_isA(const ::std::string& typeId, + const ::Ice::Context* ctx, + const ::IceInternal::Function<void (bool)>& response, + const ::IceInternal::Function<void (const ::Ice::Exception&)>& exception, + const ::IceInternal::Function<void (bool)>& sent) { class Cpp11CB : public ::IceInternal::Cpp11FnCallbackNC { @@ -281,11 +280,10 @@ IceProxy::Ice::Object::__begin_ice_isA( } Ice::AsyncResultPtr -IceProxy::Ice::Object::__begin_ice_id( - const ::Ice::Context* ctx, - const ::IceInternal::Function<void (const ::std::string&)>& response, - const ::IceInternal::Function<void (const ::Ice::Exception&)>& exception, - const ::IceInternal::Function<void (bool)>& sent) +IceProxy::Ice::Object::__begin_ice_id(const ::Ice::Context* ctx, + const ::IceInternal::Function<void (const ::std::string&)>& response, + const ::IceInternal::Function<void (const ::Ice::Exception&)>& exception, + const ::IceInternal::Function<void (bool)>& sent) { class Cpp11CB : public ::IceInternal::Cpp11FnCallbackNC { @@ -573,13 +571,13 @@ IceProxy::Ice::Object::begin_ice_ping(const Context* ctx, OutgoingAsyncPtr __result = new OutgoingAsync(this, ice_ping_name, del, cookie); try { - __result->__prepare(ice_ping_name, Nonmutating, ctx); - __result->__writeEmptyParams(); - __result->__invoke(true); + __result->prepare(ice_ping_name, Nonmutating, ctx); + __result->writeEmptyParams(); + __result->invoke(); } catch(const Exception& __ex) { - __result->__invokeExceptionAsync(__ex); + __result->abort(__ex); } return __result; } @@ -647,13 +645,13 @@ IceProxy::Ice::Object::begin_ice_ids(const Context* ctx, OutgoingAsyncPtr __result = new OutgoingAsync(this, ice_ids_name, del, cookie); try { - __result->__prepare(ice_ids_name, Nonmutating, ctx); - __result->__writeEmptyParams(); - __result->__invoke(true); + __result->prepare(ice_ids_name, Nonmutating, ctx); + __result->writeEmptyParams(); + __result->invoke(); } catch(const Exception& __ex) { - __result->__invokeExceptionAsync(__ex); + __result->abort(__ex); } return __result; } @@ -690,13 +688,13 @@ IceProxy::Ice::Object::begin_ice_id(const Context* ctx, OutgoingAsyncPtr __result = new OutgoingAsync(this, ice_id_name, del, cookie); try { - __result->__prepare(ice_id_name, Nonmutating, ctx); - __result->__writeEmptyParams(); - __result->__invoke(true); + __result->prepare(ice_id_name, Nonmutating, ctx); + __result->writeEmptyParams(); + __result->invoke(); } catch(const Exception& __ex) { - __result->__invokeExceptionAsync(__ex); + __result->abort(__ex); } return __result; } @@ -818,13 +816,13 @@ IceProxy::Ice::Object::begin_ice_invoke(const string& operation, OutgoingAsyncPtr __result = new OutgoingAsync(this, ice_invoke_name, del, cookie); try { - __result->__prepare(operation, mode, ctx); - __result->__writeParamEncaps(inEncaps.first, static_cast<Int>(inEncaps.second - inEncaps.first)); - __result->__invoke(true); + __result->prepare(operation, mode, ctx); + __result->writeParamEncaps(inEncaps.first, static_cast<Int>(inEncaps.second - inEncaps.first)); + __result->invoke(); } catch(const Exception& __ex) { - __result->__invokeExceptionAsync(__ex); + __result->abort(__ex); } return __result; } @@ -1389,17 +1387,16 @@ AsyncResultPtr IceProxy::Ice::Object::begin_ice_getConnectionInternal(const ::IceInternal::CallbackBasePtr& del, const ::Ice::LocalObjectPtr& cookie) { - ::IceInternal::GetConnectionOutgoingAsyncPtr __result = - new ::IceInternal::GetConnectionOutgoingAsync(this, ice_getConnection_name, del, cookie); + ProxyGetConnectionPtr result = new ProxyGetConnection(this, ice_getConnection_name, del, cookie); try { - __result->__invoke(); + result->invoke(); } - catch(const Exception& __ex) + catch(const Exception& ex) { - __result->__invokeExceptionAsync(__ex); + result->abort(ex); } - return __result; + return result; } ConnectionPtr @@ -1435,32 +1432,31 @@ IceProxy::Ice::Object::ice_getCachedConnection() const void IceProxy::Ice::Object::ice_flushBatchRequests() { - BatchOutgoing __og(this, ice_flushBatchRequests_name); - __og.invoke(); + FlushBatch og(this, ice_flushBatchRequests_name); + og.invoke(); } ::Ice::AsyncResultPtr IceProxy::Ice::Object::begin_ice_flushBatchRequestsInternal(const ::IceInternal::CallbackBasePtr& del, const ::Ice::LocalObjectPtr& cookie) { - ::IceInternal::ProxyBatchOutgoingAsyncPtr __result = - new ::IceInternal::ProxyBatchOutgoingAsync(this, ice_flushBatchRequests_name, del, cookie); + ProxyFlushBatchPtr result = new ProxyFlushBatch(this, ice_flushBatchRequests_name, del, cookie); try { - __result->__invoke(); + result->invoke(); } - catch(const Exception& __ex) + catch(const Exception& ex) { - __result->__invokeExceptionAsync(__ex); + result->abort(ex); } - return __result; + return result; } void -IceProxy::Ice::Object::end_ice_flushBatchRequests(const AsyncResultPtr& __result) +IceProxy::Ice::Object::end_ice_flushBatchRequests(const AsyncResultPtr& result) { - AsyncResult::__check(__result, this, ice_flushBatchRequests_name); - __result->__wait(); + AsyncResult::__check(result, this, ice_flushBatchRequests_name); + result->__wait(); } Int diff --git a/cpp/src/Ice/ProxyFactory.cpp b/cpp/src/Ice/ProxyFactory.cpp index 68ca8b02598..fb2aea3e337 100644 --- a/cpp/src/Ice/ProxyFactory.cpp +++ b/cpp/src/Ice/ProxyFactory.cpp @@ -223,7 +223,7 @@ IceInternal::ProxyFactory::checkRetryAfterException(const LocalException& ex, co // // Don't retry invocation timeouts. // - if(dynamic_cast<const InvocationTimeoutException*>(&ex)) + if(dynamic_cast<const InvocationTimeoutException*>(&ex) || dynamic_cast<const InvocationCanceledException*>(&ex)) { ex.ice_throw(); } diff --git a/cpp/src/Ice/RequestHandler.cpp b/cpp/src/Ice/RequestHandler.cpp index 2cbf7826213..07ec753912d 100644 --- a/cpp/src/Ice/RequestHandler.cpp +++ b/cpp/src/Ice/RequestHandler.cpp @@ -14,6 +14,7 @@ using namespace std; using namespace IceInternal; IceUtil::Shared* IceInternal::upCast(RequestHandler* p) { return p; } +IceUtil::Shared* IceInternal::upCast(CancellationHandler* p) { return p; } RetryException::RetryException(const Ice::LocalException& ex) { @@ -32,10 +33,6 @@ RetryException::get() const return _ex.get(); } -RequestHandler::~RequestHandler() -{ -} - RequestHandler::RequestHandler(const ReferencePtr& reference) : _reference(reference), _response(reference->getMode() == Reference::ModeTwoway) diff --git a/cpp/src/Ice/RequestHandler.h b/cpp/src/Ice/RequestHandler.h index 73c3e818b56..68ff00d647d 100644 --- a/cpp/src/Ice/RequestHandler.h +++ b/cpp/src/Ice/RequestHandler.h @@ -31,7 +31,7 @@ namespace IceInternal class BasicStream; -class OutgoingMessageCallback; +class OutgoingBase; // // An exception wrapper, which is used to notify that the request @@ -51,11 +51,17 @@ private: IceUtil::UniquePtr<Ice::LocalException> _ex; }; -class RequestHandler : virtual public ::IceUtil::Shared +class CancellationHandler : virtual public IceUtil::Shared { public: - virtual ~RequestHandler(); + virtual void requestCanceled(OutgoingBase*, const Ice::LocalException&) = 0; + virtual void asyncRequestCanceled(const OutgoingAsyncBasePtr&, const Ice::LocalException&) = 0; +}; + +class RequestHandler : public CancellationHandler +{ +public: virtual RequestHandlerPtr connect() = 0; virtual RequestHandlerPtr update(const RequestHandlerPtr&, const RequestHandlerPtr&) = 0; @@ -64,11 +70,8 @@ public: virtual void finishBatchRequest(BasicStream*) = 0; virtual void abortBatchRequest() = 0; - virtual bool sendRequest(OutgoingMessageCallback*) = 0; - virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncMessageCallbackPtr&) = 0; - - virtual void requestTimedOut(OutgoingMessageCallback*) = 0; - virtual void asyncRequestTimedOut(const OutgoingAsyncMessageCallbackPtr&) = 0; + virtual bool sendRequest(OutgoingBase*) = 0; + virtual AsyncStatus sendAsyncRequest(const OutgoingAsyncBasePtr&) = 0; const ReferencePtr& getReference() const { return _reference; } // Inlined for performances. diff --git a/cpp/src/Ice/RetryQueue.cpp b/cpp/src/Ice/RetryQueue.cpp index adfb6bf9440..c70ed379edd 100644 --- a/cpp/src/Ice/RetryQueue.cpp +++ b/cpp/src/Ice/RetryQueue.cpp @@ -18,7 +18,7 @@ using namespace IceInternal; IceUtil::Shared* IceInternal::upCast(RetryQueue* p) { return p; } -IceInternal::RetryTask::RetryTask(const RetryQueuePtr& queue, const AsyncResultPtr& outAsync) : +IceInternal::RetryTask::RetryTask(const RetryQueuePtr& queue, const ProxyOutgoingAsyncBasePtr& outAsync) : _queue(queue), _outAsync(outAsync) { } @@ -26,14 +26,7 @@ IceInternal::RetryTask::RetryTask(const RetryQueuePtr& queue, const AsyncResultP void IceInternal::RetryTask::runTimerTask() { - try - { - _outAsync->__processRetry(); - } - catch(const Ice::LocalException& ex) - { - _outAsync->__invokeExceptionAsync(ex); - } + _outAsync->retry(); // Retry again the invocation. // // NOTE: this must be called last, destroy() blocks until all task @@ -44,10 +37,37 @@ IceInternal::RetryTask::runTimerTask() _queue->remove(this); } +void +IceInternal::RetryTask::requestCanceled(OutgoingBase*, const Ice::LocalException&) +{ + assert(false); +} + +void +IceInternal::RetryTask::asyncRequestCanceled(const OutgoingAsyncBasePtr& outAsync, const Ice::LocalException&) +{ + if(_queue->cancel(this)) + { + // + // We just retry the outgoing async now rather than marking it + // as finished. The retry will check for the cancellation + // exception and terminate appropriately the request. + // + _outAsync->retry(); + } +} + void IceInternal::RetryTask::destroy() { - _outAsync->__invokeExceptionAsync(CommunicatorDestroyedException(__FILE__, __LINE__)); + try + { + _outAsync->abort(CommunicatorDestroyedException(__FILE__, __LINE__)); + } + catch(const CommunicatorDestroyedException&) + { + // Abort shouldn't throw if there's no callback, ignore. + } } bool @@ -61,7 +81,7 @@ IceInternal::RetryQueue::RetryQueue(const InstancePtr& instance) : _instance(ins } void -IceInternal::RetryQueue::add(const AsyncResultPtr& out, int interval) +IceInternal::RetryQueue::add(const ProxyOutgoingAsyncBasePtr& out, int interval) { Lock sync(*this); if(!_instance) @@ -78,6 +98,7 @@ IceInternal::RetryQueue::add(const AsyncResultPtr& out, int interval) throw CommunicatorDestroyedException(__FILE__, __LINE__); } _requests.insert(task); + out->cancelable(task); } void @@ -119,4 +140,17 @@ IceInternal::RetryQueue::remove(const RetryTaskPtr& task) } } - +bool +IceInternal::RetryQueue::cancel(const RetryTaskPtr& task) +{ + Lock sync(*this); + if(_requests.erase(task) > 0) + { + if(!_instance && _requests.empty()) + { + notify(); // If we are destroying the queue, destroy is probably waiting on the queue to be empty. + } + return _instance->timer()->cancel(task); + } + return false; +} diff --git a/cpp/src/Ice/RetryQueue.h b/cpp/src/Ice/RetryQueue.h index 5a0b7cf52a2..71c9c946d8d 100644 --- a/cpp/src/Ice/RetryQueue.h +++ b/cpp/src/Ice/RetryQueue.h @@ -16,25 +16,31 @@ #include <Ice/RetryQueueF.h> #include <Ice/OutgoingAsyncF.h> #include <Ice/InstanceF.h> +#include <Ice/RequestHandler.h> // For CancellationHandler namespace IceInternal { -class RetryTask : public IceUtil::TimerTask +class RetryTask : public IceUtil::TimerTask, public CancellationHandler { public: - RetryTask(const RetryQueuePtr&, const Ice::AsyncResultPtr&); + RetryTask(const RetryQueuePtr&, const ProxyOutgoingAsyncBasePtr&); virtual void runTimerTask(); + + virtual void requestCanceled(OutgoingBase*, const Ice::LocalException&); + virtual void asyncRequestCanceled(const OutgoingAsyncBasePtr&, const Ice::LocalException&); + void destroy(); bool operator<(const RetryTask&) const; + private: const RetryQueuePtr _queue; - const Ice::AsyncResultPtr _outAsync; + const ProxyOutgoingAsyncBasePtr _outAsync; }; typedef IceUtil::Handle<RetryTask> RetryTaskPtr; @@ -44,12 +50,13 @@ public: RetryQueue(const InstancePtr&); - void add(const Ice::AsyncResultPtr&, int); + void add(const ProxyOutgoingAsyncBasePtr&, int); void destroy(); private: void remove(const RetryTaskPtr&); + bool cancel(const RetryTaskPtr&); friend class RetryTask; InstancePtr _instance; diff --git a/cpp/src/Ice/winrt/Makefile.mak b/cpp/src/Ice/winrt/Makefile.mak index 7eda814e8f6..c05ba0bc7e0 100644 --- a/cpp/src/Ice/winrt/Makefile.mak +++ b/cpp/src/Ice/winrt/Makefile.mak @@ -7,13 +7,14 @@ # # ********************************************************************** -top_srcdir = ..\..\.. +top_srcdir = ..\..\.. LIBNAME = $(SDK_LIBRARY_PATH)\ice.lib TARGETS = $(LIBNAME) SOURCE_DIR = .. OBJS = $(ARCH)\$(CONFIG)\Acceptor.obj \ $(ARCH)\$(CONFIG)\ACM.obj \ + $(ARCH)\$(CONFIG)\AsyncResult.obj \ $(ARCH)\$(CONFIG)\Base64.obj \ $(ARCH)\$(CONFIG)\Buffer.obj \ $(ARCH)\$(CONFIG)\BasicStream.obj \ diff --git a/cpp/src/IceDiscovery/LocatorI.h b/cpp/src/IceDiscovery/LocatorI.h index 700f4305129..bb48d8cb509 100644 --- a/cpp/src/IceDiscovery/LocatorI.h +++ b/cpp/src/IceDiscovery/LocatorI.h @@ -13,6 +13,8 @@ #include <Ice/Locator.h> #include <Ice/ProxyF.h> +#include <set> + namespace IceDiscovery { diff --git a/cpp/src/IceDiscovery/LookupI.h b/cpp/src/IceDiscovery/LookupI.h index 1a249b4e0da..58e1e7ca044 100644 --- a/cpp/src/IceDiscovery/LookupI.h +++ b/cpp/src/IceDiscovery/LookupI.h @@ -13,6 +13,7 @@ #include <IceDiscovery/IceDiscovery.h> #include <IceDiscovery/LocatorI.h> +#include <IceUtil/Timer.h> #include <Ice/Properties.h> namespace IceDiscovery diff --git a/cpp/src/IceGrid/AdapterCache.h b/cpp/src/IceGrid/AdapterCache.h index 8c37a623def..78258c2ff54 100644 --- a/cpp/src/IceGrid/AdapterCache.h +++ b/cpp/src/IceGrid/AdapterCache.h @@ -16,6 +16,8 @@ #include <IceGrid/Query.h> #include <IceGrid/Internal.h> +#include <set> + namespace IceGrid { diff --git a/cpp/src/slice2cpp/Gen.cpp b/cpp/src/slice2cpp/Gen.cpp index 5bf6c662656..57f3337c06f 100644 --- a/cpp/src/slice2cpp/Gen.cpp +++ b/cpp/src/slice2cpp/Gen.cpp @@ -373,8 +373,7 @@ Slice::Gen::generate(const UnitPtr& p) { H << "\n#include <Ice/Proxy.h>"; H << "\n#include <Ice/GCObject.h>"; - H << "\n#include <Ice/Outgoing.h>"; - H << "\n#include <Ice/OutgoingAsync.h>"; + H << "\n#include <Ice/AsyncResult.h>"; H << "\n#include <Ice/Incoming.h>"; if(p->hasContentsWithMetaData("amd")) { @@ -382,11 +381,14 @@ Slice::Gen::generate(const UnitPtr& p) } C << "\n#include <Ice/LocalException.h>"; C << "\n#include <Ice/ObjectFactory.h>"; + C << "\n#include <Ice/Outgoing.h>"; + C << "\n#include <Ice/OutgoingAsync.h>"; } else if(p->hasLocalClassDefsWithAsync()) { H << "\n#include <Ice/Proxy.h>"; - H << "\n#include <Ice/OutgoingAsync.h>"; + H << "\n#include <Ice/AsyncResult.h>"; + C << "\n#include <Ice/OutgoingAsync.h>"; } else if(p->hasNonLocalClassDecls()) { @@ -2184,26 +2186,26 @@ Slice::Gen::ProxyVisitor::visitOperation(const OperationPtr& p) C << flatName << ", __del, __cookie);"; C << nl << "try"; C << sb; - C << nl << "__result->__prepare(" << flatName << ", " << operationModeToString(p->sendMode()) << ", __ctx);"; + C << nl << "__result->prepare(" << flatName << ", " << operationModeToString(p->sendMode()) << ", __ctx);"; if(inParams.empty()) { - C << nl << "__result->__writeEmptyParams();"; + C << nl << "__result->writeEmptyParams();"; } else { - C << nl << "::IceInternal::BasicStream* __os = __result->__startWriteParams(" << opFormatTypeToString(p) <<");"; + C << nl << "::IceInternal::BasicStream* __os = __result->startWriteParams(" << opFormatTypeToString(p) <<");"; writeMarshalCode(C, inParams, 0, TypeContextInParam); if(p->sendsClasses(false)) { C << nl << "__os->writePendingObjects();"; } - C << nl << "__result->__endWriteParams();"; + C << nl << "__result->endWriteParams();"; } - C << nl << "__result->__invoke(true);"; + C << nl << "__result->invoke();"; C << eb; C << nl << "catch(const ::Ice::Exception& __ex)"; C << sb; - C << nl << "__result->__invokeExceptionAsync(__ex);"; + C << nl << "__result->abort(__ex);"; C << eb; C << nl << "return __result;"; C << eb; diff --git a/cpp/src/slice2cs/Gen.cpp b/cpp/src/slice2cs/Gen.cpp index b877d04ce69..8ba2d479750 100644 --- a/cpp/src/slice2cs/Gen.cpp +++ b/cpp/src/slice2cs/Gen.cpp @@ -5312,8 +5312,8 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) _out << sb; if(op->returnsData()) { - _out << nl << "IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)r__;"; - _out << nl << "IceInternal.OutgoingAsync.check(outAsync__, this, " << flatName << ");"; + _out << nl << "IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, " + << flatName << ");"; _out << nl << "try"; _out << sb; @@ -5480,11 +5480,11 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) _out << nl << "result__.writeEmptyParams();"; } - _out << nl << "result__.invoke(true);"; + _out << nl << "result__.invoke();"; _out << eb; _out << nl << "catch(Ice.Exception ex__)"; _out << sb; - _out << nl << "result__.invokeExceptionAsync(ex__);"; + _out << nl << "result__.abort(ex__);"; _out << eb; _out << nl << "return result__;"; _out << eb; diff --git a/cpp/src/slice2java/Gen.cpp b/cpp/src/slice2java/Gen.cpp index a288cfd8290..8eaccb5650e 100644 --- a/cpp/src/slice2java/Gen.cpp +++ b/cpp/src/slice2java/Gen.cpp @@ -4752,8 +4752,8 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) out << sb; if(op->returnsData()) { - out << nl << "IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase)__iresult;"; - out << nl << "IceInternal.OutgoingAsyncBase.check(__result, this, __" << op->name() << "_name);"; + out << nl << "IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __" + << op->name() << "_name);"; out << nl << "try"; out << sb; @@ -5737,11 +5737,11 @@ Slice::Gen::HelperVisitor::writeOperation(const ClassDefPtr& p, const string& pa out << nl << "__result.writeEmptyParams();"; } - out << nl << "__result.invoke(true);"; + out << nl << "__result.invoke();"; out << eb; out << nl << "catch(Ice.Exception __ex)"; out << sb; - out << nl << "__result.invokeExceptionAsync(__ex);"; + out << nl << "__result.abort(__ex);"; out << eb; out << nl << "return __result;"; out << eb; diff --git a/cpp/test/Ice/ami/AllTests.cpp b/cpp/test/Ice/ami/AllTests.cpp index c164220c2ae..406461975b7 100644 --- a/cpp/test/Ice/ami/AllTests.cpp +++ b/cpp/test/Ice/ami/AllTests.cpp @@ -1983,6 +1983,14 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated) test(r->isSent()); test(r->isCompleted()); test(p->waitForBatch(2)); + + // Ensure it also works with a twoway proxy + cb = new FlushCallback(); + r = p->ice_getConnection()->begin_flushBatchRequests( + Ice::newCallback(cb, &FlushCallback::completedAsync, &FlushCallback::sentAsync)); + cb->check(); + test(r->isSent()); + test(r->isCompleted()); } { @@ -2657,6 +2665,73 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated) communicator->end_flushBatchRequests(r); } } + + if(p->ice_getConnection()) + { + testController->holdAdapter(); + + Ice::AsyncResultPtr r; + Ice::ByteSeq seq; + seq.resize(1024); // Make sure the request doesn't compress too well. + for(Ice::ByteSeq::iterator q = seq.begin(); q != seq.end(); ++q) + { + *q = static_cast<Ice::Byte>(IceUtilInternal::random(255)); + } + while((r = p->begin_opWithPayload(seq))->sentSynchronously()); + + test(!r->isSent()); + + Ice::AsyncResultPtr r1 = p->begin_ice_ping(); + Ice::AsyncResultPtr r2 = p->begin_ice_id(); + r1->cancel(); + r2->cancel(); + try + { + p->end_ice_ping(r1); + test(false); + } + catch(const Ice::InvocationCanceledException&) + { + } + try + { + p->end_ice_id(r2); + test(false); + } + catch(const Ice::InvocationCanceledException&) + { + } + + testController->resumeAdapter(); + p->ice_ping(); + test(!r1->isSent() && r1->isCompleted()); + test(!r2->isSent() && r2->isCompleted()); + + testController->holdAdapter(); + r1 = p->begin_op(); + r2 = p->begin_ice_id(); + r1->waitForSent(); + r2->waitForSent(); + r1->cancel(); + r2->cancel(); + try + { + p->end_op(r1); + test(false); + } + catch(const Ice::InvocationCanceledException&) + { + } + try + { + p->end_ice_id(r2); + test(false); + } + catch(const Ice::InvocationCanceledException&) + { + } + testController->resumeAdapter(); + } } cout << "ok" << endl; diff --git a/cpp/test/Ice/retry/AllTests.cpp b/cpp/test/Ice/retry/AllTests.cpp index 8722e3aa32c..3df2727cfd3 100644 --- a/cpp/test/Ice/retry/AllTests.cpp +++ b/cpp/test/Ice/retry/AllTests.cpp @@ -112,7 +112,7 @@ allTests(const Ice::CommunicatorPtr& communicator) retry1->op(false); cout << "ok" << endl; - int invocationCount = 3; + testInvocationCount(3); cout << "calling operation to kill connection with second proxy... " << flush; try @@ -127,15 +127,15 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const Ice::ConnectionLostException&) { } - testInvocationCount(invocationCount + 1); + testInvocationCount(1); testFailureCount(1); testRetryCount(0); cout << "ok" << endl; cout << "calling regular operation with first proxy again... " << flush; retry1->op(false); - testInvocationCount(invocationCount + 2); - testFailureCount(1); + testInvocationCount(1); + testFailureCount(0); testRetryCount(0); cout << "ok" << endl; @@ -145,66 +145,66 @@ allTests(const Ice::CommunicatorPtr& communicator) cout << "calling regular AMI operation with first proxy... " << flush; retry1->begin_op(false, newCallback_Retry_op(cb1, &CallbackSuccess::response, &CallbackSuccess::exception)); cb1->check(); - testInvocationCount(invocationCount + 3); - testFailureCount(1); + testInvocationCount(1); + testFailureCount(0); testRetryCount(0); cout << "ok" << endl; cout << "calling AMI operation to kill connection with second proxy... " << flush; retry2->begin_op(true, newCallback_Retry_op(cb2, &CallbackFail::response, &CallbackFail::exception)); cb2->check(); - testInvocationCount(invocationCount + 4); - testFailureCount(2); + testInvocationCount(1); + testFailureCount(1); testRetryCount(0); cout << "ok" << endl; cout << "calling regular AMI operation with first proxy again... " << flush; retry1->begin_op(false, newCallback_Retry_op(cb1, &CallbackSuccess::response, &CallbackSuccess::exception)); cb1->check(); - testInvocationCount(invocationCount + 5); - testFailureCount(2); + testInvocationCount(1); + testFailureCount(0); testRetryCount(0); cout << "ok" << endl; cout << "testing idempotent operation... " << flush; - test(retry1->opIdempotent(0) == 4); - testInvocationCount(invocationCount + 6); - testFailureCount(2); + test(retry1->opIdempotent(4) == 4); + testInvocationCount(1); + testFailureCount(0); + testRetryCount(4); + test(retry1->end_opIdempotent(retry1->begin_opIdempotent(4)) == 4); + testInvocationCount(1); + testFailureCount(0); testRetryCount(4); - test(retry1->end_opIdempotent(retry1->begin_opIdempotent(4)) == 8); - testInvocationCount(invocationCount + 7); - testFailureCount(2); - testRetryCount(8); cout << "ok" << endl; cout << "testing non-idempotent operation... " << flush; try { - retry1->opNotIdempotent(8); + retry1->opNotIdempotent(); test(false); } catch(const Ice::LocalException&) { } - testInvocationCount(invocationCount + 8); - testFailureCount(3); - testRetryCount(8); + testInvocationCount(1); + testFailureCount(1); + testRetryCount(0); try { - retry1->end_opNotIdempotent(retry1->begin_opNotIdempotent(9)); + retry1->end_opNotIdempotent(retry1->begin_opNotIdempotent()); test(false); } catch(const Ice::LocalException&) { } - testInvocationCount(invocationCount + 9); - testFailureCount(4); - testRetryCount(8); + testInvocationCount(1); + testFailureCount(1); + testRetryCount(0); cout << "ok" << endl; if(!retry1->ice_getConnection()) { - invocationCount = invocationCount + 10; + testInvocationCount(-1); cout << "testing system exception... " << flush; try { @@ -214,9 +214,9 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const SystemFailure&) { } - test(invocationCount + 1); - testFailureCount(5); - testRetryCount(8); + testInvocationCount(1); + testFailureCount(1); + testRetryCount(0); try { retry1->end_opSystemException(retry1->begin_opSystemException()); @@ -225,11 +225,38 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const SystemFailure&) { } - testInvocationCount(invocationCount + 2); - testFailureCount(6); - testRetryCount(8); + testInvocationCount(1); + testFailureCount(1); + testRetryCount(0); cout << "ok" << endl; } + cout << "testing invocation timeout and retries... " << flush; + try + { + retry1->ice_invocationTimeout(50)->opIdempotent(4); // No more than 2 retries before timeout kicks-in + test(false); + } + catch(const Ice::InvocationTimeoutException&) + { + testRetryCount(2); + retry1->opIdempotent(-1); // Reset the counter + testRetryCount(-1); + } + try + { + // No more than 2 retries before timeout kicks-in + RetryPrx prx = retry1->ice_invocationTimeout(50); + prx->end_opIdempotent(prx->begin_opIdempotent(4)); + test(false); + } + catch(const Ice::InvocationTimeoutException&) + { + testRetryCount(2); + retry1->opIdempotent(-1); + testRetryCount(-1); + } + cout << "ok" << endl; + return retry1; } diff --git a/cpp/test/Ice/retry/Client.cpp b/cpp/test/Ice/retry/Client.cpp index 5b877b2c1a9..53bed9b8c2f 100644 --- a/cpp/test/Ice/retry/Client.cpp +++ b/cpp/test/Ice/retry/Client.cpp @@ -38,7 +38,7 @@ main(int argc, char* argv[]) initData.properties = Ice::createProperties(argc, argv); initData.observer = getObserver(); - initData.properties->setProperty("Ice.RetryIntervals", "0 10 20 30"); + initData.properties->setProperty("Ice.RetryIntervals", "0 1 100 1"); // // This test kills connections, so we don't want warnings. diff --git a/cpp/test/Ice/retry/Collocated.cpp b/cpp/test/Ice/retry/Collocated.cpp index 8bb1be3b5ca..46729831b47 100644 --- a/cpp/test/Ice/retry/Collocated.cpp +++ b/cpp/test/Ice/retry/Collocated.cpp @@ -45,7 +45,7 @@ main(int argc, char* argv[]) initData.properties = Ice::createProperties(argc, argv); initData.observer = getObserver(); - initData.properties->setProperty("Ice.RetryIntervals", "0 10 20 30"); + initData.properties->setProperty("Ice.RetryIntervals", "0 1 100 1"); // // This test kills connections, so we don't want warnings. diff --git a/cpp/test/Ice/retry/InstrumentationI.cpp b/cpp/test/Ice/retry/InstrumentationI.cpp index a39a2804b38..f60ba5706c9 100644 --- a/cpp/test/Ice/retry/InstrumentationI.cpp +++ b/cpp/test/Ice/retry/InstrumentationI.cpp @@ -143,6 +143,12 @@ Ice::Instrumentation::CommunicatorObserverPtr communicatorObserver = new Communi void testEqual(int& value, int expected) { + if(expected < 0) + { + value = 0; + return; + } + int retry = 0; while(++retry < 100) { @@ -160,6 +166,7 @@ testEqual(int& value, int expected) std::cerr << "value = " << value << ", expected = " << expected << std::endl; test(false); } + value = 0; } } diff --git a/cpp/test/Ice/retry/Test.ice b/cpp/test/Ice/retry/Test.ice index 61297d94557..cd8c2595796 100644 --- a/cpp/test/Ice/retry/Test.ice +++ b/cpp/test/Ice/retry/Test.ice @@ -17,10 +17,10 @@ interface Retry void op(bool kill); idempotent int opIdempotent(int c); - void opNotIdempotent(int c); + void opNotIdempotent(); void opSystemException(); - void shutdown(); + idempotent void shutdown(); }; }; diff --git a/cpp/test/Ice/retry/TestI.cpp b/cpp/test/Ice/retry/TestI.cpp index b3545fa4c7a..9a0ed3fc81d 100644 --- a/cpp/test/Ice/retry/TestI.cpp +++ b/cpp/test/Ice/retry/TestI.cpp @@ -11,13 +11,6 @@ #include <TestI.h> #include <SystemFailure.h> -namespace -{ - -const int nRetry = 4; // See Ice.RetryIntervals configuration in Client.cpp/Collocated.cpp - -} - RetryI::RetryI() : _counter(0) { } @@ -39,9 +32,15 @@ RetryI::op(bool kill, const Ice::Current& current) } int -RetryI::opIdempotent(int counter, const Ice::Current& current) +RetryI::opIdempotent(int nRetry, const Ice::Current& current) { - if(counter + nRetry > _counter) + if(nRetry < 0) + { + _counter = 0; + return 0; + } + + if(nRetry > _counter) { ++_counter; if(current.con) @@ -52,19 +51,16 @@ RetryI::opIdempotent(int counter, const Ice::Current& current) { throw Ice::ConnectionLostException(__FILE__, __LINE__); } + return 0; } - return _counter; + int counter = _counter; + _counter = 0; + return counter; } void -RetryI::opNotIdempotent(int counter, const Ice::Current& current) +RetryI::opNotIdempotent(const Ice::Current& current) { - if(_counter != counter) - { - return; - } - - ++_counter; if(current.con) { current.con->close(true); diff --git a/cpp/test/Ice/retry/TestI.h b/cpp/test/Ice/retry/TestI.h index 24405acbf99..c049fadfbd6 100644 --- a/cpp/test/Ice/retry/TestI.h +++ b/cpp/test/Ice/retry/TestI.h @@ -20,7 +20,7 @@ public: virtual void op(bool, const Ice::Current&); virtual int opIdempotent(int, const Ice::Current&); - virtual void opNotIdempotent(int, const Ice::Current&); + virtual void opNotIdempotent(const Ice::Current&); virtual void opSystemException(const Ice::Current&); virtual void shutdown(const Ice::Current&); diff --git a/cs/src/Ice/AsyncResult.cs b/cs/src/Ice/AsyncResult.cs new file mode 100644 index 00000000000..e8db66e4b0d --- /dev/null +++ b/cs/src/Ice/AsyncResult.cs @@ -0,0 +1,701 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +namespace Ice +{ + /// + /// <summary> + /// Callback that requires the application to down-cast the proxy. + /// </summary> + /// + public delegate void AsyncCallback(AsyncResult r); + + /// + /// <summary> + /// Callback for the successful completion of an operation + /// that returns no data. + /// </summary> + /// + public delegate void OnewayCallback(); + + /// + /// <summary> + /// Callback for the successful completion of an operation + /// that returns no data. + /// </summary> + /// + public delegate void SentCallback(bool sentSynchronously); + + /// + /// <summary> + /// Called when an invocation raises an exception. + /// </summary> + /// + public delegate void ExceptionCallback(Ice.Exception ex); + + /// + /// <summary> + /// <!-- TODO --> + /// </summary> + public interface AsyncResult : System.IAsyncResult + { + void cancel(); + + Ice.Communicator getCommunicator(); + + Ice.Connection getConnection(); + + ObjectPrx getProxy(); + + bool isCompleted_(); + void waitForCompleted(); + + bool isSent(); + void waitForSent(); + + void throwLocalException(); + + bool sentSynchronously(); + + string getOperation(); + + AsyncResult whenSent(Ice.AsyncCallback cb); + AsyncResult whenSent(Ice.SentCallback cb); + + AsyncResult whenCompleted(Ice.ExceptionCallback excb); + } + + public interface AsyncResult<T> : AsyncResult + { + AsyncResult<T> whenCompleted(T cb, Ice.ExceptionCallback excb); + + new AsyncResult<T> whenCompleted(Ice.ExceptionCallback excb); + new AsyncResult<T> whenSent(Ice.SentCallback cb); + } +} + +namespace IceInternal +{ + using System.Collections.Generic; + using System.Diagnostics; + using System.Threading; + + public delegate void ProxyTwowayCallback<T>(Ice.AsyncResult result, T cb, Ice.ExceptionCallback excb); + public delegate void ProxyOnewayCallback<T>(T cb); + + public class AsyncResultI : Ice.AsyncResult + { + public virtual void cancel() + { + cancel(new Ice.InvocationCanceledException()); + } + + public Ice.Communicator getCommunicator() + { + return _communicator; + } + + public virtual Ice.Connection getConnection() + { + return null; + } + + public virtual Ice.ObjectPrx getProxy() + { + return null; + } + + public bool isCompleted_() + { + lock(this) + { + return (state_ & StateDone) != 0; + } + } + + public void waitForCompleted() + { + lock(this) + { + while((state_ & StateDone) == 0) + { + System.Threading.Monitor.Wait(this); + } + } + } + + public bool isSent() + { + lock(this) + { + return (state_ & StateSent) != 0; + } + } + + public void waitForSent() + { + lock(this) + { + while((state_ & StateSent) == 0 && _exception == null) + { + System.Threading.Monitor.Wait(this); + } + } + } + + public void throwLocalException() + { + lock(this) + { + if(_exception != null) + { + throw _exception; + } + } + } + + public bool sentSynchronously() + { + return sentSynchronously_; // No lock needed + } + + // + // Implementation of System.IAsyncResult properties + // + + public bool IsCompleted + { + get + { + return isCompleted_(); + } + } + + public bool CompletedSynchronously + { + get + { + if(getProxy() != null && getProxy().ice_isTwoway()) + { + return false; + } + return sentSynchronously_; + } + } + + public object AsyncState + { + get + { + return _cookie; // No lock needed, cookie is immutable. + } + } + + public WaitHandle AsyncWaitHandle + { + get + { + lock(this) + { + if(_waitHandle == null) + { +#if SILVERLIGHT + _waitHandle = new ManualResetEvent(false); +#else + _waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); +#endif + } + if((state_ & StateDone) != 0) + { + _waitHandle.Set(); + } + return _waitHandle; + } + } + } + + public Ice.AsyncResult whenSent(Ice.AsyncCallback cb) + { + lock(this) + { + if(cb == null) + { + throw new System.ArgumentException("callback is null"); + } + if(_sentCallback != null) + { + throw new System.ArgumentException("sent callback already set"); + } + _sentCallback = cb; + if((state_ & StateSent) == 0) + { + return this; + } + } + + if(sentSynchronously_) + { + try + { + _sentCallback(this); + } + catch(System.Exception ex) + { + warning(ex); + } + } + else + { + instance_.clientThreadPool().dispatch(() => + { + try + { + _sentCallback(this); + } + catch(System.Exception ex) + { + warning(ex); + } + }, cachedConnection_); + } + return this; + } + + public Ice.AsyncResult whenSent(Ice.SentCallback cb) + { + lock(this) + { + if(cb == null) + { + throw new System.ArgumentException("callback is null"); + } + if(_sentCallback != null) + { + throw new System.ArgumentException("sent callback already set"); + } + _sentCallback = (Ice.AsyncResult result) => + { + cb(result.sentSynchronously()); + }; + if((state_ & StateSent) == 0) + { + return this; + } + } + + if(sentSynchronously_) + { + try + { + cb(true); + } + catch(System.Exception ex) + { + warning(ex); + } + } + else + { + instance_.clientThreadPool().dispatch(() => + { + try + { + cb(false); + } + catch(System.Exception ex) + { + warning(ex); + } + }, cachedConnection_); + } + return this; + } + + public Ice.AsyncResult whenCompletedWithAsyncCallback(Ice.AsyncCallback cb) + { + setCompletedCallback(cb); + return this; + } + + public Ice.AsyncResult whenCompleted(Ice.ExceptionCallback cb) + { + if(cb == null) + { + throw new System.ArgumentException("callback is null"); + } + lock(this) + { + if(exceptionCallback_ != null) + { + throw new System.ArgumentException("callback already set"); + } + exceptionCallback_ = cb; + } + setCompletedCallback(getCompletedCallback()); + return this; + } + + public string getOperation() + { + return _operation; + } + + public void invokeSent(Ice.AsyncCallback cb) + { + Debug.Assert(cb != null); + try + { + cb(this); + } + catch(System.Exception ex) + { + warning(ex); + } + + if(observer_ != null) + { + Ice.ObjectPrx proxy = getProxy(); + if(proxy == null || !proxy.ice_isTwoway()) + { + observer_.detach(); + observer_ = null; + } + } + } + + public void invokeCompleted(Ice.AsyncCallback cb) + { + Debug.Assert(cb != null); + try + { + cb(this); + } + catch(System.Exception ex) + { + warning(ex); + } + + if(observer_ != null) + { + observer_.detach(); + observer_ = null; + } + } + + public void invokeCompletedAsync(Ice.AsyncCallback cb) + { + // + // This is called when it's not safe to call the exception callback synchronously + // from this thread. Instead the exception callback is called asynchronously from + // the client thread pool. + // + Debug.Assert(cb != null); + + // CommunicatorDestroyedException is the only exception that can propagate directly. + instance_.clientThreadPool().dispatch(() => + { + invokeCompleted(cb); + }, cachedConnection_); + } + + public void cancelable(CancellationHandler handler) + { + lock(this) + { + if(_cancellationException == null) + { + _cancellationHandler = handler; + return; + } + } + handler.asyncRequestCanceled((OutgoingAsyncBase)this, _cancellationException); + } + + public bool wait() + { + lock(this) + { + if((state_ & StateEndCalled) != 0) + { + throw new System.ArgumentException("end_ method called more than once"); + } + state_ |= StateEndCalled; + while((state_ & StateDone) == 0) + { + System.Threading.Monitor.Wait(this); + } + if(_exception != null) + { + throw _exception; + } + return (state_ & StateOK) != 0; + } + } + + public virtual void cacheMessageBuffers() + { + } + + protected AsyncResultI(Ice.Communicator communicator, Instance instance, string op, object cookie) + { + instance_ = instance; + sentSynchronously_ = false; + state_ = 0; + + _communicator = communicator; + _operation = op; + _exception = null; + _cookie = cookie; + } + + protected Ice.AsyncCallback sent(bool done) + { + lock(this) + { + Debug.Assert(_exception == null); + + bool alreadySent = (state_ & StateSent) != 0; + state_ |= StateSent; + if(done) + { + state_ |= StateDone | StateOK; + _cancellationHandler = null; + if(observer_ != null && _sentCallback == null) + { + observer_.detach(); + observer_ = null; + } + + // + // For oneway requests after the data has been sent + // the buffers can be reused unless this is a + // collocated invocation. For collocated invocations + // the buffer won't be reused because it has already + // been marked as cached in invokeCollocated. + // + cacheMessageBuffers(); + } + if(_waitHandle != null) + { + _waitHandle.Set(); + } + System.Threading.Monitor.PulseAll(this); + return !alreadySent ? _sentCallback : null; + } + } + + protected Ice.AsyncCallback finished(bool ok) + { + lock(this) + { + state_ |= StateDone; + if(ok) + { + state_ |= StateOK; + } + _cancellationHandler = null; + if(_completedCallback == null) + { + if(observer_ != null) + { + observer_.detach(); + observer_ = null; + } + } + if(_waitHandle != null) + { + _waitHandle.Set(); + } + System.Threading.Monitor.PulseAll(this); + return _completedCallback; + } + } + + protected Ice.AsyncCallback finished(Ice.Exception ex) + { + lock(this) + { + state_ |= StateDone; + _exception = ex; + _cancellationHandler = null; + if(observer_ != null) + { + observer_.failed(ex.ice_name()); + } + if(_completedCallback == null) + { + if(observer_ != null) + { + observer_.detach(); + observer_ = null; + } + } + if(_waitHandle != null) + { + _waitHandle.Set(); + } + System.Threading.Monitor.PulseAll(this); + return _completedCallback; + } + } + + protected void invokeSentAsync(Ice.AsyncCallback cb) + { + // + // This is called when it's not safe to call the exception callback synchronously + // from this thread. Instead the exception callback is called asynchronously from + // the client thread pool. + // + Debug.Assert(cb != null); + try + { + instance_.clientThreadPool().dispatch(() => + { + invokeSent(cb); + }, cachedConnection_); + } + catch(Ice.CommunicatorDestroyedException) + { + } + } + + protected void setCompletedCallback(Ice.AsyncCallback cb) + { + lock(this) + { + if(cb == null) + { + throw new System.ArgumentException("callback is null"); + } + if(_completedCallback != null) + { + throw new System.ArgumentException("callback already set"); + } + _completedCallback = cb; + if((state_ & StateDone) == 0) + { + return; + } + else if((getProxy() == null || !getProxy().ice_isTwoway()) && _exception == null) + { + return; + } + } + + instance_.clientThreadPool().dispatch(() => + { + try + { + cb(this); + } + catch(System.Exception ex) + { + warning(ex); + } + }, cachedConnection_); + } + + protected virtual Ice.AsyncCallback getCompletedCallback() + { + return (Ice.AsyncResult result) => + { + Debug.Assert(exceptionCallback_ != null); + try + { + ((AsyncResultI)result).wait(); + } + catch(Ice.Exception ex) + { + exceptionCallback_(ex); + return; + } + }; + } + + protected void cancel(Ice.LocalException ex) + { + lock(this) + { + _cancellationException = ex; + if(_cancellationHandler == null) + { + return; + } + } + _cancellationHandler.asyncRequestCanceled((OutgoingAsyncBase)this, ex); + } + + protected void checkCanceled() + { + lock(this) + { + if(_cancellationException != null) + { + throw _cancellationException; + } + } + } + + protected virtual Ice.Instrumentation.InvocationObserver getObserver() + { + return observer_; + } + + protected static T check<T>(Ice.AsyncResult r, string operation) + { + if(r == null) + { + throw new System.ArgumentException("AsyncResult == null"); + } + if(r.getOperation() != operation) + { + throw new System.ArgumentException("Incorrect operation for end_" + operation + " method: " + + r.getOperation()); + } + if(!(r is T)) + { + throw new System.ArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + return (T)r; + } + + protected void warning(System.Exception ex) + { + if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + { + instance_.initializationData().logger.warning("exception raised by AMI callback:\n" + ex); + } + } + + protected IceInternal.Instance instance_; + protected Ice.Instrumentation.InvocationObserver observer_; + protected Ice.Connection cachedConnection_; + protected bool sentSynchronously_; + + private readonly Ice.Communicator _communicator; + private readonly string _operation; + private readonly object _cookie; + private Ice.Exception _exception; + private EventWaitHandle _waitHandle; + + private CancellationHandler _cancellationHandler; + private Ice.LocalException _cancellationException; + + private Ice.AsyncCallback _completedCallback; + private Ice.AsyncCallback _sentCallback; + protected Ice.ExceptionCallback exceptionCallback_; + + protected const int StateOK = 0x1; + protected const int StateDone = 0x2; + protected const int StateSent = 0x4; + protected const int StateEndCalled = 0x8; + protected const int StateCachedBuffers = 0x10; + protected int state_; + } +} diff --git a/cs/src/Ice/CollocatedRequestHandler.cs b/cs/src/Ice/CollocatedRequestHandler.cs index a53801b98fc..632934a7d33 100644 --- a/cs/src/Ice/CollocatedRequestHandler.cs +++ b/cs/src/Ice/CollocatedRequestHandler.cs @@ -165,12 +165,12 @@ namespace IceInternal } } - public bool sendAsyncRequest(OutgoingAsyncMessageCallback outAsync, out Ice.AsyncCallback sentCallback) + public bool sendAsyncRequest(OutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback) { return outAsync.invokeCollocated(this, out sentCallback); } - public void asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex) + public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) { lock(this) { @@ -182,8 +182,12 @@ namespace IceInternal _asyncRequests.Remove(requestId); } _sendAsyncRequests.Remove(outAsync); - outAsync.dispatchInvocationCancel(ex, _reference.getInstance().clientThreadPool(), null); - return; // We're done + Ice.AsyncCallback cb = outAsync.completed(ex); + if(cb != null) + { + outAsync.invokeCompletedAsync(cb); + } + return; } if(outAsync is OutgoingAsync) { @@ -194,8 +198,12 @@ namespace IceInternal if(e.Value == o) { _asyncRequests.Remove(e.Key); - outAsync.dispatchInvocationCancel(ex, _reference.getInstance().clientThreadPool(), null); - return; // We're done + Ice.AsyncCallback cb = outAsync.completed(ex); + if(cb != null) + { + outAsync.invokeCompletedAsync(cb); + } + return; } } } @@ -204,7 +212,8 @@ namespace IceInternal public void sendResponse(int requestId, BasicStream os, byte status) { - OutgoingAsync outAsync = null; + Ice.AsyncCallback cb = null; + OutgoingAsync outAsync; lock(this) { Debug.Assert(_response); @@ -219,18 +228,15 @@ namespace IceInternal if(_asyncRequests.TryGetValue(requestId, out outAsync)) { - os.swap(outAsync.istr__); _asyncRequests.Remove(requestId); + outAsync.getIs().swap(os); + cb = outAsync.completed(); } } - if(outAsync != null) + if(cb != null) { - Ice.AsyncCallback cb = outAsync.finished(); - if(cb != null) - { - outAsync.invokeCompleted(cb); - } + outAsync.invokeCompleted(cb); } _adapter.decDirectCount(); } @@ -252,21 +258,7 @@ namespace IceInternal public void invokeException(int requestId, Ice.LocalException ex, int invokeNum) { - if(requestId > 0) - { - OutgoingAsync outAsync = null; - lock(this) - { - if(_asyncRequests.TryGetValue(requestId, out outAsync)) - { - _asyncRequests.Remove(requestId); - } - } - if(outAsync != null) - { - outAsync.finished(ex); - } - } + handleException(requestId, ex); _adapter.decDirectCount(); } @@ -288,7 +280,7 @@ namespace IceInternal return null; } - public void invokeAsyncRequest(OutgoingAsync outAsync, bool synchronous, out Ice.AsyncCallback sentCallback) + public bool invokeAsyncRequest(OutgoingAsync outAsync, bool synchronous, out Ice.AsyncCallback sentCallback) { int requestId = 0; if(_reference.getInvocationTimeout() > 0 || _response) @@ -304,6 +296,7 @@ namespace IceInternal { _sendAsyncRequests.Add(outAsync, requestId); } + outAsync.cancelable(this); } } @@ -321,7 +314,7 @@ namespace IceInternal { if(sentAsync(outAsync)) { - invokeAll(outAsync.ostr__, requestId, 1, false); + invokeAll(outAsync.getOs(), requestId, 1, false); } }, null); } @@ -331,7 +324,7 @@ namespace IceInternal { if(sentAsync(outAsync)) { - invokeAll(outAsync.ostr__, requestId, 1, false); + invokeAll(outAsync.getOs(), requestId, 1, false); } }, null); } @@ -339,7 +332,7 @@ namespace IceInternal { if(sentAsync(outAsync)) { - invokeAll(outAsync.ostr__, requestId, 1, false); + invokeAll(outAsync.getOs(), requestId, 1, false); } } sentCallback = null; @@ -350,14 +343,15 @@ namespace IceInternal { if(sentAsync(outAsync)) { - invokeAll(outAsync.ostr__, requestId, 1, false); + invokeAll(outAsync.getOs(), requestId, 1, false); } }, null); sentCallback = null; } + return false; } - public bool invokeAsyncBatchRequests(BatchOutgoingAsync outAsync, out Ice.AsyncCallback sentCallback) + public bool invokeAsyncBatchRequests(OutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback) { int invokeNum; lock(this) @@ -373,10 +367,11 @@ namespace IceInternal if(_reference.getInvocationTimeout() > 0) { _sendAsyncRequests.Add(outAsync, 0); + outAsync.cancelable(this); } Debug.Assert(!_batchStream.isEmpty()); - _batchStream.swap(outAsync.ostr__); + _batchStream.swap(outAsync.getOs()); // // Reset the batch stream. @@ -397,7 +392,7 @@ namespace IceInternal { if(sentAsync(outAsync)) { - invokeAll(outAsync.ostr__, 0, invokeNum, true); + invokeAll(outAsync.getOs(), 0, invokeNum, true); } }, null); sentCallback = null; @@ -411,7 +406,7 @@ namespace IceInternal } - private bool sentAsync(OutgoingAsyncMessageCallback outAsync) + private bool sentAsync(OutgoingAsyncBase outAsync) { if(_reference.getInvocationTimeout() > 0) { @@ -492,18 +487,20 @@ namespace IceInternal return; // Ignore exception for oneway messages. } - OutgoingAsync outAsync = null; + OutgoingAsync outAsync; + Ice.AsyncCallback cb = null; lock(this) { if(_asyncRequests.TryGetValue(requestId, out outAsync)) { _asyncRequests.Remove(requestId); + cb = outAsync.completed(ex); } } - if(outAsync != null) + if(cb != null) { - outAsync.finished(ex); + outAsync.invokeCompleted(cb); } } @@ -517,8 +514,7 @@ namespace IceInternal private int _requestId; - private Dictionary<OutgoingAsyncMessageCallback, int> _sendAsyncRequests = - new Dictionary<OutgoingAsyncMessageCallback, int>(); + private Dictionary<OutgoingAsyncBase, int> _sendAsyncRequests = new Dictionary<OutgoingAsyncBase, int>(); private Dictionary<int, OutgoingAsync> _asyncRequests = new Dictionary<int, OutgoingAsync>(); private BasicStream _batchStream; diff --git a/cs/src/Ice/CommunicatorI.cs b/cs/src/Ice/CommunicatorI.cs index 418285cbc64..8b86b1c2179 100644 --- a/cs/src/Ice/CommunicatorI.cs +++ b/cs/src/Ice/CommunicatorI.cs @@ -177,8 +177,8 @@ namespace Ice // This callback object receives the results of all invocations // of Connection.begin_flushBatchRequests. // - IceInternal.CommunicatorBatchOutgoingAsync result = - new IceInternal.CommunicatorBatchOutgoingAsync(this, instance_, __flushBatchRequests_name, cookie); + IceInternal.CommunicatorFlushBatch result = + new IceInternal.CommunicatorFlushBatch(this, instance_, __flushBatchRequests_name, cookie); if(cb != null) { @@ -200,8 +200,8 @@ namespace Ice public void end_flushBatchRequests(AsyncResult result) { - IceInternal.OutgoingAsyncBase outAsync = (IceInternal.OutgoingAsyncBase)result; - IceInternal.OutgoingAsyncBase.check(outAsync, this, __flushBatchRequests_name); + IceInternal.CommunicatorFlushBatch outAsync = + IceInternal.CommunicatorFlushBatch.check(result, this, __flushBatchRequests_name); outAsync.wait(); } diff --git a/cs/src/Ice/ConnectRequestHandler.cs b/cs/src/Ice/ConnectRequestHandler.cs index 7676ee84d55..eed058479e7 100644 --- a/cs/src/Ice/ConnectRequestHandler.cs +++ b/cs/src/Ice/ConnectRequestHandler.cs @@ -26,12 +26,12 @@ namespace IceInternal this.os.swap(os); } - internal Request(OutgoingAsyncMessageCallback outAsync) + internal Request(OutgoingAsyncBase outAsync) { this.outAsync = outAsync; } - internal OutgoingAsyncMessageCallback outAsync = null; + internal OutgoingAsyncBase outAsync = null; internal BasicStream os = null; internal Ice.AsyncCallback sentCallback = null; } @@ -143,7 +143,7 @@ namespace IceInternal _connection.abortBatchRequest(); } - public bool sendAsyncRequest(OutgoingAsyncMessageCallback outAsync, out Ice.AsyncCallback sentCallback) + public bool sendAsyncRequest(OutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback) { lock(this) { @@ -152,6 +152,7 @@ namespace IceInternal if(!initialized()) { _requests.AddLast(new Request(outAsync)); + outAsync.cancelable(this); sentCallback = null; return false; } @@ -164,7 +165,7 @@ namespace IceInternal return outAsync.send(_connection, _compress, _response, out sentCallback); } - public void asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex) + public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) { lock(this) { @@ -182,8 +183,12 @@ namespace IceInternal if(request.outAsync == outAsync) { _requests.Remove(p); - outAsync.dispatchInvocationCancel(ex, _reference.getInstance().clientThreadPool(), null); - return; // We're done + Ice.AsyncCallback cb = outAsync.completed(ex); + if(cb != null) + { + outAsync.invokeCompletedAsync(cb); + } + return; } p = p.Next; } @@ -476,7 +481,11 @@ namespace IceInternal { if(request.outAsync != null) { - request.outAsync.finished(_exception); + Ice.AsyncCallback cb = request.outAsync.completed(_exception); + if(cb != null) + { + request.outAsync.invokeCompleted(cb); + } } } _requests.Clear(); diff --git a/cs/src/Ice/ConnectionFactory.cs b/cs/src/Ice/ConnectionFactory.cs index 47f4ec450aa..88cbb58d094 100644 --- a/cs/src/Ice/ConnectionFactory.cs +++ b/cs/src/Ice/ConnectionFactory.cs @@ -434,7 +434,7 @@ namespace IceInternal } } - public void flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) + public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) { ICollection<Ice.ConnectionI> c = new List<Ice.ConnectionI>(); @@ -1418,7 +1418,7 @@ namespace IceInternal } } - public void flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) + public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) { // // connections() is synchronized, no need to synchronize here. diff --git a/cs/src/Ice/ConnectionI.cs b/cs/src/Ice/ConnectionI.cs index 88f92f334bd..6b7ce6d7510 100644 --- a/cs/src/Ice/ConnectionI.cs +++ b/cs/src/Ice/ConnectionI.cs @@ -17,7 +17,8 @@ namespace Ice using System.Threading; using Ice.Instrumentation; - public sealed class ConnectionI : IceInternal.EventHandler, IceInternal.ResponseHandler, Connection + public sealed class ConnectionI : + IceInternal.EventHandler, IceInternal.ResponseHandler, IceInternal.CancellationHandler, Connection { public interface StartCallback { @@ -384,7 +385,7 @@ namespace Ice public bool sendAsyncRequest(IceInternal.OutgoingAsync og, bool compress, bool response, out Ice.AsyncCallback sentCallback) { - IceInternal.BasicStream os = og.ostr__; + IceInternal.BasicStream os = og.getOs(); lock(this) { @@ -427,8 +428,7 @@ namespace Ice os.writeInt(requestId); } - og.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, - os.size() - IceInternal.Protocol.headerSize - 4); + og.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId); bool sent; try @@ -444,6 +444,11 @@ namespace Ice throw _exception; } + if(response || !sent) + { + og.cancelable(this); // Notify the request that it's cancelable + } + if(response) { // @@ -672,8 +677,8 @@ namespace Ice public void end_flushBatchRequests(AsyncResult r) { - IceInternal.OutgoingAsyncBase outAsync = (IceInternal.OutgoingAsyncBase)r; - IceInternal.OutgoingAsyncBase.check(outAsync, this, __flushBatchRequests_name); + IceInternal.ConnectionFlushBatch outAsync = + IceInternal.ConnectionFlushBatch.check(r, this, __flushBatchRequests_name); outAsync.wait(); } @@ -681,28 +686,17 @@ namespace Ice private AsyncResult begin_flushBatchRequestsInternal(AsyncCallback cb, object cookie) { - IceInternal.ConnectionBatchOutgoingAsync result = - new IceInternal.ConnectionBatchOutgoingAsync(this, _communicator, _instance, __flushBatchRequests_name, - cookie); - + IceInternal.ConnectionFlushBatch result = + new IceInternal.ConnectionFlushBatch(this, _communicator, _instance, __flushBatchRequests_name, cookie); if(cb != null) { result.whenCompletedWithAsyncCallback(cb); } - - try - { - result.invoke(); - } - catch(LocalException ex) - { - result.invokeExceptionAsync(ex); - } - + result.invoke(); return result; } - public bool flushAsyncBatchRequests(IceInternal.BatchOutgoingAsync outAsync, out Ice.AsyncCallback sentCallback) + public bool flushAsyncBatchRequests(IceInternal.OutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback) { lock(this) { @@ -728,10 +722,9 @@ namespace Ice _batchStream.pos(IceInternal.Protocol.headerSize); _batchStream.writeInt(_batchRequestNum); - outAsync.attachRemoteObserver(initConnectionInfo(), _endpoint, 0, - _batchStream.size() - IceInternal.Protocol.headerSize - 4); + _batchStream.swap(outAsync.getOs()); - _batchStream.swap(outAsync.ostr__); + outAsync.attachRemoteObserver(initConnectionInfo(), _endpoint, 0); // // Send the batch stream. @@ -739,7 +732,7 @@ namespace Ice bool sent; try { - OutgoingMessage message = new OutgoingMessage(outAsync, outAsync.ostr__, _batchRequestCompress, 0); + OutgoingMessage message = new OutgoingMessage(outAsync, outAsync.getOs(), _batchRequestCompress, 0); sent = sendMessage(message); sentCallback = message.sentCallback; } @@ -749,6 +742,11 @@ namespace Ice Debug.Assert(_exception != null); throw _exception; } + + if(!sent) + { + outAsync.cancelable(this); // Notify the request that it's cancelable. + } // // Reset the batch stream. @@ -779,7 +777,7 @@ namespace Ice { _logger.error("connection callback exception:\n" + ex + '\n' + _desc); } - } , null); + } , this); } } else @@ -828,10 +826,19 @@ namespace Ice } } - public void asyncRequestCanceled(IceInternal.OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex) + public void asyncRequestCanceled(IceInternal.OutgoingAsyncBase outAsync, Ice.LocalException ex) { + // + // NOTE: This isn't called from a thread pool thread. + // + lock(this) { + if(_state >= StateClosed) + { + return; // The request has already been or will be shortly notified of the failure. + } + LinkedListNode<OutgoingMessage> p; for(p = _sendStreams.First; p != null; p = p.Next) { @@ -847,13 +854,17 @@ namespace Ice // If the request is being sent, don't remove it from the send streams, // it will be removed once the sending is finished. // - o.timedOut(); + o.canceled(); if(o != _sendStreams.First.Value) { _sendStreams.Remove(p); } - outAsync.dispatchInvocationCancel(ex, _threadPool, this); - return; // We're done. + Ice.AsyncCallback cb = outAsync.completed(ex); + if(cb != null) + { + outAsync.invokeCompletedAsync(cb); + } + return; } } @@ -865,8 +876,12 @@ namespace Ice if(kvp.Value == o) { _asyncRequests.Remove(kvp.Key); - outAsync.dispatchInvocationCancel(ex, _threadPool, this); - return; // We're done. + Ice.AsyncCallback cb = outAsync.completed(ex); + if(cb != null) + { + outAsync.invokeCompletedAsync(cb); + } + return; } } } @@ -1422,7 +1437,7 @@ namespace Ice if(m.receivedReply) { IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)m.outAsync; - Ice.AsyncCallback cb = outAsync.finished(); + Ice.AsyncCallback cb = outAsync.completed(); if(cb != null) { outAsync.invokeCompleted(cb); @@ -1596,7 +1611,7 @@ namespace Ice if(message.receivedReply) { IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)message.outAsync; - Ice.AsyncCallback cb = outAsync.finished(); + Ice.AsyncCallback cb = outAsync.completed(); if(cb != null) { outAsync.invokeCompleted(cb); @@ -1608,7 +1623,7 @@ namespace Ice foreach(OutgoingMessage m in _sendStreams) { - m.finished(_exception); + m.completed(_exception); if(m.requestId > 0) // Make sure finished isn't called twice. { _asyncRequests.Remove(m.requestId); @@ -1619,7 +1634,11 @@ namespace Ice foreach(IceInternal.OutgoingAsync o in _asyncRequests.Values) { - o.finished(_exception); + Ice.AsyncCallback cb = o.completed(_exception); + if(cb != null) + { + o.invokeCompleted(cb); + } } _asyncRequests.Clear(); @@ -2670,7 +2689,7 @@ namespace Ice { _asyncRequests.Remove(info.requestId); - outAsync.istr__.swap(info.stream); + outAsync.getIs().swap(info.stream); // // If we just received the reply for a request which isn't acknowledge as @@ -2684,7 +2703,7 @@ namespace Ice } else { - info.completedCallback = outAsync.finished(); + info.completedCallback = outAsync.completed(); if(info.completedCallback != null) { info.outAsync = outAsync; @@ -3044,7 +3063,7 @@ namespace Ice this.requestId = 0; } - internal OutgoingMessage(IceInternal.OutgoingAsyncMessageCallback outAsync, IceInternal.BasicStream stream, + internal OutgoingMessage(IceInternal.OutgoingAsyncBase outAsync, IceInternal.BasicStream stream, bool compress, int requestId) { this.stream = stream; @@ -3054,7 +3073,7 @@ namespace Ice this.isSent = false; } - internal void timedOut() + internal void canceled() { Debug.Assert(outAsync != null); outAsync = null; @@ -3081,16 +3100,20 @@ namespace Ice return sentCallback != null || receivedReply; } - internal void finished(LocalException ex) + internal void completed(LocalException ex) { if(outAsync != null) { - outAsync.finished(ex); + Ice.AsyncCallback cb = outAsync.completed(ex); + if(cb != null) + { + outAsync.invokeCompleted(cb); + } } } internal IceInternal.BasicStream stream; - internal IceInternal.OutgoingAsyncMessageCallback outAsync; + internal IceInternal.OutgoingAsyncBase outAsync; internal bool receivedReply; internal bool compress; internal int requestId; diff --git a/cs/src/Ice/ConnectionRequestHandler.cs b/cs/src/Ice/ConnectionRequestHandler.cs index 1d7a2b32ff0..a0f1edec56f 100644 --- a/cs/src/Ice/ConnectionRequestHandler.cs +++ b/cs/src/Ice/ConnectionRequestHandler.cs @@ -61,13 +61,13 @@ namespace IceInternal { _connection.abortBatchRequest(); } - - public bool sendAsyncRequest(OutgoingAsyncMessageCallback outAsync, out Ice.AsyncCallback sentCallback) + + public bool sendAsyncRequest(OutgoingAsyncBase outAsync, out Ice.AsyncCallback sentCallback) { return outAsync.send(_connection, _compress, _response, out sentCallback); } - public void asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex) + public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) { _connection.asyncRequestCanceled(outAsync, ex); } diff --git a/cs/src/Ice/Makefile b/cs/src/Ice/Makefile index dc7b66116ce..dbdd6671d1c 100644 --- a/cs/src/Ice/Makefile +++ b/cs/src/Ice/Makefile @@ -22,6 +22,7 @@ SRCS = Acceptor.cs \ AssemblyInfo.cs \ AssemblyUtil.cs \ AsyncIOThread.cs \ + AsyncResult.cs \ Base64.cs \ BasicStream.cs \ Buffer.cs \ diff --git a/cs/src/Ice/Makefile.mak b/cs/src/Ice/Makefile.mak index f900f2902ec..454302543aa 100644 --- a/cs/src/Ice/Makefile.mak +++ b/cs/src/Ice/Makefile.mak @@ -22,6 +22,7 @@ SRCS = Acceptor.cs \ AssemblyInfo.cs \ AssemblyUtil.cs \ AsyncIOThread.cs \ + AsyncResult.cs \ Base64.cs \ BasicStream.cs \ Buffer.cs \ diff --git a/cs/src/Ice/ObjectAdapterFactory.cs b/cs/src/Ice/ObjectAdapterFactory.cs index 3dd791b1030..0b9cdb2a914 100644 --- a/cs/src/Ice/ObjectAdapterFactory.cs +++ b/cs/src/Ice/ObjectAdapterFactory.cs @@ -212,7 +212,7 @@ namespace IceInternal } } - public void flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) + public void flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) { List<Ice.ObjectAdapterI> adapters; lock(this) diff --git a/cs/src/Ice/ObjectAdapterI.cs b/cs/src/Ice/ObjectAdapterI.cs index eaf5b98260e..7756016527d 100644 --- a/cs/src/Ice/ObjectAdapterI.cs +++ b/cs/src/Ice/ObjectAdapterI.cs @@ -705,7 +705,7 @@ namespace Ice } } - public void flushAsyncBatchRequests(IceInternal.CommunicatorBatchOutgoingAsync outAsync) + public void flushAsyncBatchRequests(IceInternal.CommunicatorFlushBatch outAsync) { List<IceInternal.IncomingConnectionFactory> f; lock(this) diff --git a/cs/src/Ice/OutgoingAsync.cs b/cs/src/Ice/OutgoingAsync.cs index 001573244be..910d4fae161 100644 --- a/cs/src/Ice/OutgoingAsync.cs +++ b/cs/src/Ice/OutgoingAsync.cs @@ -7,81 +7,6 @@ // // ********************************************************************** -namespace Ice -{ - using System.Threading; - using System.Collections.Generic; - using System.Diagnostics; - - /// - /// <summary> - /// Callback that requires the application to down-cast the proxy. - /// </summary> - /// - public delegate void AsyncCallback(AsyncResult r); - - /// - /// <summary> - /// Callback for the successful completion of an operation - /// that returns no data. - /// </summary> - /// - public delegate void OnewayCallback(); - - /// - /// <summary> - /// Callback for the successful completion of an operation - /// that returns no data. - /// </summary> - /// - public delegate void SentCallback(bool sentSynchronously); - - /// - /// <summary> - /// Called when an invocation raises an exception. - /// </summary> - /// - public delegate void ExceptionCallback(Ice.Exception ex); - - /// - /// <summary> - /// <!-- TODO --> - /// </summary> - public interface AsyncResult : System.IAsyncResult - { - Ice.Communicator getCommunicator(); - - Ice.Connection getConnection(); - - ObjectPrx getProxy(); - - bool isCompleted_(); - void waitForCompleted(); - - bool isSent(); - void waitForSent(); - - void throwLocalException(); - - bool sentSynchronously(); - - string getOperation(); - - AsyncResult whenSent(Ice.AsyncCallback cb); - AsyncResult whenSent(Ice.SentCallback cb); - - AsyncResult whenCompleted(Ice.ExceptionCallback excb); - } - - public interface AsyncResult<T> : AsyncResult - { - AsyncResult<T> whenCompleted(T cb, Ice.ExceptionCallback excb); - - new AsyncResult<T> whenCompleted(Ice.ExceptionCallback excb); - new AsyncResult<T> whenSent(Ice.SentCallback cb); - } -} - namespace IceInternal { using System; @@ -89,732 +14,385 @@ namespace IceInternal using System.Diagnostics; using System.Threading; - public delegate void ProxyTwowayCallback<T>(Ice.AsyncResult result, T cb, Ice.ExceptionCallback excb); - public delegate void ProxyOnewayCallback<T>(T cb); - - // - // This interface is used by the connection to handle OutgoingAsync - // and BatchOutgoingAsync messages. - // - public interface OutgoingAsyncMessageCallback - { - // - // Called by the request handler to send the request over the connection. - // - bool send(Ice.ConnectionI connection, bool compress, bool response, out Ice.AsyncCallback sentCallback); - - // - // Called by the collocated request handler to invoke the request. - // - bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCallback); - - // - // Called by the connection when the message is confirmed sent. The connection is locked - // when this is called so this method can call the sent callback. Instead, this method - // returns true if there's a sent callback and false otherwise. If true is returned, the - // connection will call the __sent() method bellow (which in turn should call the sent - // callback). - // - Ice.AsyncCallback sent(); - - // - // Called by the connection to call the user sent callback. - // - void invokeSent(Ice.AsyncCallback cb); - - // - // Called by the connection when the request failed. - // - void finished(Ice.Exception ex); - - // - // Helper to dispatch invocation timeout. - // - void dispatchInvocationCancel(Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection); - } - - abstract public class OutgoingAsyncBase : Ice.AsyncResult + public class OutgoingAsyncBase : AsyncResultI { - public virtual Ice.Communicator getCommunicator() - { - return communicator_; - } - - public virtual Ice.Connection getConnection() + public virtual bool send(Ice.ConnectionI connection, bool compress, bool response, out Ice.AsyncCallback cb) { - return null; + Debug.Assert(false); // This should be overriden if this object is used with a request handler + cb = null; + return false; } - public virtual Ice.ObjectPrx getProxy() + public virtual bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback cb) { - return null; - } - - public bool isCompleted_() - { - lock(monitor_) - { - return (state_ & StateDone) != 0; - } + Debug.Assert(false); // This should be overriden if this object is used with a request handler + cb = null; + return false; } - public void waitForCompleted() + public virtual Ice.AsyncCallback sent() { - lock(monitor_) - { - while((state_ & StateDone) == 0) - { - System.Threading.Monitor.Wait(monitor_); - } - } + return sent(true); } - public bool isSent() + public virtual Ice.AsyncCallback completed(Ice.Exception ex) { - lock(monitor_) - { - return (state_ & StateSent) != 0; - } + return finished(ex); } - public void waitForSent() + public void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId) { - lock(monitor_) + if(observer_ != null) { - while((state_ & StateSent) == 0 && exception_ == null) + int size = os_.size() - Protocol.headerSize - 4; + childObserver_ = getObserver().getRemoteObserver(info, endpt, requestId, size); + if(childObserver_ != null) { - System.Threading.Monitor.Wait(monitor_); + childObserver_.attach(); } } } - public void throwLocalException() + public void attachCollocatedObserver(Ice.ObjectAdapter adapter, int requestId) { - lock(monitor_) + if(observer_ != null) { - if(exception_ != null) + int size = os_.size() - Protocol.headerSize - 4; + childObserver_ = getObserver().getCollocatedObserver(adapter, requestId, size); + if(childObserver_ != null) { - throw exception_; + childObserver_.attach(); } } } - public bool sentSynchronously() + public IceInternal.BasicStream getOs() { - return sentSynchronously_; // No lock needed, immutable once invoke() is called - } - - // - // Implementation of System.IAsyncResult properties - // - - public bool IsCompleted - { - get - { - return isCompleted_(); - } + return os_; } - public bool CompletedSynchronously + protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, string op, object cookie) : + base(com, instance, op, cookie) { - get - { - if(getProxy() != null && getProxy().ice_isTwoway()) - { - return false; - } - return sentSynchronously_; - } + os_ = new BasicStream(instance, Ice.Util.currentProtocolEncoding); } - public object AsyncState + protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, string op, object cookie, BasicStream os) : + base(com, instance, op, cookie) { - get - { - return _cookie; // No lock needed, cookie is immutable. - } + os_ = os; } - public WaitHandle AsyncWaitHandle + protected new Ice.AsyncCallback sent(bool done) { - get + if(done) { - lock(monitor_) + if(childObserver_ != null) { - if(waitHandle_ == null) - { -#if SILVERLIGHT - waitHandle_ = new ManualResetEvent(false); -#else - waitHandle_ = new EventWaitHandle(false, EventResetMode.ManualReset); -#endif - } - if((state_ & StateDone) != 0) - { - waitHandle_.Set(); - } - return waitHandle_; + childObserver_.detach(); + childObserver_ = null; } } + return base.sent(done); } - public Ice.AsyncResult whenSent(Ice.AsyncCallback cb) + protected new Ice.AsyncCallback finished(Ice.Exception ex) { - lock(monitor_) + if(childObserver_ != null) { - if(cb == null) - { - throw new System.ArgumentException("callback is null"); - } - if(sentCallback_ != null) - { - throw new System.ArgumentException("sent callback already set"); - } - sentCallback_ = cb; - if((state_ & StateSent) == 0) - { - return this; - } + childObserver_.failed(ex.ice_name()); + childObserver_.detach(); + childObserver_ = null; } - - if(sentSynchronously_) - { - try - { - sentCallback_(this); - } - catch(System.Exception ex) - { - warning(ex); - } - } - else - { - instance_.clientThreadPool().dispatch(() => - { - try - { - sentCallback_(this); - } - catch(System.Exception ex) - { - warning(ex); - } - }, cachedConnection_); - } - return this; + return base.finished(ex); } - public Ice.AsyncResult whenSent(Ice.SentCallback cb) - { - lock(monitor_) - { - if(cb == null) - { - throw new System.ArgumentException("callback is null"); - } - if(sentCallback_ != null) - { - throw new System.ArgumentException("sent callback already set"); - } - sentCallback_ = (Ice.AsyncResult result) => - { - cb(result.sentSynchronously()); - }; - if((state_ & StateSent) == 0) - { - return this; - } - } - - if(sentSynchronously_) - { - try - { - cb(true); - } - catch(System.Exception ex) - { - warning(ex); - } - } - else - { - instance_.clientThreadPool().dispatch(() => - { - try - { - cb(false); - } - catch(System.Exception ex) - { - warning(ex); - } - }, cachedConnection_); - } - return this; - } - - public Ice.AsyncResult whenCompletedWithAsyncCallback(Ice.AsyncCallback cb) - { - setCompletedCallback(cb); - return this; - } - - public Ice.AsyncResult whenCompleted(Ice.ExceptionCallback cb) - { - if(cb == null) - { - throw new System.ArgumentException("callback is null"); - } - lock(monitor_) - { - if(exceptionCallback_ != null) - { - throw new System.ArgumentException("callback already set"); - } - exceptionCallback_ = cb; - } - setCompletedCallback(getCompletedCallback()); - return this; - } + protected BasicStream os_; + protected Ice.Instrumentation.ChildInvocationObserver childObserver_; + } - public string getOperation() + // + // Base class for proxy based invocations. This class handles the + // retry for proxy invocations. It also ensures the child observer is + // correct notified of failures and make sure the retry task is + // correctly canceled when the invocation completes. + // + public class ProxyOutgoingAsyncBase : OutgoingAsyncBase, TimerTask + { + public static ProxyOutgoingAsyncBase check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation) { - return operation_; + return ProxyOutgoingAsyncBase.check<ProxyOutgoingAsyncBase>(r, prx, operation); } - public IceInternal.BasicStream ostr__ + public override Ice.ObjectPrx getProxy() { - get - { - return os_; - } + return proxy_; } - public bool wait() + public override Ice.AsyncCallback sent() { - lock(monitor_) - { - if((state_ & StateEndCalled) != 0) - { - throw new System.ArgumentException("end_ method called more than once"); - } - state_ |= StateEndCalled; - while((state_ & StateDone) == 0) - { - System.Threading.Monitor.Wait(monitor_); - } - if(exception_ != null) - { - throw exception_; - } - return (state_ & StateOK) != 0; - } + return sent(!proxy_.ice_isTwoway()); } - public void throwUserException() + public override Ice.AsyncCallback completed(Ice.Exception exc) { - try - { - is_.startReadEncaps(); - is_.throwException(null); - } - catch(Ice.UserException) + if(childObserver_ != null) { - is_.endReadEncaps(); - throw; + childObserver_.failed(exc.ice_name()); + childObserver_.detach(); + childObserver_ = null; } - } - virtual public void invokeExceptionAsync(Ice.Exception ex) - { // - // This is called when it's not safe to call the exception callback synchronously - // from this thread. Instead the exception callback is called asynchronously from - // the client thread pool. + // NOTE: at this point, synchronization isn't needed, no other threads should be + // calling on the callback. // try { - instance_.clientThreadPool().dispatch(() => - { - invokeException(ex); - }, cachedConnection_); + instance_.retryQueue().add(this, handleException(exc)); + return null; } - catch(Ice.CommunicatorDestroyedException) + catch(Ice.Exception ex) { - throw; // CommunicatorDestroyedException is the only exception that can propagate directly. + return finished(ex); // No retries, we're done } } - virtual public void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId, int sz) + public void retry() { - if(observer_ != null) - { - childObserver_ = observer_.getRemoteObserver(info, endpt, requestId, sz); - if(childObserver_ != null) - { - childObserver_.attach(); - } - } + invokeImpl(false); } - virtual public void attachCollocatedObserver(Ice.ObjectAdapter adapter, int requestId) + public virtual void abort(Ice.Exception ex) { - if(observer_ != null) + Debug.Assert(childObserver_ == null); + Ice.AsyncCallback cb = finished(ex); + if(cb != null) { - childObserver_ = observer_.getCollocatedObserver(adapter, - requestId, - os_.size() - IceInternal.Protocol.headerSize - 4); - if(childObserver_ != null) - { - childObserver_.attach(); - } + invokeCompletedAsync(cb); } - } - - public void invokeSentAsync(Ice.AsyncCallback callback) - { - // - // This is called when it's not safe to call the exception callback synchronously - // from this thread. Instead the exception callback is called asynchronously from - // the client thread pool. - // - if(callback != null) + else if(ex is Ice.CommunicatorDestroyedException) { - try - { - instance_.clientThreadPool().dispatch(() => - { - invokeSent(callback); - }, cachedConnection_); - } - catch(Ice.CommunicatorDestroyedException) - { - } + // + // If it's a communicator destroyed exception, don't swallow + // it but instead notify the user thread. Even if no callback + // was provided. + // + throw ex; } } - abstract internal void processRetry(); - - public static void check(OutgoingAsyncBase r, Ice.ObjectPrx prx, string operation) + public void runTimerTask() { - check(r, operation); - if(r.getProxy() != prx) - { - throw new System.ArgumentException("Proxy for call to end_" + operation + - " does not match proxy that was used to call corresponding begin_" + - operation + " method"); - } + cancel(new Ice.InvocationTimeoutException()); } - public static void check(OutgoingAsyncBase r, Ice.Connection con, string operation) + protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, string op, object cookie) : + base(prx.ice_getCommunicator(), prx.reference__().getInstance(), op, cookie) { - check(r, operation); - if(r.getConnection() != con) - { - throw new System.ArgumentException("Connection for call to end_" + operation + - " does not match connection that was used to call " + - "corresponding begin_" + operation + " method"); - } + proxy_ = prx; + mode_ = Ice.OperationMode.Normal; + _cnt = 0; + _sent = false; } - public static void check(OutgoingAsyncBase r, Ice.Communicator com, string operation) + protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, string op, object cookie, BasicStream os) : + base(prx.ice_getCommunicator(), prx.reference__().getInstance(), op, cookie, os) { - check(r, operation); - if(r.getCommunicator() != com) - { - throw new System.ArgumentException("Communicator for call to end_" + operation + - " does not match communicator that was used to call " + - "corresponding begin_" + operation + " method"); - } + proxy_ = prx; + mode_ = Ice.OperationMode.Normal; + _cnt = 0; + _sent = false; } - protected static void check(OutgoingAsyncBase r, string operation) + protected static T check<T>(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation) { - if(r == null) - { - throw new System.ArgumentException("AsyncResult == null"); - } - if(r.getOperation() != operation) + if(r != null && r.getProxy() != prx) { - throw new System.ArgumentException("Incorrect operation for end_" + operation + " method: " + - r.getOperation()); + throw new System.ArgumentException("Proxy for call to end_" + operation + + " does not match proxy that was used to call corresponding begin_" + + operation + " method"); } + return check<T>(r, operation); } - protected OutgoingAsyncBase(Ice.Communicator communicator, Instance instance, string op, object cookie) - { - communicator_ = communicator; - instance_ = instance; - operation_ = op; - // Lazy initialized when response is received. - //is_ = new IceInternal.BasicStream(instance); - os_ = new IceInternal.BasicStream(instance, Ice.Util.currentProtocolEncoding); - state_ = 0; - sentSynchronously_ = false; - exception_ = null; - _cookie = cookie; - } - - protected OutgoingAsyncBase(Ice.Communicator communicator, Instance instance, string op, object cookie, - BasicStream iss, BasicStream os) - { - communicator_ = communicator; - instance_ = instance; - operation_ = op; - is_ = iss; - os_ = os; - state_ = 0; - sentSynchronously_ = false; - exception_ = null; - _cookie = cookie; - } - - protected void setCompletedCallback(Ice.AsyncCallback cb) + protected void invokeImpl(bool userThread) { - lock(monitor_) + try { - if(cb == null) - { - throw new System.ArgumentException("callback is null"); - } - if(completedCallback_ != null) + if(userThread) { - throw new System.ArgumentException("callback already set"); - } - completedCallback_ = cb; - if((state_ & StateDone) == 0) - { - return; + int invocationTimeout = proxy_.reference__().getInvocationTimeout(); + if(invocationTimeout > 0) + { + instance_.timer().schedule(this, invocationTimeout); + } } - else if((getProxy() == null || getProxy().ice_isOneway()) && exception_ == null) + else // If not called from the user thread, it's called from the retry queue { - return; + checkCanceled(); // Cancellation exception aren't retriable + if(observer_ != null) + { + observer_.retried(); + } } - } - instance_.clientThreadPool().dispatch(() => + while(true) { try { - cb(this); + _sent = false; + handler_ = proxy_.getRequestHandler__(); + Ice.AsyncCallback sentCallback; + if(handler_.sendAsyncRequest(this, out sentCallback)) + { + if(userThread) + { + sentSynchronously_ = true; + if(sentCallback != null) + { + invokeSent(sentCallback); // Call from the user thread. + } + } + else + { + if(sentCallback != null) + { + invokeSentAsync(sentCallback); // Call from a client thread pool thread. + } + } + } + return; // We're done! } - catch(System.Exception ex) + catch(RetryException ex) { - warning(ex); + handleRetryException(ex); + } + catch(Ice.Exception ex) + { + if(childObserver_ != null) + { + childObserver_.failed(ex.ice_name()); + childObserver_.detach(); + childObserver_ = null; + } + int interval = handleException(ex); + if(interval > 0) + { + instance_.retryQueue().add(this, interval); + return; + } + else if(observer_ != null) + { + checkCanceled(); + observer_.retried(); + } } - }, cachedConnection_); - - } - - protected void invokeSent(Ice.AsyncCallback cb) - { - // - // Note: no need to change the state_ here, specializations are responsible for - // changing the state. - // - - if(cb != null) - { - try - { - cb(this); - } - catch(System.Exception ex) - { - warning(ex); - } - } - - if(observer_ != null) - { - Ice.ObjectPrx proxy = getProxy(); - if(proxy == null || !proxy.ice_isTwoway()) - { - observer_.detach(); - observer_ = null; } } - } - - protected void invokeCompleted(Ice.AsyncCallback cb) - { - // - // Note: no need to change the state_ here, specializations are responsible for - // changing the state. - // - - if(cb != null) + catch(Ice.Exception ex) { - try + // + // If called from the user thread we re-throw, the exception + // will be catch by the caller and abort() will be called. + // + if(userThread) { - cb(this); + throw ex; } - catch(System.Exception ex) + Ice.AsyncCallback cb = finished(ex); // No retries, we're done + if(cb != null) { - warning(ex); + invokeCompletedAsync(cb); } } - - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } } - protected void invokeException(Ice.Exception ex) + protected new Ice.AsyncCallback sent(bool done) { - Ice.AsyncCallback cb; - lock(monitor_) - { - state_ |= StateDone; - os_.resize(0, false); // Clear buffer now, instead of waiting for AsyncResult deallocation - exception_ = ex; - System.Threading.Monitor.PulseAll(monitor_); - if(waitHandle_ != null) - { - waitHandle_.Set(); - } - cb = completedCallback_; - } - - if(cb != null) + _sent = true; + if(done) { - try - { - cb(this); - } - catch(System.Exception exc) + if(proxy_.reference__().getInvocationTimeout() > 0) { - warning(exc); + instance_.timer().cancel(this); } } - - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } + return base.sent(done); } - protected virtual Ice.AsyncCallback getCompletedCallback() + protected new Ice.AsyncCallback finished(Ice.Exception ex) { - return (Ice.AsyncResult result) => { - Debug.Assert(exceptionCallback_ != null); - try - { - ((OutgoingAsyncBase)result).wait(); - } - catch(Ice.Exception ex) - { - exceptionCallback_(ex); - return; - } - }; - } - - protected void runTimerTask__() - { - IceInternal.RequestHandler handler; - lock(monitor_) - { - - handler = timeoutRequestHandler_; - timeoutRequestHandler_ = null; - } - - if(handler != null) + if(proxy_.reference__().getInvocationTimeout() > 0) { - handler.asyncRequestCanceled((OutgoingAsyncMessageCallback)this, new Ice.InvocationTimeoutException()); + instance_.timer().cancel(this); } + return base.finished(ex); } - protected void warning(System.Exception ex) + protected new Ice.AsyncCallback finished(bool ok) { - if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + if(proxy_.reference__().getInvocationTimeout() > 0) { - instance_.initializationData().logger.warning("exception raised by AMI callback:\n" + ex); + instance_.timer().cancel(this); } + return base.finished(ok); } - protected Ice.Communicator communicator_; - protected IceInternal.Instance instance_; - protected string operation_; - protected Ice.Connection cachedConnection_; - - protected readonly object monitor_ = new object(); - protected IceInternal.BasicStream is_; - protected IceInternal.BasicStream os_; - - protected IceInternal.RequestHandler timeoutRequestHandler_; - - protected const int StateOK = 0x1; - protected const int StateDone = 0x2; - protected const int StateSent = 0x4; - protected const int StateEndCalled = 0x8; - protected const int StateCachedBuffers = 0x10; - - protected int state_; - protected bool sentSynchronously_; - - // - // If true this AMI request is being used for a generated synchronous invocation. - // - protected bool synchronous_; - - protected Ice.Exception exception_; - protected EventWaitHandle waitHandle_; + protected virtual void handleRetryException(RetryException exc) + { + proxy_.setRequestHandler__(handler_, null); // Clear request handler and always retry. + } - protected Ice.Instrumentation.InvocationObserver observer_; - protected Ice.Instrumentation.ChildInvocationObserver childObserver_; + protected virtual int handleException(Ice.Exception exc) + { + return proxy_.handleException__(exc, handler_, mode_, _sent, ref _cnt); + } - protected Ice.AsyncCallback completedCallback_; - protected Ice.AsyncCallback sentCallback_; - protected Ice.ExceptionCallback exceptionCallback_; + protected Ice.ObjectPrxHelperBase proxy_; + protected RequestHandler handler_; + protected Ice.OperationMode mode_; - private object _cookie; + private int _cnt; + private bool _sent; } - abstract public class OutgoingAsync : OutgoingAsyncBase, OutgoingAsyncMessageCallback, TimerTask + public class OutgoingAsync : ProxyOutgoingAsyncBase { - public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie) : - base(prx.ice_getCommunicator(), prx.reference__().getInstance(), operation, cookie) + public new static OutgoingAsync check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation) + { + return ProxyOutgoingAsyncBase.check<OutgoingAsync>(r, prx, operation); + } + + public OutgoingAsync(Ice.ObjectPrx prx, string operation, object cookie) : + base((Ice.ObjectPrxHelperBase)prx, operation, cookie) { - _proxy = prx; - _encoding = Protocol.getCompatibleEncoding(_proxy.reference__().getEncoding()); + _encoding = Protocol.getCompatibleEncoding(proxy_.reference__().getEncoding()); + _is = null; } - public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie, BasicStream iss, - BasicStream os) : - base(prx.ice_getCommunicator(), prx.reference__().getInstance(), operation, cookie, iss, os) + public OutgoingAsync(Ice.ObjectPrx prx, string operation, object cookie, BasicStream istr, BasicStream ostr) : + base((Ice.ObjectPrxHelperBase)prx, operation, cookie, ostr) { - _proxy = prx; - _encoding = Protocol.getCompatibleEncoding(_proxy.reference__().getEncoding()); + _encoding = Protocol.getCompatibleEncoding(proxy_.reference__().getEncoding()); + _is = istr; } - public void prepare(string operation, Ice.OperationMode mode, Dictionary<string, string> context, - bool explicitContext, bool synchronous) + public void prepare(string operation, Ice.OperationMode mode, Dictionary<string, string> ctx, + bool explicitCtx, bool synchronous) { - handler_ = null; - _sent = false; - cnt_ = 0; - _mode = mode; - sentSynchronously_ = false; - synchronous_ = synchronous; + Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(proxy_.reference__().getProtocol())); - Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(_proxy.reference__().getProtocol())); + mode_ = mode; + _synchronous = synchronous; - if(explicitContext && context == null) + if(explicitCtx && ctx == null) { - context = emptyContext_; + ctx = _emptyContext; } + observer_ = ObserverHelper.get(proxy_, operation, ctx); - observer_ = ObserverHelper.get(_proxy, operation, context); - - switch(_proxy.reference__().getMode()) + switch(proxy_.reference__().getMode()) { case Reference.Mode.ModeTwoway: case Reference.Mode.ModeOneway: @@ -831,14 +409,14 @@ namespace IceInternal { try { - handler_ = _proxy.getRequestHandler__(); + handler_ = proxy_.getRequestHandler__(); handler_.prepareBatchRequest(os_); break; } catch(RetryException) { // Clear request handler and retry. - _proxy.setRequestHandler__(handler_, null); + proxy_.setRequestHandler__(handler_, null); } catch(Ice.LocalException ex) { @@ -847,7 +425,7 @@ namespace IceInternal observer_.failed(ex.ice_name()); } // Clear request handler - _proxy.setRequestHandler__(handler_, null); + proxy_.setRequestHandler__(handler_, null); handler_ = null; throw ex; } @@ -856,7 +434,7 @@ namespace IceInternal } } - Reference rf = _proxy.reference__(); + Reference rf = proxy_.reference__(); rf.getIdentity().write__(os_); @@ -878,12 +456,12 @@ namespace IceInternal os_.writeByte((byte)mode); - if(context != null) + if(ctx != null) { // // Explicit context // - Ice.ContextHelper.write(os_, context); + Ice.ContextHelper.write(os_, ctx); } else { @@ -904,422 +482,215 @@ namespace IceInternal } } - public override Ice.ObjectPrx getProxy() - { - return _proxy; - } - - public virtual bool send(Ice.ConnectionI connection, bool compress, bool response, out Ice.AsyncCallback sentCB) + public override bool send(Ice.ConnectionI con, bool compress, bool response, out Ice.AsyncCallback sentCB) { - // Store away the connection for passing to the dispatcher. - cachedConnection_ = connection; - return connection.sendAsyncRequest(this, compress, response, out sentCB); + cachedConnection_ = con; + return con.sendAsyncRequest(this, compress, response, out sentCB); } - public virtual bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCallback) + public override bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCB) { - // The BasicStream cannot be cached if the proxy is - // not a twoway or there is an invocation timeout set. - if(!_proxy.ice_isTwoway() || _proxy.reference__().getInvocationTimeout() > 0) + // The BasicStream cannot be cached if the proxy is not a twoway or there is an invocation timeout set. + if(!proxy_.ice_isTwoway() || proxy_.reference__().getInvocationTimeout() > 0) { // Disable caching by marking the streams as cached! state_ |= StateCachedBuffers; } - handler.invokeAsyncRequest(this, synchronous_, out sentCallback); - return false; + return handler.invokeAsyncRequest(this, _synchronous, out sentCB); } - public virtual Ice.AsyncCallback sent() + public override void abort(Ice.Exception ex) { - lock(monitor_) + Reference.Mode mode = proxy_.reference__().getMode(); + if(mode == Reference.Mode.ModeBatchOneway || mode == Reference.Mode.ModeBatchDatagram) { - bool alreadySent = (state_ & StateSent) != 0; - state_ |= StateSent; - _sent = true; - - Debug.Assert((state_ & StateDone) == 0); - if(!_proxy.ice_isTwoway()) + if(handler_ != null) { - if(childObserver_ != null) - { - childObserver_.detach(); - childObserver_ = null; - } - if(observer_ != null && sentCallback_ == null) - { - observer_.detach(); - observer_ = null; - } - if(timeoutRequestHandler_ != null) - { - instance_.timer().cancel(this); - timeoutRequestHandler_ = null; - } - state_ |= StateDone | StateOK; - //_os.resize(0, false); // Don't clear the buffer now, it's needed for the collocation optimization - if(waitHandle_ != null) - { - waitHandle_.Set(); - } + // + // If we didn't finish a batch oneway or datagram request, we + // must notify the connection about that we give up ownership + // of the batch stream. + // + handler_.abortBatchRequest(); } - System.Threading.Monitor.PulseAll(monitor_); - - return alreadySent ? null : sentCallback_; // Don't call the sent call is already sent. } - } - - public virtual new void invokeSent(Ice.AsyncCallback cb) - { - base.invokeSent(cb); - } - public virtual new void invokeCompleted(Ice.AsyncCallback cb) - { - base.invokeCompleted(cb); + base.abort(ex); } - public virtual void finished(Ice.Exception exc) + public void invoke() { - lock(monitor_) + Reference.Mode mode = proxy_.reference__().getMode(); + if(mode == Reference.Mode.ModeBatchOneway || mode == Reference.Mode.ModeBatchDatagram) { - Debug.Assert((state_ & StateDone) == 0); - if(childObserver_ != null) - { - childObserver_.failed(exc.ice_name()); - childObserver_.detach(); - childObserver_ = null; - } - if(timeoutRequestHandler_ != null) + if(handler_ != null) { - instance_.timer().cancel(this); - timeoutRequestHandler_ = null; + sentSynchronously_ = true; + handler_.finishBatchRequest(os_); + finished(true); } + return; // Don't call sent/completed callback for batch AMI requests } // - // NOTE: at this point, synchronization isn't needed, no other threads should be - // calling on the callback. + // NOTE: invokeImpl doesn't throw so this can be called from the + // try block with the catch block calling abort() in case of an + // exception. // - try - { - handleException(exc); - } - catch(Ice.Exception ex) - { - invokeException(ex); - } + invokeImpl(true); // userThread = true } - internal override void processRetry() + public Ice.AsyncCallback completed() { - invoke(false); - } + Debug.Assert(_is != null); // _is has been initialized prior to this call - public void - dispatchInvocationCancel(Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection) - { - OutgoingAsync self = this; - threadPool.dispatch(() => - { - self.finished(ex); - }, connection); - } + // + // NOTE: this method is called from ConnectionI.parseMessage + // with the connection locked. Therefore, it must not invoke + // any user callbacks. + // - public Ice.AsyncCallback finished() - { - Debug.Assert(_proxy.ice_isTwoway()); // Can only be called for twoways. + Debug.Assert(proxy_.ice_isTwoway()); // Can only be called for twoways. + + if(childObserver_ != null) + { + childObserver_.reply(_is.size() - Protocol.headerSize - 4); + childObserver_.detach(); + childObserver_ = null; + } byte replyStatus; try { - lock(monitor_) - { - Debug.Assert(exception_ == null && (state_ & StateDone) == 0); - Debug.Assert(is_ != null); + replyStatus = _is.readByte(); - if(childObserver_ != null) - { - childObserver_.reply(is_.size() - Protocol.headerSize - 4); - childObserver_.detach(); - childObserver_ = null; - } + switch(replyStatus) + { + case ReplyStatus.replyOK: + { + break; + } - if(timeoutRequestHandler_ != null) + case ReplyStatus.replyUserException: + { + if(observer_ != null) { - instance_.timer().cancel(this); - timeoutRequestHandler_ = null; + observer_.userException(); } + break; + } - replyStatus = is_.readByte(); + case ReplyStatus.replyObjectNotExist: + case ReplyStatus.replyFacetNotExist: + case ReplyStatus.replyOperationNotExist: + { + Ice.Identity id = new Ice.Identity(); + id.read__(_is); - switch(replyStatus) + // + // For compatibility with the old FacetPath. + // + string[] facetPath = _is.readStringSeq(); + string facet; + if(facetPath.Length > 0) { - case ReplyStatus.replyOK: - { - break; - } - - case ReplyStatus.replyUserException: - { - if(observer_ != null) - { - observer_.userException(); - } - break; - } - - case ReplyStatus.replyObjectNotExist: - case ReplyStatus.replyFacetNotExist: - case ReplyStatus.replyOperationNotExist: + if(facetPath.Length > 1) { - Ice.Identity id = new Ice.Identity(); - id.read__(is_); - - // - // For compatibility with the old FacetPath. - // - string[] facetPath = is_.readStringSeq(); - string facet; - if(facetPath.Length > 0) - { - if(facetPath.Length > 1) - { - throw new Ice.MarshalException(); - } - facet = facetPath[0]; - } - else - { - facet = ""; - } - - string operation = is_.readString(); - - Ice.RequestFailedException ex = null; - switch(replyStatus) - { - case ReplyStatus.replyObjectNotExist: - { - ex = new Ice.ObjectNotExistException(); - break; - } - - case ReplyStatus.replyFacetNotExist: - { - ex = new Ice.FacetNotExistException(); - break; - } - - case ReplyStatus.replyOperationNotExist: - { - ex = new Ice.OperationNotExistException(); - break; - } - - default: - { - Debug.Assert(false); - break; - } - } - - ex.id = id; - ex.facet = facet;; - ex.operation = operation; - throw ex; + throw new Ice.MarshalException(); } + facet = facetPath[0]; + } + else + { + facet = ""; + } - case ReplyStatus.replyUnknownException: - case ReplyStatus.replyUnknownLocalException: - case ReplyStatus.replyUnknownUserException: - { - string unknown = is_.readString(); + string operation = _is.readString(); - Ice.UnknownException ex = null; - switch(replyStatus) - { - case ReplyStatus.replyUnknownException: - { - ex = new Ice.UnknownException(); - break; - } - case ReplyStatus.replyUnknownLocalException: - { - ex = new Ice.UnknownLocalException(); - break; - } - case ReplyStatus.replyUnknownUserException: - { - ex = new Ice.UnknownUserException(); - break; - } - default: - { - Debug.Assert(false); - break; - } - } - ex.unknown = unknown; - throw ex; - } - - default: - { - throw new Ice.UnknownReplyStatusException(); - } + Ice.RequestFailedException ex = null; + switch(replyStatus) + { + case ReplyStatus.replyObjectNotExist: + { + ex = new Ice.ObjectNotExistException(); + break; } - state_ |= StateDone; - //os_.resize(0, false); // Clear buffer now, instead of waiting for AsyncResult deallocation - if(waitHandle_ != null) + case ReplyStatus.replyFacetNotExist: { - waitHandle_.Set(); + ex = new Ice.FacetNotExistException(); + break; } - if(replyStatus == ReplyStatus.replyOK) + + case ReplyStatus.replyOperationNotExist: { - state_ |= StateOK; + ex = new Ice.OperationNotExistException(); + break; } - System.Threading.Monitor.PulseAll(monitor_); - if(completedCallback_ == null) + default: { - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } - return null; + Debug.Assert(false); + break; } - return completedCallback_; - } - } - catch(Ice.LocalException exc) - { - // - // We don't call finished(exc) here because we don't want - // to invoke the completion callback. The completion - // callback is invoked by the connection is this method - // returns true. - // - try - { - handleException(exc); - return null; + } + + ex.id = id; + ex.facet = facet; + ex.operation = operation; + throw ex; } - catch(Ice.LocalException ex) + + case ReplyStatus.replyUnknownException: + case ReplyStatus.replyUnknownLocalException: + case ReplyStatus.replyUnknownUserException: { - lock(monitor_) - { - state_ |= StateDone; - exception_ = ex; - if(waitHandle_ != null) - { - waitHandle_.Set(); - } - System.Threading.Monitor.PulseAll(monitor_); + string unknown = _is.readString(); - if(completedCallback_ == null) - { - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } - return null; - } - return completedCallback_; + Ice.UnknownException ex = null; + switch(replyStatus) + { + case ReplyStatus.replyUnknownException: + { + ex = new Ice.UnknownException(); + break; } - } - } - } - public bool invoke(bool userThread) - { - Reference.Mode mode = _proxy.reference__().getMode(); - if(mode == Reference.Mode.ModeBatchOneway || mode == Reference.Mode.ModeBatchDatagram) - { - state_ |= StateDone | StateOK; - handler_.finishBatchRequest(os_); - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } - return true; - } + case ReplyStatus.replyUnknownLocalException: + { + ex = new Ice.UnknownLocalException(); + break; + } - while(true) - { - try - { - _sent = false; - handler_ = _proxy.getRequestHandler__(); - Ice.AsyncCallback sentCallback; - bool sent = handler_.sendAsyncRequest(this, out sentCallback); - if(sent) + case ReplyStatus.replyUnknownUserException: { - if(userThread) // Only set sentSynchronously_ If called synchronously by the user thread. - { - sentSynchronously_ = true; - invokeSent(sentCallback); - } - else - { - invokeSentAsync(sentCallback); - } + ex = new Ice.UnknownUserException(); + break; } - if(_proxy.ice_isTwoway() || !sent) + default: { - lock(monitor_) - { - if((state_ & StateDone) == 0) - { - int invocationTimeout = handler_.getReference().getInvocationTimeout(); - if(invocationTimeout > 0) - { - instance_.timer().schedule(this, invocationTimeout); - timeoutRequestHandler_ = handler_; - } - } - } + Debug.Assert(false); + break; + } } - } - catch(RetryException) - { - _proxy.setRequestHandler__(handler_, null); // Clear request handler and retry. - continue; + ex.unknown = unknown; + throw ex; } - catch(Ice.Exception ex) + + default: { - handleException(ex); + throw new Ice.UnknownReplyStatusException(); + } } - break; - } - return sentSynchronously_; - } - - public IceInternal.BasicStream startReadParams() - { - is_.startReadEncaps(); - return is_; - } - - public void endReadParams() - { - is_.endReadEncaps(); - } - - public void readEmptyParams() - { - is_.skipEmptyEncaps(); - } - public byte[] readParamEncaps() - { - Ice.EncodingVersion encoding; - return is_.readEncaps(out encoding); + return finished(replyStatus == ReplyStatus.replyOK); + } + catch(Ice.Exception ex) + { + return completed(ex); + } } public BasicStream startWriteParams(Ice.FormatType format) @@ -1350,326 +721,353 @@ namespace IceInternal } } - public IceInternal.BasicStream istr__ + public IceInternal.BasicStream startReadParams() { - get + _is.startReadEncaps(); + return _is; + } + + public void endReadParams() + { + _is.endReadEncaps(); + } + + public void readEmptyParams() + { + _is.skipEmptyEncaps(); + } + + public byte[] readParamEncaps() + { + Ice.EncodingVersion encoding; + return _is.readEncaps(out encoding); + } + + public BasicStream getIs() + { + // _is can already be initialized if the invocation is retried + if(_is == null) { - if(is_ == null) // _is can already be initialized if the invocation is retried - { - is_ = new IceInternal.BasicStream(instance_, Ice.Util.currentProtocolEncoding); - } - return is_; + _is = new IceInternal.BasicStream(instance_, Ice.Util.currentProtocolEncoding); } + return _is; } - public void - runTimerTask() + public void throwUserException() { - runTimerTask__(); + try + { + _is.startReadEncaps(); + _is.throwException(null); + } + catch(Ice.UserException ex) + { + _is.endReadEncaps(); + throw ex; + } } - public void - cacheMessageBuffers() + public override void cacheMessageBuffers() { - if(_proxy.reference__().getInstance().cacheMessageBuffers() > 0) + if(proxy_.reference__().getInstance().cacheMessageBuffers() > 0) { lock(this) { - if((state_ & StateCachedBuffers) > 0) { + if((state_ & StateCachedBuffers) > 0) + { return; } state_ |= StateCachedBuffers; } - if(is_ != null) + if(_is != null) { - is_.reset(); + _is.reset(); } os_.reset(); - _proxy.cacheMessageBuffers(is_, os_); + proxy_.cacheMessageBuffers(_is, os_); + + _is = null; + os_ = null; } } - override public void invokeExceptionAsync(Ice.Exception ex) + private Ice.EncodingVersion _encoding; + private BasicStream _is; + + // + // If true this AMI request is being used for a generated synchronous invocation. + // + private bool _synchronous; + + private static Dictionary<string, string> _emptyContext = new Dictionary<string, string>(); + } + + public class CommunicatorFlushBatch : IceInternal.AsyncResultI + { + public static CommunicatorFlushBatch check(Ice.AsyncResult r, Ice.Communicator com, string operation) { - if((state_ & StateDone) == 0 && handler_ != null) + if(r != null && r.getCommunicator() != com) { - // - // If we didn't finish a batch oneway or datagram request, we - // must notify the connection about that we give up ownership - // of the batch stream. - // - Reference.Mode mode = _proxy.reference__().getMode(); - if(mode == Reference.Mode.ModeBatchOneway || mode == Reference.Mode.ModeBatchDatagram) - { - handler_.abortBatchRequest(); - } + throw new System.ArgumentException("Communicator for call to end_" + operation + + " does not match communicator that was used to call " + + "corresponding begin_" + operation + " method"); } - base.invokeExceptionAsync(ex); + return AsyncResultI.check<CommunicatorFlushBatch>(r, operation); } + + public CommunicatorFlushBatch(Ice.Communicator communicator, Instance instance, string op, object cookie) : + base(communicator, instance, op, cookie) + { - private void handleException(Ice.Exception exc) + observer_ = ObserverHelper.get(instance, op); + + // + // _useCount is initialized to 1 to prevent premature callbacks. + // The caller must invoke ready() after all flush requests have + // been initiated. + // + _useCount = 1; + } + + public void flushConnection(Ice.ConnectionI con) { + lock(this) + { + ++_useCount; + } + try { - int interval = _proxy.handleException__(exc, handler_, _mode, _sent, ref cnt_); - if(observer_ != null) + Ice.AsyncCallback sentCB; + con.flushAsyncBatchRequests(new FlushBatch(this), out sentCB); + Debug.Assert(sentCB == null); + } + catch(Ice.LocalException ex) + { + doCheck(false); + throw ex; + } + } + + public void ready() + { + doCheck(true); + } + + private void doCheck(bool userThread) + { + lock(this) + { + Debug.Assert(_useCount > 0); + if(--_useCount > 0) { - observer_.retried(); // Invocation is being retried. + return; } + } - // - // Schedule the retry. Note that we always schedule the retry - // on the retry queue even if the invocation can be retried - // immediately. This is required because it might not be safe - // to retry from this thread (this is for instance called by - // finished(BasicStream) which is called with the connection - // locked. - // - instance_.retryQueue().add(this, interval); + Ice.AsyncCallback sentCB = sent(true); + if(userThread) + { + sentSynchronously_ = true; + if(sentCB != null) + { + invokeSent(sentCB); + } } - catch(Ice.Exception ex) + else { - if(observer_ != null) + if(sentCB != null) { - observer_.failed(ex.ice_name()); + invokeSentAsync(sentCB); } - throw ex; } } - private class TaskI : TimerTask + class FlushBatch : OutgoingAsyncBase { - internal TaskI(OutgoingAsync @out) + public FlushBatch(CommunicatorFlushBatch outAsync) : + base(outAsync.getCommunicator(), outAsync.instance_, outAsync.getOperation(), null) { - _out = @out; + _outAsync = outAsync; } - public void runTimerTask() + public override Ice.AsyncCallback sent() { - _out.runTimerTask__(); + if(childObserver_ != null) + { + childObserver_.detach(); + childObserver_ = null; + } + _outAsync.doCheck(false); + return null; + } + + public override Ice.AsyncCallback completed(Ice.Exception ex) + { + if(childObserver_ != null) + { + childObserver_.failed(ex.ice_name()); + childObserver_.detach(); + childObserver_ = null; + } + _outAsync.doCheck(false); + return null; + } + + protected override Ice.Instrumentation.InvocationObserver getObserver() + { + return _outAsync.getObserver(); } - private OutgoingAsync _out; - } - - private readonly Ice.ObjectPrxHelperBase _proxy; - private readonly Ice.EncodingVersion _encoding; - - private RequestHandler handler_; - private int cnt_; - private Ice.OperationMode _mode; - private bool _sent; - - private static Dictionary<string, string> emptyContext_ = new Dictionary<string, string>(); + private CommunicatorFlushBatch _outAsync; + }; + private int _useCount; } - abstract public class OutgoingAsync<T> : OutgoingAsync, Ice.AsyncResult<T> + + public class ConnectionFlushBatch : OutgoingAsyncBase { - public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie) : - base(prx, operation, cookie) + public static ConnectionFlushBatch check(Ice.AsyncResult r, Ice.Connection con, string operation) { + if(r != null && r.getConnection() != con) + { + throw new System.ArgumentException("Connection for call to end_" + operation + + " does not match connection that was used to call " + + "corresponding begin_" + operation + " method"); + } + return AsyncResultI.check<ConnectionFlushBatch>(r, operation); } - public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie, BasicStream iss, - BasicStream os) : - base(prx, operation, cookie, iss, os) + public ConnectionFlushBatch(Ice.ConnectionI con, Ice.Communicator communicator, Instance instance, string op, + object cookie) : + base(communicator, instance, op, cookie) { + _connection = con; } - new public Ice.AsyncResult<T> whenCompleted(Ice.ExceptionCallback excb) + public override Ice.Connection getConnection() { - base.whenCompleted(excb); - return this; + return _connection; } - virtual public Ice.AsyncResult<T> whenCompleted(T cb, Ice.ExceptionCallback excb) + public void invoke() { - if(cb == null && excb == null) + try { - throw new System.ArgumentException("callback is null"); + Ice.AsyncCallback sentCB; + if(_connection.flushAsyncBatchRequests(this, out sentCB)) + { + sentSynchronously_ = true; + if(sentCB != null) + { + invokeSent(sentCB); + } + } } - lock(monitor_) + catch(Ice.Exception ex) { - if(responseCallback_ != null || exceptionCallback_ != null) + Ice.AsyncCallback cb = completed(ex); + if(cb != null) { - throw new System.ArgumentException("callback already set"); + invokeCompletedAsync(cb); } - responseCallback_ = cb; - exceptionCallback_ = excb; } - setCompletedCallback(getCompletedCallback()); - return this; - } - - new public Ice.AsyncResult<T> whenSent(Ice.SentCallback cb) - { - base.whenSent(cb); - return this; } - protected T responseCallback_; + private Ice.ConnectionI _connection; } - public class TwowayOutgoingAsync<T> : OutgoingAsync<T> + public class ProxyFlushBatch : ProxyOutgoingAsyncBase { - public TwowayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyTwowayCallback<T> cb, - object cookie) : - base(prx, operation, cookie) - { - Debug.Assert(cb != null); - _completed = cb; - } - - public TwowayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyTwowayCallback<T> cb, - object cookie, BasicStream iss, BasicStream os) : - base(prx, operation, cookie, iss, os) + public new static ProxyFlushBatch check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation) { - Debug.Assert(cb != null); - _completed = cb; + return ProxyOutgoingAsyncBase.check<ProxyFlushBatch>(r, prx, operation); } - override protected Ice.AsyncCallback getCompletedCallback() - { - return (Ice.AsyncResult result) => { _completed(this, responseCallback_, exceptionCallback_); }; - } - - private ProxyTwowayCallback<T> _completed; - } - - public class OnewayOutgoingAsync<T> : OutgoingAsync<T> - { - public OnewayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyOnewayCallback<T> cb, - object cookie) : + public ProxyFlushBatch(Ice.ObjectPrxHelperBase prx, string operation, object cookie) : base(prx, operation, cookie) { - Debug.Assert(cb != null); - _completed = cb; + observer_ = ObserverHelper.get(prx, operation); } - public OnewayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyOnewayCallback<T> cb, - object cookie, BasicStream iss, BasicStream os) : - base(prx, operation, cookie, iss, os) + public override Ice.AsyncCallback sent() { - Debug.Assert(cb != null); - _completed = cb; + return sent(true); // Overriden because the flush is done even if using a two-way proxy. } - override protected Ice.AsyncCallback getCompletedCallback() + public override bool send(Ice.ConnectionI con, bool compress, bool response, out Ice.AsyncCallback sentCB) { - return (Ice.AsyncResult result) => { - try - { - IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)result; - ((Ice.ObjectPrxHelperBase)(outAsync__.getProxy())).end__(outAsync__, outAsync__.getOperation()); - } - catch(Ice.Exception ex__) - { - if(exceptionCallback_ != null) - { - exceptionCallback_(ex__); - } - return; - } - _completed(responseCallback_); - }; + cachedConnection_ = con; + return con.flushAsyncBatchRequests(this, out sentCB); } - private ProxyOnewayCallback<T> _completed; - } - - public class GetConnectionOutgoingAsync : OutgoingAsyncBase, OutgoingAsyncMessageCallback, - Ice.AsyncResult<Ice.Callback_Object_ice_getConnection> - { - public GetConnectionOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, - ProxyTwowayCallback<Ice.Callback_Object_ice_getConnection> cb, - object cookie) : - base(prx.ice_getCommunicator(), prx.reference__().getInstance(), operation, cookie) + public override bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCB) { - _proxy = prx; - _completed = cb; - _cnt = 0; - observer_ = ObserverHelper.get(prx, operation); + return handler.invokeAsyncBatchRequests(this, out sentCB); } public void invoke() { - while(true) - { - try - { - _handler = _proxy.getRequestHandler__(); - Ice.AsyncCallback sentCallback; - _handler.sendAsyncRequest(this, out sentCallback); - } - catch(RetryException) - { - _proxy.setRequestHandler__(_handler, null); - } - catch(Ice.Exception ex) - { - handleException(ex); - } - break; - } + Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(proxy_.reference__().getProtocol())); + invokeImpl(true); // userThread = true } - public bool send(Ice.ConnectionI connection, bool compress, bool response, out Ice.AsyncCallback sentCallback) + protected override void handleRetryException(RetryException exc) { - sent(); - sentCallback = null; - return false; + proxy_.setRequestHandler__(handler_, null); // Clear request handler + throw exc.get(); // No retries, we want to notify the user of potentially lost batch requests } - public bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCallback) + protected override int handleException(Ice.Exception exc) { - sent(); - sentCallback = null; - return false; + proxy_.setRequestHandler__(handler_, null); // Clear request handler + throw exc; // No retries, we want to notify the user of potentially lost batch requests } + } - public Ice.AsyncCallback sent() + public class ProxyGetConnection : ProxyOutgoingAsyncBase, Ice.AsyncResult<Ice.Callback_Object_ice_getConnection> + { + public new static ProxyGetConnection check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation) { - lock(monitor_) - { - state_ |= StateDone; - System.Threading.Monitor.PulseAll(monitor_); - } - invokeCompleted(completedCallback_); - return null; + return ProxyOutgoingAsyncBase.check<ProxyGetConnection>(r, prx, operation); } - new public void invokeSent(Ice.AsyncCallback cb) + public ProxyGetConnection(Ice.ObjectPrxHelperBase prx, string operation, + ProxyTwowayCallback<Ice.Callback_Object_ice_getConnection> cb, object cookie) : + base(prx, operation, cookie) { - // No sent callback + observer_ = ObserverHelper.get(prx, operation); + _completed = cb; } - public void finished(Ice.Exception exc) + public override bool send(Ice.ConnectionI con, bool compress, bool response, out Ice.AsyncCallback sentCB) { - try - { - handleException(exc); - } - catch(Ice.Exception ex) + sentCB = null; + cachedConnection_ = con; + Ice.AsyncCallback cb = finished(true); + if(cb != null) { - invokeExceptionAsync(ex); + invokeCompletedAsync(cb); } + return true; } - internal override void processRetry() + public override bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCB) { - invoke(); + sentCB = null; + Ice.AsyncCallback cb = finished(true); + if(cb != null) + { + invokeCompletedAsync(cb); + } + return true; } - public void - dispatchInvocationCancel(Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection) + public void invoke() { - GetConnectionOutgoingAsync self = this; - threadPool.dispatch(() => - { - self.finished(ex); - }, connection); + invokeImpl(true); // userThread = true } new public Ice.AsyncResult<Ice.Callback_Object_ice_getConnection> whenCompleted(Ice.ExceptionCallback excb) @@ -1685,7 +1083,7 @@ namespace IceInternal { throw new System.ArgumentException("callback is null"); } - lock(monitor_) + lock(this) { if(_responseCallback != null || exceptionCallback_ != null) { @@ -1704,391 +1102,127 @@ namespace IceInternal return this; } - public override Ice.ObjectPrx getProxy() - { - return _proxy; - } - protected override Ice.AsyncCallback getCompletedCallback() { return (Ice.AsyncResult result) => { _completed(this, _responseCallback, exceptionCallback_); }; } - private void handleException(Ice.Exception exc) - { - try - { - instance_.retryQueue().add(this, _proxy.handleException__(exc, _handler, Ice.OperationMode.Idempotent, - false, ref _cnt)); - if(observer_ != null) - { - observer_.retried(); // Invocation is being retried - } - } - catch(Ice.Exception ex) - { - if(observer_ != null) - { - observer_.failed(ex.ice_name()); - } - throw ex; - } - } - - private readonly Ice.ObjectPrxHelperBase _proxy; private ProxyTwowayCallback<Ice.Callback_Object_ice_getConnection> _completed; - private int _cnt; - private Ice.Callback_Object_ice_getConnection _responseCallback = null; - private RequestHandler _handler = null; } - public class BatchOutgoingAsync : OutgoingAsyncBase, OutgoingAsyncMessageCallback, TimerTask + public abstract class OutgoingAsync<T> : OutgoingAsync, Ice.AsyncResult<T> { - public BatchOutgoingAsync(Ice.Communicator communicator, Instance instance, string operation, object cookie) : - base(communicator, instance, operation, cookie) + public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie) : + base(prx, operation, cookie) { } - public bool send(Ice.ConnectionI connection, bool compress, bool response, out Ice.AsyncCallback sentCallback) + public OutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, object cookie, BasicStream iss, + BasicStream os) : + base(prx, operation, cookie, iss, os) { - // Store away the connection for passing to the dispatcher. - cachedConnection_ = connection; - return connection.flushAsyncBatchRequests(this, out sentCallback); } - public bool invokeCollocated(CollocatedRequestHandler handler, out Ice.AsyncCallback sentCallback) + new public Ice.AsyncResult<T> whenCompleted(Ice.ExceptionCallback excb) { - return handler.invokeAsyncBatchRequests(this, out sentCallback); + base.whenCompleted(excb); + return this; } - virtual public Ice.AsyncCallback sent() + virtual public Ice.AsyncResult<T> whenCompleted(T cb, Ice.ExceptionCallback excb) { - lock(monitor_) + if(cb == null && excb == null) { - Debug.Assert((state_ & (StateDone | StateOK | StateSent)) == 0); - state_ |= (StateDone | StateOK | StateSent); - //_os.resize(0, false); // Don't clear the buffer now, it's needed for the collocation optimization - if(childObserver_ != null) - { - childObserver_.detach(); - childObserver_ = null; - } - if(timeoutRequestHandler_ != null) - { - instance_.timer().cancel(this); - timeoutRequestHandler_ = null; - } - System.Threading.Monitor.PulseAll(monitor_); - if(waitHandle_ != null) - { - waitHandle_.Set(); - } - - if(sentCallback_ == null) - { - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } - } - return sentCallback_; + throw new System.ArgumentException("callback is null"); } - } - - public new void invokeSent(Ice.AsyncCallback cb) - { - base.invokeSent(cb); - } - - virtual public void finished(Ice.Exception exc) - { lock(this) { - if(childObserver_ != null) - { - childObserver_.failed(exc.ice_name()); - childObserver_.detach(); - childObserver_ = null; - } - if(timeoutRequestHandler_ != null) - { - instance_.timer().cancel(this); - timeoutRequestHandler_ = null; - } - } - invokeException(exc); - } - - internal override void processRetry() - { - Debug.Assert(false); // Retries are never scheduled. - } - - public void - dispatchInvocationCancel(Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection) - { - BatchOutgoingAsync self = this; - threadPool.dispatch(() => - { - self.finished(ex); - }, connection); - } - - public void - runTimerTask() - { - runTimerTask__(); - } - } - - public class ProxyBatchOutgoingAsync : BatchOutgoingAsync - { - public ProxyBatchOutgoingAsync(Ice.ObjectPrxHelperBase proxy, string operation, object cookie) : - base(proxy.ice_getCommunicator(), proxy.reference__().getInstance(), operation, cookie) - { - _proxy = proxy; - observer_ = ObserverHelper.get(proxy, operation); - } - - public void invoke() - { - Protocol.checkSupportedProtocol(_proxy.reference__().getProtocol()); - - RequestHandler handler = null; - try - { - handler = _proxy.getRequestHandler__(); - Ice.AsyncCallback sentCallback; - if(handler.sendAsyncRequest(this, out sentCallback)) - { - sentSynchronously_ = true; - if(sentCallback != null) - { - invokeSent(sentCallback); - } - } - else - { - lock(monitor_) - { - if((state_ & StateDone) == 0) - { - int invocationTimeout = handler.getReference().getInvocationTimeout(); - if(invocationTimeout > 0) - { - instance_.timer().schedule(this, invocationTimeout); - timeoutRequestHandler_ = handler; - } - } - } - } - } - catch(RetryException) - { - // - // Clear request handler but don't retry or throw. Retrying - // isn't useful, there were no batch requests associated with - // the proxy's request handler. - // - _proxy.setRequestHandler__(handler, null); - } - catch(Ice.Exception ex) - { - if(observer_ != null) + if(responseCallback_ != null || exceptionCallback_ != null) { - observer_.failed(ex.ice_name()); + throw new System.ArgumentException("callback already set"); } - _proxy.setRequestHandler__(handler, null); // Clear request handler - throw ex; // Throw to notify the user lthat batch requests were potentially lost. + responseCallback_ = cb; + exceptionCallback_ = excb; } + setCompletedCallback(getCompletedCallback()); + return this; } - public override Ice.ObjectPrx getProxy() + new public Ice.AsyncResult<T> whenSent(Ice.SentCallback cb) { - return _proxy; + base.whenSent(cb); + return this; } - private readonly Ice.ObjectPrxHelperBase _proxy; + protected T responseCallback_; } - public class ConnectionBatchOutgoingAsync : BatchOutgoingAsync + public class TwowayOutgoingAsync<T> : OutgoingAsync<T> { - public ConnectionBatchOutgoingAsync(Ice.ConnectionI con, Ice.Communicator communicator, Instance instance, - string operation, object cookie) : - base(communicator, instance, operation, cookie) + public TwowayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyTwowayCallback<T> cb, + object cookie) : + base(prx, operation, cookie) { - _connection = con; + Debug.Assert(cb != null); + _completed = cb; } - public void invoke() + public TwowayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyTwowayCallback<T> cb, + object cookie, BasicStream iss, BasicStream os) : + base(prx, operation, cookie, iss, os) { - Ice.AsyncCallback sentCallback; - if(_connection.flushAsyncBatchRequests(this, out sentCallback)) - { - sentSynchronously_ = true; - invokeSent(sentCallback); - } + Debug.Assert(cb != null); + _completed = cb; } - public override Ice.Connection getConnection() + override protected Ice.AsyncCallback getCompletedCallback() { - return _connection; + return (Ice.AsyncResult result) => { _completed(this, responseCallback_, exceptionCallback_); }; } - private Ice.ConnectionI _connection; + private ProxyTwowayCallback<T> _completed; } - public class CommunicatorBatchOutgoingAsync : OutgoingAsyncBase + public class OnewayOutgoingAsync<T> : OutgoingAsync<T> { - public CommunicatorBatchOutgoingAsync(Ice.Communicator communicator, Instance instance, String operation, - object cookie) : - base(communicator, instance, operation, cookie) - { - // - // _useCount is initialized to 1 to prevent premature callbacks. - // The caller must invoke ready() after all flush requests have - // been initiated. - // - _useCount = 1; - - // - // Assume all connections are flushed synchronously. - // - sentSynchronously_ = true; - - // - // Attach observer - // - observer_ = ObserverHelper.get(instance, operation); - } - - public void flushConnection(Ice.ConnectionI con) - { - lock(monitor_) - { - ++_useCount; - } - - - try - { - Ice.AsyncCallback sentCallback; - if(!con.flushAsyncBatchRequests(new BatchOutgoingAsyncI(this), out sentCallback)) - { - sentSynchronously_ = false; - } - Debug.Assert(sentCallback == null); - } - catch(Ice.LocalException) - { - check(false); - throw; - } - } - - public void ready() - { - check(true); - } - - internal override void processRetry() + public OnewayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyOnewayCallback<T> cb, + object cookie) : + base(prx, operation, cookie) { - Debug.Assert(false); // Retries are never scheduled. + Debug.Assert(cb != null); + _completed = cb; } - private void check(bool userThread) + public OnewayOutgoingAsync(Ice.ObjectPrxHelperBase prx, string operation, ProxyOnewayCallback<T> cb, + object cookie, BasicStream iss, BasicStream os) : + base(prx, operation, cookie, iss, os) { - Ice.AsyncCallback sentCallback = null; - lock(monitor_) - { - Debug.Assert(_useCount > 0); - if(--_useCount > 0) - { - return; - } - - state_ |= (StateDone | StateOK | StateSent); - os_.resize(0, false); // Clear buffer now, instead of waiting for AsyncResult deallocation - sentCallback = sentCallback_; - System.Threading.Monitor.PulseAll(monitor_); - if(waitHandle_ != null) - { - waitHandle_.Set(); - } - } - - // - // sentSynchronously_ is immutable here. - // - if(sentCallback == null) - { - if(observer_ != null) - { - observer_.detach(); - observer_ = null; - } - } - else - { - if(!sentSynchronously_ || !userThread) - { - invokeSentAsync(sentCallback); - } - else - { - invokeSent(sentCallback); - } - } + Debug.Assert(cb != null); + _completed = cb; } - class BatchOutgoingAsyncI : BatchOutgoingAsync + override protected Ice.AsyncCallback getCompletedCallback() { - public BatchOutgoingAsyncI(CommunicatorBatchOutgoingAsync outAsync) : - base(outAsync.communicator_, outAsync.instance_, outAsync.operation_, null) - { - _outAsync = outAsync; - } - - override public Ice.AsyncCallback sent() - { - if(childObserver_ != null) - { - childObserver_.detach(); - childObserver_ = null; - } - _outAsync.check(false); - return null; - } - - override public void finished(Ice.Exception ex) - { - if(childObserver_ != null) + return (Ice.AsyncResult result) => + { + try { - childObserver_.failed(ex.ice_name()); - childObserver_.detach(); - childObserver_ = null; + IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)result; + ((Ice.ObjectPrxHelperBase)(outAsync__.getProxy())).end__(outAsync__, outAsync__.getOperation()); } - _outAsync.check(false); - } - - override public void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, - int requestId, int sz) - { - if(_outAsync.observer_ != null) + catch(Ice.Exception ex__) { - childObserver_ = _outAsync.observer_.getRemoteObserver(info, endpt, requestId, sz); - if(childObserver_ != null) + if(exceptionCallback_ != null) { - childObserver_.attach(); + exceptionCallback_(ex__); } + return; } - } - - private CommunicatorBatchOutgoingAsync _outAsync; - }; + _completed(responseCallback_); + }; + } - private int _useCount; + private ProxyOnewayCallback<T> _completed; } } diff --git a/cs/src/Ice/Proxy.cs b/cs/src/Ice/Proxy.cs index fea163fbf6d..c0650815d2b 100644 --- a/cs/src/Ice/Proxy.cs +++ b/cs/src/Ice/Proxy.cs @@ -789,8 +789,7 @@ namespace Ice public bool end_ice_isA(AsyncResult r__) { - IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)r__; - IceInternal.OutgoingAsync.check(outAsync__, this, __ice_isA_name); + IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_isA_name); try { if(!outAsync__.wait()) @@ -841,11 +840,11 @@ namespace Ice IceInternal.BasicStream os__ = result__.startWriteParams(FormatType.DefaultFormat); os__.writeString(id); result__.endWriteParams(); - result__.invoke(true); + result__.invoke(); } catch(Ice.Exception ex__) { - result__.invokeExceptionAsync(ex__); + result__.abort(ex__); } return result__; } @@ -1014,11 +1013,11 @@ namespace Ice { result__.prepare(__ice_ping_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__); result__.writeEmptyParams(); - result__.invoke(true); + result__.invoke(); } catch(Ice.Exception ex__) { - result__.invokeExceptionAsync(ex__); + result__.abort(ex__); } return result__; } @@ -1083,8 +1082,7 @@ namespace Ice public string[] end_ice_ids(AsyncResult r__) { - IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)r__; - IceInternal.OutgoingAsync.check(outAsync__, this, __ice_ids_name); + IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_ids_name); try { if(!outAsync__.wait()) @@ -1132,11 +1130,11 @@ namespace Ice { result__.prepare(__ice_ids_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__); result__.writeEmptyParams(); - result__.invoke(true); + result__.invoke(); } catch(Ice.Exception ex__) { - result__.invokeExceptionAsync(ex__); + result__.abort(ex__); } return result__; } @@ -1211,8 +1209,7 @@ namespace Ice public string end_ice_id(AsyncResult r__) { - IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)r__; - IceInternal.OutgoingAsync.check(outAsync__, this, __ice_id_name); + IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_id_name); try { if(!outAsync__.wait()) @@ -1260,11 +1257,11 @@ namespace Ice { result__.prepare(__ice_id_name, OperationMode.Nonmutating, context__, explicitCtx__, synchronous__); result__.writeEmptyParams(); - result__.invoke(true); + result__.invoke(); } catch(Ice.Exception ex__) { - result__.invokeExceptionAsync(ex__); + result__.abort(ex__); } return result__; } @@ -1365,8 +1362,7 @@ namespace Ice public bool end_ice_invoke(out byte[] outEncaps, AsyncResult r__) { - IceInternal.OutgoingAsync outAsync__ = (IceInternal.OutgoingAsync)r__; - IceInternal.OutgoingAsync.check(outAsync__, this, __ice_invoke_name); + IceInternal.OutgoingAsync outAsync__ = IceInternal.OutgoingAsync.check(r__, this, __ice_invoke_name); try { bool ok = outAsync__.wait(); @@ -1410,11 +1406,11 @@ namespace Ice { result__.prepare(operation, mode, context__, explicitCtx__, synchronous__); result__.writeParamEncaps(inEncaps); - result__.invoke(true); + result__.invoke(); } catch(Ice.Exception ex__) { - result__.invokeExceptionAsync(ex__); + result__.abort(ex__); } return result__; } @@ -2126,60 +2122,63 @@ namespace Ice internal const string __ice_getConnection_name = "ice_getConnection"; - public AsyncResult begin_ice_getConnection(Ice.AsyncCallback cb__, object cookie__) + public AsyncResult begin_ice_getConnection(Ice.AsyncCallback cb, object cookie) { - return begin_ice_getConnectionInternal(cb__, cookie__); + return begin_ice_getConnectionInternal(cb, cookie); } - public Connection end_ice_getConnection(Ice.AsyncResult r__) + public Connection end_ice_getConnection(Ice.AsyncResult r) { - IceInternal.GetConnectionOutgoingAsync outAsync__ = (IceInternal.GetConnectionOutgoingAsync)r__; - IceInternal.GetConnectionOutgoingAsync.check(outAsync__, this, __ice_getConnection_name); - outAsync__.wait(); + IceInternal.ProxyGetConnection outAsync = + IceInternal.ProxyGetConnection.check(r, this, __ice_getConnection_name); + outAsync.wait(); return ice_getCachedConnection(); } - private AsyncResult<Callback_Object_ice_getConnection> begin_ice_getConnectionInternal(Ice.AsyncCallback cb__, - object cookie__) + private AsyncResult<Callback_Object_ice_getConnection> begin_ice_getConnectionInternal(Ice.AsyncCallback cb, + object cookie) { - IceInternal.GetConnectionOutgoingAsync result__ = - new IceInternal.GetConnectionOutgoingAsync(this, __ice_getConnection_name, - ice_getConnection_completed__, cookie__); - if(cb__ != null) + IceInternal.ProxyGetConnection result = new IceInternal.ProxyGetConnection(this, + __ice_getConnection_name, + ice_getConnection_completed__, + cookie); + if(cb != null) { - result__.whenCompletedWithAsyncCallback(cb__); + result.whenCompletedWithAsyncCallback(cb); } try { - result__.invoke(); + result.invoke(); } - catch(Ice.Exception ex__) + catch(Ice.Exception ex) { - result__.invokeExceptionAsync(ex__); + result.abort(ex); } - return result__; + return result; } - private void ice_getConnection_completed__(AsyncResult r__, - Callback_Object_ice_getConnection cb__, - Ice.ExceptionCallback excb__) + + + private void ice_getConnection_completed__(AsyncResult r, + Callback_Object_ice_getConnection cb, + Ice.ExceptionCallback excb) { - Connection ret__; + Connection ret; try { - ret__ = end_ice_getConnection(r__); + ret = end_ice_getConnection(r); } - catch(Ice.Exception ex__) + catch(Ice.Exception ex) { - if(excb__ != null) + if(excb != null) { - excb__(ex__); + excb(ex); } return; } - if(cb__ != null) + if(cb != null) { - cb__(ret__); + cb(ret); } } @@ -2227,30 +2226,31 @@ namespace Ice return begin_ice_flushBatchRequests(null, null); } - public AsyncResult begin_ice_flushBatchRequests(Ice.AsyncCallback cb__, object cookie__) + public AsyncResult begin_ice_flushBatchRequests(Ice.AsyncCallback cb, object cookie) { - IceInternal.ProxyBatchOutgoingAsync result__ = - new IceInternal.ProxyBatchOutgoingAsync(this, __ice_flushBatchRequests_name, cookie__); - if(cb__ != null) + IceInternal.ProxyFlushBatch result = new IceInternal.ProxyFlushBatch(this, + __ice_flushBatchRequests_name, + cookie); + if(cb != null) { - result__.whenCompletedWithAsyncCallback(cb__); + result.whenCompletedWithAsyncCallback(cb); } try { - result__.invoke(); + result.invoke(); } - catch(Ice.Exception ex__) + catch(Ice.Exception ex) { - result__.invokeExceptionAsync(ex__); + result.abort(ex); } - return result__; + return result; } - public void end_ice_flushBatchRequests(Ice.AsyncResult r__) + public void end_ice_flushBatchRequests(Ice.AsyncResult r) { - IceInternal.BatchOutgoingAsync outAsync__ = (IceInternal.BatchOutgoingAsync)r__; - IceInternal.BatchOutgoingAsync.check(outAsync__, this, __ice_flushBatchRequests_name); - outAsync__.wait(); + IceInternal.ProxyFlushBatch outAsync = + IceInternal.ProxyFlushBatch.check(r, this, __ice_flushBatchRequests_name); + outAsync.wait(); } /// <summary> @@ -2389,15 +2389,15 @@ namespace Ice } } - public void end__(AsyncResult result, string operation) + public void end__(AsyncResult r, string operation) { - IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)result; - IceInternal.OutgoingAsync.check(outAsync, this, operation); + IceInternal.ProxyOutgoingAsyncBase result = IceInternal.ProxyOutgoingAsyncBase.check(r, this, operation); try { - bool ok = outAsync.wait(); + bool ok = result.wait(); if(_reference.getMode() == IceInternal.Reference.Mode.ModeTwoway) { + IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)result; if(!ok) { try @@ -2414,9 +2414,9 @@ namespace Ice } finally { - if(outAsync != null) + if(result != null) { - outAsync.cacheMessageBuffers(); + result.cacheMessageBuffers(); } } } diff --git a/cs/src/Ice/ProxyFactory.cs b/cs/src/Ice/ProxyFactory.cs index 5f9995016f7..1ae060faeea 100644 --- a/cs/src/Ice/ProxyFactory.cs +++ b/cs/src/Ice/ProxyFactory.cs @@ -202,7 +202,7 @@ namespace IceInternal // // Don't retry invocation timeouts. // - if(ex is Ice.InvocationTimeoutException) + if(ex is Ice.InvocationTimeoutException || ex is Ice.InvocationCanceledException) { throw ex; } diff --git a/cs/src/Ice/RequestHandler.cs b/cs/src/Ice/RequestHandler.cs index 6cd82e4666a..6cef5d16d4b 100644 --- a/cs/src/Ice/RequestHandler.cs +++ b/cs/src/Ice/RequestHandler.cs @@ -12,7 +12,12 @@ using Ice.Instrumentation; namespace IceInternal { - public interface RequestHandler + public interface CancellationHandler + { + void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex); + } + + public interface RequestHandler : CancellationHandler { RequestHandler connect(); RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler); @@ -21,9 +26,7 @@ namespace IceInternal void finishBatchRequest(BasicStream @out); void abortBatchRequest(); - bool sendAsyncRequest(OutgoingAsyncMessageCallback @out, out Ice.AsyncCallback cb); - - void asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex); + bool sendAsyncRequest(OutgoingAsyncBase @out, out Ice.AsyncCallback cb); Reference getReference(); diff --git a/cs/src/Ice/RetryQueue.cs b/cs/src/Ice/RetryQueue.cs index cf549beb95d..4379ecdc0fd 100644 --- a/cs/src/Ice/RetryQueue.cs +++ b/cs/src/Ice/RetryQueue.cs @@ -12,9 +12,9 @@ namespace IceInternal using System.Collections.Generic; using System.Diagnostics; - public class RetryTask : TimerTask + public class RetryTask : TimerTask, CancellationHandler { - public RetryTask(RetryQueue retryQueue, OutgoingAsyncBase outAsync) + public RetryTask(RetryQueue retryQueue, ProxyOutgoingAsyncBase outAsync) { _retryQueue = retryQueue; _outAsync = outAsync; @@ -22,14 +22,7 @@ namespace IceInternal public void runTimerTask() { - try - { - _outAsync.processRetry(); - } - catch(Ice.LocalException ex) - { - _outAsync.invokeExceptionAsync(ex); - } + _outAsync.retry(); // // NOTE: this must be called last, destroy() blocks until all task @@ -40,13 +33,34 @@ namespace IceInternal _retryQueue.remove(this); } + public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) + { + Debug.Assert(_outAsync == outAsync); + if(_retryQueue.cancel(this)) + { + // + // We just retry the outgoing async now rather than marking it + // as finished. The retry will check for the cancellation + // exception and terminate appropriately the request. + // + _outAsync.retry(); + } + } + public void destroy() { - _outAsync.invokeExceptionAsync(new Ice.CommunicatorDestroyedException()); + try + { + _outAsync.abort(new Ice.CommunicatorDestroyedException()); + } + catch(Ice.CommunicatorDestroyedException) + { + // Abort can throw if there's no callback, just ignore in this case + } } private RetryQueue _retryQueue; - private OutgoingAsyncBase _outAsync; + private ProxyOutgoingAsyncBase _outAsync; } public class RetryQueue @@ -56,7 +70,7 @@ namespace IceInternal _instance = instance; } - public void add(OutgoingAsyncBase outAsync, int interval) + public void add(ProxyOutgoingAsyncBase outAsync, int interval) { lock(this) { @@ -67,11 +81,11 @@ namespace IceInternal RetryTask task = new RetryTask(this, outAsync); _instance.timer().schedule(task, interval); _requests.Add(task, null); + outAsync.cancelable(task); } } - public void - destroy() + public void destroy() { lock(this) { @@ -96,8 +110,7 @@ namespace IceInternal } } - public void - remove(RetryTask task) + public void remove(RetryTask task) { lock(this) { @@ -111,6 +124,23 @@ namespace IceInternal } } + public bool cancel(RetryTask task) + { + lock(this) + { + if(_requests.Remove(task)) + { + if(_instance == null && _requests.Count == 0) + { + // If we are destroying the queue, destroy is probably waiting on the queue to be empty. + System.Threading.Monitor.Pulse(this); + } + return _instance.timer().cancel(task); + } + return false; + } + } + private Instance _instance; private Dictionary<RetryTask, object> _requests = new Dictionary<RetryTask, object>(); } diff --git a/cs/test/Ice/ami/AllTests.cs b/cs/test/Ice/ami/AllTests.cs index 14099e70e6d..f449f3eaddf 100644 --- a/cs/test/Ice/ami/AllTests.cs +++ b/cs/test/Ice/ami/AllTests.cs @@ -1701,6 +1701,21 @@ public class AllTests : TestCommon.TestApp test(r.isSent()); test(r.IsCompleted); test(p.waitForBatch(2)); + + FlushCallback cb2 = new FlushCallback(cookie); + Ice.AsyncResult r2 = b1.begin_ice_flushBatchRequests( + (Ice.AsyncResult result) => + { + cb2.completedAsync(result); + }, cookie); + r2.whenSent( + (Ice.AsyncResult result) => + { + cb2.sentAsync(result); + }); + cb2.check(); + test(r2.isSent()); + test(r2.IsCompleted); } if(p.ice_getConnection() != null) @@ -2597,6 +2612,86 @@ public class AllTests : TestCommon.TestApp communicator.end_flushBatchRequests(r); } } + + if(p.ice_getConnection() != null) + { + Ice.AsyncResult r1 = null; + Ice.AsyncResult r2 = null; + testController.holdAdapter(); + try + { + Ice.AsyncResult r = null; + byte[] seq = new byte[10024]; + (new System.Random()).NextBytes(seq); + for(int i = 0; i < 200; ++i) // 2MB + { + r = p.begin_opWithPayload(seq); + } + + test(!r.isSent()); + + r1 = p.begin_ice_ping(); + r2 = p.begin_ice_id(); + r1.cancel(); + r2.cancel(); + try + { + p.end_ice_ping(r1); + test(false); + } + catch(Ice.InvocationCanceledException) + { + } + try + { + p.end_ice_id(r2); + test(false); + } + catch(Ice.InvocationCanceledException) + { + } + + } + finally + { + testController.resumeAdapter(); + p.ice_ping(); + test(!r1.isSent() && r1.isCompleted_()); + test(!r2.isSent() && r2.isCompleted_()); + } + + + testController.holdAdapter(); + try + { + r1 = p.begin_op(); + r2 = p.begin_ice_id(); + r1.waitForSent(); + r2.waitForSent(); + r1.cancel(); + r2.cancel(); + try + { + p.end_op(r1); + test(false); + } + catch(Ice.InvocationCanceledException) + { + } + try + { + p.end_ice_id(r2); + test(false); + } + catch(Ice.InvocationCanceledException) + { + } + } + finally + { + testController.resumeAdapter(); + } + } } WriteLine("ok"); diff --git a/cs/test/Ice/retry/AllTests.cs b/cs/test/Ice/retry/AllTests.cs index f3383ccc7d1..32c91dd55f8 100644 --- a/cs/test/Ice/retry/AllTests.cs +++ b/cs/test/Ice/retry/AllTests.cs @@ -96,7 +96,7 @@ public class AllTests : TestCommon.TestApp retry1.op(false); WriteLine("ok"); - int invocationCount = 3; + Instrumentation.testInvocationCount(3); Write("calling operation to kill connection with second proxy... "); Flush(); @@ -112,7 +112,7 @@ public class AllTests : TestCommon.TestApp catch(Ice.ConnectionLostException) { } - Instrumentation.testInvocationCount(invocationCount + 1); + Instrumentation.testInvocationCount(1); Instrumentation.testFailureCount(1); Instrumentation.testRetryCount(0); WriteLine("ok"); @@ -120,8 +120,8 @@ public class AllTests : TestCommon.TestApp Write("calling regular operation with first proxy again... "); Flush(); retry1.op(false); - Instrumentation.testInvocationCount(invocationCount + 2); - Instrumentation.testFailureCount(1); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(0); WriteLine("ok"); @@ -138,8 +138,8 @@ public class AllTests : TestCommon.TestApp test(false); }); cb.check(); - Instrumentation.testInvocationCount(invocationCount + 3); - Instrumentation.testFailureCount(1); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(0); WriteLine("ok"); @@ -155,8 +155,8 @@ public class AllTests : TestCommon.TestApp cb.called(); }); cb.check(); - Instrumentation.testInvocationCount(invocationCount + 4); - Instrumentation.testFailureCount(2); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); Instrumentation.testRetryCount(0); WriteLine("ok"); @@ -171,50 +171,51 @@ public class AllTests : TestCommon.TestApp test(false); }); cb.check(); - Instrumentation.testInvocationCount(invocationCount + 5); - Instrumentation.testFailureCount(2); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(0); WriteLine("ok"); Write("testing idempotent operation... "); - test(retry1.opIdempotent(0) == 4); - Instrumentation.testInvocationCount(invocationCount + 6); - Instrumentation.testFailureCount(2); + test(retry1.opIdempotent(4) == 4); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); + Instrumentation.testRetryCount(4); + test(retry1.end_opIdempotent(retry1.begin_opIdempotent(4)) == 4); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(4); - test(retry1.end_opIdempotent(retry1.begin_opIdempotent(4)) == 8); - Instrumentation.testInvocationCount(invocationCount + 7); - Instrumentation.testFailureCount(2); - Instrumentation.testRetryCount(8); WriteLine("ok"); Write("testing non-idempotent operation... "); try { - retry1.opNotIdempotent(8); + retry1.opNotIdempotent(); test(false); } catch(Ice.LocalException) { } - Instrumentation.testInvocationCount(invocationCount + 8); - Instrumentation.testFailureCount(3); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); try { - retry1.end_opNotIdempotent(retry1.begin_opNotIdempotent(9)); + retry1.end_opNotIdempotent(retry1.begin_opNotIdempotent()); test(false); } catch(Ice.LocalException) { } - Instrumentation.testInvocationCount(invocationCount + 9); - Instrumentation.testFailureCount(4); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); WriteLine("ok"); if(retry1.ice_getConnection() == null) { - invocationCount = invocationCount + 10; + Instrumentation.testInvocationCount(1); + Write("testing system exception... "); try { @@ -224,9 +225,9 @@ public class AllTests : TestCommon.TestApp catch(SystemFailure) { } - Instrumentation.testInvocationCount(invocationCount + 1); - Instrumentation.testFailureCount(5); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); try { retry1.end_opSystemException(retry1.begin_opSystemException()); @@ -235,12 +236,41 @@ public class AllTests : TestCommon.TestApp catch(SystemFailure) { } - Instrumentation.testInvocationCount(invocationCount + 2); - Instrumentation.testFailureCount(6); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); WriteLine("ok"); } + Write("testing invocation timeout and retries... "); + Flush(); + try + { + // No more than 2 retries before timeout kicks-in + ((Test.RetryPrx)retry1.ice_invocationTimeout(50)).opIdempotent(4); + test(false); + } + catch(Ice.InvocationTimeoutException) + { + Instrumentation.testRetryCount(2); + retry1.opIdempotent(-1); // Reset the counter + Instrumentation.testRetryCount(-1); + } + try + { + // No more than 2 retries before timeout kicks-in + Test.RetryPrx prx = (Test.RetryPrx)retry1.ice_invocationTimeout(50); + prx.end_opIdempotent(prx.begin_opIdempotent(4)); + test(false); + } + catch(Ice.InvocationTimeoutException) + { + Instrumentation.testRetryCount(2); + retry1.opIdempotent(-1); // Reset the counter + Instrumentation.testRetryCount(-1); + } + WriteLine("ok"); + #if SILVERLIGHT retry1.shutdown(); #else diff --git a/cs/test/Ice/retry/Client.cs b/cs/test/Ice/retry/Client.cs index 6edf7610149..3623ddddc8f 100644 --- a/cs/test/Ice/retry/Client.cs +++ b/cs/test/Ice/retry/Client.cs @@ -37,7 +37,7 @@ public class Client initData.properties = Ice.Util.createProperties(ref args); initData.observer = Instrumentation.getObserver(); - initData.properties.setProperty("Ice.RetryIntervals", "0 10 20 30"); + initData.properties.setProperty("Ice.RetryIntervals", "0 1 100 1"); // // This test kills connections, so we don't want warnings. diff --git a/cs/test/Ice/retry/Collocated.cs b/cs/test/Ice/retry/Collocated.cs index 191d4c0e6d7..a4e93bcc1d1 100644 --- a/cs/test/Ice/retry/Collocated.cs +++ b/cs/test/Ice/retry/Collocated.cs @@ -41,7 +41,7 @@ public class Collocated initData.properties = Ice.Util.createProperties(ref args); initData.observer = Instrumentation.getObserver(); - initData.properties.setProperty("Ice.RetryIntervals", "0 10 20 30"); + initData.properties.setProperty("Ice.RetryIntervals", "0 1 100 1"); // // This test kills connections, so we don't want warnings. diff --git a/cs/test/Ice/retry/Instrumentation.cs b/cs/test/Ice/retry/Instrumentation.cs index 169dc8e95fb..01a93ad3534 100644 --- a/cs/test/Ice/retry/Instrumentation.cs +++ b/cs/test/Ice/retry/Instrumentation.cs @@ -129,8 +129,14 @@ public class Instrumentation static private void testEqual(ref int value, int expected) { + if(expected < 0) + { + value = 0; + return; + } + int retry = 0; - while(retry < 100) + while(++retry < 100) { lock(mutex) { @@ -147,6 +153,7 @@ public class Instrumentation System.Diagnostics.Debug.Assert(false); throw new System.Exception(); } + value = 0; } static public void diff --git a/cs/test/Ice/retry/RetryI.cs b/cs/test/Ice/retry/RetryI.cs index 93d8987b997..024b4890b6b 100644 --- a/cs/test/Ice/retry/RetryI.cs +++ b/cs/test/Ice/retry/RetryI.cs @@ -30,9 +30,9 @@ public sealed class RetryI : Test.RetryDisp_ } } - public override int opIdempotent(int counter, Ice.Current current) + public override int opIdempotent(int nRetry, Ice.Current current) { - if(counter + nRetry > _counter) + if(nRetry > _counter) { ++_counter; if(current.con != null) @@ -43,18 +43,15 @@ public sealed class RetryI : Test.RetryDisp_ { throw new Ice.ConnectionLostException(); } + return 0; } - return _counter; + int counter = _counter; + _counter = 0; + return counter; } - public override void opNotIdempotent(int counter, Ice.Current current) + public override void opNotIdempotent(Ice.Current current) { - if(_counter != counter) - { - return; - } - - ++_counter; if(current.con != null) { current.con.close(true); @@ -76,5 +73,4 @@ public sealed class RetryI : Test.RetryDisp_ } private int _counter; - static readonly int nRetry = 4; } diff --git a/cs/test/Ice/retry/Test.ice b/cs/test/Ice/retry/Test.ice index 61297d94557..cd8c2595796 100644 --- a/cs/test/Ice/retry/Test.ice +++ b/cs/test/Ice/retry/Test.ice @@ -17,10 +17,10 @@ interface Retry void op(bool kill); idempotent int opIdempotent(int c); - void opNotIdempotent(int c); + void opNotIdempotent(); void opSystemException(); - void shutdown(); + idempotent void shutdown(); }; }; diff --git a/java/src/Ice/AsyncResult.java b/java/src/Ice/AsyncResult.java index df247ac9358..477dec5f5ac 100644 --- a/java/src/Ice/AsyncResult.java +++ b/java/src/Ice/AsyncResult.java @@ -16,6 +16,13 @@ package Ice; **/ public interface AsyncResult { + /** + * If not completed, cancels the request. This is a local + * operation, it won't cancel the request on the server side. The + * request won't be sent if it was waiting to be sent or the + * response will be ignored if it received after the callback. + **/ + public void cancel(); /** * Returns the communicator that sent the invocation. diff --git a/java/src/Ice/CommunicatorI.java b/java/src/Ice/CommunicatorI.java index 76d46baab6a..fab8cf98605 100644 --- a/java/src/Ice/CommunicatorI.java +++ b/java/src/Ice/CommunicatorI.java @@ -263,8 +263,10 @@ public final class CommunicatorI implements Communicator // This callback object receives the results of all invocations // of Connection.begin_flushBatchRequests. // - IceInternal.CommunicatorBatchOutgoingAsync result = - new IceInternal.CommunicatorBatchOutgoingAsync(this, _instance, __flushBatchRequests_name, cb); + IceInternal.CommunicatorFlushBatch result = new IceInternal.CommunicatorFlushBatch(this, + _instance, + __flushBatchRequests_name, + cb); connectionFactory.flushAsyncBatchRequests(result); adapterFactory.flushAsyncBatchRequests(result); @@ -282,8 +284,8 @@ public final class CommunicatorI implements Communicator public void end_flushBatchRequests(AsyncResult r) { - IceInternal.OutgoingAsyncBase ri = (IceInternal.OutgoingAsyncBase)r; - IceInternal.OutgoingAsyncBase.check(ri, this, __flushBatchRequests_name); + IceInternal.CommunicatorFlushBatch ri = + IceInternal.CommunicatorFlushBatch.check(r, this, __flushBatchRequests_name); ri.__wait(); } diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java index 73880042340..9ee6ac10121 100644 --- a/java/src/Ice/ConnectionI.java +++ b/java/src/Ice/ConnectionI.java @@ -9,7 +9,8 @@ package Ice; -public final class ConnectionI extends IceInternal.EventHandler implements Connection, IceInternal.ResponseHandler +public final class ConnectionI extends IceInternal.EventHandler + implements Connection, IceInternal.ResponseHandler, IceInternal.CancellationHandler { public interface StartCallback { @@ -373,8 +374,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne os.writeInt(requestId); } - out.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, os.size() - - IceInternal.Protocol.headerSize - 4); + out.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId); int status; try @@ -388,6 +388,11 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne throw (Ice.LocalException) _exception.fillInStackTrace(); } + if(response || (status & IceInternal.AsyncStatus.Queued) > 0) + { + out.cancelable(this); // Notify the request that it's cancelable + } + if(response) { // @@ -640,29 +645,21 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne private Ice.AsyncResult begin_flushBatchRequestsInternal(IceInternal.CallbackBase cb) { - IceInternal.ConnectionBatchOutgoingAsync result = new IceInternal.ConnectionBatchOutgoingAsync(this, - _communicator, _instance, __flushBatchRequests_name, cb); - try - { - result.__invoke(); - } - catch(LocalException __ex) - { - result.invokeExceptionAsync(__ex); - } - + IceInternal.ConnectionFlushBatch result = + new IceInternal.ConnectionFlushBatch(this, _communicator, _instance, __flushBatchRequests_name, cb); + result.invoke(); return result; } @Override public void end_flushBatchRequests(AsyncResult ir) { - IceInternal.OutgoingAsyncBase r = (IceInternal.OutgoingAsyncBase) ir; - IceInternal.OutgoingAsyncBase.check(r, this, __flushBatchRequests_name); + IceInternal.ConnectionFlushBatch r = + IceInternal.ConnectionFlushBatch.check(ir, this, __flushBatchRequests_name); r.__wait(); } - synchronized public int flushAsyncBatchRequests(IceInternal.BatchOutgoingAsync outAsync) + synchronized public int flushAsyncBatchRequests(IceInternal.OutgoingAsyncBase outAsync) { waitBatchStreamInUse(); @@ -687,11 +684,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _batchStream.pos(IceInternal.Protocol.headerSize); _batchStream.writeInt(_batchRequestNum); - outAsync.attachRemoteObserver(initConnectionInfo(), _endpoint, 0, _batchStream.size() - - IceInternal.Protocol.headerSize - 4); - _batchStream.swap(outAsync.getOs()); + outAsync.attachRemoteObserver(initConnectionInfo(), _endpoint, 0); + // // Send the batch stream. // @@ -708,6 +704,11 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne throw (Ice.LocalException) _exception.fillInStackTrace(); } + if((status & IceInternal.AsyncStatus.Queued) > 0) + { + outAsync.cancelable(this); // Notify the request that it's cancelable. + } + // // Reset the batch stream. // @@ -728,12 +729,8 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { if(callback != null) { - class CallbackWorkItem extends IceInternal.DispatchWorkItem + _threadPool.dispatch(new IceInternal.DispatchWorkItem(this) { - public CallbackWorkItem() - { - } - @Override public void run() { @@ -746,8 +743,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _logger.error("connection callback exception:\n" + ex + '\n' + _desc); } } - }; - _threadPool.dispatch(new CallbackWorkItem()); + }); } } else @@ -793,9 +789,14 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne return _monitor != null ? _monitor.getACM() : new ACM(0, ACMClose.CloseOff, ACMHeartbeat.HeartbeatOff); } - synchronized public boolean asyncRequestCanceled(IceInternal.OutgoingAsyncMessageCallback outAsync, - Ice.LocalException ex) + @Override + synchronized public void asyncRequestCanceled(IceInternal.OutgoingAsyncBase outAsync, Ice.LocalException ex) { + if(_state >= StateClosed) + { + return; // The request has already been or will be shortly notified of the failure. + } + java.util.Iterator<OutgoingMessage> it = _sendStreams.iterator(); while(it.hasNext()) { @@ -815,13 +816,16 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // it's fine if the OutgoingAsync output stream is released (and // as long as canceled requests cannot be retried). // - o.timedOut(); + o.canceled(); if(o != _sendStreams.getFirst()) { it.remove(); } - outAsync.dispatchInvocationCancel(ex, _threadPool, this); - return true; // We're done + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + return; } } @@ -834,12 +838,13 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(it2.next() == o) { it2.remove(); - outAsync.dispatchInvocationCancel(ex, _threadPool, this); - return true; // We're done. + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } } } } - return false; } @Override @@ -1469,7 +1474,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne for(OutgoingMessage p : _sendStreams) { - p.finished(_exception); + p.completed(_exception); if(p.requestId > 0) // Make sure finished isn't called twice. { _asyncRequests.remove(p.requestId); @@ -1480,7 +1485,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne for(IceInternal.OutgoingAsync p : _asyncRequests.values()) { - p.finished(_exception); + if(p.completed(_exception)) + { + p.invokeCompleted(); + } } _asyncRequests.clear(); @@ -2580,7 +2588,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels); info.requestId = info.stream.readInt(); IceInternal.OutgoingAsync outAsync = _asyncRequests.remove(info.requestId); - if(outAsync != null && outAsync.finished(info.stream)) + if(outAsync != null && outAsync.completed(info.stream)) { info.outAsync = outAsync; ++info.messageDispatchCount; @@ -2999,7 +3007,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne this.requestId = 0; } - OutgoingMessage(IceInternal.OutgoingAsyncMessageCallback out, IceInternal.BasicStream stream, boolean compress, + OutgoingMessage(IceInternal.OutgoingAsyncBase out, IceInternal.BasicStream stream, boolean compress, int requestId) { this.stream = stream; @@ -3008,7 +3016,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne this.requestId = requestId; } - public void timedOut() + public void canceled() { assert (outAsync != null); outAsync = null; @@ -3035,16 +3043,16 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne return false; } - public void finished(Ice.LocalException ex) + public void completed(Ice.LocalException ex) { - if(outAsync != null) + if(outAsync != null && outAsync.completed(ex)) { - outAsync.finished(ex); + outAsync.invokeCompleted(); } } public IceInternal.BasicStream stream; - public IceInternal.OutgoingAsyncMessageCallback outAsync; + public IceInternal.OutgoingAsyncBase outAsync; public boolean compress; public int requestId; boolean adopt; diff --git a/java/src/Ice/ObjectAdapterI.java b/java/src/Ice/ObjectAdapterI.java index 7538fc16ced..48ad2739082 100644 --- a/java/src/Ice/ObjectAdapterI.java +++ b/java/src/Ice/ObjectAdapterI.java @@ -13,8 +13,6 @@ import java.util.Map; public final class ObjectAdapterI implements ObjectAdapter { - - @Override public String getName() @@ -751,7 +749,7 @@ public final class ObjectAdapterI implements ObjectAdapter } public void - flushAsyncBatchRequests(IceInternal.CommunicatorBatchOutgoingAsync outAsync) + flushAsyncBatchRequests(IceInternal.CommunicatorFlushBatch outAsync) { java.util.List<IceInternal.IncomingConnectionFactory> f; synchronized(this) diff --git a/java/src/Ice/ObjectPrxHelperBase.java b/java/src/Ice/ObjectPrxHelperBase.java index 17b426c69cb..3f7bb25d9ad 100644 --- a/java/src/Ice/ObjectPrxHelperBase.java +++ b/java/src/Ice/ObjectPrxHelperBase.java @@ -286,11 +286,11 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable IceInternal.BasicStream __os = __result.startWriteParams(Ice.FormatType.DefaultFormat); __os.writeString(__id); __result.endWriteParams(); - __result.invoke(true); + __result.invoke(); } catch(Exception __ex) { - __result.invokeExceptionAsync(__ex); + __result.abort(__ex); } return __result; } @@ -305,8 +305,7 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable public final boolean end_ice_isA(AsyncResult __iresult) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase)__iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, __ice_isA_name); + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __ice_isA_name); try { if(!__result.__wait()) @@ -544,11 +543,11 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable { __result.prepare(__ice_ping_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); __result.writeEmptyParams(); - __result.invoke(true); + __result.invoke(); } catch(Exception __ex) { - __result.invokeExceptionAsync(__ex); + __result.abort(__ex); } return __result; } @@ -777,11 +776,11 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable { __result.prepare(__ice_ids_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); __result.writeEmptyParams(); - __result.invoke(true); + __result.invoke(); } catch(Exception __ex) { - __result.invokeExceptionAsync(__ex); + __result.abort(__ex); } return __result; } @@ -797,8 +796,7 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable public final String[] end_ice_ids(AsyncResult __iresult) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase) __iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, __ice_ids_name); + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __ice_ids_name); try { if(!__result.__wait()) @@ -1054,11 +1052,11 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable { __result.prepare(__ice_id_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); __result.writeEmptyParams(); - __result.invoke(true); + __result.invoke(); } catch(Exception __ex) { - __result.invokeExceptionAsync(__ex); + __result.abort(__ex); } return __result; } @@ -1073,8 +1071,7 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable public final String end_ice_id(AsyncResult __iresult) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase) __iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, __ice_id_name); + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __ice_id_name); try { if(!__result.__wait()) @@ -1444,11 +1441,11 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable { __result.prepare(operation, mode, __context, __explicitCtx, __synchronous); __result.writeParamEncaps(inParams); - __result.invoke(true); + __result.invoke(); } catch(Exception __ex) { - __result.invokeExceptionAsync(__ex); + __result.abort(__ex); } return __result; } @@ -1468,8 +1465,7 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable public final boolean end_ice_invoke(ByteSeqHolder outParams, AsyncResult __iresult) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase) __iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, __ice_invoke_name); + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __ice_invoke_name); try { boolean ok = __result.__wait(); @@ -2427,49 +2423,47 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable private static final String __ice_getConnection_name = "ice_getConnection"; private AsyncResult - begin_ice_getConnectionInternal(IceInternal.CallbackBase __cb) + begin_ice_getConnectionInternal(IceInternal.CallbackBase cb) { - IceInternal.GetConnectionOutgoingAsync __result = - new IceInternal.GetConnectionOutgoingAsync(this, __ice_getConnection_name, __cb); + IceInternal.ProxyGetConnection result = new IceInternal.ProxyGetConnection(this, __ice_getConnection_name, cb); try { - __result.__invoke(); + result.invoke(); } - catch(Exception __ex) + catch(Exception ex) { - __result.invokeExceptionAsync(__ex); + result.abort(ex); } - return __result; + return result; } @Override public Ice.Connection - end_ice_getConnection(AsyncResult __iresult) + end_ice_getConnection(AsyncResult r) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase)__iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, __ice_getConnection_name); - __result.__wait(); + IceInternal.ProxyGetConnection result = IceInternal.ProxyGetConnection.check(r, this, __ice_getConnection_name); + result.__wait(); return ice_getCachedConnection(); } - static public final void __ice_getConnection_completed(TwowayCallbackArg1<Ice.Connection> __cb, AsyncResult __result) + static public final void __ice_getConnection_completed(TwowayCallbackArg1<Ice.Connection> cb, AsyncResult result) { - Ice.Connection __ret = null; + Ice.Connection ret = null; try { - __ret = __result.getProxy().end_ice_getConnection(__result); + ret = result.getProxy().end_ice_getConnection(result); } - catch(LocalException __ex) + catch(LocalException ex) { - __cb.exception(__ex); + cb.exception(ex); return; } - catch(SystemException __ex) + catch(SystemException ex) { - __cb.exception(__ex); + cb.exception(ex); return; } - __cb.response(__ret); + cb.response(ret); } /** @@ -2578,28 +2572,26 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable private static final String __ice_flushBatchRequests_name = "ice_flushBatchRequests"; private AsyncResult - begin_ice_flushBatchRequestsInternal(IceInternal.CallbackBase __cb) + begin_ice_flushBatchRequestsInternal(IceInternal.CallbackBase cb) { - IceInternal.ProxyBatchOutgoingAsync __result = - new IceInternal.ProxyBatchOutgoingAsync(this, __ice_flushBatchRequests_name, __cb); + IceInternal.ProxyFlushBatch result = new IceInternal.ProxyFlushBatch(this, __ice_flushBatchRequests_name, cb); try { - __result.__invoke(); + result.invoke(); } - catch(Exception __ex) + catch(Exception ex) { - __result.invokeExceptionAsync(__ex); + result.abort(ex); } - return __result; + return result; } @Override public void - end_ice_flushBatchRequests(AsyncResult __iresult) + end_ice_flushBatchRequests(AsyncResult r) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase)__iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, __ice_flushBatchRequests_name); - __result.__wait(); + IceInternal.ProxyFlushBatch result = IceInternal.ProxyFlushBatch.check(r, this, __ice_flushBatchRequests_name); + result.__wait(); } /** @@ -2721,34 +2713,34 @@ public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable } public final void - __end(AsyncResult __iresult, String operation) + __end(AsyncResult r, String operation) { - IceInternal.OutgoingAsyncBase __result = (IceInternal.OutgoingAsyncBase)__iresult; - IceInternal.OutgoingAsyncBase.check(__result, this, operation); + IceInternal.ProxyOutgoingAsyncBase result = IceInternal.ProxyOutgoingAsyncBase.check(r, this, operation); try { - boolean ok = __result.__wait(); + boolean ok = result.__wait(); if(_reference.getMode() == IceInternal.Reference.ModeTwoway) { + IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)result; if(!ok) { try { - __result.throwUserException(); + outAsync.throwUserException(); } - catch(UserException __ex) + catch(UserException ex) { - throw new UnknownUserException(__ex.ice_name(), __ex); + throw new UnknownUserException(ex.ice_name(), ex); } } - __result.readEmptyParams(); + outAsync.readEmptyParams(); } } finally { - if(__result != null) + if(result != null) { - __result.cacheMessageBuffers(); + result.cacheMessageBuffers(); } } } diff --git a/java/src/IceInternal/AsyncResultI.java b/java/src/IceInternal/AsyncResultI.java new file mode 100644 index 00000000000..9d7445584fe --- /dev/null +++ b/java/src/IceInternal/AsyncResultI.java @@ -0,0 +1,475 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import Ice.AsyncResult; +import Ice.Communicator; +import Ice.CommunicatorDestroyedException; +import Ice.Connection; + +public class AsyncResultI implements AsyncResult +{ + @Override + public void cancel() + { + cancel(new Ice.InvocationCanceledException()); + } + + @Override + public Communicator getCommunicator() + { + return _communicator; + } + + @Override + public Connection getConnection() + { + return null; + } + + @Override + public Ice.ObjectPrx getProxy() + { + return null; + } + + @Override + public final boolean isCompleted() + { + synchronized(this) + { + return (_state & StateDone) > 0; + } + } + + @Override + public final void waitForCompleted() + { + synchronized(this) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + while((_state & StateDone) == 0) + { + try + { + this.wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + } + } + + @Override + public final boolean isSent() + { + synchronized(this) + { + return (_state & StateSent) > 0; + } + } + + @Override + public final void waitForSent() + { + synchronized(this) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + while((_state & StateSent) == 0 && _exception == null) + { + try + { + this.wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + } + } + + @Override + public final void throwLocalException() + { + synchronized(this) + { + if(_exception != null) + { + throw _exception; + } + } + } + + @Override + public final boolean sentSynchronously() + { + return _sentSynchronously; // No lock needed, immutable + } + + @Override + public final String getOperation() + { + return _operation; + } + + public final void invokeSent() + { + assert(_callback != null); + + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(_callback.getClass().getClassLoader()); + } + + try + { + _callback.__sent(this); + } + catch(RuntimeException ex) + { + warning(ex); + } + catch(AssertionError exc) + { + error(exc); + } + catch(OutOfMemoryError exc) + { + error(exc); + } + finally + { + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(null); + } + } + + if(_observer != null) + { + Ice.ObjectPrx proxy = getProxy(); + if(proxy == null || !proxy.ice_isTwoway()) + { + _observer.detach(); + _observer = null; + } + } + } + + public final void invokeCompleted() + { + assert(_callback != null); + + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(_callback.getClass().getClassLoader()); + } + + try + { + _callback.__completed(this); + } + catch(RuntimeException ex) + { + warning(ex); + } + catch(AssertionError exc) + { + error(exc); + } + catch(OutOfMemoryError exc) + { + error(exc); + } + finally + { + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(null); + } + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + } + + public final void invokeCompletedAsync() + { + // + // CommunicatorDestroyedCompleted is the only exception that can propagate directly + // from this method. + // + _instance.clientThreadPool().dispatch(new DispatchWorkItem(_cachedConnection) + { + @Override + public void run() + { + invokeCompleted(); + } + }); + } + + public void cancelable(final CancellationHandler handler) + { + synchronized(this) + { + if(_cancellationException == null) + { + _cancellationHandler = handler; + return; + } + } + handler.asyncRequestCanceled((OutgoingAsyncBase)this, _cancellationException); + } + + public final boolean __wait() + { + try + { + synchronized(this) + { + if((_state & StateEndCalled) > 0) + { + throw new IllegalArgumentException("end_ method called more than once"); + } + + _state |= StateEndCalled; + if(Thread.interrupted()) + { + throw new InterruptedException(); + } + while((_state & StateDone) == 0) + { + this.wait(); + } + + if(_exception != null) + { + throw (Ice.Exception)_exception.fillInStackTrace(); + } + + return (_state & StateOK) > 0; + } + } + catch(InterruptedException ex) + { + Ice.OperationInterruptedException exc = new Ice.OperationInterruptedException(); + cancel(exc); // Must be called outside the synchronization + throw exc; + } + } + + public void cacheMessageBuffers() + { + } + + protected AsyncResultI(Communicator communicator, Instance instance, String op, CallbackBase del) + { + _communicator = communicator; + _instance = instance; + _operation = op; + _state = 0; + _sentSynchronously = false; + _exception = null; + _callback = del; + } + + protected boolean sent(boolean done) + { + synchronized(this) + { + assert(_exception == null); + + boolean alreadySent = (_state & StateSent) != 0; + _state |= StateSent; + if(done) + { + _state |= StateDone | StateOK; + _cancellationHandler = null; + if(_observer != null && (_callback == null || !_callback.__hasSentCallback())) + { + _observer.detach(); + _observer = null; + } + + // + // For oneway requests after the data has been sent + // the buffers can be reused unless this is a + // collocated invocation. For collocated invocations + // the buffer won't be reused because it has already + // been marked as cached in invokeCollocated. + // + cacheMessageBuffers(); + } + this.notifyAll(); + return !alreadySent && _callback != null && _callback.__hasSentCallback(); + } + } + + protected boolean finished(boolean ok) + { + synchronized(this) + { + _state |= StateDone; + if(ok) + { + _state |= StateOK; + } + _cancellationHandler = null; + if(_callback == null) + { + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + } + this.notifyAll(); + return _callback != null; + } + } + + protected boolean finished(Ice.Exception ex) + { + synchronized(this) + { + _state |= StateDone; + _exception = ex; + _cancellationHandler = null; + if(_observer != null) + { + _observer.failed(ex.ice_name()); + } + if(_callback == null) + { + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + } + this.notifyAll(); + return _callback != null; + } + } + + protected final void invokeSentAsync() + { + // + // This is called when it's not safe to call the sent callback + // synchronously from this thread. Instead the exception callback + // is called asynchronously from the client thread pool. + // + try + { + _instance.clientThreadPool().dispatch(new DispatchWorkItem(_cachedConnection) + { + @Override + public void run() + { + invokeSent(); + } + }); + } + catch(CommunicatorDestroyedException exc) + { + } + } + + protected void cancel(Ice.LocalException ex) + { + synchronized(this) + { + _cancellationException = ex; + if(_cancellationHandler == null) + { + return; + } + } + _cancellationHandler.asyncRequestCanceled((OutgoingAsyncBase)this, ex); + } + + protected void checkCanceled() + { + synchronized(this) + { + if(_cancellationException != null) + { + throw _cancellationException; + } + } + } + + protected Ice.Instrumentation.InvocationObserver getObserver() + { + return _observer; + } + + protected static void check(AsyncResult r, String operation) + { + if(r == null) + { + throw new IllegalArgumentException("AsyncResult == null"); + } + else if(r.getOperation() != operation) // Do NOT use equals() here - we are comparing reference equality + { + throw new IllegalArgumentException("Incorrect operation for end_" + operation + " method: " + + r.getOperation()); + } + } + + private final void warning(RuntimeException ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + { + String s = "exception raised by AMI callback:\n" + Ex.toString(ex); + _instance.initializationData().logger.warning(s); + } + } + + private final void error(Error error) + { + String s = "error raised by AMI callback:\n" + Ex.toString(error); + _instance.initializationData().logger.error(s); + } + + protected final Instance _instance; + protected Ice.Instrumentation.InvocationObserver _observer; + protected Connection _cachedConnection; + protected boolean _sentSynchronously; + + private final Communicator _communicator; + private final String _operation; + private final CallbackBase _callback; + + private Ice.Exception _exception; + + private CancellationHandler _cancellationHandler; + private Ice.LocalException _cancellationException; + + protected static final byte StateOK = 0x1; + protected static final byte StateDone = 0x2; + protected static final byte StateSent = 0x4; + protected static final byte StateEndCalled = 0x8; + protected static final byte StateCachedBuffers = 0x10; + protected byte _state; +} diff --git a/java/src/IceInternal/BatchOutgoingAsync.java b/java/src/IceInternal/BatchOutgoingAsync.java deleted file mode 100644 index ff8ba712185..00000000000 --- a/java/src/IceInternal/BatchOutgoingAsync.java +++ /dev/null @@ -1,117 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -package IceInternal; - -abstract public class BatchOutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMessageCallback -{ - BatchOutgoingAsync(Ice.Communicator communicator, Instance instance, String operation, CallbackBase callback) - { - super(communicator, instance, operation, callback); - } - - @Override - public int - send(Ice.ConnectionI connection, boolean compress, boolean response) - { - _cachedConnection = connection; - return connection.flushAsyncBatchRequests(this); - } - - @Override - public int - invokeCollocated(CollocatedRequestHandler handler) - { - return handler.invokeAsyncBatchRequests(this); - } - - @Override - public boolean - sent() - { - synchronized(_monitor) - { - _state |= StateDone | StateOK | StateSent; - //_os.resize(0, false); // Don't clear the buffer now, it's needed for the collocation optimization - if(_childObserver != null) - { - _childObserver.detach(); - _childObserver = null; - } - if(_timeoutRequestHandler != null) - { - _future.cancel(false); - _future = null; - _timeoutRequestHandler = null; - } - _monitor.notifyAll(); - - if(_callback == null || !_callback.__hasSentCallback()) - { - if(_observer != null) - { - _observer.detach(); - _observer = null; - } - return false; - } - return true; - } - } - - @Override - public void - invokeSent() - { - invokeSentInternal(); - } - - @Override - public void - finished(Ice.Exception exc) - { - synchronized(_monitor) - { - if(_childObserver != null) - { - _childObserver.failed(exc.ice_name()); - _childObserver.detach(); - _childObserver = null; - } - if(_timeoutRequestHandler != null) - { - _future.cancel(false); - _future = null; - _timeoutRequestHandler = null; - } - } - invokeException(exc); - } - - @Override - public void - processRetry() - { - assert(false); // Retries are never scheduled - } - - @Override - public void - dispatchInvocationCancel(final Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection) - { - threadPool.dispatch(new DispatchWorkItem(connection) - { - @Override - public void run() - { - BatchOutgoingAsync.this.finished(ex); - } - }); - } -} diff --git a/java/src/IceInternal/CancellationHandler.java b/java/src/IceInternal/CancellationHandler.java new file mode 100644 index 00000000000..0182f403cb4 --- /dev/null +++ b/java/src/IceInternal/CancellationHandler.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface CancellationHandler +{ + void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex); +} diff --git a/java/src/IceInternal/CollocatedRequestHandler.java b/java/src/IceInternal/CollocatedRequestHandler.java index 8de4a93ebc4..48d7bfa5b7d 100644 --- a/java/src/IceInternal/CollocatedRequestHandler.java +++ b/java/src/IceInternal/CollocatedRequestHandler.java @@ -13,8 +13,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler { private class InvokeAllAsync extends DispatchWorkItem { - private InvokeAllAsync(OutgoingAsyncMessageCallback outAsync, BasicStream os, int requestId, int invokeNum, - boolean batch) + private InvokeAllAsync(OutgoingAsyncBase outAsync, BasicStream os, int requestId, int invokeNum, boolean batch) { _outAsync = outAsync; _os = os; @@ -32,7 +31,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler } } - private final OutgoingAsyncMessageCallback _outAsync; + private final OutgoingAsyncBase _outAsync; private BasicStream _os; private final int _requestId; private final int _invokeNum; @@ -186,14 +185,14 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler @Override public int - sendAsyncRequest(OutgoingAsyncMessageCallback outAsync) + sendAsyncRequest(OutgoingAsyncBase outAsync) { return outAsync.invokeCollocated(this); } @Override - synchronized public boolean - asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex) + synchronized public void + asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) { Integer requestId = _sendAsyncRequests.get(outAsync); if(requestId != null) @@ -203,8 +202,11 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler _asyncRequests.remove(requestId); } _sendAsyncRequests.remove(outAsync); - outAsync.dispatchInvocationCancel(ex, _reference.getInstance().clientThreadPool(), null); - return true; // We're done + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + return; } if(outAsync instanceof OutgoingAsync) @@ -216,12 +218,14 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler if(e.getValue() == o) { _asyncRequests.remove(e.getKey()); - outAsync.dispatchInvocationCancel(ex, _reference.getInstance().clientThreadPool(), null); - return true; // We're done + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + return; } } } - return false; } @Override @@ -242,9 +246,13 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler } outAsync = _asyncRequests.remove(requestId); + if(outAsync != null && !outAsync.completed(os)) + { + outAsync = null; + } } - if(outAsync != null && outAsync.finished(os)) + if(outAsync != null) { outAsync.invokeCompleted(); } @@ -271,18 +279,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler public void invokeException(int requestId, Ice.LocalException ex, int invokeNum) { - if(requestId > 0) - { - OutgoingAsync outAsync = null; - synchronized(this) - { - outAsync = _asyncRequests.remove(requestId); - } - if(outAsync != null) - { - outAsync.finished(ex); - } - } + handleException(requestId, ex); _adapter.decDirectCount(); } @@ -307,7 +304,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler return null; } - void invokeAsyncRequest(OutgoingAsync outAsync, boolean synchronous) + int invokeAsyncRequest(OutgoingAsync outAsync, boolean synchronous) { int requestId = 0; if((_reference.getInstance().queueRequests() || _reference.getInvocationTimeout() > 0) || _response) @@ -323,6 +320,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler { _sendAsyncRequests.put(outAsync, requestId); } + outAsync.cancelable(this); } } @@ -355,9 +353,10 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler { _adapter.getThreadPool().dispatch(new InvokeAllAsync(outAsync, outAsync.getOs(), requestId, 1, false)); } + return AsyncStatus.Queued; } - int invokeAsyncBatchRequests(BatchOutgoingAsync outAsync) + int invokeAsyncBatchRequests(OutgoingAsyncBase outAsync) { int invokeNum; synchronized(this) @@ -370,6 +369,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler if(_reference.getInstance().queueRequests() || _reference.getInvocationTimeout() > 0) { _sendAsyncRequests.put(outAsync, 0); + outAsync.cancelable(this); } assert(!_batchStream.isEmpty()); @@ -404,7 +404,7 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler } private boolean - sentAsync(final OutgoingAsyncMessageCallback outAsync) + sentAsync(final OutgoingAsyncBase outAsync) { if(_reference.getInstance().queueRequests() || _reference.getInvocationTimeout() > 0) { @@ -511,10 +511,15 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler synchronized(this) { outAsync = _asyncRequests.remove(requestId); + if(outAsync != null && !outAsync.completed(ex)) + { + outAsync = null; + } } + if(outAsync != null) { - outAsync.finished(ex); + outAsync.invokeCompleted(); } } @@ -567,8 +572,8 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler // A map of outstanding requests that can be canceled. A request // can be canceled if it has an invocation timeout, or we support // interrupts. - private java.util.Map<OutgoingAsyncMessageCallback, Integer> _sendAsyncRequests = - new java.util.HashMap<OutgoingAsyncMessageCallback, Integer>(); + private java.util.Map<OutgoingAsyncBase, Integer> _sendAsyncRequests = + new java.util.HashMap<OutgoingAsyncBase, Integer>(); private java.util.Map<Integer, OutgoingAsync> _asyncRequests = new java.util.HashMap<Integer, OutgoingAsync>(); diff --git a/java/src/IceInternal/CommunicatorBatchOutgoingAsync.java b/java/src/IceInternal/CommunicatorFlushBatch.java index ab1854cbce1..19e55ecc91c 100644 --- a/java/src/IceInternal/CommunicatorBatchOutgoingAsync.java +++ b/java/src/IceInternal/CommunicatorFlushBatch.java @@ -16,12 +16,29 @@ import java.util.concurrent.RejectedExecutionException; import Ice.CommunicatorDestroyedException; -public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase +public class CommunicatorFlushBatch extends IceInternal.AsyncResultI { - public CommunicatorBatchOutgoingAsync(Ice.Communicator communicator, Instance instance, String operation, - CallbackBase callback) + public static CommunicatorFlushBatch check(Ice.AsyncResult r, Ice.Communicator com, String operation) { - super(communicator, instance, operation, callback); + check(r, operation); + if(!(r instanceof CommunicatorFlushBatch)) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + if(r.getCommunicator() != com) + { + throw new IllegalArgumentException("Communicator for call to end_" + operation + + " does not match communicator that was used to call corresponding " + + "begin_" + operation + " method"); + } + return (CommunicatorFlushBatch)r; + } + + public CommunicatorFlushBatch(Ice.Communicator communicator, Instance instance, String op, CallbackBase callback) + { + super(communicator, instance, op, callback); + + _observer = ObserverHelper.get(instance, op); // // _useCount is initialized to 1 to prevent premature callbacks. @@ -29,34 +46,22 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase // been initiated. // _useCount = 1; - - // - // Assume all connections are flushed synchronously. - // - _sentSynchronously = true; - - // - // Attach observer - // - _observer = ObserverHelper.get(instance, operation); } public void flushConnection(final Ice.ConnectionI con) { - class BatchOutgoingAsyncI extends BatchOutgoingAsync + class FlushBatch extends OutgoingAsyncBase { - public - BatchOutgoingAsyncI() + public FlushBatch() { - super(CommunicatorBatchOutgoingAsync.this._communicator, - CommunicatorBatchOutgoingAsync.this._instance, - CommunicatorBatchOutgoingAsync.this._operation, + super(CommunicatorFlushBatch.this.getCommunicator(), + CommunicatorFlushBatch.this._instance, + CommunicatorFlushBatch.this.getOperation(), null); } @Override - public boolean - sent() + public boolean sent() { if(_childObserver != null) { @@ -69,8 +74,7 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase // TODO: MJN: This is missing a test. @Override - public void - finished(Ice.Exception ex) + public boolean completed(Ice.Exception ex) { if(_childObserver != null) { @@ -79,37 +83,23 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase _childObserver = null; } doCheck(false); + return false; } - @Override - public void - attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId, int size) - { - if(CommunicatorBatchOutgoingAsync.this._observer != null) - { - _childObserver = CommunicatorBatchOutgoingAsync.this._observer.getRemoteObserver(info, endpt, - requestId, size); - if(_childObserver != null) - { - _childObserver.attach(); - } - } - } - - @Override - protected void cancelRequest() + @Override + protected Ice.Instrumentation.InvocationObserver getObserver() { + return CommunicatorFlushBatch.this._observer; } } - synchronized(_monitor) + synchronized(this) { ++_useCount; } try { - int status; if(_instance.queueRequests()) { Future<Integer> future = _instance.getQueueExecutor().submit(new Callable<Integer>() @@ -117,7 +107,7 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase @Override public Integer call() throws RetryException { - return con.flushAsyncBatchRequests(new BatchOutgoingAsyncI()); + return con.flushAsyncBatchRequests(new FlushBatch()); } }); @@ -126,7 +116,7 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase { try { - status = future.get(); + future.get(); if(interrupted) { Thread.currentThread().interrupt(); @@ -160,11 +150,7 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase } else { - status = con.flushAsyncBatchRequests(new BatchOutgoingAsyncI()); - } - if((status & AsyncStatus.Sent) > 0) - { - _sentSynchronously = false; + con.flushAsyncBatchRequests(new FlushBatch()); } } catch(Ice.LocalException ex) @@ -181,53 +167,28 @@ public class CommunicatorBatchOutgoingAsync extends OutgoingAsyncBase private void doCheck(boolean userThread) { - synchronized(_monitor) + synchronized(this) { assert(_useCount > 0); if(--_useCount > 0) { return; } - _state |= StateDone | StateOK | StateSent; - _os.resize(0, false); // Clear buffer now, instead of waiting for AsyncResult deallocation - _monitor.notifyAll(); } - if(_callback == null || !_callback.__hasSentCallback()) - { - if(_observer != null) - { - _observer.detach(); - _observer = null; - } - } - else + if(sent(true)) { - // - // sentSynchronously_ is immutable here. - // - if(!_sentSynchronously || !userThread) + if(userThread) { - invokeSentAsync(); + _sentSynchronously = true; + invokeSent(); } else { - invokeSentInternal(); + invokeSentAsync(); } } } - @Override - public void - processRetry() - { - assert(false); // Retries are never scheduled - } - - @Override - protected void cancelRequest() - { - } - private int _useCount; } diff --git a/java/src/IceInternal/ConnectRequestHandler.java b/java/src/IceInternal/ConnectRequestHandler.java index 91957af1a0c..e4c1e6b1727 100644 --- a/java/src/IceInternal/ConnectRequestHandler.java +++ b/java/src/IceInternal/ConnectRequestHandler.java @@ -22,12 +22,12 @@ public class ConnectRequestHandler this.os.swap(os); } - Request(OutgoingAsyncMessageCallback out) + Request(OutgoingAsyncBase out) { this.outAsync = out; } - OutgoingAsyncMessageCallback outAsync = null; + OutgoingAsyncBase outAsync = null; BasicStream os = null; } @@ -149,7 +149,7 @@ public class ConnectRequestHandler @Override public int - sendAsyncRequest(OutgoingAsyncMessageCallback out) + sendAsyncRequest(OutgoingAsyncBase out) throws RetryException { synchronized(this) @@ -159,6 +159,7 @@ public class ConnectRequestHandler if(!initialized()) { _requests.add(new Request(out)); + out.cancelable(this); return AsyncStatus.Queued; } } @@ -171,14 +172,14 @@ public class ConnectRequestHandler } @Override - public boolean - asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex) + public void + asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) { synchronized(this) { if(_exception != null) { - return false; // The request has been notified of a failure already. + return; // The request has been notified of a failure already. } if(!initialized()) @@ -190,14 +191,17 @@ public class ConnectRequestHandler if(request.outAsync == outAsync) { it.remove(); - outAsync.dispatchInvocationCancel(ex, _reference.getInstance().clientThreadPool(), null); - return true; // We're done + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + return; } } assert(false); // The request has to be queued if it timed out and we're not initialized yet. } } - return _connection.asyncRequestCanceled(outAsync, ex); + _connection.asyncRequestCanceled(outAsync, ex); } @Override @@ -394,8 +398,7 @@ public class ConnectRequestHandler _flushing = true; } - final java.util.List<OutgoingAsyncMessageCallback> sentCallbacks = - new java.util.ArrayList<OutgoingAsyncMessageCallback>(); + final java.util.List<OutgoingAsyncBase> sentCallbacks = new java.util.ArrayList<OutgoingAsyncBase>(); try { java.util.Iterator<Request> p = _requests.iterator(); // _requests is immutable when _flushing = true @@ -476,7 +479,7 @@ public class ConnectRequestHandler @Override public void run() { - for(OutgoingAsyncMessageCallback callback : sentCallbacks) + for(OutgoingAsyncBase callback : sentCallbacks) { callback.invokeSent(); } @@ -546,7 +549,10 @@ public class ConnectRequestHandler { if(request.outAsync != null) { - request.outAsync.finished(_exception); + if(request.outAsync.completed(_exception)) + { + request.outAsync.invokeCompleted(); + } } } _requests.clear(); diff --git a/java/src/IceInternal/ConnectionBatchOutgoingAsync.java b/java/src/IceInternal/ConnectionBatchOutgoingAsync.java deleted file mode 100644 index 5a1f0a30886..00000000000 --- a/java/src/IceInternal/ConnectionBatchOutgoingAsync.java +++ /dev/null @@ -1,107 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -package IceInternal; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; - -import Ice.CommunicatorDestroyedException; - -public class ConnectionBatchOutgoingAsync extends BatchOutgoingAsync -{ - public ConnectionBatchOutgoingAsync(Ice.ConnectionI con, Ice.Communicator communicator, Instance instance, - String operation, CallbackBase callback) - { - super(communicator, instance, operation, callback); - _connection = con; - } - - public void __invoke() - { - int status; - if(_instance.queueRequests()) - { - Future<Integer> future = _instance.getQueueExecutor().submit(new Callable<Integer>() - { - @Override - public Integer call() throws RetryException - { - return _connection.flushAsyncBatchRequests(ConnectionBatchOutgoingAsync.this); - } - }); - - boolean interrupted = false; - while(true) - { - try - { - status = future.get(); - if(interrupted) - { - Thread.currentThread().interrupt(); - } - break; - } - catch(InterruptedException ex) - { - interrupted = true; - } - catch(RejectedExecutionException e) - { - throw new CommunicatorDestroyedException(); - } - catch(ExecutionException e) - { - try - { - throw e.getCause(); - } - catch(RuntimeException ex) - { - throw ex; - } - catch(Throwable ex) - { - assert(false); - } - } - } - } - else - { - status = _connection.flushAsyncBatchRequests(this); - } - - if((status & AsyncStatus.Sent) > 0) - { - _sentSynchronously = true; - if((status & AsyncStatus.InvokeSentCallback) > 0) - { - invokeSent(); - } - } - } - - @Override - public Ice.Connection getConnection() - { - return _connection; - } - - @Override - protected void cancelRequest() - { - _connection.asyncRequestCanceled(this, new Ice.OperationInterruptedException()); - } - - private Ice.ConnectionI _connection; -} diff --git a/java/src/IceInternal/ConnectionFlushBatch.java b/java/src/IceInternal/ConnectionFlushBatch.java new file mode 100644 index 00000000000..4b3da0bcb5e --- /dev/null +++ b/java/src/IceInternal/ConnectionFlushBatch.java @@ -0,0 +1,128 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; + +import Ice.CommunicatorDestroyedException; + +public class ConnectionFlushBatch extends OutgoingAsyncBase +{ + public static ConnectionFlushBatch check(Ice.AsyncResult r, Ice.Connection con, String operation) + { + check(r, operation); + if(!(r instanceof ConnectionFlushBatch)) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + if(r.getConnection() != con) + { + throw new IllegalArgumentException("Connection for call to end_" + operation + + " does not match connection that was used to call corresponding " + + "begin_" + operation + " method"); + } + return (ConnectionFlushBatch)r; + } + + public ConnectionFlushBatch(Ice.ConnectionI con, Ice.Communicator communicator, Instance instance, + String operation, CallbackBase callback) + { + super(communicator, instance, operation, callback); + _connection = con; + } + + @Override + public Ice.Connection getConnection() + { + return _connection; + } + + public void invoke() + { + try + { + int status; + if(_instance.queueRequests()) + { + Future<Integer> future = _instance.getQueueExecutor().submit( + new Callable<Integer>() + { + @Override + public Integer call() throws RetryException + { + return _connection.flushAsyncBatchRequests(ConnectionFlushBatch.this); + } + }); + + boolean interrupted = false; + while(true) + { + try + { + status = future.get(); + if(interrupted) + { + Thread.currentThread().interrupt(); + } + break; + } + catch(InterruptedException ex) + { + interrupted = true; + } + catch(RejectedExecutionException e) + { + throw new CommunicatorDestroyedException(); + } + catch(ExecutionException e) + { + try + { + throw e.getCause(); + } + catch(RuntimeException ex) + { + throw ex; + } + catch(Throwable ex) + { + assert(false); + } + } + } + } + else + { + status = _connection.flushAsyncBatchRequests(this); + } + + if((status & AsyncStatus.Sent) > 0) + { + _sentSynchronously = true; + if((status & AsyncStatus.InvokeSentCallback) > 0) + { + invokeSent(); + } + } + } + catch(Ice.Exception ex) + { + if(completed(ex)) + { + invokeCompletedAsync(); + } + } + } + + private Ice.ConnectionI _connection; +} diff --git a/java/src/IceInternal/ConnectionRequestHandler.java b/java/src/IceInternal/ConnectionRequestHandler.java index f7ca7bb5b29..924b633e670 100644 --- a/java/src/IceInternal/ConnectionRequestHandler.java +++ b/java/src/IceInternal/ConnectionRequestHandler.java @@ -69,17 +69,17 @@ public class ConnectionRequestHandler implements RequestHandler } @Override - public int sendAsyncRequest(OutgoingAsyncMessageCallback out) + public int sendAsyncRequest(OutgoingAsyncBase out) throws RetryException { return out.send(_connection, _compress, _response); } @Override - public boolean - asyncRequestCanceled(OutgoingAsyncMessageCallback outgoingAsync, Ice.LocalException ex) + public void + asyncRequestCanceled(OutgoingAsyncBase outgoingAsync, Ice.LocalException ex) { - return _connection.asyncRequestCanceled(outgoingAsync, ex); + _connection.asyncRequestCanceled(outgoingAsync, ex); } @Override @@ -103,8 +103,8 @@ public class ConnectionRequestHandler implements RequestHandler return _connection; } - public ConnectionRequestHandler(Reference ref, Ice.ConnectionI connection, - boolean compress) { + public ConnectionRequestHandler(Reference ref, Ice.ConnectionI connection, boolean compress) + { _reference = ref; _response = _reference.getMode() == Reference.ModeTwoway; _connection = connection; diff --git a/java/src/IceInternal/GetConnectionOutgoingAsync.java b/java/src/IceInternal/GetConnectionOutgoingAsync.java deleted file mode 100644 index 55653630ca2..00000000000 --- a/java/src/IceInternal/GetConnectionOutgoingAsync.java +++ /dev/null @@ -1,148 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -package IceInternal; - -public class GetConnectionOutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMessageCallback -{ - public GetConnectionOutgoingAsync(Ice.ObjectPrxHelperBase prx, String operation, CallbackBase cb) - { - super(prx.ice_getCommunicator(), ((Ice.ObjectPrxHelperBase) prx).__reference().getInstance(), operation, cb); - _proxy = (Ice.ObjectPrxHelperBase) prx; - _cnt = 0; - _observer = ObserverHelper.get(prx, operation); - } - - public void __invoke() - { - while(true) - { - try - { - _handler = _proxy.__getRequestHandler(); - _handler.sendAsyncRequest(this); - } - catch(RetryException ex) - { - _proxy.__setRequestHandler(_handler, null); - } - catch(Ice.Exception ex) - { - handleException(ex); - } - break; - } - } - - @Override - public Ice.ObjectPrx getProxy() - { - return _proxy; - } - - @Override - public int send(Ice.ConnectionI conection, boolean compress, boolean response) - throws RetryException - { - sent(); - return 0; - } - - @Override - public int invokeCollocated(CollocatedRequestHandler handler) - { - sent(); - return 0; - } - - @Override - public boolean sent() - { - synchronized(_monitor) - { - _state |= StateDone; - _monitor.notifyAll(); - } - invokeCompleted(); - return false; - } - - @Override - public void invokeSent() - { - // No sent callback - } - - @Override - public void finished(Ice.Exception exc) - { - try - { - handleException(exc); - } - catch(Ice.Exception ex) - { - invokeExceptionAsync(ex); - } - } - - @Override - void processRetry() - { - __invoke(); - } - - @Override - public void dispatchInvocationCancel(final Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection) - { - threadPool.dispatch(new DispatchWorkItem(connection) - { - @Override - public void run() - { - GetConnectionOutgoingAsync.this.finished(ex); - } - }); - } - - @Override - protected void cancelRequest() - { - if(_handler != null) - { - _handler.asyncRequestCanceled(this, new Ice.OperationInterruptedException()); - } - } - - private void handleException(Ice.Exception exc) - { - try - { - Ice.Holder<Integer> interval = new Ice.Holder<Integer>(); - _cnt = _proxy.__handleException(exc, _handler, Ice.OperationMode.Idempotent, false, interval, _cnt); - if(_observer != null) - { - _observer.retried(); // Invocation is being retried - } - _instance.retryQueue().add(this, interval.value); - } - catch(Ice.Exception ex) - { - if(_observer != null) - { - _observer.failed(ex.ice_name()); - } - throw ex; - } - } - - private Ice.ObjectPrxHelperBase _proxy; - private RequestHandler _handler = null; - private int _cnt; -} diff --git a/java/src/IceInternal/IncomingConnectionFactory.java b/java/src/IceInternal/IncomingConnectionFactory.java index 89dcf9b44ed..31306a14ca6 100644 --- a/java/src/IceInternal/IncomingConnectionFactory.java +++ b/java/src/IceInternal/IncomingConnectionFactory.java @@ -170,7 +170,7 @@ public final class IncomingConnectionFactory extends EventHandler implements Ice } public void - flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) + flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) { for(Ice.ConnectionI c : connections()) // connections() is synchronized, no need to synchronize here. { diff --git a/java/src/IceInternal/ObjectAdapterFactory.java b/java/src/IceInternal/ObjectAdapterFactory.java index 63c3e592669..a723537cd7e 100644 --- a/java/src/IceInternal/ObjectAdapterFactory.java +++ b/java/src/IceInternal/ObjectAdapterFactory.java @@ -218,7 +218,7 @@ public final class ObjectAdapterFactory } public void - flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) + flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) { java.util.List<Ice.ObjectAdapterI> adapters; synchronized(this) diff --git a/java/src/IceInternal/OutgoingAsync.java b/java/src/IceInternal/OutgoingAsync.java index ef4d3d7c959..e42c817b42c 100644 --- a/java/src/IceInternal/OutgoingAsync.java +++ b/java/src/IceInternal/OutgoingAsync.java @@ -9,41 +9,47 @@ package IceInternal; -public class OutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMessageCallback +public class OutgoingAsync extends ProxyOutgoingAsyncBase { + public static OutgoingAsync check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (OutgoingAsync)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + public OutgoingAsync(Ice.ObjectPrx prx, String operation, CallbackBase cb) { - super(prx.ice_getCommunicator(), ((Ice.ObjectPrxHelperBase) prx).__reference().getInstance(), operation, cb); - _proxy = (Ice.ObjectPrxHelperBase) prx; + super((Ice.ObjectPrxHelperBase)prx, operation, cb); _encoding = Protocol.getCompatibleEncoding(_proxy.__reference().getEncoding()); + _is = null; } - public OutgoingAsync(Ice.ObjectPrx prx, String operation, CallbackBase cb, IceInternal.BasicStream is, - IceInternal.BasicStream os) + public OutgoingAsync(Ice.ObjectPrx prx, String operation, CallbackBase cb, BasicStream is, BasicStream os) { - super(prx.ice_getCommunicator(), ((Ice.ObjectPrxHelperBase) prx).__reference().getInstance(), operation, cb, - is, os); - _proxy = (Ice.ObjectPrxHelperBase) prx; + super((Ice.ObjectPrxHelperBase)prx, operation, cb, os); _encoding = Protocol.getCompatibleEncoding(_proxy.__reference().getEncoding()); + _is = is; } public void prepare(String operation, Ice.OperationMode mode, java.util.Map<String, String> ctx, boolean explicitCtx, boolean synchronous) { - _handler = null; - _cnt = 0; - _sent = false; + Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(_proxy.__reference().getProtocol())); + _mode = mode; - _sentSynchronously = false; _synchronous = synchronous; - Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(_proxy.__reference().getProtocol())); - if(explicitCtx && ctx == null) { ctx = _emptyContext; } - _observer = ObserverHelper.get(_proxy, operation, ctx); switch(_proxy.__reference().getMode()) @@ -137,12 +143,6 @@ public class OutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMes } @Override - public Ice.ObjectPrx getProxy() - { - return _proxy; - } - - @Override public int send(Ice.ConnectionI connection, boolean compress, boolean response) throws RetryException { _cachedConnection = connection; @@ -158,117 +158,52 @@ public class OutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMes // Disable caching by marking the streams as cached! _state |= StateCachedBuffers; } - handler.invokeAsyncRequest(this, _synchronous); - return AsyncStatus.Queued; + return handler.invokeAsyncRequest(this, _synchronous); } @Override - public boolean sent() + public void abort(Ice.Exception ex) { - synchronized(_monitor) + int mode = _proxy.__reference().getMode(); + if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram) { - boolean alreadySent = (_state & StateSent) != 0; - _state |= StateSent; - _sent = true; - - assert ((_state & StateDone) == 0); - - if(!_proxy.ice_isTwoway()) + if(_handler != null) { - if(_childObserver != null) - { - _childObserver.detach(); - _childObserver = null; - } - if(_observer != null && (_callback == null || !_callback.__hasSentCallback())) - { - _observer.detach(); - _observer = null; - } - if(_timeoutRequestHandler != null) - { - _future.cancel(false); - _future = null; - _timeoutRequestHandler = null; - } - _state |= StateDone | StateOK; - // _os.resize(0, false); // Don't clear the buffer now, it's - // needed for the collocation optimization - - // For oneway requests after the data has been sent the buffers - // can be reused unless this is a collocated invocation. For - // collocated invocations the buffer won't be reused as the - // because it has already been marked as cached in - // invokeCollocated. - cacheMessageBuffers(); + // + // If we didn't finish a batch oneway or datagram request, we + // must notify the connection about that we give up ownership + // of the batch stream. + // + _handler.abortBatchRequest(); } - _monitor.notifyAll(); - - // Don't call the sent call is already sent. - return !alreadySent && _callback != null && _callback.__hasSentCallback(); } - } - @Override - public void invokeSent() - { - invokeSentInternal(); + super.abort(ex); } - @Override - public void finished(Ice.Exception exc) + public void invoke() { - synchronized(_monitor) + int mode = _proxy.__reference().getMode(); + if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram) { - assert ((_state & StateDone) == 0); - if(_childObserver != null) - { - _childObserver.failed(exc.ice_name()); - _childObserver.detach(); - _childObserver = null; - } - if(_timeoutRequestHandler != null) + if(_handler != null) { - _future.cancel(false); - _future = null; - _timeoutRequestHandler = null; + _sentSynchronously = true; + _handler.finishBatchRequest(_os); + finished(true); } + return; // Don't call sent/completed callback for batch AMI requests } // - // NOTE: at this point, synchronization isn't needed, no other threads - // should be calling on the callback. + // NOTE: invokeImpl doesn't throw so this can be called from the + // try block with the catch block calling abort() in case of an + // exception. // - try - { - handleException(exc); - } - catch(Ice.Exception ex) - { - invokeException(ex); - } - } - - @Override - void processRetry() - { - invoke(false); - } - - @Override - public void dispatchInvocationCancel(final Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection) - { - threadPool.dispatch(new DispatchWorkItem(connection) - { - @Override - public void run() - { - OutgoingAsync.this.finished(ex); - } - }); + invokeImpl(true); // userThread = true } - public final boolean finished(BasicStream is) + public final boolean completed(BasicStream is) { // // NOTE: this method is called from ConnectionI.parseMessage @@ -276,291 +211,153 @@ public class OutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMes // any user callbacks. // - assert (_proxy.ice_isTwoway()); // Can only be called for twoways. - + assert(_proxy.ice_isTwoway()); // Can only be called for twoways. + + if(_childObserver != null) + { + _childObserver.reply(is.size() - Protocol.headerSize - 4); + _childObserver.detach(); + _childObserver = null; + } + byte replyStatus; try { - synchronized(_monitor) + // _is can already be initialized if the invocation is retried + if(_is == null) + { + _is = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding); + } + _is.swap(is); + replyStatus = _is.readByte(); + + switch(replyStatus) + { + case ReplyStatus.replyOK: + { + break; + } + + case ReplyStatus.replyUserException: { - assert (_exception == null && (_state & StateDone) == 0); - if(_childObserver != null) + if(_observer != null) { - _childObserver.reply(is.size() - Protocol.headerSize - 4); - _childObserver.detach(); - _childObserver = null; + _observer.userException(); } - - if(_timeoutRequestHandler != null) + break; + } + + case ReplyStatus.replyObjectNotExist: + case ReplyStatus.replyFacetNotExist: + case ReplyStatus.replyOperationNotExist: + { + Ice.Identity id = new Ice.Identity(); + id.__read(_is); + + // + // For compatibility with the old FacetPath. + // + String[] facetPath = _is.readStringSeq(); + String facet; + if(facetPath.length > 0) { - _future.cancel(false); - _future = null; - _timeoutRequestHandler = null; + if(facetPath.length > 1) + { + throw new Ice.MarshalException(); + } + facet = facetPath[0]; } - - // _is can already be initialized if the invocation is retried - if(_is == null) + else { - _is = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding); + facet = ""; } - _is.swap(is); - replyStatus = _is.readByte(); - + + String operation = _is.readString(); + + Ice.RequestFailedException ex = null; switch(replyStatus) { - case ReplyStatus.replyOK: - { - break; - } - - case ReplyStatus.replyUserException: - { - if(_observer != null) - { - _observer.userException(); - } - break; - } - - case ReplyStatus.replyObjectNotExist: - case ReplyStatus.replyFacetNotExist: - case ReplyStatus.replyOperationNotExist: - { - Ice.Identity id = new Ice.Identity(); - id.__read(_is); - - // - // For compatibility with the old FacetPath. - // - String[] facetPath = _is.readStringSeq(); - String facet; - if(facetPath.length > 0) - { - if(facetPath.length > 1) - { - throw new Ice.MarshalException(); - } - facet = facetPath[0]; - } - else - { - facet = ""; - } - - String operation = _is.readString(); - - Ice.RequestFailedException ex = null; - switch(replyStatus) - { - case ReplyStatus.replyObjectNotExist: - { - ex = new Ice.ObjectNotExistException(); - break; - } - - case ReplyStatus.replyFacetNotExist: - { - ex = new Ice.FacetNotExistException(); - break; - } - - case ReplyStatus.replyOperationNotExist: - { - ex = new Ice.OperationNotExistException(); - break; - } - - default: - { - assert (false); - break; - } - } - - ex.id = id; - ex.facet = facet; - ex.operation = operation; - throw ex; - } - - case ReplyStatus.replyUnknownException: - case ReplyStatus.replyUnknownLocalException: - case ReplyStatus.replyUnknownUserException: - { - String unknown = _is.readString(); - - Ice.UnknownException ex = null; - switch(replyStatus) - { - case ReplyStatus.replyUnknownException: - { - ex = new Ice.UnknownException(); - break; - } - - case ReplyStatus.replyUnknownLocalException: - { - ex = new Ice.UnknownLocalException(); - break; - } - - case ReplyStatus.replyUnknownUserException: - { - ex = new Ice.UnknownUserException(); - break; - } - - default: - { - assert (false); - break; - } - } - - ex.unknown = unknown; - throw ex; - } + case ReplyStatus.replyObjectNotExist: + { + ex = new Ice.ObjectNotExistException(); + break; + } - default: - { - throw new Ice.UnknownReplyStatusException(); - } + case ReplyStatus.replyFacetNotExist: + { + ex = new Ice.FacetNotExistException(); + break; } - if(replyStatus == ReplyStatus.replyOK) + case ReplyStatus.replyOperationNotExist: { - _state |= StateOK; + ex = new Ice.OperationNotExistException(); + break; } - _state |= StateDone; - _monitor.notifyAll(); - if(_callback == null) + default: { - if(_observer != null) - { - _observer.detach(); - _observer = null; - } - return false; + assert(false); + break; } - return true; - } - } - catch(Ice.Exception exc) - { - // - // We don't call finished(exc) here because we don't want - // to invoke the completion callback. The completion - // callback is invoked by the connection is this method - // returns true. - // - try - { - handleException(exc); - return false; + } + + ex.id = id; + ex.facet = facet; + ex.operation = operation; + throw ex; } - catch(Ice.LocalException ex) + + case ReplyStatus.replyUnknownException: + case ReplyStatus.replyUnknownLocalException: + case ReplyStatus.replyUnknownUserException: { - synchronized(_monitor) - { - _state |= StateDone; - _exception = ex; - _monitor.notifyAll(); + String unknown = _is.readString(); - if(_callback == null) - { - if(_observer != null) - { - _observer.detach(); - _observer = null; - } - return false; - } - return true; + Ice.UnknownException ex = null; + switch(replyStatus) + { + case ReplyStatus.replyUnknownException: + { + ex = new Ice.UnknownException(); + break; } - } - } - } - public final boolean invoke(boolean userThread) - { - int mode = _proxy.__reference().getMode(); - if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram) - { - _state |= StateDone | StateOK; - _handler.finishBatchRequest(_os); - if(_observer != null) - { - _observer.detach(); - _observer = null; - } - return true; - } + case ReplyStatus.replyUnknownLocalException: + { + ex = new Ice.UnknownLocalException(); + break; + } - while(true) - { - try - { - _sent = false; - _handler = _proxy.__getRequestHandler(); - int status = _handler.sendAsyncRequest(this); - if((status & AsyncStatus.Sent) > 0) + case ReplyStatus.replyUnknownUserException: { - if(userThread) - { - _sentSynchronously = true; - if((status & AsyncStatus.InvokeSentCallback) > 0) - { - invokeSent(); // Call from the user thread. - } - } - else - { - if((status & AsyncStatus.InvokeSentCallback) > 0) - { - // Call from a client thread pool thread. - invokeSentAsync(); - } - } + ex = new Ice.UnknownUserException(); + break; } - if(mode == IceInternal.Reference.ModeTwoway || (status & AsyncStatus.Sent) == 0) + default: { - synchronized(_monitor) - { - if((_state & StateDone) == 0) - { - int invocationTimeout = _handler.getReference().getInvocationTimeout(); - if(invocationTimeout > 0) - { - _future = _instance.timer().schedule(new Runnable() - { - @Override - public void run() - { - timeout(); - } - }, invocationTimeout, java.util.concurrent.TimeUnit.MILLISECONDS); - _timeoutRequestHandler = _handler; - } - } - } + assert(false); + break; + } } + + ex.unknown = unknown; + throw ex; } - catch(RetryException ex) + + default: { - // Clear request handler and retry. - _proxy.__setRequestHandler(_handler, null); - continue; + throw new Ice.UnknownReplyStatusException(); } - catch(Ice.Exception ex) - { - // This will throw if the invocation can't be retried. - handleException(ex); } - break; + + return finished(replyStatus == ReplyStatus.replyOK); + } + catch(Ice.Exception ex) + { + return completed(ex); } - return _sentSynchronously; } public BasicStream startWriteParams(Ice.FormatType format) @@ -591,12 +388,48 @@ public class OutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMes } } + public IceInternal.BasicStream startReadParams() + { + _is.startReadEncaps(); + return _is; + } + + public void endReadParams() + { + _is.endReadEncaps(); + } + + public void readEmptyParams() + { + _is.skipEmptyEncaps(null); + } + + public byte[] readParamEncaps() + { + return _is.readEncaps(null); + } + + public final void throwUserException() + throws Ice.UserException + { + try + { + _is.startReadEncaps(); + _is.throwException(null); + } + catch(Ice.UserException ex) + { + _is.endReadEncaps(); + throw ex; + } + } + @Override public void cacheMessageBuffers() { if(_proxy.__reference().getInstance().cacheMessageBuffers() > 0) { - synchronized(_monitor) + synchronized(this) { if((_state & StateCachedBuffers) > 0) { @@ -612,76 +445,14 @@ public class OutgoingAsync extends OutgoingAsyncBase implements OutgoingAsyncMes _os.reset(); _proxy.cacheMessageBuffers(_is, _os); - } - } - @Override - public void invokeExceptionAsync(final Ice.Exception ex) - { - if((_state & StateDone) == 0 && _handler != null) - { - // - // If we didn't finish a batch oneway or datagram request, we - // must notify the connection about that we give up ownership - // of the batch stream. - // - int mode = _proxy.__reference().getMode(); - if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram) - { - _handler.abortBatchRequest(); - } - } - - super.invokeExceptionAsync(ex); - } - - @Override - protected void cancelRequest() - { - if(_handler != null) - { - _handler.asyncRequestCanceled(this, new Ice.OperationInterruptedException()); + _is = null; + _os = null; } } - private void handleException(Ice.Exception exc) - { - try - { - Ice.Holder<Integer> interval = new Ice.Holder<Integer>(); - _cnt = _proxy.__handleException(exc, _handler, _mode, _sent, interval, _cnt); - if(_observer != null) - { - _observer.retried(); // Invocation is being retried. - } - - // - // Schedule the retry. Note that we always schedule the retry - // on the retry queue even if the invocation can be retried - // immediately. This is required because it might not be safe - // to retry from this thread (this is for instance called by - // finished(BasicStream) which is called with the connection - // locked. - // - _instance.retryQueue().add(this, interval.value); - } - catch(Ice.Exception ex) - { - if(_observer != null) - { - _observer.failed(ex.ice_name()); - } - throw ex; - } - } - - final private Ice.ObjectPrxHelperBase _proxy; final private Ice.EncodingVersion _encoding; - - private RequestHandler _handler; - private int _cnt; - private Ice.OperationMode _mode; - private boolean _sent; + private BasicStream _is; // // If true this AMI request is being used for a generated synchronous invocation. diff --git a/java/src/IceInternal/OutgoingAsyncBase.java b/java/src/IceInternal/OutgoingAsyncBase.java index 2e6aa221f4d..f04b09ea941 100644 --- a/java/src/IceInternal/OutgoingAsyncBase.java +++ b/java/src/IceInternal/OutgoingAsyncBase.java @@ -9,385 +9,41 @@ package IceInternal; -import Ice.AsyncResult; -import Ice.Communicator; -import Ice.CommunicatorDestroyedException; -import Ice.Connection; -import Ice.ObjectPrx; -import Ice.UserException; - -/** - * An AsyncResult object is the return value of an asynchronous invocation. - * With this object, an application can obtain several attributes of the - * invocation and discover its outcome. - **/ -public abstract class OutgoingAsyncBase implements Ice.AsyncResult +// +// Base class for handling asynchronous invocations. This class is +// responsible for the handling of the output stream and the child +// invocation observer. +// +public abstract class OutgoingAsyncBase extends IceInternal.AsyncResultI { - protected OutgoingAsyncBase(Communicator communicator, IceInternal.Instance instance, String op, - IceInternal.CallbackBase del) + public int send(Ice.ConnectionI connection, boolean compress, boolean response) throws RetryException { - _communicator = communicator; - _instance = instance; - _operation = op; - _os = new IceInternal.BasicStream(instance, IceInternal.Protocol.currentProtocolEncoding); - _state = 0; - _sentSynchronously = false; - _exception = null; - _callback = del; - } - - protected OutgoingAsyncBase(Communicator communicator, Instance instance, String op, CallbackBase del, - BasicStream is, BasicStream os) - { - _communicator = communicator; - _instance = instance; - _operation = op; - _os = os; - _is = is; - _state = 0; - _sentSynchronously = false; - _exception = null; - _callback = del; - } - - /** - * Returns the communicator that sent the invocation. - * - * @return The communicator. - **/ - @Override - public Communicator getCommunicator() - { - return _communicator; - } - - /** - * Returns the connection that was used for the invocation. - * - * @return The connection. - **/ - @Override - public Connection getConnection() - { - return null; - } - - /** - * Returns the proxy that was used to call the <code>begin_</code> method. - * - * @return The proxy. - **/ - @Override - public ObjectPrx getProxy() - { - return null; - } - - /** - * Indicates whether the result of an invocation is available. - * - * @return True if the result is available, which means a call to the <code>end_</code> - * method will not block. The method returns false if the result is not yet available. - **/ - @Override - public final boolean isCompleted() - { - synchronized(_monitor) - { - return (_state & StateDone) > 0; - } + assert(false); // This should be overriden if this object is used with a request handler + return AsyncStatus.Queued; } - /** - * Blocks the caller until the result of the invocation is available. - **/ - @Override - public final void waitForCompleted() + public int invokeCollocated(CollocatedRequestHandler handler) { - synchronized(_monitor) - { - if(Thread.interrupted()) - { - throw new Ice.OperationInterruptedException(); - } - while((_state & StateDone) == 0) - { - try - { - _monitor.wait(); - } - catch(InterruptedException ex) - { - throw new Ice.OperationInterruptedException(); - } - } - } + assert(false); // This should be overriden if this object is used with a request handler + return AsyncStatus.Queued; } - /** - * When you call the <code>begin_</code> method, the Ice run time attempts to - * write the corresponding request to the client-side transport. If the - * transport cannot accept the request, the Ice run time queues the request - * for later transmission. This method returns true if, at the time it is called, - * the request has been written to the local transport (whether it was initially - * queued or not). Otherwise, if the request is still queued, this method returns - * false. - * - * @return True if the request has been sent, or false if the request is queued. - **/ - @Override - public final boolean isSent() + public boolean sent() { - synchronized(_monitor) - { - return (_state & StateSent) > 0; - } + return sent(true); } - /** - * Blocks the caller until the request has been written to the client-side transport. - **/ - @Override - public final void waitForSent() + public boolean completed(Ice.Exception ex) { - synchronized(_monitor) - { - if(Thread.interrupted()) - { - throw new Ice.OperationInterruptedException(); - } - while((_state & StateSent) == 0 && _exception == null) - { - try - { - _monitor.wait(); - } - catch(InterruptedException ex) - { - throw new Ice.OperationInterruptedException(); - } - } - } + return finished(ex); } - /** - * If the invocation failed with a local exception, throws the local exception. - **/ - @Override - public final void throwLocalException() + public final void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId) { - synchronized(_monitor) - { - if(_exception != null) - { - throw _exception; - } - } - } - - /** - * This method returns true if a request was written to the client-side - * transport without first being queued. If the request was initially - * queued, this method returns false (independent of whether the request - * is still in the queue or has since been written to the client-side transport). - * - * @return True if the request was sent without being queued, or false - * otherwise. - **/ - @Override - public final boolean sentSynchronously() - { - return _sentSynchronously; // No lock needed, immutable once __send() is called - } - - /** - * Returns the name of the operation. - * - * @return The operation name. - **/ - @Override - public final String getOperation() - { - return _operation; - } - - public final IceInternal.BasicStream getOs() - { - return _os; - } - - public IceInternal.BasicStream - startReadParams() - { - _is.startReadEncaps(); - return _is; - } - - public void - endReadParams() - { - _is.endReadEncaps(); - } - - public void - readEmptyParams() - { - _is.skipEmptyEncaps(null); - } - - public byte[] - readParamEncaps() - { - return _is.readEncaps(null); - } - - public final boolean __wait() - { - try - { - synchronized(_monitor) - { - if((_state & StateEndCalled) > 0) - { - throw new java.lang.IllegalArgumentException("end_ method called more than once"); - } - - _state |= StateEndCalled; - if(Thread.interrupted()) - { - throw new InterruptedException(); - } - while((_state & StateDone) == 0) - { - _monitor.wait(); - } - - if(_exception != null) - { - throw (Ice.Exception)_exception.fillInStackTrace(); - } - - return (_state & StateOK) > 0; - } - } - catch(InterruptedException ex) - { - // This must be called outside of the monitor as the - // invocation will potentially want to lock the - // connection (which in turn may want to lock the outgoing - // to notify that the message has been sent). - cancelRequest(); - throw new Ice.OperationInterruptedException(); - } - } - - public final void throwUserException() - throws UserException - { - try - { - _is.startReadEncaps(); - _is.throwException(null); - } - catch(UserException ex) - { - _is.endReadEncaps(); - throw ex; - } - } - - public void invokeExceptionAsync(final Ice.Exception ex) - { - // - // This is called when it's not safe to call the exception callback synchronously - // from this thread. Instead the exception callback is called asynchronously from - // the client thread pool. - // - try - { - _instance.clientThreadPool().dispatch(new IceInternal.DispatchWorkItem(_cachedConnection) - { - @Override - public void - run() - { - invokeException(ex); - } - }); - } - catch(CommunicatorDestroyedException exc) - { - throw exc; // CommunicatorDestroyedException is the only exception that can propagate directly. - } - } - - public final void invokeException(Ice.Exception ex) - { - synchronized(_monitor) - { - _state |= StateDone; - //_os.resize(0, false); // Clear buffer now, instead of waiting for AsyncResult deallocation - _exception = ex; - _monitor.notifyAll(); - } - - invokeCompleted(); - } - - protected final void invokeSentInternal() - { - // - // Note: no need to change the _state here, specializations are responsible for - // changing the state. - // - - if(_callback != null) - { - if(_instance.useApplicationClassLoader()) - { - Thread.currentThread().setContextClassLoader(_callback.getClass().getClassLoader()); - } - - try - { - _callback.__sent(this); - } - catch(RuntimeException ex) - { - warning(ex); - } - catch(AssertionError exc) - { - error(exc); - } - catch(OutOfMemoryError exc) - { - error(exc); - } - finally - { - if(_instance.useApplicationClassLoader()) - { - Thread.currentThread().setContextClassLoader(null); - } - } - } - if(_observer != null) { - Ice.ObjectPrx proxy = getProxy(); - if(proxy == null || !proxy.ice_isTwoway()) - { - _observer.detach(); - } - } - } - - public void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId, int size) - { - if(_observer != null) - { - _childObserver = _observer.getRemoteObserver(info, endpt, requestId, size); + final int size = _os.size() - IceInternal.Protocol.headerSize - 4; + _childObserver = getObserver().getRemoteObserver(info, endpt, requestId, size); if(_childObserver != null) { _childObserver.attach(); @@ -395,13 +51,12 @@ public abstract class OutgoingAsyncBase implements Ice.AsyncResult } } - void attachCollocatedObserver(Ice.ObjectAdapter adapter, int requestId) + public final void attachCollocatedObserver(Ice.ObjectAdapter adapter, int requestId) { if(_observer != null) { - _childObserver = _observer.getCollocatedObserver(adapter, - requestId, - _os.size() - IceInternal.Protocol.headerSize - 4); + final int size = _os.size() - IceInternal.Protocol.headerSize - 4; + _childObserver = getObserver().getCollocatedObserver(adapter, requestId, size); if(_childObserver != null) { _childObserver.attach(); @@ -409,185 +64,49 @@ public abstract class OutgoingAsyncBase implements Ice.AsyncResult } } - abstract void processRetry(); - - final protected void invokeSentAsync() - { - // - // This is called when it's not safe to call the sent callback synchronously - // from this thread. Instead the exception callback is called asynchronously from - // the client thread pool. - // - try - { - _instance.clientThreadPool().dispatch(new IceInternal.DispatchWorkItem(_cachedConnection) - { - @Override - public void run() - { - invokeSentInternal(); - } - }); - } - catch(CommunicatorDestroyedException exc) - { - } - } - - public static void check(AsyncResult r, ObjectPrx prx, String operation) - { - check(r, operation); - if(r.getProxy() != prx) - { - throw new IllegalArgumentException("Proxy for call to end_" + operation + - " does not match proxy that was used to call corresponding begin_" + - operation + " method"); - } - } - - public static void check(AsyncResult r, Connection con, String operation) + public final IceInternal.BasicStream getOs() { - check(r, operation); - if(r.getConnection() != con) - { - throw new IllegalArgumentException("Connection for call to end_" + operation + - " does not match connection that was used to call corresponding begin_" + - operation + " method"); - } + return _os; } - public static void check(AsyncResult r, Communicator com, String operation) + protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, String op, CallbackBase del) { - check(r, operation); - if(r.getCommunicator() != com) - { - throw new IllegalArgumentException("Communicator for call to end_" + operation + - " does not match communicator that was used to call corresponding " + - "begin_" + operation + " method"); - } + super(com, instance, op, del); + _os = new BasicStream(instance, Protocol.currentProtocolEncoding); } - public void cacheMessageBuffers() + protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, String op, CallbackBase del, BasicStream os) { + super(com, instance, op, del); + _os = os; } - public final void invokeCompleted() + @Override + protected boolean sent(boolean done) { - // - // Note: no need to change the _state here, specializations are responsible for - // changing the state. - // - - if(_callback != null) + if(done) { - if(_instance.useApplicationClassLoader()) - { - Thread.currentThread().setContextClassLoader(_callback.getClass().getClassLoader()); - } - - try - { - _callback.__completed(this); - } - catch(RuntimeException ex) - { - warning(ex); - } - catch(AssertionError exc) - { - error(exc); - } - catch(OutOfMemoryError exc) - { - error(exc); - } - finally + if(_childObserver != null) { - if(_instance.useApplicationClassLoader()) - { - Thread.currentThread().setContextClassLoader(null); - } + _childObserver.detach(); + _childObserver = null; } } - - if(_observer != null) - { - _observer.detach(); - _observer = null; - } + return super.sent(done); } - protected void - timeout() - { - IceInternal.RequestHandler handler; - synchronized(_monitor) - { - handler = _timeoutRequestHandler; - _timeoutRequestHandler = null; - } - - if(handler != null) - { - handler.asyncRequestCanceled((IceInternal.OutgoingAsyncMessageCallback)this, - new Ice.InvocationTimeoutException()); - } - } - - private static void check(AsyncResult r, String operation) - { - if(r == null) - { - throw new IllegalArgumentException("AsyncResult == null"); - } - else if(r.getOperation() != operation) // Do NOT use equals() here - we are comparing reference equality - { - throw new IllegalArgumentException("Incorrect operation for end_" + operation + " method: " + - r.getOperation()); - } - } - - private final void warning(RuntimeException ex) + @Override + protected boolean finished(Ice.Exception ex) { - if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + if(_childObserver != null) { - String s = "exception raised by AMI callback:\n" + IceInternal.Ex.toString(ex); - _instance.initializationData().logger.warning(s); + _childObserver.failed(ex.ice_name()); + _childObserver.detach(); + _childObserver = null; } + return super.finished(ex); } - private final void error(Error error) - { - String s = "error raised by AMI callback:\n" + IceInternal.Ex.toString(error); - _instance.initializationData().logger.error(s); - } - - abstract protected void cancelRequest(); - - protected Communicator _communicator; - protected IceInternal.Instance _instance; - protected String _operation; - protected Ice.Connection _cachedConnection; - - protected java.lang.Object _monitor = new java.lang.Object(); - protected IceInternal.BasicStream _is; - protected IceInternal.BasicStream _os; - - protected IceInternal.RequestHandler _timeoutRequestHandler; - protected java.util.concurrent.Future<?> _future; - - protected static final byte StateOK = 0x1; - protected static final byte StateDone = 0x2; - protected static final byte StateSent = 0x4; - protected static final byte StateEndCalled = 0x8; - protected static final byte StateCachedBuffers = 0x10; - - protected byte _state; - protected boolean _sentSynchronously; - protected Ice.Exception _exception; - - protected Ice.Instrumentation.InvocationObserver _observer; + protected BasicStream _os; protected Ice.Instrumentation.ChildInvocationObserver _childObserver; - - protected IceInternal.CallbackBase _callback; } diff --git a/java/src/IceInternal/OutgoingAsyncMessageCallback.java b/java/src/IceInternal/OutgoingAsyncMessageCallback.java deleted file mode 100644 index 7b1f5972434..00000000000 --- a/java/src/IceInternal/OutgoingAsyncMessageCallback.java +++ /dev/null @@ -1,53 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -package IceInternal; - -// -// This interface is used by the connection to handle OutgoingAsync -// and BatchOutgoingAsync messages. -// -public interface OutgoingAsyncMessageCallback -{ - // - // Called by the request handler to send the request over the connection. - // - int send(Ice.ConnectionI conection, boolean compress, boolean response) - throws RetryException; - - // - // Called by the collocated request handler to invoke the request. - // - int invokeCollocated(CollocatedRequestHandler handler); - - // - // Called by the connection when the message is confirmed sent. The - // connection is locked when this is called so this method can't call the - // sent callback. Instead, this method returns true if there's a sent - // callback and false otherwise. If true is returned, the connection will - // call the __invokeSent() method bellow (which in turn should call the sent - // callback). - // - boolean sent(); - - // - // Called by the connection to call the user sent callback. - // - void invokeSent(); - - // - // Called by the connection when the request failed. - // - void finished(Ice.Exception ex); - - // - // Helper to dispatch the cancellation exception. - // - void dispatchInvocationCancel(Ice.LocalException ex, ThreadPool threadPool, Ice.Connection connection); -} diff --git a/java/src/IceInternal/OutgoingConnectionFactory.java b/java/src/IceInternal/OutgoingConnectionFactory.java index 534888ec89e..116038ad537 100644 --- a/java/src/IceInternal/OutgoingConnectionFactory.java +++ b/java/src/IceInternal/OutgoingConnectionFactory.java @@ -265,7 +265,7 @@ public final class OutgoingConnectionFactory } public void - flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) + flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) { java.util.List<Ice.ConnectionI> c = new java.util.LinkedList<Ice.ConnectionI>(); diff --git a/java/src/IceInternal/ProxyBatchOutgoingAsync.java b/java/src/IceInternal/ProxyBatchOutgoingAsync.java deleted file mode 100644 index 4a575142da7..00000000000 --- a/java/src/IceInternal/ProxyBatchOutgoingAsync.java +++ /dev/null @@ -1,97 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -package IceInternal; - -public class ProxyBatchOutgoingAsync extends BatchOutgoingAsync -{ - public ProxyBatchOutgoingAsync(Ice.ObjectPrxHelperBase prx, String operation, CallbackBase callback) - { - super(prx.ice_getCommunicator(), prx.__reference().getInstance(), operation, callback); - _proxy = prx; - _observer = ObserverHelper.get(prx, operation); - } - - public void __invoke() - { - Protocol.checkSupportedProtocol(_proxy.__reference().getProtocol()); - - try - { - _handler = _proxy.__getRequestHandler(); - int status = _handler.sendAsyncRequest(this); - if((status & AsyncStatus.Sent) > 0) - { - _sentSynchronously = true; - if((status & AsyncStatus.InvokeSentCallback) > 0) - { - invokeSent(); - } - } - else - { - synchronized(_monitor) - { - if((_state & StateDone) == 0) - { - int invocationTimeout = _handler.getReference().getInvocationTimeout(); - if(invocationTimeout > 0) - { - _future = _instance.timer().schedule(new Runnable() - { - @Override - public void run() - { - timeout(); - } - }, invocationTimeout, java.util.concurrent.TimeUnit.MILLISECONDS); - _timeoutRequestHandler = _handler; - } - } - } - } - } - catch(RetryException ex) - { - // - // Clear request handler but don't retry or throw. Retrying - // isn't useful, there were no batch requests associated with - // the proxy's request handler. - // - _proxy.__setRequestHandler(_handler, null); - } - catch(Ice.Exception ex) - { - if(_observer != null) - { - _observer.failed(ex.ice_name()); - } - _proxy.__setRequestHandler(_handler, null); // Clear request handler - throw ex; // Throw to notify the user lthat batch requests were potentially lost. - } - } - - @Override - public Ice.ObjectPrx getProxy() - { - return _proxy; - } - - @Override - protected void cancelRequest() - { - if(_handler != null) - { - _handler.asyncRequestCanceled(this, new Ice.OperationInterruptedException()); - } - } - - final private Ice.ObjectPrxHelperBase _proxy; - private RequestHandler _handler = null; -} diff --git a/java/src/IceInternal/ProxyFactory.java b/java/src/IceInternal/ProxyFactory.java index fb664c89b9b..a5165c37374 100644 --- a/java/src/IceInternal/ProxyFactory.java +++ b/java/src/IceInternal/ProxyFactory.java @@ -217,7 +217,7 @@ public final class ProxyFactory // // Don't retry invocation timeouts. // - if(ex instanceof Ice.InvocationTimeoutException) + if(ex instanceof Ice.InvocationTimeoutException || ex instanceof Ice.InvocationCanceledException) { throw ex; } diff --git a/java/src/IceInternal/ProxyFlushBatch.java b/java/src/IceInternal/ProxyFlushBatch.java new file mode 100644 index 00000000000..d3708dc67e3 --- /dev/null +++ b/java/src/IceInternal/ProxyFlushBatch.java @@ -0,0 +1,71 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProxyFlushBatch extends ProxyOutgoingAsyncBase +{ + public static ProxyFlushBatch check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (ProxyFlushBatch)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + public ProxyFlushBatch(Ice.ObjectPrxHelperBase prx, String operation, CallbackBase callback) + { + super(prx, operation, callback); + _observer = ObserverHelper.get(prx, operation); + } + + @Override + public boolean sent() + { + return sent(true); // Overriden because the flush is done even if using a two-way proxy. + } + + @Override + public int send(Ice.ConnectionI connection, boolean compress, boolean response) + { + _cachedConnection = connection; + return connection.flushAsyncBatchRequests(this); + } + + @Override + public int invokeCollocated(CollocatedRequestHandler handler) + { + return handler.invokeAsyncBatchRequests(this); + } + + public void invoke() + { + Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(_proxy.__reference().getProtocol())); + invokeImpl(true); // userThread = true + } + + @Override + protected void handleRetryException(RetryException exc) + { + _proxy.__setRequestHandler(_handler, null); // Clear request handler + throw exc.get(); // No retries, we want to notify the user of potentially lost batch requests + } + + @Override + protected int handleException(Ice.Exception exc) + { + _proxy.__setRequestHandler(_handler, null); // Clear request handler + throw exc; // No retries, we want to notify the user of potentially lost batch requests + } +} diff --git a/java/src/IceInternal/ProxyGetConnection.java b/java/src/IceInternal/ProxyGetConnection.java new file mode 100644 index 00000000000..9f5388218db --- /dev/null +++ b/java/src/IceInternal/ProxyGetConnection.java @@ -0,0 +1,59 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProxyGetConnection extends ProxyOutgoingAsyncBase +{ + public static ProxyGetConnection check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (ProxyGetConnection)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + public ProxyGetConnection(Ice.ObjectPrxHelperBase prx, String operation, CallbackBase cb) + { + super(prx, operation, cb); + _observer = ObserverHelper.get(prx, operation); + } + + @Override + public int send(Ice.ConnectionI connection, boolean compress, boolean response) + throws RetryException + { + _cachedConnection = connection; + if(finished(true)) + { + invokeCompletedAsync(); + } + return AsyncStatus.Sent; + } + + @Override + public int invokeCollocated(CollocatedRequestHandler handler) + { + if(finished(true)) + { + invokeCompletedAsync(); + } + return AsyncStatus.Sent; + } + + public void invoke() + { + invokeImpl(true); // userThread = true + } +} diff --git a/java/src/IceInternal/ProxyOutgoingAsyncBase.java b/java/src/IceInternal/ProxyOutgoingAsyncBase.java new file mode 100644 index 00000000000..eca0de9fcf6 --- /dev/null +++ b/java/src/IceInternal/ProxyOutgoingAsyncBase.java @@ -0,0 +1,278 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// Base class for proxy based invocations. This class handles the +// retry for proxy invocations. It also ensures the child observer is +// correct notified of failures and make sure the retry task is +// correctly canceled when the invocation completes. +// +public abstract class ProxyOutgoingAsyncBase extends OutgoingAsyncBase +{ + public static ProxyOutgoingAsyncBase check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (ProxyOutgoingAsyncBase)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + @Override + public Ice.ObjectPrx getProxy() + { + return _proxy; + } + + @Override + public boolean sent() + { + return sent(!_proxy.ice_isTwoway()); + } + + @Override + public boolean completed(Ice.Exception exc) + { + if(_childObserver != null) + { + _childObserver.failed(exc.ice_name()); + _childObserver.detach(); + _childObserver = null; + } + + // + // NOTE: at this point, synchronization isn't needed, no other threads should be + // calling on the callback. + // + try + { + _instance.retryQueue().add(this, handleException(exc)); + return false; + } + catch(Ice.Exception ex) + { + return finished(ex); // No retries, we're done + } + } + + public void retry() + { + invokeImpl(false); + } + + public void abort(Ice.Exception ex) + { + assert(_childObserver == null); + if(finished(ex)) + { + invokeCompletedAsync(); + } + else if(ex instanceof Ice.CommunicatorDestroyedException) + { + // + // If it's a communicator destroyed exception, don't swallow + // it but instead notify the user thread. Even if no callback + // was provided. + // + throw ex; + } + } + + protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, String op, CallbackBase delegate) + { + super(prx.ice_getCommunicator(), prx.__reference().getInstance(), op, delegate); + _proxy = prx; + _mode = Ice.OperationMode.Normal; + _cnt = 0; + _sent = false; + } + + protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, String op, CallbackBase delegate, BasicStream os) + { + super(prx.ice_getCommunicator(), prx.__reference().getInstance(), op, delegate, os); + _proxy = prx; + _mode = Ice.OperationMode.Normal; + _cnt = 0; + _sent = false; + } + + protected static Ice.AsyncResult checkImpl(Ice.AsyncResult r, Ice.ObjectPrx p, String operation) + { + check(r, operation); + if(r.getProxy() != p) + { + throw new IllegalArgumentException("Proxy for call to end_" + operation + + " does not match proxy that was used to call corresponding " + + "begin_" + operation + " method"); + } + return r; + } + + protected void invokeImpl(boolean userThread) + { + try + { + if(userThread) + { + int invocationTimeout = _proxy.__reference().getInvocationTimeout(); + if(invocationTimeout > 0) + { + _future = _instance.timer().schedule( + new Runnable() + { + @Override + public void run() + { + cancel(new Ice.InvocationTimeoutException()); + } + }, invocationTimeout, java.util.concurrent.TimeUnit.MILLISECONDS); + } + } + else // If not called from the user thread, it's called from the retry queue + { + checkCanceled(); // Cancellation exception aren't retriable + if(_observer != null) + { + _observer.retried(); + } + } + + while(true) + { + try + { + _sent = false; + _handler = _proxy.__getRequestHandler(); + int status = _handler.sendAsyncRequest(this); + if((status & AsyncStatus.Sent) > 0) + { + if(userThread) + { + _sentSynchronously = true; + if((status & AsyncStatus.InvokeSentCallback) > 0) + { + invokeSent(); // Call the sent callback from the user thread. + } + } + else + { + if((status & AsyncStatus.InvokeSentCallback) > 0) + { + invokeSentAsync(); // Call the sent callback from a client thread pool thread. + } + } + } + return; // We're done! + } + catch(RetryException ex) + { + handleRetryException(ex); + } + catch(Ice.Exception ex) + { + if(_childObserver != null) + { + _childObserver.failed(ex.ice_name()); + _childObserver.detach(); + _childObserver = null; + } + final int interval = handleException(ex); + if(interval > 0) + { + _instance.retryQueue().add(this, interval); + return; + } + else if(_observer != null) + { + checkCanceled(); + _observer.retried(); + } + } + } + } + catch(Ice.Exception ex) + { + // + // If called from the user thread we re-throw, the exception + // will be catch by the caller and abort() will be called. + // + if(userThread) + { + throw ex; + } + else if(finished(ex)) // No retries, we're done + { + invokeCompletedAsync(); + } + } + } + + @Override + protected boolean sent(boolean done) + { + _sent = true; + if(done) + { + if(_future != null) + { + _future.cancel(false); + _future = null; + } + } + return super.sent(done); + } + + @Override + protected boolean finished(Ice.Exception ex) + { + if(_future != null) + { + _future.cancel(false); + _future = null; + } + return super.finished(ex); + } + + @Override + protected boolean finished(boolean ok) + { + if(_future != null) + { + _future.cancel(false); + _future = null; + } + return super.finished(ok); + } + + protected void handleRetryException(RetryException exc) + { + _proxy.__setRequestHandler(_handler, null); // Clear request handler and always retry. + } + + protected int handleException(Ice.Exception exc) + { + Ice.Holder<Integer> interval = new Ice.Holder<Integer>(); + _cnt = _proxy.__handleException(exc, _handler, _mode, _sent, interval, _cnt); + return interval.value; + } + + final protected Ice.ObjectPrxHelperBase _proxy; + protected RequestHandler _handler; + protected Ice.OperationMode _mode; + + private java.util.concurrent.Future<?> _future; + private int _cnt; + private boolean _sent; +} diff --git a/java/src/IceInternal/QueueRequestHandler.java b/java/src/IceInternal/QueueRequestHandler.java index 5f40ea37403..fdb7a672e2a 100644 --- a/java/src/IceInternal/QueueRequestHandler.java +++ b/java/src/IceInternal/QueueRequestHandler.java @@ -124,7 +124,7 @@ public class QueueRequestHandler implements RequestHandler @Override public int - sendAsyncRequest(final OutgoingAsyncMessageCallback out) throws RetryException + sendAsyncRequest(final OutgoingAsyncBase out) throws RetryException { try { @@ -148,15 +148,16 @@ public class QueueRequestHandler implements RequestHandler } @Override - public boolean - asyncRequestCanceled(final OutgoingAsyncMessageCallback outAsync, final Ice.LocalException ex) + public void + asyncRequestCanceled(final OutgoingAsyncBase outAsync, final Ice.LocalException ex) { - return performCallable(new Callable<Boolean>() + performCallable(new Callable<Void>() { @Override - public Boolean call() + public Void call() { - return _delegate.asyncRequestCanceled(outAsync, ex); + _delegate.asyncRequestCanceled(outAsync, ex); + return null; } }); } diff --git a/java/src/IceInternal/RequestHandler.java b/java/src/IceInternal/RequestHandler.java index 1e0e4a7909a..f87b215919f 100644 --- a/java/src/IceInternal/RequestHandler.java +++ b/java/src/IceInternal/RequestHandler.java @@ -9,7 +9,7 @@ package IceInternal; -public interface RequestHandler +public interface RequestHandler extends CancellationHandler { RequestHandler connect(); RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler); @@ -19,11 +19,9 @@ public interface RequestHandler void finishBatchRequest(BasicStream out); void abortBatchRequest(); - int sendAsyncRequest(OutgoingAsyncMessageCallback out) + int sendAsyncRequest(OutgoingAsyncBase out) throws RetryException; - boolean asyncRequestCanceled(OutgoingAsyncMessageCallback outAsync, Ice.LocalException ex); - Reference getReference(); Ice.ConnectionI getConnection(); diff --git a/java/src/IceInternal/RetryQueue.java b/java/src/IceInternal/RetryQueue.java index 2c322d1cb72..82831529545 100644 --- a/java/src/IceInternal/RetryQueue.java +++ b/java/src/IceInternal/RetryQueue.java @@ -16,8 +16,7 @@ public class RetryQueue _instance = instance; } - synchronized public void - add(OutgoingAsyncBase outAsync, int interval) + synchronized public void add(ProxyOutgoingAsyncBase outAsync, int interval) { if(_instance == null) { @@ -26,10 +25,10 @@ public class RetryQueue RetryTask task = new RetryTask(this, outAsync); task.setFuture(_instance.timer().schedule(task, interval, java.util.concurrent.TimeUnit.MILLISECONDS)); _requests.add(task); + outAsync.cancelable(task); } - synchronized public void - destroy() + synchronized public void destroy() { java.util.HashSet<RetryTask> keep = new java.util.HashSet<RetryTask>(); for(RetryTask task : _requests) @@ -65,14 +64,14 @@ public class RetryQueue } } - synchronized void - remove(RetryTask task) + synchronized boolean remove(RetryTask task) { - _requests.remove(task); + boolean removed = _requests.remove(task); if(_instance == null && _requests.isEmpty()) { notify(); } + return removed; } private Instance _instance; diff --git a/java/src/IceInternal/RetryTask.java b/java/src/IceInternal/RetryTask.java index 64a54bd45b5..974dc998a79 100644 --- a/java/src/IceInternal/RetryTask.java +++ b/java/src/IceInternal/RetryTask.java @@ -9,26 +9,18 @@ package IceInternal; -class RetryTask implements Runnable +class RetryTask implements Runnable, CancellationHandler { - RetryTask(RetryQueue queue, OutgoingAsyncBase outAsync) + RetryTask(RetryQueue queue, ProxyOutgoingAsyncBase outAsync) { _queue = queue; _outAsync = outAsync; } @Override - public void - run() + public void run() { - try - { - _outAsync.processRetry(); - } - catch(Ice.LocalException ex) - { - _outAsync.invokeExceptionAsync(ex); - } + _outAsync.retry(); // // NOTE: this must be called last, destroy() blocks until all task @@ -39,12 +31,32 @@ class RetryTask implements Runnable _queue.remove(this); } - public boolean - destroy() + @Override + public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) + { + if(_queue.remove(this) && _future.cancel(false)) + { + // + // We just retry the outgoing async now rather than marking it + // as finished. The retry will check for the cancellation + // exception and terminate appropriately the request. + // + _outAsync.retry(); + } + } + + public boolean destroy() { if(_future.cancel(false)) { - _outAsync.invokeExceptionAsync(new Ice.CommunicatorDestroyedException()); + try + { + _outAsync.abort(new Ice.CommunicatorDestroyedException()); + } + catch(Ice.CommunicatorDestroyedException ex) + { + // Abort can throw if there's no callback, just ignore in this case + } return true; } return false; @@ -56,6 +68,6 @@ class RetryTask implements Runnable } private final RetryQueue _queue; - private final OutgoingAsyncBase _outAsync; + private final ProxyOutgoingAsyncBase _outAsync; private java.util.concurrent.Future<?> _future; } diff --git a/java/test/Ice/ami/AMI.java b/java/test/Ice/ami/AMI.java index aa3f9c9b328..ab1591c3c10 100644 --- a/java/test/Ice/ami/AMI.java +++ b/java/test/Ice/ami/AMI.java @@ -1722,6 +1722,26 @@ public class AMI test(r.isSent()); test(r.isCompleted()); test(p.waitForBatch(2)); + + final FlushCallback cb2 = new FlushCallback(); + Ice.AsyncResult r2 = b1.begin_ice_flushBatchRequests( + new Ice.Callback() + { + @Override + public void completed(Ice.AsyncResult result) + { + cb2.completedAsync(result); + } + + @Override + public void sent(Ice.AsyncResult result) + { + cb2.sentAsync(result); + } + }); + cb2.check(); + test(r2.isSent()); + test(r2.isCompleted()); } if(p.ice_getConnection() != null) @@ -2400,6 +2420,82 @@ public class AMI communicator.end_flushBatchRequests(r); } } + + if(p.ice_getConnection() != null) + { + Ice.AsyncResult r1 = null; + Ice.AsyncResult r2 = null; + + testController.holdAdapter(); + try + { + Ice.AsyncResult r; + byte[] seq = new byte[10024]; + new java.util.Random().nextBytes(seq); // Make sure the request doesn't compress too well. + while((r = p.begin_opWithPayload(seq)).sentSynchronously()); + + test(!r.isSent()); + + r1 = p.begin_ice_ping(); + r2 = p.begin_ice_id(); + r1.cancel(); + r2.cancel(); + try + { + p.end_ice_ping(r1); + test(false); + } + catch(Ice.InvocationCanceledException ex) + { + } + try + { + p.end_ice_id(r2); + test(false); + } + catch(Ice.InvocationCanceledException ex) + { + } + } + finally + { + testController.resumeAdapter(); + p.ice_ping(); + test(!r1.isSent() && r1.isCompleted()); + test(!r2.isSent() && r2.isCompleted()); + } + + testController.holdAdapter(); + try + { + r1 = p.begin_op(); + r2 = p.begin_ice_id(); + r1.waitForSent(); + r2.waitForSent(); + r1.cancel(); + r2.cancel(); + try + { + p.end_op(r1); + test(false); + } + catch(Ice.InvocationCanceledException ex) + { + } + try + { + p.end_ice_id(r2); + test(false); + } + catch(Ice.InvocationCanceledException ex) + { + } + } + finally + { + testController.resumeAdapter(); + } + } } out.println("ok"); diff --git a/java/test/Ice/ami/lambda/AMI.java b/java/test/Ice/ami/lambda/AMI.java index 0e013b97435..65bd185a849 100644 --- a/java/test/Ice/ami/lambda/AMI.java +++ b/java/test/Ice/ami/lambda/AMI.java @@ -881,6 +881,15 @@ public class AMI test(r.isSent()); test(r.isCompleted()); test(p.waitForBatch(2)); + + final FlushCallback cb2 = new FlushCallback(); + Ice.AsyncResult r2 = b1.ice_getConnection().begin_flushBatchRequests( + null, + (Ice.Exception ex) -> cb2.exception(ex), + (boolean sentSynchronously) -> cb2.sent(sentSynchronously)); + cb2.check(); + test(r2.isSent()); + test(r2.isCompleted()); } { diff --git a/java/test/Ice/retry/AllTests.java b/java/test/Ice/retry/AllTests.java index 42f40727eef..cdcdc586961 100644 --- a/java/test/Ice/retry/AllTests.java +++ b/java/test/Ice/retry/AllTests.java @@ -139,7 +139,7 @@ public class AllTests retry1.op(false); out.println("ok"); - int invocationCount = 3; + Instrumentation.testInvocationCount(3); out.print("calling operation to kill connection with second proxy... "); out.flush(); @@ -155,7 +155,7 @@ public class AllTests catch(Ice.ConnectionLostException ex) { } - Instrumentation.testInvocationCount(invocationCount + 1); + Instrumentation.testInvocationCount(1); Instrumentation.testFailureCount(1); Instrumentation.testRetryCount(0); out.println("ok"); @@ -163,8 +163,8 @@ public class AllTests out.print("calling regular operation with first proxy again... "); out.flush(); retry1.op(false); - Instrumentation.testInvocationCount(invocationCount + 2); - Instrumentation.testFailureCount(1); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(0); out.println("ok"); @@ -174,66 +174,67 @@ public class AllTests out.print("calling regular AMI operation with first proxy... "); retry1.begin_op(false, cb1); cb1.check(); - Instrumentation.testInvocationCount(invocationCount + 3); - Instrumentation.testFailureCount(1); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(0); out.println("ok"); out.print("calling AMI operation to kill connection with second proxy... "); retry2.begin_op(true, cb2); cb2.check(); - Instrumentation.testInvocationCount(invocationCount + 4); - Instrumentation.testFailureCount(2); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); Instrumentation.testRetryCount(0); out.println("ok"); out.print("calling regular AMI operation with first proxy again... "); retry1.begin_op(false, cb1); cb1.check(); - Instrumentation.testInvocationCount(invocationCount + 5); - Instrumentation.testFailureCount(2); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(0); out.println("ok"); out.print("testing idempotent operation... "); - test(retry1.opIdempotent(0) == 4); - Instrumentation.testInvocationCount(invocationCount + 6); - Instrumentation.testFailureCount(2); + test(retry1.opIdempotent(4) == 4); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); + Instrumentation.testRetryCount(4); + test(retry1.end_opIdempotent(retry1.begin_opIdempotent(4)) == 4); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(0); Instrumentation.testRetryCount(4); - test(retry1.end_opIdempotent(retry1.begin_opIdempotent(4)) == 8); - Instrumentation.testInvocationCount(invocationCount + 7); - Instrumentation.testFailureCount(2); - Instrumentation.testRetryCount(8); out.println("ok"); out.print("testing non-idempotent operation... "); try { - retry1.opNotIdempotent(8); + retry1.opNotIdempotent(); test(false); } catch(Ice.LocalException ex) { } - Instrumentation.testInvocationCount(invocationCount + 8); - Instrumentation.testFailureCount(3); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); try { - retry1.end_opNotIdempotent(retry1.begin_opNotIdempotent(9)); + retry1.end_opNotIdempotent(retry1.begin_opNotIdempotent()); test(false); } catch(Ice.LocalException ex) { } - Instrumentation.testInvocationCount(invocationCount + 9); - Instrumentation.testFailureCount(4); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); out.println("ok"); if(retry1.ice_getConnection() == null) { - invocationCount = invocationCount + 10; + Instrumentation.testInvocationCount(1); + out.print("testing system exception... "); try { @@ -243,9 +244,9 @@ public class AllTests catch(SystemFailure ex) { } - Instrumentation.testInvocationCount(invocationCount + 1); - Instrumentation.testFailureCount(5); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); try { retry1.end_opSystemException(retry1.begin_opSystemException()); @@ -254,12 +255,41 @@ public class AllTests catch(SystemFailure ex) { } - Instrumentation.testInvocationCount(invocationCount + 2); - Instrumentation.testFailureCount(6); - Instrumentation.testRetryCount(8); + Instrumentation.testInvocationCount(1); + Instrumentation.testFailureCount(1); + Instrumentation.testRetryCount(0); out.println("ok"); } + out.print("testing invocation timeout and retries... "); + out.flush(); + try + { + // No more than 2 retries before timeout kicks-in + ((RetryPrx)retry1.ice_invocationTimeout(50)).opIdempotent(4); + test(false); + } + catch(Ice.InvocationTimeoutException ex) + { + Instrumentation.testRetryCount(2); + retry1.opIdempotent(-1); // Reset the counter + Instrumentation.testRetryCount(-1); + } + try + { + // No more than 2 retries before timeout kicks-in + RetryPrx prx = (RetryPrx)retry1.ice_invocationTimeout(50); + prx.end_opIdempotent(prx.begin_opIdempotent(4)); + test(false); + } + catch(Ice.InvocationTimeoutException ex) + { + Instrumentation.testRetryCount(2); + retry1.opIdempotent(-1); // Reset the counter + Instrumentation.testRetryCount(-1); + } + out.println("ok"); + return retry1; } } diff --git a/java/test/Ice/retry/Client.java b/java/test/Ice/retry/Client.java index aaec9406b13..190fda805dd 100644 --- a/java/test/Ice/retry/Client.java +++ b/java/test/Ice/retry/Client.java @@ -31,7 +31,7 @@ public class Client extends test.Util.Application initData.properties.setProperty("Ice.Package.Test", "test.Ice.retry"); - initData.properties.setProperty("Ice.RetryIntervals", "0 10 20 30"); + initData.properties.setProperty("Ice.RetryIntervals", "0 1 100 1"); // // We don't want connection warnings because of the timeout diff --git a/java/test/Ice/retry/Collocated.java b/java/test/Ice/retry/Collocated.java index 63868d1d64a..a193c18eaf4 100644 --- a/java/test/Ice/retry/Collocated.java +++ b/java/test/Ice/retry/Collocated.java @@ -35,7 +35,7 @@ public class Collocated extends test.Util.Application initData.properties.setProperty("Ice.Package.Test", "test.Ice.retry"); - initData.properties.setProperty("Ice.RetryIntervals", "0 10 20 30"); + initData.properties.setProperty("Ice.RetryIntervals", "0 1 100 1"); // // We don't want connection warnings because of the timeout diff --git a/java/test/Ice/retry/Instrumentation.java b/java/test/Ice/retry/Instrumentation.java index 4c825ba7231..609a8225ef2 100644 --- a/java/test/Ice/retry/Instrumentation.java +++ b/java/test/Ice/retry/Instrumentation.java @@ -149,8 +149,14 @@ public class Instrumentation static private void testEqual(Ice.IntHolder value, int expected) { + if(expected < 0) + { + value.value = 0; + return; + } + int retry = 0; - while(retry < 100) + while(++retry < 100) { synchronized(Instrumentation.class) { @@ -172,6 +178,7 @@ public class Instrumentation System.err.println("value = " + value.value + ", expected = " + expected); test(false); } + value.value = 0; } static public void diff --git a/java/test/Ice/retry/RetryI.java b/java/test/Ice/retry/RetryI.java index 31a0b104f55..f2afcc881dd 100644 --- a/java/test/Ice/retry/RetryI.java +++ b/java/test/Ice/retry/RetryI.java @@ -36,9 +36,15 @@ public final class RetryI extends _RetryDisp @Override public int - opIdempotent(int counter, Ice.Current current) + opIdempotent(int nRetry, Ice.Current current) { - if(counter + nRetry > _counter) + if(nRetry < 0) + { + _counter = 0; + return 0; + } + + if(nRetry > _counter) { ++_counter; if(current.con != null) @@ -49,20 +55,18 @@ public final class RetryI extends _RetryDisp { throw new Ice.ConnectionLostException(); } + return 0; } - return _counter; + + int counter = _counter; + _counter = 0; + return counter; } @Override public void - opNotIdempotent(int counter, Ice.Current current) + opNotIdempotent(Ice.Current current) { - if(_counter != counter) - { - return; - } - - ++_counter; if(current.con != null) { current.con.close(true); @@ -88,5 +92,4 @@ public final class RetryI extends _RetryDisp } private int _counter; - static final int nRetry = 4; } diff --git a/java/test/Ice/retry/Test.ice b/java/test/Ice/retry/Test.ice index aeffa8e72fc..0e1be095f41 100644 --- a/java/test/Ice/retry/Test.ice +++ b/java/test/Ice/retry/Test.ice @@ -18,10 +18,10 @@ interface Retry void op(bool kill); idempotent int opIdempotent(int c); - void opNotIdempotent(int c); + void opNotIdempotent(); void opSystemException(); - void shutdown(); + idempotent void shutdown(); }; }; diff --git a/js/test/Ice/retry/Test.ice b/js/test/Ice/retry/Test.ice index 61297d94557..bd73167b511 100644 --- a/js/test/Ice/retry/Test.ice +++ b/js/test/Ice/retry/Test.ice @@ -20,7 +20,7 @@ interface Retry void opNotIdempotent(int c); void opSystemException(); - void shutdown(); + idempotent void shutdown(); }; }; diff --git a/py/modules/IcePy/Operation.cpp b/py/modules/IcePy/Operation.cpp index ac5221029fd..740a8ff8902 100644 --- a/py/modules/IcePy/Operation.cpp +++ b/py/modules/IcePy/Operation.cpp @@ -24,7 +24,7 @@ #include <Ice/LocalException.h> #include <Ice/Logger.h> #include <Ice/ObjectAdapter.h> -#include <Ice/OutgoingAsync.h> +#include <Ice/AsyncResult.h> #include <Ice/Properties.h> #include <Ice/Proxy.h> #include <Slice/PythonUtil.h> @@ -814,6 +814,25 @@ asyncResultGetCommunicator(AsyncResultObject* self) extern "C" #endif static PyObject* +asyncResultCancel(AsyncResultObject* self) +{ + try + { + (*self->result)->cancel(); + } + catch(...) + { + assert(false); + } + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef WIN32 +extern "C" +#endif +static PyObject* asyncResultGetConnection(AsyncResultObject* self) { if(self->connection) @@ -1255,6 +1274,8 @@ static PyMethodDef AMDCallbackMethods[] = static PyMethodDef AsyncResultMethods[] = { + { STRCAST("cancel"), reinterpret_cast<PyCFunction>(asyncResultCancel), METH_NOARGS, + PyDoc_STR(STRCAST("cancels the invocation")) }, { STRCAST("getCommunicator"), reinterpret_cast<PyCFunction>(asyncResultGetCommunicator), METH_NOARGS, PyDoc_STR(STRCAST("returns the communicator for the invocation")) }, { STRCAST("getConnection"), reinterpret_cast<PyCFunction>(asyncResultGetConnection), METH_NOARGS, diff --git a/py/modules/IcePy/Operation.h b/py/modules/IcePy/Operation.h index e9691c63f8f..6dc478eebb4 100644 --- a/py/modules/IcePy/Operation.h +++ b/py/modules/IcePy/Operation.h @@ -13,7 +13,7 @@ #include <Config.h> #include <Ice/Current.h> #include <Ice/Object.h> -#include <Ice/OutgoingAsyncF.h> +#include <Ice/AsyncResultF.h> #include <Ice/CommunicatorF.h> namespace IcePy diff --git a/py/modules/IcePy/Types.h b/py/modules/IcePy/Types.h index 2acd5f54320..7a96cf1fafd 100644 --- a/py/modules/IcePy/Types.h +++ b/py/modules/IcePy/Types.h @@ -15,6 +15,8 @@ #include <Ice/Stream.h> #include <IceUtil/OutputUtil.h> +#include <set> + namespace IcePy { diff --git a/py/test/Ice/ami/AllTests.py b/py/test/Ice/ami/AllTests.py index ed5e6603f6a..5ddefdd8c4a 100644 --- a/py/test/Ice/ami/AllTests.py +++ b/py/test/Ice/ami/AllTests.py @@ -977,6 +977,66 @@ def allTests(communicator, collocated): test(r.getCommunicator() == communicator) test(r.getProxy() == None) # Expected communicator.end_flushBatchRequests(r) + + if(p.ice_getConnection()): + r1 = None; + r2 = None; + + if sys.version_info[0] == 2: + b = [chr(random.randint(0, 255)) for x in range(0, 1024)] # Make sure the request doesn't compress too well. + seq = ''.join(b) + else: + b = [random.randint(0, 255) for x in range(0, 1024)] # Make sure the request doesn't compress too well. + seq = bytes(b) + + testController.holdAdapter() + while(True): + r = p.begin_opWithPayload(seq) + if not r.sentSynchronously(): + break + + test(not r.isSent()) + + r1 = p.begin_ice_ping() + r2 = p.begin_ice_id() + r1.cancel() + r2.cancel() + try: + p.end_ice_ping(r1) + test(false) + except(Ice.InvocationCanceledException): + pass + + try: + p.end_ice_id(r2) + test(false) + except(Ice.InvocationCanceledException): + pass + + testController.resumeAdapter() + p.ice_ping() + test(not r1.isSent() and r1.isCompleted()) + test(not r2.isSent() and r2.isCompleted()) + + testController.holdAdapter() + + r1 = p.begin_op() + r2 = p.begin_ice_id() + r1.waitForSent() + r2.waitForSent() + r1.cancel() + r2.cancel() + try: + p.end_op(r1) + test(false) + except: + pass + try: + p.end_ice_id(r2) + test(false) + except: + pass + testController.resumeAdapter() print("ok") diff --git a/slice/Ice/LocalException.ice b/slice/Ice/LocalException.ice index 249a92cc0c2..6665d71d6ad 100644 --- a/slice/Ice/LocalException.ice +++ b/slice/Ice/LocalException.ice @@ -641,6 +641,18 @@ local exception InvocationTimeoutException extends TimeoutException /** * + * This exception indicates that an asynchronous invocation failed + * because it was canceled explicitly by the user using the + * <tt>Ice::AsyncResult::cancel</tt> method. + * + **/ +["cpp:ice_print"] +local exception InvocationCanceledException +{ +}; + +/** + * * A generic exception base for all kinds of protocol error * conditions. * |