[thrift] Ruby TThreadedServer and TThreadPoolServer

Summary: They both use the same handler for all connections and thus assume the handler is thread-safe. The TThreadPoolServer preserves threads, so it wouldn't be too hard to make a variant that used a separate handler for each thread and thus didn't require thread safety.

Reviewed By: mcslee

Test Plan: loads without error

Revert Plan: ok

Other Notes: contributed by William Morgan (w@adap.tv)


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665438 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/rb/lib/thrift/server/tserver.rb b/lib/rb/lib/thrift/server/tserver.rb
index 95e6297..6bfc1e0 100644
--- a/lib/rb/lib/thrift/server/tserver.rb
+++ b/lib/rb/lib/thrift/server/tserver.rb
@@ -50,4 +50,72 @@
 
 end
 
+begin
+  require 'fastthread'
+rescue LoadError
+  require 'thread'
+end
+
+class TThreadedServer < TServer
+  def serve()
+    begin
+      @serverTransport.listen()
+      while (true)
+        client = @serverTransport.accept()
+        trans = @transportFactory.getTransport(client)
+        prot = @protocolFactory.getProtocol(trans)
+        Thread.new(prot, trans) do |p, t|
+          begin
+            while (true)
+              @processor.process(p, p)
+            end
+          rescue TTransportException, TProtocolException => e
+          ensure
+            t.close()
+          end
+        end
+      end
+    ensure
+      @serverTransport.close()
+    end
+  end
+end
+
+class TThreadPoolServer < TServer
+  def initialize(processor, serverTransport, transportFactory=nil, protocolFactory=nil, num=20)
+    super(processor, serverTransport, transportFactory, protocolFactory)
+    @q = SizedQueue.new(num)
+  end
+
+  def serve()
+    @serverTransport.listen()
+
+    begin
+      while (true)
+        @q.push(:token)
+        Thread.new do
+          begin
+            while (true)
+              client = @serverTransport.accept()
+              trans = @transportFactory.getTransport(client)
+              prot = @protocolFactory.getProtocol(trans)
+              begin
+                while (true)
+                  @processor.process(prot, prot)
+                end
+              rescue TTransportException, TProtocolException => e
+              ensure
+                trans.close()
+              end
+            end
+          ensure
+            @q.pop() # thread died!
+          end
+        end
+      end
+    ensure
+      @serverTransport.close()
+    end
+  end
+end