Files
reddit/r2/r2/lib/rpc.py
ketralnis 2869eaf8b9 New features:
* Activate negative-result caching for HardCache chain
    * begin migration to pylibmc:
       * Add pylibmc to the list of required packages in preparation for the replacement of the memcached library
       * Start using pylibmc for the rendercaches
    * Tweak the computation of the normalized hot page to be a bit faster when the precomputer is available, by relying on the precomputer's internal permacached structure.
    * Default to a SelfEmptyingCache for scripts run from `paster run'.  Note that processes that run forever are still responsible for resetting their local-caches, but this can now be done with g.reset_caches()
    * threaded messaging patch part 1: backend changes only.  This will allow migrate.py to be run to move new onto inbox and will start tracking message trees for users.
    * Specify some queries to run at most once per day
    * Refactored safemarkdown() and added soup testing

    Additions:
    * Added _byID_rel()
    * Made error messages more verbose for:
       1. byID lookups of too-big thing_ids
       2. memcache failures
       3. Solr Nones
    * Award._all_awards() now sorts by date
    * Trophy.by_{account,award}() now cache properly
    * new feedback page with helpful links
    * Try to reduce the length of the query-queue by not adding known-long queries at all, rather than adding them and skipping them
    * whitespace clean up
    * simplify the 'why did my CC get denied' email checking.
    * added missing translation strings and users now get PMs when they are added as translators

    Bugfixes:
    * Fix a bug in unsaving
    * BeautifulSoup stopped hosting 3.0.7a, but 3.0.8 still uses the good parser
    * Better search error handling
    * Properly reset the cache-chains (incl. the hardcache; d'oh!) per-request
    * Fix an attribute error on listings where some items have author_ids and some don't
    * Bug when forcing recalculation of memoized functions
    * the subreddit creation and edit form aren't dealing with errors properly
    * buttons fix
2010-05-17 13:27:17 -07:00

164 lines
5.6 KiB
Python

# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is Reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of the
# Original Code is CondeNet, Inc.
#
# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
import socket, cPickle as pickle
from threading import Thread
from SocketServer import DatagramRequestHandler, StreamRequestHandler, ThreadingMixIn, UDPServer, TCPServer
class CustomThreadingMixIn(ThreadingMixIn):
"""Mix-in class to handle each request in a new thread."""
def __init__(self, thread_class = Thread):
self.thread_class = thread_class
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = self.thread_class(target = self.process_request_thread,
args = (request, client_address))
if self.daemon_threads:
t.setDaemon (1)
t.start()
class Responses:
OK, ERROR = range(2)
class SimpleHandler:
def handle(self):
try:
fn_name, a, kw = pickle.load(self.rfile)
fn = getattr(self.server.container, fn_name)
res = (Responses.OK, fn(*a, **kw))
except Exception, e:
res = (Responses.ERROR, e)
try:
self.wfile.write(pickle.dumps(res, -1))
except:
res = (Responses.ERROR, 'Error while pickling.' )
self.wfile.write(pickle.dumps(res, -1))
class SimpleUDPHandler(SimpleHandler, DatagramRequestHandler): pass
class SimpleTCPHandler(SimpleHandler, StreamRequestHandler): pass
class ThreadedUDPServer(CustomThreadingMixIn, UDPServer):
def __init__(self, server_address, RequestHandlerClass, container,
thread_class = Thread):
UDPServer.__init__(self, server_address, RequestHandlerClass)
CustomThreadingMixIn.__init__(self, thread_class)
self.container = container
self.daemon_threads = True
class ThreadedTCPServer(CustomThreadingMixIn, TCPServer):
def __init__(self, server_address, RequestHandlerClass, container,
thread_class = Thread):
self.allow_reuse_address = True
TCPServer.__init__(self, server_address, RequestHandlerClass)
CustomThreadingMixIn.__init__(self, thread_class)
self.container = container
self.daemon_threads = True
class Server:
def __init__(self, container, addr='', port=5000,
daemon=True, tcp=False, thread_class = Thread):
if tcp:
self.s = ThreadedTCPServer((addr, port), SimpleTCPHandler,
container, thread_class)
else:
self.s = ThreadedUDPServer((addr, port), SimpleUDPHandler,
container, thread_class)
self.handle_thread = thread_class(target = self.s.serve_forever)
self.handle_thread.setDaemon(daemon)
self.handle_thread.start()
class RemoteCall:
def __init__(self, client, response_required):
self.client = client
self.response_required = response_required
def __getattr__(self, attr):
def fn(*a, **kw):
return self.client.send(self.response_required, attr, a, kw)
return fn
class Client:
def __init__(self, host='localhost', port=5000, tcp=False):
self.conninfo = (host, port)
self.call = RemoteCall(self, True)
self.call_nr = RemoteCall(self, False)
self.tcp = tcp
def send(self, response_required, fn, a, kw):
msg = pickle.dumps((fn, a, kw), -1)
#get socket + send
if self.tcp:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(self.conninfo)
except:
return
s.send(msg)
else:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(10)
s.sendto(msg, self.conninfo)
if response_required:
infile = s.makefile('rb')
error_code, res = pickle.load(infile)
#close
try:
if self.tcp: s.close()
except: pass
#return
if error_code == Responses.OK:
return res
else:
raise Exception, res
elif self.tcp:
try:
s.close()
except: pass
class TH:
def add(self, x,y):
return x + y
def echo(self, str):
return str
#s = Server(TH)
#c = Client()
#print c.call.add(1,2)
def test_length(client):
x = 0
while True:
print len(client.call.echo(['x' for i in range(x)]))
x += 100
def perf_test(client):
for x in range(1000):
client.call.echo('test')