Example #1
0
 def thread_func(testclass, mainTransaction, funcToRun):
     self.assertIsNone(LockingTransaction.get())
     LockingTransaction._transactions.local = LockingTransaction()
     LockingTransaction._transactions.local._info = Info(TransactionState.Running, LockingTransaction._transactions.local._startPoint)
     funcToRun(testclass, mainTransaction)
     LockingTransaction._transactions = thread_local()
     self.assertIsNone(LockingTransaction.get())
Example #2
0
 def __init__(self):
     self.__queue = Queue()
     self.__lock = Lock()
     # Mapping of LID to deque (so can serialise messages for same LID). Appended to right, removed from left.
     self.__lid_mapping = {}
     self.__local = thread_local()
     self.__new_msg = Event()
Example #3
0
 def thread_func(testclass, mainTransaction, funcToRun):
     self.assertIsNone(LockingTransaction.get())
     LockingTransaction._transactions.local = LockingTransaction()
     LockingTransaction._transactions.local._info = Info(
         TransactionState.Running,
         LockingTransaction._transactions.local._startPoint)
     funcToRun(testclass, mainTransaction)
     LockingTransaction._transactions = thread_local()
     self.assertIsNone(LockingTransaction.get())
Example #4
0
    def _cache_thread_local(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if not hasattr(wrapper.cache, 'result'):
                wrapper.cache.result = func(*args, **kwargs)
            return wrapper.cache.result

        wrapper.cache = thread_local()
        return wrapper
Example #5
0
def running_transaction(thetest):
    # Fake a running transaction
    LockingTransaction._transactions.local = LockingTransaction()
    LockingTransaction._transactions.local._info = Info(TransactionState.Running, LockingTransaction._transactions.local._startPoint)
    LockingTransaction.ensureGet()._readPoint = -1
    LockingTransaction.transactionCounter = count()
    LockingTransaction.ensureGet()._startPoint = time()
    yield
    # Clean up and remove LockingTransaction we created
    LockingTransaction._transactions = thread_local()
    thetest.assertIsNone(LockingTransaction.get())
Example #6
0
def running_transaction(thetest):
    # Fake a running transaction
    LockingTransaction._transactions.local = LockingTransaction()
    LockingTransaction._transactions.local._info = Info(
        TransactionState.Running,
        LockingTransaction._transactions.local._startPoint)
    LockingTransaction.ensureGet()._readPoint = -1
    LockingTransaction.transactionCounter = count()
    LockingTransaction.ensureGet()._startPoint = time()
    yield
    # Clean up and remove LockingTransaction we created
    LockingTransaction._transactions = thread_local()
    thetest.assertIsNone(LockingTransaction.get())
Example #7
0
 def setUp(self):
     # Poor-man's version of a threading.Barrier (which was added in 3.2). Make a
     # new threading.Lock and immediately acquire it. Spawn the sync_server thread,
     # then acquire the lock again. The second acquire() call will block until the
     # sync server thread is initialized -- it calls release() before entering the
     # serve_forever loop. This isn't totally free of race conditions -- a test
     # method could conceivably be run between sync_server's calls to
     # self.lock.release() and server.serve_forever. We just need our test runs
     # to behave as deterministically as possible, so hopefully this is good
     # enough for now.
     # TODO: use a real threading.Barrier when we drop support for Python 2
     self.lock = Lock()
     self.lock.acquire()
     self.thread_local = thread_local()
     self.server_thread = Thread(target=self.sync_server)
     self.server_thread.start()
     self.lock.acquire()
     self.remote_sync_server = ServerProxy(LOCAL_SYNC_SERVER_URL, allow_none=True)
     self.lock.release()
Example #8
0
 def setUp(self):
     # Poor-man's version of a threading.Barrier (which was added in 3.2). Make a
     # new threading.Lock and immediately acquire it. Spawn the sync_server thread,
     # then acquire the lock again. The second acquire() call will block until the
     # sync server thread is initialized -- it calls release() before entering the
     # serve_forever loop. This isn't totally free of race conditions -- a test
     # method could conceivably be run between sync_server's calls to
     # self.lock.release() and server.serve_forever. We just need our test runs
     # to behave as deterministically as possible, so hopefully this is good
     # enough for now.
     # TODO: use a real threading.Barrier when we drop support for Python 2
     self.lock = Lock()
     self.lock.acquire()
     self.thread_local = thread_local()
     self.server_thread = Thread(target=self.sync_server)
     self.server_thread.start()
     self.lock.acquire()
     self.remote_sync_server = ServerProxy(LOCAL_SYNC_SERVER_URL,
                                           allow_none=True)
     self.lock.release()
Example #9
0
 def __new__(mcls, name, bases, dct):
     dct.setdefault('__singleton_value__', thread_local())
     return super(ThreadLocalSingletonType,
                  mcls).__new__(mcls, name, bases, dct)
Example #10
0
 def local(self):
     return thread_local()
#
#        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.

from threading import Thread, local as thread_local
from Queue import Queue

from cloudify import amqp_client


thread_storage = thread_local()


class AMQPWrappedThread(Thread):
    """
    creates an amqp client before calling the target method.
    This thread is always set as a daemon.
    """

    def __init__(self, target, *args, **kwargs):

        def wrapped_target():
            client = amqp_client.create_client()
            self.started_amqp_client.put_nowait(True)
            thread_storage.amqp_client = client
            try:
Example #12
0
 def __init__ ( self ):
     """ Initializes the object.
     """
     self.facets_logger = None
     self.main_thread   = None
     self.thread_local  = thread_local()
Example #13
0
 def __init__ ( self ):
     self.traits_logger = None
     self.main_thread   = None
     self.thread_local  = thread_local()
Example #14
0
    def local(self): return thread_local()

    def queue(self, max_size=None):
Example #15
0
from threading import local as thread_local

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, Session

from core.config import get_env

_thread_local = thread_local()


def set_current_test_db_session(db_session: scoped_session) -> None:
    """ スレッドローカルにテスト用のDBセッションをセット

    Args:
        db_session (scoped_session): テスト用のDBセッション
    """
    setattr(_thread_local, 'db_session', db_session)


def get_current_test_db_session() -> scoped_session:
    """ スレッドローカルからテスト用のDBセッションを取得

    Returns:
        scoped_session: テスト用のDBセッション
    """
    return getattr(_thread_local, 'db_session')


class TestingDBSession(Session):
    """ commit()の挙動を変えるため、Sessionクラスをオーバーライド
    """
Example #16
0
 def __init__(self):
     super(ThreadLocalSecurityContext, self).__init__(thread_local())
Example #17
0
class ExecutionController(Controller):
    """
    The Controller object has two functions: it holds the state of the script
    thread, and it controls execution of scripts via a C trace function.

    The `script_thread_entry` method is called in a separate thread, which then
    processes the requests put into `self.queue` by the server thread.

    When `set_break` is called, execution is suspended and `_breakfunc` is
    called which waits until somebody calls `set_continue` or `set_stop`.  Since
    `break_only_in_filename` is given at creation time, a break request will
    only break when the execution frame is one from the toplevel script.

    The attributes `currentframe` and `lineno` correspond to the current
    execution frame and the current line number in the toplevel script.

    See the docstring of pyctl.Controller for more details on the inner
    working of the Controller object and the trace function.
    """

    thread_data = thread_local()

    def __init__(self, log, eventfunc, startupsetup, simmode, autosim):
        self.log = log  # daemon logger object
        self.eventfunc = eventfunc  # event emitting callback
        self.setup = startupsetup  # first setup on start
        # start in simulation mode?
        self.simmode = simmode and SIMULATION or SLAVE
        self.autosim = autosim  # simulate script when running it?

        self.queue = ScriptQueue()  # user scripts get put here
        self.current_script = None  # currently executed script
        # namespaces in which scripts execute
        self.namespace = session.namespace
        # completer for the namespaces
        self.completer = NicosCompleter(self.namespace)
        self.watchexprs = set()  # watch expressions to evaluate
        self.watchlock = Lock()  # lock for watch expression list modification
        self.estop_functions = []  # functions to run on emergency stop
        self.thread = None  # thread executing scripts
        self.reqid_work = None  # ID of the last executing request

        self.debugger = None  # currently running debugger (Rpdb)
        self.last_handler = None  # handler of current exec/eval
        # only one user or admin can issue non-read-only commands
        self.controlling_user = None
        Controller.__init__(self, break_only_in_filename='<script>')
        self.set_observer(self._observer)

    def _setup(self):
        # this code is executed as the first thing when the daemon starts
        session.handleInitialSetup(self.setup, self.simmode)
        # remove this function from the user namespace after completion
        self.namespace.pop('NicosSetup', None)

    def _observer(self, status, lineno):
        if status != STATUS_INBREAK:
            # Do not go into pause state immediately, since we will skip
            # many breakpoints if not on the highest level.
            self.eventfunc('status', (status, lineno))

    def _breakfunc(self, frame, flag):
        # check level of breakpoint reached
        fn = frame.f_code.co_filename
        if fn.startswith('<break>'):  # '<break>n' means stoplevel n
            bplevel = int(fn[7:])
        else:
            bplevel = BREAK_AFTER_LINE
        # flag is a tuple (mode, required stoplevel, user name)
        if flag[1] < bplevel or flag[0] in ('stop', 'emergency stop'):
            # don't pause/stop here...
            self.set_continue(flag)
        else:
            self.log.info('script paused in %s', self.current_location())
            session.log.info('Script paused by %s', flag[2])
            self.eventfunc('status', (STATUS_INBREAK, self.lineno))
        new_flag = self.wait_for_continue()
        # new_flag is either a flag coming from Handler.stop(), from
        # Handler.continue() or the old one from above
        if new_flag[0] == 'continue':
            # level is ignored here
            self.log.info('paused script continued')
            session.log.info('Script continued by %s', new_flag[2])
        elif new_flag[1] < bplevel:
            # didn't pause/stop here, try again on next breakpoint
            self.set_break(new_flag)
        elif new_flag[0] in ('stop', 'emergency stop'):
            # we can stop here, do it
            self.log.info('paused script now stopped: %s', new_flag)
            self.set_stop(new_flag)

    def current_location(self, verbose=False):
        frame = self.currentframe
        if verbose:
            return '\n' + ''.join(traceback.format_stack(frame))
        else:
            return traceback.format_stack(frame, 1)[0].strip()[5:]. \
                replace('\n    ', ': ')

    def new_request(self, request, notify=True):
        assert isinstance(request, Request)
        # first send the notification, otherwise the request could be processed
        # (resulting in a "processing" event) before the "request" event is
        # even sent
        if notify:
            self.eventfunc('request', request.serialize())
        # put the script on the queue (will not block)
        self.queue.put(request)
        return request.reqid

    def block_all_requests(self):
        deleted = self.queue.delete_all()
        self.eventfunc('blocked', deleted)

    def block_requests(self, requests):
        for req in requests:
            self.queue.delete_one(req)
            self.eventfunc('blocked', [req])

    def script_stop(self, level, user, message=None):
        """High-level "stop" routine."""
        if self.status == STATUS_STOPPING:
            return
        elif self.status == STATUS_RUNNING:
            self.log.info('script stop request while running')
            suffix = user.name
            if message:
                suffix += ': ' + message
            if level == BREAK_AFTER_LINE:
                session.log.info('Stop after command requested by %s', suffix)
            else:
                session.log.info('Stop requested by %s', suffix)
            self.block_all_requests()
            self.set_break(('stop', level, user.name))
            if level >= BREAK_NOW:
                session.countloop_request = ('pause',
                                             'Stopped by %s' % user.name)
        else:
            self.log.info('script stop request while in break')
            self.block_all_requests()
            self.set_continue(('stop', level, user.name))

    def script_immediate_stop(self, user, message=None):
        """High-level "immediate stop"/estop routine."""
        if self.status in (STATUS_IDLE, STATUS_IDLEEXC):
            # only execute emergency stop functions
            self.new_request(EmergencyStopRequest(user))
            return
        elif self.status == STATUS_STOPPING:
            return
        suffix = user.name
        if message:
            suffix += ': ' + message
        session.log.warning('Immediate stop requested by %s', suffix)
        self.block_all_requests()
        if self.status == STATUS_RUNNING:
            self.set_break(('emergency stop', 5, user.name))
        else:
            # in break
            self.set_continue(('emergency stop', 5, user.name))

    def get_queue(self):
        return self.queue.serialize_queue()

    def get_current_handler(self):
        # both of these attributes are weakrefs, so we have to call them to get
        # either the handler or None
        if self.last_handler:
            return self.last_handler()
        elif self.current_script and self.current_script.handler:
            return self.current_script.handler()
        return None

    def exec_script(self, code, user, handler):
        # execute code in the script namespace (this is called not from
        # the script thread, but from a handle thread)
        self.thread_data.user = user
        temp_request = ScriptRequest(code, None, user)
        temp_request.parse()
        session.log.log(INPUT, formatScript(temp_request, '---'))
        self.last_handler = weakref.ref(handler)
        try:
            for block in temp_request.code:
                exec(block, self.namespace)
        finally:
            self.last_handler = None

    def eval_expression(self, expr, handler, stringify=False):
        self.last_handler = weakref.ref(handler)
        ns = {'session': session, 'config': config}
        ns.update(self.namespace)
        try:
            ret = eval(expr, ns)
            if stringify:
                return repr(ret)
            return ret
        except Exception as err:
            if stringify:
                return '<cannot be evaluated: %s>' % err
            return err
        finally:
            self.last_handler = None

    def simulate_script(self, uuid, code, name, user):
        req = ScriptRequest(code, name, user)
        # use a uuid provided from client
        if uuid:
            req.reqid = uuid
        self.simulate_request(req)

    def simulate_request(self, request, quiet=False):
        code, _ = parseScript(request.text, request.name, compilecode=False)
        session.runSimulation(code[0], request.reqid, wait=False, quiet=quiet)

    def add_watch_expression(self, val):
        self.watchlock.acquire()
        try:
            self.watchexprs.add(val)
        finally:
            self.watchlock.release()

    def remove_watch_expression(self, val):
        self.watchlock.acquire()
        try:
            self.watchexprs.discard(val)
        finally:
            self.watchlock.release()

    def remove_all_watch_expressions(self, group):
        self.watchlock.acquire()
        try:
            for expr in self.watchexprs.copy():
                if expr.endswith(group):
                    self.watchexprs.remove(expr)
        finally:
            self.watchlock.release()

    def eval_watch_expressions(self):
        ret = {}
        self.watchlock.acquire()
        try:
            vals = list(self.watchexprs)
        finally:
            self.watchlock.release()
        for val in vals:
            try:
                expr = val.partition(':')[0]
                ret[val] = repr(eval(expr, self.namespace))
            except Exception as err:
                ret[val] = '<cannot be evaluated: %s>' % err
        return ret

    def debug_start(self, request):
        # remote debugging support: tell the Controller that we want the
        # debugger called immediately; we then wait for debugger commands from
        # the client and feed them to the Rpdb stdin queue
        self.debugger = Rpdb(self.debug_end)
        request.settrace = self.debugger.set_trace
        self.new_request(request)
        # let clients know we're debugging and expect commands via debug_input
        self.eventfunc('debugging', True)

    def debug_running(self):
        # remote debugging support of running script: set_debug() calls the
        # given set_trace during the next call to the controller's C trace
        # function, and then the debugger takes over; we then wait for debugger
        # commands from the client and feed them to the Rpdb stdin queue
        self.debugger = Rpdb(self.debug_end)
        self.set_debug(self.debugger.set_trace)
        # let clients know we're debugging and expect commands via debug_input
        self.eventfunc('debugging', True)

    def debug_input(self, line):
        # some debugger commands arrived from a client
        if self.debugger:
            self.debugger.stdin.put(line)

    def debug_end(self, tracing=True):
        # this is called by the debugger when a command such as "continue" or
        # "quit" is entered, which means that debugging is finished
        self.debugger = None
        self.eventfunc('debugging', False)
        # set our own trace function again (Pdb replaced it)
        if tracing:
            self.reset_trace()
        else:
            sys.settrace(None)

    def complete_line(self, line, lastword):
        if not session._spmode:
            return self.completer.get_matches(lastword, line)
        spmatches = session._spmhandler.complete(lastword, line)
        return [m + ' ' for m in spmatches]

    def add_estop_function(self, func, args):
        if not callable(func):
            raise TypeError('emergency stop function must be a callable')
        if not isinstance(args, tuple):
            raise TypeError('emergency stop function args must be a tuple')
        self.estop_functions.append((func, args))
        return len(self.estop_functions)

    def execute_estop(self, user):
        self.log.warning('emergency stop caught, executing ESFs')
        session.log.info('Stopping devices for immediate stop')
        # now execute emergency stop functions
        for (func, args) in self.estop_functions:
            try:
                self.log.info('executing ESF: %s%s', func, args)
                func(*args)
            except Exception:
                self.log.exception('ESF raised error')
            else:
                self.log.info('ESF finished')

    def rearrange_queue(self, ids):
        """Rearrange the queued scripts according to the given id sequence."""
        def match_ids(client_ids, queued_ids):
            """Checks consistency between the ID sequences."""
            queued_idset = set(queued_ids)
            client_idset = set(client_ids)
            if queued_idset ^ client_idset:
                if client_idset - queued_idset:
                    temp = client_idset - queued_idset
                    if set(client_ids[:len(temp)]) ^ temp:
                        raise RequestError('Inconsistency between clients '
                                           'script IDs and queued IDs')

                    # remove already executed scripts from clients id sequence
                    client_ids = client_ids[len(temp):]

                if queued_idset - client_idset:
                    temp = queued_idset - client_idset
                    if set(queued_ids[:-len(temp)]) ^ temp:
                        raise RequestError('Inconsistency between clients '
                                           'script IDs and queued IDs')

        with self.queue as qop:
            match_ids(ids, qop.get_ids())
            for new_index, script_id in enumerate(ids):
                qop.move_item(script_id, new_index)
                self.eventfunc('rearranged', qop.get_ids())

    def update_script(self, reqid, newcode, reason, user):
        """The desired update can be either for the executed script or a
        queued script.
        """
        with self.queue as qop:
            # check if currently executed script needs update
            if reqid == self.current_script.reqid or reqid is None:
                self.current_script.update(newcode, reason, self, user)
                self.log.info('running script updated by %s', user.name)
                if session.cache and self.autosim:
                    self.simulate_request(self.current_script, quiet=True)
                    self.current_script.setSimstate('running')
                return

            # update queued script with newuser and code
            qop.update(reqid, newcode, user)
            self.log.info('queued script %s updated by %s', reqid, user.name)
            self.eventfunc('updated', qop.get_item(reqid).serialize())

    def start_script_thread(self, *args):
        if self.thread:
            raise RuntimeError('script thread already started')
        self.thread = createThread('daemon script_thread',
                                   self.script_thread_entry,
                                   args=args)

    def script_thread_entry(self):
        """The script execution thread entry point.  This thread executes setup
        code, then waits for scripts on self.queue.  The script is then
        executed in the context of self.namespace, using the controller (self)
        to watch execution.
        """
        self.log.debug('script_thread (re)started')
        session.script_thread_id = current_thread().ident
        try:
            self.namespace['NicosSetup'] = self._setup
            # and put it in the queue as the first request
            request = ScriptRequest('NicosSetup()',
                                    'setting up NICOS',
                                    system_user,
                                    quiet=True,
                                    format='py')
            self.new_request(request, notify=False)

            while 1:
                # get a script (or other request) from the queue
                request = self.queue.get()
                self.thread_data.user = request.user

                if isinstance(request, EmergencyStopRequest):
                    self.log.info('executing estop request from %s',
                                  request.user.name)
                    self.execute_estop(request.user.name)
                    continue
                elif not isinstance(request, ScriptRequest):
                    self.log.error('unknown request: %s', request)
                    continue
                self.log.info('processing script %s by %s', request.reqid,
                              request.user.name)
                self.reqid_work = request.reqid
                if session.cache and self.autosim:
                    self.simulate_request(request, quiet=True)
                    request.setSimstate('running')
                # notify clients that we're processing this request now
                self.eventfunc('processing', request.serialize())
                # parse the script and split it into blocks
                try:
                    self.current_script = request
                    self.current_script.parse()
                except Exception:
                    session.log.log(INPUT, formatScript(request))
                    session.logUnhandledException(cut_frames=1)
                    continue
                try:
                    self.current_script.execute(self)
                except ControlStop as err:
                    if err.args[0] == 'emergency stop':
                        # block all pending requests (should have been done
                        # already, but to be on the safe side do it here again)
                        self.block_all_requests()
                        self.execute_estop(err.args[2])
                    else:
                        # in this case, we have already blocked all scripts
                        # queued before the "stop" command was given; scripts
                        # that are queued after that should be executed, so
                        # we don't block requests here
                        session.log.info('Script stopped by %s', err.args[2])
                except BdbQuit as err:  # pylint: disable=bad-except-order
                    session.log.error('Script stopped through debugger')
                except Exception as err:  # pylint: disable=bad-except-order
                    # the topmost two frames are still in the
                    # daemon, so don't display them to the user
                    # perhaps also send an error notification
                    try:
                        session.scriptEvent('exception', sys.exc_info())
                    except Exception:
                        # last resort: do not exit script thread even if we
                        # can't handle this exception
                        pass
                if self.debugger:
                    self.debug_end(tracing=False)
                session.clearActions()
                session.scriptEvent('finish', None)
        except Exception:
            self.log.exception('unhandled exception in script thread')
            session.log.error('internal error in NICOS daemon, please restart')
        finally:
            self.thread = None
# 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.

from threading import Thread, local as thread_local
from Queue import Queue

from cloudify import amqp_client

thread_storage = thread_local()


class AMQPWrappedThread(Thread):
    """
    creates an amqp client before calling the target method.
    This thread is always set as a daemon.
    """
    def __init__(self, target, *args, **kwargs):
        def wrapped_target():
            client = amqp_client.create_client()
            self.started_amqp_client.put_nowait(True)
            thread_storage.amqp_client = client
            try:
                self.target_method()
            finally:
Example #19
0
 def __init__ ( self ):
     self.traits_logger = None
     self.main_thread   = None
     self.thread_local  = thread_local()
Example #20
0
    "context",
    "current_step",
    "StepTiming",
    "Counters",
]

COLLECT_TIMING = False

TIMING_PATH = "timing.csv"
TIMING_MODE = "a"
TIMING_BUFFERING = 1
TIMING_FILE: Optional[IO] = None

LOG_ALL_STEPS = False

THREAD_LOCAL = thread_local()
COUNTED_THREADS = 0


@utd.expand_doc()
def collect_timing(
    collect: bool,
    path: str = TIMING_PATH,  # pylint: disable=used-prior-global-declaration
    mode: str = TIMING_MODE,  # pylint: disable=used-prior-global-declaration
    *,
    buffering: int = TIMING_BUFFERING,  # pylint: disable=used-prior-global-declaration
) -> None:
    """
    Specify whether, where and how to collect timing information.

    By default, we do not. Override this by setting the ``METACELLS_COLLECT_TIMING`` environment