This file is indexed.

/usr/lib/python2.7/dist-packages/ZODB/utils.txt is in python-zodb 1:3.9.7-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
ZODB Utilits Module
===================

The ZODB.utils module provides a number of helpful, somewhat random
:), utility functions.

    >>> import ZODB.utils

This document documents a few of them. Over time, it may document
more. 

64-bit integers and strings
---------------------------------

ZODB uses 64-bit transaction ids that are typically represented as
strings, but are sometimes manipulated as integers.  Object ids are
strings too and it is common to ise 64-bit strings that are just
packed integers.

Functions p64 and u64 pack and unpack integers as strings:

    >>> ZODB.utils.p64(250347764455111456)
    '\x03yi\xf7"\xa8\xfb '

    >>> print ZODB.utils.u64('\x03yi\xf7"\xa8\xfb ')
    250347764455111456

The contant z64 has zero packed as a 64-bit string:

    >>> ZODB.utils.z64
    '\x00\x00\x00\x00\x00\x00\x00\x00'

Transaction id generation
-------------------------

Storages assign transaction ids as transactions are committed.  These
are based on UTC time, but must be strictly increasing.  The
newTid function akes this pretty easy.

To see this work (in a predictable way), we'll first hack time.time:

    >>> import time
    >>> old_time = time.time
    >>> time.time = lambda : 1224825068.12

Now, if we ask for a new time stamp, we'll get one based on our faux
time:

    >>> tid = ZODB.utils.newTid(None)
    >>> tid
    '\x03yi\xf7"\xa54\x88'

newTid requires an old tid as an argument. The old tid may be None, if
we don't have a previous transaction id.

This time is based on the current time, which we can see by converting
it to a time stamp.

    >>> import ZODB.TimeStamp
    >>> print ZODB.TimeStamp.TimeStamp(tid)
    2008-10-24 05:11:08.120000

To assure that we get a new tid that is later than the old, we can
pass an existing tid.  Let's pass the tid we just got.

    >>> tid2 = ZODB.utils.newTid(tid)
    >>> long(ZODB.utils.u64(tid)), long(ZODB.utils.u64(tid2))
    (250347764454864008L, 250347764454864009L)

Here, since we called it at the same time, we got a time stamp that
was only slightly larger than the previos one.  Of course, at a later
time, the time stamp we get will be based on the time:

    >>> time.time = lambda : 1224825069.12
    >>> tid = ZODB.utils.newTid(tid2)
    >>> print ZODB.TimeStamp.TimeStamp(tid)
    2008-10-24 05:11:09.120000


    >>> time.time = old_time


Locking support
---------------

Storages are required to be thread safe.  The locking descriptor helps
automate that. It arranges for a lock to be acquired when a function
is called and released when a function exits.  To demonstrate this,
we'll create a "lock" type that simply prints when it is called:

    >>> class Lock:
    ...     def acquire(self):
    ...         print 'acquire'
    ...     def release(self):
    ...         print 'release'

Now we'll demonstrate the descriptor:

    >>> class C:
    ...     _lock = Lock()
    ...     _lock_acquire = _lock.acquire
    ...     _lock_release = _lock.release
    ...
    ...     @ZODB.utils.locked
    ...     def meth(self, *args, **kw):
    ...         print 'meth', args, kw

The descriptor expects the instance it wraps to have a '_lock
attribute.

    >>> C().meth(1, 2, a=3)
    acquire
    meth (1, 2) {'a': 3}
    release

.. Edge cases

   We can get the method from the class:

    >>> C.meth # doctest: +ELLIPSIS
    <ZODB.utils.Locked object at ...>

    >>> C.meth(C())
    acquire
    meth () {}
    release

    >>> class C2:
    ...     _lock = Lock()
    ...     _lock_acquire = _lock.acquire
    ...     _lock_release = _lock.release

    >>> C.meth(C2()) # doctest: +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
    ...
    TypeError: unbound method meth() must be called with C instance
    as first argument (got C2 instance instead)

Preconditions
-------------

Often, we want to supply method preconditions. The locking descriptor
supports optional method preconditions [1]_.

    >>> class C:
    ...     def __init__(self):
    ...         _lock = Lock()
    ...         self._lock_acquire = _lock.acquire
    ...         self._lock_release = _lock.release
    ...         self._opened = True
    ...         self._transaction = None
    ...
    ...     def opened(self):
    ...         """The object is open
    ...         """
    ...         print 'checking if open'
    ...         return self._opened
    ...
    ...     def not_in_transaction(self):
    ...         """The object is not in a transaction
    ...         """
    ...         print 'checking if in a transaction'
    ...         return self._transaction is None
    ...
    ...     @ZODB.utils.locked(opened, not_in_transaction)
    ...     def meth(self, *args, **kw):
    ...         print 'meth', args, kw

    >>> c = C()
    >>> c.meth(1, 2, a=3)
    acquire
    checking if open
    checking if in a transaction
    meth (1, 2) {'a': 3}
    release

    >>> c._transaction = 1
    >>> c.meth(1, 2, a=3) # doctest: +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
    ...
    AssertionError:
    ('Failed precondition: ', 'The object is not in a transaction')

    >>> c._opened = False
    >>> c.meth(1, 2, a=3) # doctest: +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
    ...
    AssertionError: ('Failed precondition: ', 'The object is open')


.. [1] Arguably, preconditions should be handled via separate
   descriptors, but for ZODB storages, almost all methods need to be
   locked.  Combining preconditions with locking provides both
   efficiency and concise expressions.  A more general-purpose
   facility would almost certainly provide separate descriptors for
   preconditions.