You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2011/10/21 00:39:50 UTC
svn commit: r1187108 - in /trafficserver/traffic/trunk: ./ iocore/net/
proxy/http/
Author: amc
Date: Thu Oct 20 22:39:49 2011
New Revision: 1187108
URL: http://svn.apache.org/viewvc?rev=1187108&view=rev
Log:
TS-934 Wrapper for NetVConnection to allow safer locking of connection objects between threads.
Modified:
trafficserver/traffic/trunk/CHANGES
trafficserver/traffic/trunk/iocore/net/I_NetVConnection.h
trafficserver/traffic/trunk/iocore/net/NetVConnection.cc
trafficserver/traffic/trunk/iocore/net/UnixNet.cc
trafficserver/traffic/trunk/iocore/net/UnixNetVConnection.cc
trafficserver/traffic/trunk/proxy/http/HttpSM.cc
trafficserver/traffic/trunk/proxy/http/HttpServerSession.cc
trafficserver/traffic/trunk/proxy/http/HttpServerSession.h
Modified: trafficserver/traffic/trunk/CHANGES
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/CHANGES?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/CHANGES (original)
+++ trafficserver/traffic/trunk/CHANGES Thu Oct 20 22:39:49 2011
@@ -1,5 +1,10 @@
-*- coding: utf-8 -*-
Changes with Apache Traffic Server 3.1.1
+
+ *) [TS-934] Added some wrapping around NetVConnection for server
+ handling so that connection objects can be safely locked across
+ threads.
+
*) [TS-991] Fixed race / stall condition for WCCP during restart.
*) [TS-985] ts/ts.h uses C++ comments, which are technically not C.
Modified: trafficserver/traffic/trunk/iocore/net/I_NetVConnection.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/iocore/net/I_NetVConnection.h?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/iocore/net/I_NetVConnection.h (original)
+++ trafficserver/traffic/trunk/iocore/net/I_NetVConnection.h Thu Oct 20 22:39:49 2011
@@ -402,6 +402,7 @@ public:
unsigned int attributes;
EThread *thread;
+ volatile uint32_t generation; ///< Counter for re-use checking.
/// PRIVATE: The public interface is VIO::reenable()
virtual void reenable(VIO * vio) = 0;
@@ -459,6 +460,88 @@ public:
is_other_side_transparent = value;
}
+ /** Struct for holding a reference to a connection.
+ The problem is that connections are accessed across thread boundaries
+ and re-used so that a pointer to a VC can become not only stale
+ but a reference to another connection entirely aynchronously. The
+ lock is contained within the connection so it can't be reliably accessed
+ from just a raw pointer.
+ */
+ struct Handle {
+ typedef Handle self; ///< Self reference type.
+
+ NetVConnection* _vc; ///< Pointer to the VC.
+ uint32_t _generation; ///< Generation of VC when assigned.
+ ProxyMutexPtr _mutex; ///< Shared mutex with VC at time of assignment.
+
+ /// Default constructor.
+ Handle() : _vc(0), _generation(0) {}
+ /// Construct from VC.
+ Handle(NetVConnection* vc) { *this = vc; }
+ /// Assign VC.
+ self& operator = (NetVConnection* vc) {
+ _vc = vc;
+ if (vc) {
+ _mutex = vc->mutex;
+ _generation = vc->generation;
+ } else {
+ _generation = 0;
+ _mutex.clear();
+ }
+ return *this;
+ }
+
+ /// Dereference operator.
+ NetVConnection* operator -> () { return _vc; }
+ /// Get referenced VC.
+ NetVConnection* getVC() { return _vc; }
+ /// Get pointer mutex.
+ ProxyMutexPtr& getMutex() { return _mutex; }
+ /** Check if this reference is still valid.
+ This should only be called under lock of @a _mutex.
+ @return @c true
+ */
+ bool isValid() {
+ return _vc && // have a connection
+ _mutex.m_ptr == _vc->mutex.m_ptr && // and it's still the same mutex
+ _generation == _vc->generation // and same generation.
+ ;
+ }
+ /** Invoke @c do_io_close on the underlying VC.
+ This handles locking and validating the VC. If a lock can be obtained
+ then the operation is performed immediately. If not then it is
+ scheduled on the thread holding the lock.
+ */
+ void do_locked_io_close(int lerrno = -1);
+ };
+
+ /** A subclass of @c Handle that can be used in @c IntrusivePtrList.
+ */
+
+ /** Use this to schedule closing the connection.
+
+ This can be needed if the connection is part of a transaction
+ but being handled in another thread. The continuation mutex is a
+ shared reference to the VC mutex so that it is not garbage
+ collected and can be checked against the VC after being locked.
+ */
+ struct Close_callback : public Continuation {
+ typedef Continuation super; ///< Super type.
+ typedef Close_callback self; ///< Self reference type.
+
+ Handle _vcptr; ///< Reference to the target VC.
+ int _lerrno; ///< Errno value to pass to @c do_io_close.
+
+ int try_close(int, Event *);
+
+ Close_callback(Handle const& vcptr, int lerrno = -1)
+ : super(&*(vcptr._mutex))
+ , _vcptr(vcptr)
+ , _lerrno(lerrno) {
+ SET_HANDLER(&self::try_close);
+ }
+ };
+
private:
NetVConnection(const NetVConnection &);
NetVConnection & operator =(const NetVConnection &);
@@ -485,14 +568,15 @@ NetVConnection::NetVConnection():
VConnection(NULL),
attributes(0),
thread(NULL),
+ generation(1),
got_local_addr(0),
got_remote_addr(0),
is_internal_request(false),
is_transparent(false),
is_other_side_transparent(false)
{
- memset(&local_addr, 0, sizeof(local_addr));
- memset(&remote_addr, 0, sizeof(remote_addr));
+ ink_zero(local_addr);
+ ink_zero(remote_addr);
}
#endif
Modified: trafficserver/traffic/trunk/iocore/net/NetVConnection.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/iocore/net/NetVConnection.cc?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/iocore/net/NetVConnection.cc (original)
+++ trafficserver/traffic/trunk/iocore/net/NetVConnection.cc Thu Oct 20 22:39:49 2011
@@ -44,3 +44,64 @@ NetVConnection::cancel_OOB()
return;
}
+int
+NetVConnection::Close_callback::try_close(int, Event *) {
+ // Mutex for this continuation is the original VC mutex so if we're
+ // being dispatched, it should be locked enough to check.
+ if (_vcptr.isValid()) {
+ _vcptr->do_io_close(_lerrno);
+ }
+ delete this;
+ return EVENT_DONE;
+}
+
+void
+NetVConnection::Handle::do_locked_io_close(int lerrno) {
+ EThread* t = this_ethread();
+ // If the VC or the mutex isn't there, we're done.
+ bool handled = ! (_vc && _mutex.m_ptr);
+ /* This loop is an attempt to avoid race conditions. We need to
+ shut down the VC without colliding with another thread.
+
+ First we try to get the lock. If that works then if our
+ reference is still valid we can do the shutdown directly. If
+ it's not valid we assume that someone else already did the
+ shutdown (such a collision being precisely what we're trying to
+ avoid).
+
+ If we can't get the lock, we need to schedule a retry on the
+ thread that owns the lock. However, we're racing at this because
+ without the lock the VC or the lock itself can change. In
+ particular, the thread owning the lock can drop it and leave us
+ without a valid thread. So we grab what we can and check it. If
+ we have a thread, we schedule there. Otherwise the lock has been
+ dropped so we cycle back to trying the lock.
+
+ We presume that there's extremely little chance of this just
+ missing the lock happening and an infinitesmal chance of it
+ happening more than once. So the loop shouldn't go more than once
+ or twice and then only vary rarely. Further, based on experience
+ in a high throughput environment we should expect to not get the
+ lock in the first place only in rare circumstances. For most
+ situations and in most environments we should not ever do the
+ scheduling. Unfortunately it does happen under some circumstances
+ so we have to deal with it.
+ */
+ while (!handled) {
+ MUTEX_TRY_LOCK(lock, _mutex, t);
+ if (lock) {
+ if (this->isValid()) _vc->do_io_close(lerrno);
+ handled = true;
+ } else {
+ // Gosh, it's probable that the VC has gone bad at this point but
+ // we can't reliably detect that without the lock.
+ EThread* ot = _mutex->thread_holding;
+ ink_assert(ot != t); // we should have the lock in that case.
+ if (ot) {
+ // schedule shutdown on other thread.
+ ot->schedule_imm(NEW(new UnixNetVConnection::Close_callback(*this, lerrno)));
+ handled = true;
+ }
+ }
+ }
+}
Modified: trafficserver/traffic/trunk/iocore/net/UnixNet.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/iocore/net/UnixNet.cc?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/iocore/net/UnixNet.cc (original)
+++ trafficserver/traffic/trunk/iocore/net/UnixNet.cc Thu Oct 20 22:39:49 2011
@@ -51,6 +51,7 @@ struct InactivityCop : public Continuati
forl_LL(UnixNetVConnection, vc, nh->open_list)
nh->cop_list.push(vc);
while (UnixNetVConnection *vc = nh->cop_list.pop()) {
+ MUTEX_LOCK(lock, vc->mutex, this_ethread());
if (vc->closed) {
close_UnixNetVConnection(vc, e->ethread);
continue;
Modified: trafficserver/traffic/trunk/iocore/net/UnixNetVConnection.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/iocore/net/UnixNetVConnection.cc?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/iocore/net/UnixNetVConnection.cc (original)
+++ trafficserver/traffic/trunk/iocore/net/UnixNetVConnection.cc Thu Oct 20 22:39:49 2011
@@ -1106,11 +1106,12 @@ UnixNetVConnection::free(EThread *t)
{
NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, -1);
// clear variables for reuse
+ ++generation;
+ this->mutex.clear();
got_remote_addr = 0;
got_local_addr = 0;
read.vio.mutex.clear();
write.vio.mutex.clear();
- this->mutex.clear();
flags = 0;
accept_port = 0;
SET_CONTINUATION_HANDLER(this, (NetVConnHandler) & UnixNetVConnection::startEvent);
Modified: trafficserver/traffic/trunk/proxy/http/HttpSM.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/http/HttpSM.cc?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/http/HttpSM.cc (original)
+++ trafficserver/traffic/trunk/proxy/http/HttpSM.cc Thu Oct 20 22:39:49 2011
@@ -5931,8 +5931,8 @@ HttpSM::kill_this()
if (second_cache_sm)
second_cache_sm->end_both();
transform_cache_sm.end_both();
- tunnel.deallocate_buffers();
vc_table.cleanup_all();
+ tunnel.deallocate_buffers();
// It possible that a plugin added transform hook
// but the hook never executed due to a client abort
Modified: trafficserver/traffic/trunk/proxy/http/HttpServerSession.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/http/HttpServerSession.cc?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/http/HttpServerSession.cc (original)
+++ trafficserver/traffic/trunk/proxy/http/HttpServerSession.cc Thu Oct 20 22:39:49 2011
@@ -41,7 +41,7 @@ ClassAllocator<HttpServerSession> httpSe
void
HttpServerSession::destroy()
{
- ink_release_assert(server_vc == NULL);
+ ink_release_assert(server_vc.getVC() == NULL);
ink_assert(read_buffer);
ink_assert(server_trans_stat == 0);
magic = HTTP_SS_MAGIC_DEAD;
@@ -119,7 +119,7 @@ HttpServerSession::do_io_close(int alerr
this->server_trans_stat--;
}
- server_vc->do_io_close(alerrno);
+ server_vc.do_locked_io_close(alerrno);
Debug("http_ss", "[%" PRId64 "] session closed", con_id);
server_vc = NULL;
Modified: trafficserver/traffic/trunk/proxy/http/HttpServerSession.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/http/HttpServerSession.h?rev=1187108&r1=1187107&r2=1187108&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/http/HttpServerSession.h (original)
+++ trafficserver/traffic/trunk/proxy/http/HttpServerSession.h Thu Oct 20 22:39:49 2011
@@ -110,7 +110,7 @@ public:
void attach_hostname(const char *hostname);
NetVConnection *get_netvc()
{
- return server_vc;
+ return server_vc.getVC();
};
// Keys for matching hostnames
@@ -160,7 +160,7 @@ public:
private:
HttpServerSession(HttpServerSession &);
- NetVConnection *server_vc;
+ NetVConnection::Handle server_vc;
int magic;
IOBufferReader *buf_reader;