File: SharedResource.py

package info (click to toggle)
zope-ldapuserfolder 2.9-1%2Blenny1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 636 kB
  • ctags: 508
  • sloc: python: 4,896; makefile: 33; xml: 15
file content (119 lines) | stat: -rw-r--r-- 3,656 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
##############################################################################
#
# Copyright (c) 2000-2008 Jens Vagelpohl and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" SharedResource: Unique resource store

$Id: SharedResource.py 1485 2008-06-04 16:08:38Z jens $
"""

"""Shared Resource.

'Shared Resource' is a module that manages resources shared by all threads. 
Such resources can be controlled much more easily. A shared resource provides
locking capabilities (via Python's RLock) and performs automatic locking for 
function calls. Access to non-functions is not protected.

A shared resource is identified by an id. The application
is responsible that id s are unique.
"""

from threading import _RLock, Lock

_ResourceMap = {}
_ResourceLock = Lock()

def getResource(id, factory, factoryArgs=()):
    """returns a resource for *id*.

    If such a resource does not yet exist, one is created
    by calling *factory* with *factoryArgs*.
    Note, that *factory* and *factoryArgs* should only
    depend on *id* and not any other context, as no
    object is created, when a resource for *id* already
    exists.
    """
    _ResourceLock.acquire()

    try:
        try:
            return _ResourceMap[id]
        except KeyError:
            _ResourceMap[id] = _SharedResource(factory(*factoryArgs))
            return _ResourceMap[id]
    finally: 
        _ResourceLock.release()

def setResource(id, resource):
    """ Forcibly set the resource """
    _ResourceLock.acquire()

    try:
        _ResourceMap[id] = _SharedResource(resource)
    finally:
        _ResourceLock.release()


class _SharedResource(_RLock):
    # for __setattr__
    _myAttributes = { '_target' : None
      	            # _RLock instance variables
      	            , '_RLock__block' : None
      	            , '_RLock__count' : None
      	            , '_RLock__owner' : None
      	            # Verbose instance variables
      	            , '_Verbose__verbose' : None
      	            }
    _myAttributes.update(_RLock.__dict__)
    _isMyAttribute = _myAttributes.has_key
    _target = None

    def __init__(self, target):
        self._target = target
        _RLock.__init__(self)

    def __getattr__(self, key):
        a = getattr(self._target, key)
        if callable(a): 
            a = _SharedCallable(self,a)

        return a

    def __setattr__(self, key, value):
        if self._isMyAttribute(key): 
            self.__dict__[key] = value
        else:
            setattr(self._target, key, value)

    def _type(self):
        return type(self._target)

    # def __delattr__(self,key,value): # do not implement for the time being

    def __len__(self): return len(self._target)
    def __getitem__(self, key): return self._target[key]
    def __setitem__(self, key, value): self._target[key] = value
    def __delitem__(self, key): del self._target[key]


class _SharedCallable:
    def __init__(self, lock, callable):
        self._lock = lock
        self._callable = callable

    def __call__(self, *args, **kw):
        self._lock.acquire()
        try: 
            return self._callable(*args, **kw)
        finally: 
            self._lock.release()