Those classes are for common use case. - Event serializing with single queue - request producer/consumer model which will be used for blocking call to be decoupled from hot path
So introduce helper classes to handle them. They will be used by later commit. Signed-off-by: Isaku Yamahata <[email protected]> --- ryu/controller/handler_utils.py | 164 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 ryu/controller/handler_utils.py diff --git a/ryu/controller/handler_utils.py b/ryu/controller/handler_utils.py new file mode 100644 index 0000000..06be463 --- /dev/null +++ b/ryu/controller/handler_utils.py @@ -0,0 +1,164 @@ +# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation. +# Copyright (C) 2011, 2012 Isaku Yamahata <yamahata at private email ne jp> +# +# Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import types + +from ryu.controller import (dispatcher, + event, + handler) + + +LOG = logging.getLogger(__name__) + + +@classmethod +def _cls_nop(_cls, *_args, **_kwargs): + pass + + +def cls_init_once(bound_cls_method, *args, **kwargs): + bound_cls_method(*args, **kwargs) + setattr(bound_cls_method.im_self, bound_cls_method.__name__, _cls_nop) + + +def _cls_set_attr(cls, name, attr): + if not hasattr(cls, name): + setattr(cls, name, attr) + else: + LOG.warn('already attribute %s is defined', name) + + +class QueueSerializer(object): + @classmethod + def _create_proxy_handlers(cls, ev_clses): + for (ev, ev_dispatcher) in ev_clses: + handler_name = 'proxy_%s_%s_handler' % (ev.__name__, ev_dispatcher) + handler_ = lambda self, ev_: self._ev_q.queue(ev_) + handler_ = handler.set_ev_cls(ev, ev_dispatcher)(handler_) + method = types.MethodType(handler_, None, cls) + _cls_set_attr(cls, handler_name, method) + + def __init__(self, queue_name, ev_dispatcher, ev_clses): + super(QueueSerializer, self).__init__() + cls_init_once(self._create_proxy_handlers, ev_clses) + self._ev_q = dispatcher.EventQueueThread(queue_name, ev_dispatcher) + handler.register_instance(self) + + +class RequestQueue(object): + class _EventRequestBase(event.EventBase): + def __init__(self, *args): + super(RequestQueue._EventRequestBase, self).__init__() + self.args = args + + @classmethod + def _create_request_methods(cls, dispatcher_name, methods): + # variable, keyword, default argument aren't supported + ev_dispatcher = dispatcher.EventDispatcher(dispatcher_name) + cls._cls_ev_dispatcher = ev_dispatcher + + for method in methods: + method_name_no_strip = method.__name__ + method_name = method_name_no_strip.lstrip('_') + + # create event class _EventRequest_<method_name> + ev_cls_name = '_EventRequest_%s' % method_name + ev_cls = type(ev_cls_name, (cls._EventRequestBase,), + dict(__init__=lambda self, *args: + super(self.__class__, self).__init__(*args))) + _cls_set_attr(cls, ev_cls_name, ev_cls) + + # create request_<method_name>(self, <args>) method + request_func_name = 'request_%s' % method_name + request_func = eval( + 'lambda self, *args: self._ev_q.queue(self.%s(*args))' % + ev_cls_name) + request_method = types.MethodType(request_func, None, cls) + _cls_set_attr(cls, request_func_name, request_method) + + # create <method_name>_handler(self, <args>) method + handler_name = '%s_handler' % method_name + handler_ = eval('lambda self, ev: self.%s(*ev.args)' % + method_name_no_strip) + handler_ = handler.set_ev_cls(ev_cls, ev_dispatcher)(handler_) + method_ = types.MethodType(handler_, None, cls) + _cls_set_attr(cls, handler_name, method_) + + def __init__(self, methods): + super(RequestQueue, self).__init__() + + cls = self.__class__ + postfix = '%s_%x' % (cls.__name__, id(cls)) + queue_name = 'queue_name_%s' % postfix + dispatcher_name = 'dispatcher_name_%s' % postfix + cls_init_once(self._create_request_methods, dispatcher_name, methods) + self._ev_q = dispatcher.EventQueueThread(queue_name, + self._cls_ev_dispatcher) + handler.register_instance(self) + + def close(self): + self._ev_q.close() + + +def test(): + class RequestQueueTest(RequestQueue): + def __init__(self): + _request_methods = (RequestQueueTest.method0, + RequestQueueTest.method1, + RequestQueueTest.method2) + super(RequestQueueTest, self).__init__(_request_methods) + + def method0(self): + print('method0') + + def method1(self, arg0): + print('method1 arg0 = %s' % arg0) + + def method2(self, arg0, arg1): + print('method2 arg0 = %s arg1 = %s' % (arg0, arg1)) + + def no_method(self): + print('no_method') + + rqt = RequestQueueTest() + rqt.method0() + rqt.method1('a') + rqt.method2('b', 'c') + rqt.no_method() + + ev0 = RequestQueueTest._EventRequest_method0() + rqt.method0_handler(ev0) + ev1 = RequestQueueTest._EventRequest_method1('A') + rqt.method1_handler(ev1) + ev2 = RequestQueueTest._EventRequest_method0('B', 'C') + rqt.method2_handler(ev2) + assert not hasattr(rqt, 'no_method_handler') + + rqt.request_method0() + rqt.request_method1(1) + rqt.request_method2(2, 3) + assert not hasattr(rqt, 'request_no_method') + + rqt.close() + + +if __name__ == '__main__': + try: + test() + except: + import traceback + traceback.print_exc() -- 1.7.10.4 ------------------------------------------------------------------------------ Keep yourself connected to Go Parallel: TUNE You got it built. Now make it sing. Tune shows you how. http://goparallel.sourceforge.net _______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
