direct-io.hg

view tools/python/xen/xend/xenstore/xstransact.py @ 7418:6ef7386f7370

Protect __del__ from failure inside __init__ by setting inTransaction before
trying to create a transaction instance.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Tue Oct 18 18:07:11 2005 +0100 (2005-10-18)
parents 74d56b7ff46c
children 99ece3c06913
line source
1 # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
2 # Copyright (C) 2005 XenSource Ltd
4 # This file is subject to the terms and conditions of the GNU General
5 # Public License. See the file "COPYING" in the main directory of
6 # this archive for more details.
8 import errno
9 import threading
10 from xen.lowlevel import xs
11 from xen.xend.xenstore.xsutil import xshandle
14 class xstransact:
16 def __init__(self, path):
17 self.in_transaction = False # Set this temporarily -- if this
18 # constructor fails, then we need to
19 # protect __del__.
20 self.path = path.rstrip("/")
21 self.transaction = xshandle().transaction_start()
22 self.in_transaction = True
24 def __del__(self):
25 if self.in_transaction:
26 xshandle().transaction_end(self.transaction, True)
28 def commit(self):
29 if not self.in_transaction:
30 raise RuntimeError
31 self.in_transaction = False
32 rc = xshandle().transaction_end(self.transaction, False)
33 self.transaction = "0"
34 return rc
36 def abort(self):
37 if not self.in_transaction:
38 return True
39 self.in_transaction = False
40 rc = xshandle().transaction_end(self.transaction, True)
41 self.transaction = "0"
42 return rc
44 def _read(self, key):
45 path = "%s/%s" % (self.path, key)
46 try:
47 return xshandle().read(self.transaction, path)
48 except RuntimeError, ex:
49 raise RuntimeError(ex.args[0],
50 '%s, while reading %s' % (ex.args[1], path))
52 def read(self, *args):
53 """If no arguments are given, return the value at this transaction's
54 path. If one argument is given, treat that argument as a subpath to
55 this transaction's path, and return the value at that path.
56 Otherwise, treat each argument as a subpath to this transaction's
57 path, and return a list composed of the values at each of those
58 instead.
59 """
60 if len(args) == 0:
61 return xshandle().read(self.transaction, self.path)
62 if len(args) == 1:
63 return self._read(args[0])
64 ret = []
65 for key in args:
66 ret.append(self._read(key))
67 return ret
69 def _write(self, key, data):
70 path = "%s/%s" % (self.path, key)
71 try:
72 xshandle().write(self.transaction, path, data)
73 except RuntimeError, ex:
74 raise RuntimeError(ex.args[0],
75 ('%s, while writing %s : %s' %
76 (ex.args[1], path, str(data))))
78 def write(self, *args, **opts):
79 if len(args) == 0:
80 raise TypeError
81 if isinstance(args[0], dict):
82 for d in args:
83 if not isinstance(d, dict):
84 raise TypeError
85 for key in d.keys():
86 try:
87 self._write(key, d[key])
88 except TypeError, msg:
89 raise TypeError('Writing %s: %s: %s' %
90 (key, str(d[key]), msg))
91 elif isinstance(args[0], list):
92 for l in args:
93 if not len(l) == 2:
94 raise TypeError
95 self._write(l[0], l[1])
96 elif len(args) % 2 == 0:
97 for i in range(len(args) / 2):
98 self._write(args[i * 2], args[i * 2 + 1])
99 else:
100 raise TypeError
102 def _remove(self, key):
103 path = "%s/%s" % (self.path, key)
104 return xshandle().rm(self.transaction, path)
106 def remove(self, *args):
107 """If no arguments are given, remove this transaction's path.
108 Otherwise, treat each argument as a subpath to this transaction's
109 path, and remove each of those instead.
110 """
111 if len(args) == 0:
112 xshandle().rm(self.transaction, self.path)
113 else:
114 for key in args:
115 self._remove(key)
117 def _list(self, key):
118 path = "%s/%s" % (self.path, key)
119 l = xshandle().ls(self.transaction, path)
120 if l:
121 return map(lambda x: key + "/" + x, l)
122 return []
124 def list(self, *args):
125 """If no arguments are given, list this transaction's path, returning
126 the entries therein, or the empty list if no entries are found.
127 Otherwise, treat each argument as a subpath to this transaction's
128 path, and return the cumulative listing of each of those instead.
129 """
130 if len(args) == 0:
131 ret = xshandle().ls(self.transaction, self.path)
132 if ret is None:
133 return []
134 else:
135 return ret
136 else:
137 ret = []
138 for key in args:
139 ret.extend(self._list(key))
140 return ret
143 def list_recursive_(self, subdir, keys):
144 ret = []
145 for key in keys:
146 new_subdir = subdir + "/" + key
147 l = xshandle().ls(self.transaction, new_subdir)
148 if l:
149 ret.append([key, self.list_recursive_(new_subdir, l)])
150 else:
151 ret.append([key, xshandle().read(self.transaction, new_subdir)])
152 return ret
155 def list_recursive(self, *args):
156 """If no arguments are given, list this transaction's path, returning
157 the entries therein, or the empty list if no entries are found.
158 Otherwise, treat each argument as a subpath to this transaction's
159 path, and return the cumulative listing of each of those instead.
160 """
161 if len(args) == 0:
162 args = self.list()
163 if args is None or len(args) == 0:
164 return []
166 return self.list_recursive_(self.path, args)
169 def gather(self, *args):
170 if len(args) and type(args[0]) != tuple:
171 args = args,
172 ret = []
173 for tup in args:
174 if len(tup) == 2:
175 (key, fn) = tup
176 defval = None
177 else:
178 (key, fn, defval) = tup
180 val = self._read(key)
181 # If fn is str, then this will successfully convert None to
182 # 'None'. If it is int, then it will throw TypeError on None, or
183 # on any other non-integer value. We have to, therefore, both
184 # check explicitly for None, and catch TypeError. Either failure
185 # will result in defval being used instead.
186 if val is None:
187 val = defval
188 else:
189 try:
190 val = fn(val)
191 except TypeError:
192 val = defval
193 ret.append(val)
194 if len(ret) == 1:
195 return ret[0]
196 return ret
198 def store(self, *args):
199 if len(args) and type(args[0]) != tuple:
200 args = args,
201 for tup in args:
202 if len(tup) == 2:
203 (key, val) = tup
204 try:
205 fmt = { str : "%s",
206 int : "%i",
207 float : "%f",
208 type(None) : None }[type(val)]
209 except KeyError:
210 raise TypeError
211 else:
212 (key, val, fmt) = tup
213 if val is None:
214 self._remove(key)
215 else:
216 self._write(key, fmt % val)
219 def Read(cls, path, *args):
220 """If only one argument is given (path), return the value stored at
221 that path. If two arguments are given, treat the second argument as a
222 subpath within the first, and return the value at the composed path.
223 Otherwise, treat each argument after the first as a subpath to the
224 given path, and return a list composed of the values at each of those
225 instead. This operation is performed inside a transaction.
226 """
227 while True:
228 t = cls(path)
229 try:
230 v = t.read(*args)
231 t.abort()
232 return v
233 except:
234 t.abort()
235 raise
237 Read = classmethod(Read)
239 def Write(cls, path, *args, **opts):
240 while True:
241 t = cls(path)
242 try:
243 t.write(*args, **opts)
244 if t.commit():
245 return
246 except:
247 t.abort()
248 raise
250 Write = classmethod(Write)
252 def Remove(cls, path, *args):
253 """If only one argument is given (path), remove it. Otherwise, treat
254 each further argument as a subpath to the given path, and remove each
255 of those instead. This operation is performed inside a transaction.
256 """
257 while True:
258 t = cls(path)
259 try:
260 t.remove(*args)
261 if t.commit():
262 return
263 except:
264 t.abort()
265 raise
267 Remove = classmethod(Remove)
269 def List(cls, path, *args):
270 """If only one argument is given (path), list its contents, returning
271 the entries therein, or the empty list if no entries are found.
272 Otherwise, treat each further argument as a subpath to the given path,
273 and return the cumulative listing of each of those instead. This
274 operation is performed inside a transaction.
275 """
276 while True:
277 t = cls(path)
278 try:
279 v = t.list(*args)
280 if t.commit():
281 return v
282 except:
283 t.abort()
284 raise
286 List = classmethod(List)
288 def ListRecursive(cls, path, *args):
289 """If only one argument is given (path), list its contents
290 recursively, returning the entries therein, or the empty list if no
291 entries are found. Otherwise, treat each further argument as a
292 subpath to the given path, and return the cumulative listing of each
293 of those instead. This operation is performed inside a transaction.
294 """
295 while True:
296 t = cls(path)
297 try:
298 v = t.list_recursive(*args)
299 if t.commit():
300 return v
301 except:
302 t.abort()
303 raise
305 ListRecursive = classmethod(ListRecursive)
307 def Gather(cls, path, *args):
308 while True:
309 t = cls(path)
310 try:
311 v = t.gather(*args)
312 if t.commit():
313 return v
314 except:
315 t.abort()
316 raise
318 Gather = classmethod(Gather)
320 def Store(cls, path, *args):
321 while True:
322 t = cls(path)
323 try:
324 v = t.store(*args)
325 if t.commit():
326 return v
327 except:
328 t.abort()
329 raise
331 Store = classmethod(Store)