debuggers.hg

view tools/python/xen/xend/xenstore/xstransact.py @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children
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 from xen.xend.xenstore.xsutil import xshandle
10 class xstransact:
11 """WARNING: Be very careful if you're instantiating an xstransact object
12 yourself (i.e. not using the capitalized static helpers like .Read().
13 It is essential that you clean up the object in place via
14 t.commit/abort(): GC can happen at any time, including contexts where
15 it's not safe to to use the shared xenstore socket fd. In particular,
16 if xend forks, and GC occurs, we can have two processes trying to
17 use the same xenstore fd, and all hell breaks loose.
18 """
21 def __init__(self, path = ""):
23 self.in_transaction = False # Set this temporarily -- if this
24 # constructor fails, then we need to
25 # protect __del__.
27 assert path is not None
28 self.path = path.rstrip("/")
29 self.transaction = xshandle().transaction_start()
30 self.in_transaction = True
32 def __del__(self):
33 # see above.
34 if self.in_transaction:
35 raise RuntimeError("ERROR: GC of live transaction")
37 def commit(self):
38 if not self.in_transaction:
39 raise RuntimeError
40 self.in_transaction = False
41 rc = xshandle().transaction_end(self.transaction, False)
42 self.transaction = "0"
43 return rc
45 def abort(self):
46 if not self.in_transaction:
47 return True
48 self.in_transaction = False
49 rc = xshandle().transaction_end(self.transaction, True)
50 self.transaction = "0"
51 return rc
53 def _read(self, key):
54 path = self.prependPath(key)
55 try:
56 return xshandle().read(self.transaction, path)
57 except RuntimeError, ex:
58 raise RuntimeError(ex.args[0],
59 '%s, while reading %s' % (ex.args[1], path))
61 def read(self, *args):
62 """If no arguments are given, return the value at this transaction's
63 path. If one argument is given, treat that argument as a subpath to
64 this transaction's path, and return the value at that path.
65 Otherwise, treat each argument as a subpath to this transaction's
66 path, and return a list composed of the values at each of those
67 instead.
68 """
69 if len(args) == 0:
70 return xshandle().read(self.transaction, self.path)
71 if len(args) == 1:
72 return self._read(args[0])
73 ret = []
74 for key in args:
75 ret.append(self._read(key))
76 return ret
78 def _write(self, key, data):
79 path = self.prependPath(key)
80 try:
81 xshandle().write(self.transaction, path, data)
82 except RuntimeError, ex:
83 raise RuntimeError(ex.args[0],
84 ('%s, while writing %s : %s' %
85 (ex.args[1], path, str(data))))
87 def write(self, *args):
88 if len(args) == 0:
89 raise TypeError
90 if isinstance(args[0], dict):
91 for d in args:
92 if not isinstance(d, dict):
93 raise TypeError
94 for key in d.keys():
95 try:
96 self._write(key, d[key])
97 except TypeError, msg:
98 raise TypeError('Writing %s: %s: %s' %
99 (key, str(d[key]), msg))
100 elif isinstance(args[0], list):
101 for l in args:
102 if not len(l) == 2:
103 raise TypeError
104 self._write(l[0], l[1])
105 elif len(args) % 2 == 0:
106 for i in range(len(args) / 2):
107 self._write(args[i * 2], args[i * 2 + 1])
108 else:
109 raise TypeError
111 def _remove(self, key):
112 path = self.prependPath(key)
113 return xshandle().rm(self.transaction, path)
115 def remove(self, *args):
116 """If no arguments are given, remove this transaction's path.
117 Otherwise, treat each argument as a subpath to this transaction's
118 path, and remove each of those instead.
119 """
120 if len(args) == 0:
121 xshandle().rm(self.transaction, self.path)
122 else:
123 for key in args:
124 self._remove(key)
126 def _list(self, key):
127 path = self.prependPath(key)
128 l = xshandle().ls(self.transaction, path)
129 if l:
130 return map(lambda x: key + "/" + x, l)
131 return []
133 def list(self, *args):
134 """If no arguments are given, list this transaction's path, returning
135 the entries therein, or the empty list if no entries are found.
136 Otherwise, treat each argument as a subpath to this transaction's
137 path, and return the cumulative listing of each of those instead.
138 """
139 if len(args) == 0:
140 ret = xshandle().ls(self.transaction, self.path)
141 if ret is None:
142 return []
143 else:
144 return ret
145 else:
146 ret = []
147 for key in args:
148 ret.extend(self._list(key))
149 return ret
152 def list_recursive_(self, subdir, keys):
153 ret = []
154 for key in keys:
155 new_subdir = subdir + "/" + key
156 l = xshandle().ls(self.transaction, new_subdir)
157 if l:
158 ret.append([key, self.list_recursive_(new_subdir, l)])
159 else:
160 ret.append([key, xshandle().read(self.transaction, new_subdir)])
161 return ret
164 def list_recursive(self, *args):
165 """If no arguments are given, list this transaction's path, returning
166 the entries therein, or the empty list if no entries are found.
167 Otherwise, treat each argument as a subpath to this transaction's
168 path, and return the cumulative listing of each of those instead.
169 """
170 if len(args) == 0:
171 args = self.list()
172 if args is None or len(args) == 0:
173 return []
175 return self.list_recursive_(self.path, args)
178 def gather(self, *args):
179 if len(args) and type(args[0]) != tuple:
180 args = args,
181 ret = []
182 for tup in args:
183 if len(tup) == 2:
184 (key, fn) = tup
185 defval = None
186 else:
187 (key, fn, defval) = tup
189 val = self._read(key)
190 # If fn is str, then this will successfully convert None to 'None'
191 # (which we don't want). If it is int or float, then it will
192 # throw ValueError on any non-convertible value. We check
193 # explicitly for None, using defval instead, but allow ValueError
194 # to propagate.
195 if val is None:
196 val = defval
197 else:
198 val = fn(val)
199 ret.append(val)
200 if len(ret) == 1:
201 return ret[0]
202 return ret
204 def store(self, *args):
205 if len(args) and type(args[0]) != tuple:
206 args = args,
207 for tup in args:
208 if len(tup) == 2:
209 (key, val) = tup
210 try:
211 fmt = { str : "%s",
212 int : "%i",
213 float : "%f",
214 long : "%li",
215 type(None) : None }[type(val)]
216 except KeyError:
217 raise TypeError
218 else:
219 (key, val, fmt) = tup
220 if val is None:
221 self._remove(key)
222 else:
223 self._write(key, fmt % val)
226 def mkdir(self, *args):
227 if len(args) == 0:
228 xshandle().mkdir(self.transaction, self.path)
229 else:
230 for key in args:
231 xshandle().mkdir(self.transaction, self.prependPath(key))
234 def get_permissions(self, *args):
235 """If no arguments are given, return the permissions at this
236 transaction's path. If one argument is given, treat that argument as
237 a subpath to this transaction's path, and return the permissions at
238 that path. Otherwise, treat each argument as a subpath to this
239 transaction's path, and return a list composed of the permissions at
240 each of those instead.
241 """
242 if len(args) == 0:
243 return xshandle().get_permissions(self.transaction, self.path)
244 if len(args) == 1:
245 return self._get_permissions(args[0])
246 ret = []
247 for key in args:
248 ret.append(self._get_permissions(key))
249 return ret
252 def _get_permissions(self, key):
253 path = self.prependPath(key)
254 try:
255 return xshandle().get_permissions(self.transaction, path)
256 except RuntimeError, ex:
257 raise RuntimeError(ex.args[0],
258 '%s, while getting permissions from %s' %
259 (ex.args[1], path))
262 def set_permissions(self, *args):
263 if len(args) == 0:
264 raise TypeError
265 elif isinstance(args[0], str):
266 self.callRebased(args[0], self.set_permissions, *args[1:])
267 else:
268 if not self.path:
269 raise RuntimeError('Cannot set permissions on the root')
271 xshandle().set_permissions(self.transaction, self.path,
272 list(args))
275 def remove2(self, middlePath, *args):
276 self.callRebased(middlePath, self.remove, *args)
279 def write2(self, middlePath, *args):
280 self.callRebased(middlePath, self.write, *args)
283 def callRebased(self, middlePath, func, *args):
284 oldpath = self.path
285 self.path = self.prependPath(middlePath)
286 try:
287 func(*args)
288 finally:
289 self.path = oldpath
292 def prependPath(self, key):
293 if self.path:
294 return self.path + '/' + key
295 else:
296 return key
299 def Read(cls, path, *args):
300 """If only one argument is given (path), return the value stored at
301 that path. If two arguments are given, treat the second argument as a
302 subpath within the first, and return the value at the composed path.
303 Otherwise, treat each argument after the first as a subpath to the
304 given path, and return a list composed of the values at each of those
305 instead. This operation is performed inside a transaction.
306 """
307 return complete(path, lambda t: t.read(*args))
308 Read = classmethod(Read)
310 def Write(cls, path, *args):
311 complete(path, lambda t: t.write(*args))
312 Write = classmethod(Write)
314 def Remove(cls, path, *args):
315 """If only one argument is given (path), remove it. Otherwise, treat
316 each further argument as a subpath to the given path, and remove each
317 of those instead. This operation is performed inside a transaction.
318 """
319 complete(path, lambda t: t.remove(*args))
320 Remove = classmethod(Remove)
322 def List(cls, path, *args):
323 """If only one argument is given (path), list its contents, returning
324 the entries therein, or the empty list if no entries are found.
325 Otherwise, treat each further argument as a subpath to the given path,
326 and return the cumulative listing of each of those instead. This
327 operation is performed inside a transaction.
328 """
329 return complete(path, lambda t: t.list(*args))
330 List = classmethod(List)
332 def ListRecursive(cls, path, *args):
333 """If only one argument is given (path), list its contents
334 recursively, returning the entries therein, or the empty list if no
335 entries are found. Otherwise, treat each further argument as a
336 subpath to the given path, and return the cumulative listing of each
337 of those instead. This operation is performed inside a transaction.
338 """
339 return complete(path, lambda t: t.list_recursive(*args))
340 ListRecursive = classmethod(ListRecursive)
342 def Gather(cls, path, *args):
343 return complete(path, lambda t: t.gather(*args))
344 Gather = classmethod(Gather)
346 def Store(cls, path, *args):
347 complete(path, lambda t: t.store(*args))
348 Store = classmethod(Store)
350 def SetPermissions(cls, path, *args):
351 complete(path, lambda t: t.set_permissions(*args))
352 SetPermissions = classmethod(SetPermissions)
354 def Mkdir(cls, path, *args):
355 complete(path, lambda t: t.mkdir(*args))
356 Mkdir = classmethod(Mkdir)
359 def complete(path, f):
360 while True:
361 t = xstransact(path)
362 try:
363 result = f(t)
364 if t.commit():
365 return result
366 except:
367 t.abort()
368 raise