Revision 30b46c1d

b/pithos/backends/simple.py
44 44

  
45 45
logger = logging.getLogger(__name__)
46 46

  
47
def backend_method(func=None, autocommit=1):
48
    if func is None:
49
        def fn(func):
50
            return backend_method(func, autocommit)
51
        return fn
52

  
53
    if not autocommit:
54
        return func
55
    def fn(self, *args, **kw):
56
        self.con.execute('begin deferred')
57
        try:
58
            ret = func(self, *args, **kw)
59
            self.con.commit()
60
            return ret
61
        except:
62
            self.con.rollback()
63
            raise
64
    return fn
65

  
47 66

  
48 67
class SimpleBackend(BaseBackend):
49 68
    """A simple backend.
......
110 129
                  'namelen': self.blocker.hashlen}
111 130
        self.mapper = Mapper(**params)
112 131
    
132
    @backend_method
113 133
    def get_account_meta(self, user, account, until=None):
114 134
        """Return a dictionary with the account metadata."""
115 135
        
......
146 166
            meta.update({'until_timestamp': tstamp})
147 167
        return meta
148 168
    
169
    @backend_method
149 170
    def update_account_meta(self, user, account, meta, replace=False):
150 171
        """Update the metadata associated with the account."""
151 172
        
......
154 175
            raise NotAllowedError
155 176
        self._put_metadata(user, account, meta, replace, False)
156 177
    
178
    @backend_method
157 179
    def get_account_groups(self, user, account):
158 180
        """Return a dictionary with the user groups defined for this account."""
159 181
        
......
162 184
            raise NotAllowedError
163 185
        return self._get_groups(account)
164 186
    
187
    @backend_method
165 188
    def update_account_groups(self, user, account, groups, replace=False):
166 189
        """Update the groups associated with the account."""
167 190
        
......
171 194
        self._check_groups(groups)
172 195
        self._put_groups(account, groups, replace)
173 196
    
197
    @backend_method
174 198
    def put_account(self, user, account):
175 199
        """Create a new account with the given name."""
176 200
        
......
184 208
        else:
185 209
            raise NameError('Account already exists')
186 210
        version_id = self._put_version(account, user)
187
        self.con.commit()
188 211
    
212
    @backend_method
189 213
    def delete_account(self, user, account):
190 214
        """Delete the account with the given name."""
191 215
        
......
198 222
        sql = 'delete from versions where name = ?'
199 223
        self.con.execute(sql, (account,))
200 224
        self._del_groups(account)
201
        self.con.commit()
202 225
    
226
    @backend_method
203 227
    def list_containers(self, user, account, marker=None, limit=10000, until=None):
204 228
        """Return a list of containers existing under an account."""
205 229
        
......
219 243
            return containers[start:start + limit]
220 244
        return self._list_objects(account, '', '/', marker, limit, False, [], until)
221 245
    
246
    @backend_method
222 247
    def get_container_meta(self, user, account, container, until=None):
223 248
        """Return a dictionary with the container metadata."""
224 249
        
......
242 267
            meta.update({'until_timestamp': tstamp})
243 268
        return meta
244 269
    
270
    @backend_method
245 271
    def update_container_meta(self, user, account, container, meta, replace=False):
246 272
        """Update the metadata associated with the container."""
247 273
        
......
251 277
        path, version_id, mtime = self._get_containerinfo(account, container)
252 278
        self._put_metadata(user, path, meta, replace, False)
253 279
    
280
    @backend_method
254 281
    def get_container_policy(self, user, account, container):
255 282
        """Return a dictionary with the container policy."""
256 283
        
......
260 287
        path = self._get_containerinfo(account, container)[0]
261 288
        return self._get_policy(path)
262 289
    
290
    @backend_method
263 291
    def update_container_policy(self, user, account, container, policy, replace=False):
264 292
        """Update the policy associated with the account."""
265 293
        
......
275 303
        for k, v in policy.iteritems():
276 304
            sql = 'insert or replace into policy (name, key, value) values (?, ?, ?)'
277 305
            self.con.execute(sql, (path, k, v))
278
        self.con.commit()
279 306
    
307
    @backend_method
280 308
    def put_container(self, user, account, container, policy=None):
281 309
        """Create a new container with the given name."""
282 310
        
......
299 327
        for k, v in policy.iteritems():
300 328
            sql = 'insert or replace into policy (name, key, value) values (?, ?, ?)'
301 329
            self.con.execute(sql, (path, k, v))
302
        self.con.commit()
303 330
    
331
    @backend_method
304 332
    def delete_container(self, user, account, container, until=None):
305 333
        """Delete/purge the container with the given name."""
306 334
        
......
316 344
            c = self.con.execute(sql, (path + '/%', until))
317 345
            for v in [x[0] for x in c.fetchall()]:
318 346
                self._del_version(v)
319
            self.con.commit()
320 347
            return
321 348
        
322 349
        count = self._get_pathstats(path)[0]
......
328 355
        self.con.execute(sql, (path,))
329 356
        self._copy_version(user, account, account, True, False) # New account version (for timestamp update).
330 357
    
358
    @backend_method
331 359
    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None):
332 360
        """Return a list of objects existing under a container."""
333 361
        
......
337 365
        path, version_id, mtime = self._get_containerinfo(account, container, until)
338 366
        return self._list_objects(path, prefix, delimiter, marker, limit, virtual, keys, until)
339 367
    
368
    @backend_method
340 369
    def list_object_meta(self, user, account, container, until=None):
341 370
        """Return a list with all the container's object meta keys."""
342 371
        
......
350 379
        c = self.con.execute(sql, (path + '/%',))
351 380
        return [x[0] for x in c.fetchall()]
352 381
    
382
    @backend_method
353 383
    def get_object_meta(self, user, account, container, name, version=None):
354 384
        """Return a dictionary with the object metadata."""
355 385
        
......
367 397
        meta.update({'modified': modified, 'modified_by': muser})
368 398
        return meta
369 399
    
400
    @backend_method
370 401
    def update_object_meta(self, user, account, container, name, meta, replace=False):
371 402
        """Update the metadata associated with the object."""
372 403
        
......
375 406
        path, version_id, muser, mtime, size = self._get_objectinfo(account, container, name)
376 407
        self._put_metadata(user, path, meta, replace)
377 408
    
409
    @backend_method
378 410
    def get_object_permissions(self, user, account, container, name):
379 411
        """Return the path from which this object gets its permissions from,\
380 412
        along with a dictionary containing the permissions."""
......
384 416
        path = self._get_objectinfo(account, container, name)[0]
385 417
        return self._get_permissions(path)
386 418
    
419
    @backend_method
387 420
    def update_object_permissions(self, user, account, container, name, permissions):
388 421
        """Update the permissions associated with the object."""
389 422
        
......
394 427
        r, w = self._check_permissions(path, permissions)
395 428
        self._put_permissions(path, r, w)
396 429
    
430
    @backend_method
397 431
    def get_object_public(self, user, account, container, name):
398 432
        """Return the public URL of the object if applicable."""
399 433
        
......
404 438
            return '/public/' + path
405 439
        return None
406 440
    
441
    @backend_method
407 442
    def update_object_public(self, user, account, container, name, public):
408 443
        """Update the public status of the object."""
409 444
        
......
412 447
        path = self._get_objectinfo(account, container, name)[0]
413 448
        self._put_public(path, public)
414 449
    
450
    @backend_method
415 451
    def get_object_hashmap(self, user, account, container, name, version=None):
416 452
        """Return the object's size and a list with partial hashes."""
417 453
        
......
421 457
        hashmap = self.mapper.map_retr(version_id)
422 458
        return size, [binascii.hexlify(x) for x in hashmap]
423 459
    
460
    @backend_method
424 461
    def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions=None):
425 462
        """Create/update an object with the specified size and partial hashes."""
426 463
        
......
446 483
            self.con.execute(sql, (dest_version_id, k, v))
447 484
        if permissions is not None:
448 485
            self._put_permissions(path, r, w)
449
        self.con.commit()
450 486
    
487
    @backend_method
451 488
    def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None, src_version=None):
452 489
        """Copy an object's data and metadata."""
453 490
        
......
471 508
            self.con.execute(sql, (dest_version_id, k, v))
472 509
        if permissions is not None:
473 510
            self._put_permissions(dest_path, r, w)
474
        self.con.commit()
475 511
    
512
    @backend_method
476 513
    def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
477 514
        """Move an object's data and metadata."""
478 515
        
......
480 517
        self.copy_object(user, account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions, None)
481 518
        self.delete_object(user, account, src_container, src_name)
482 519
    
520
    @backend_method
483 521
    def delete_object(self, user, account, container, name, until=None):
484 522
        """Delete/purge an object."""
485 523
        
......
499 537
                pass
500 538
            else:
501 539
                self._del_sharing(path)
502
            self.con.commit()
503 540
            return
504 541
        
505 542
        path = self._get_objectinfo(account, container, name)[0]
506 543
        self._put_version(path, user, 0, 1)
507 544
        self._del_sharing(path)
508 545
    
546
    @backend_method
509 547
    def list_versions(self, user, account, container, name):
510 548
        """Return a list of all (version, version_timestamp) tuples for an object."""
511 549
        
......
517 555
        c = self.con.execute(sql, (path,))
518 556
        return [(int(x[0]), int(x[1])) for x in c.fetchall()]
519 557
    
558
    @backend_method(autocommit=0)
520 559
    def get_block(self, hash):
521 560
        """Return a block's data."""
522 561
        
......
526 565
            raise NameError('Block does not exist')
527 566
        return blocks[0]
528 567
    
568
    @backend_method(autocommit=0)
529 569
    def put_block(self, data):
530 570
        """Create a block and return the hash."""
531 571
        
......
533 573
        hashes, absent = self.blocker.block_stor((data,))
534 574
        return binascii.hexlify(hashes[0])
535 575
    
576
    @backend_method(autocommit=0)
536 577
    def update_block(self, hash, data, offset=0):
537 578
        """Update a known block and return the hash."""
538 579
        
......
584 625
        tstamp = int(time.time())
585 626
        sql = 'insert into versions (name, user, tstamp, size, hide) values (?, ?, ?, ?, ?)'
586 627
        id = self.con.execute(sql, (path, user, tstamp, size, hide)).lastrowid
587
        self.con.commit()
588 628
        return str(id)
589 629
    
590 630
    def _copy_version(self, user, src_path, dest_path, copy_meta=True, copy_data=True, src_version=None):
......
608 648
            # TODO: Copy properly.
609 649
            hashmap = self.mapper.map_retr(src_version_id)
610 650
            self.mapper.map_stor(dest_version_id, hashmap)
611
        self.con.commit()
612 651
        return src_version_id, dest_version_id
613 652
    
614 653
    def _get_versioninfo(self, account, container, name, until=None):
......
663 702
            else:
664 703
                sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)'
665 704
                self.con.execute(sql, (dest_version_id, k, v))
666
        self.con.commit()
667 705
    
668 706
    def _check_policy(self, policy):
669 707
        for k in policy.keys():
......
762 800
            if v:
763 801
                sql = 'insert into groups (account, gname, user) values (?, ?, ?)'
764 802
                self.con.executemany(sql, [(account, k, x) for x in v])
765
        self.con.commit()
766 803
    
767 804
    def _del_groups(self, account):
768 805
        sql = 'delete from groups where account = ?'
......
812 849
            self.con.executemany(sql, [(path, 'read', x) for x in r])
813 850
        if w:
814 851
            self.con.executemany(sql, [(path, 'write', x) for x in w])
815
        self.con.commit()
816 852
    
817 853
    def _get_public(self, path):
818 854
        sql = 'select name from public where name = ?'
......
828 864
        else:
829 865
            sql = 'insert or replace into public (name) values (?)'
830 866
        self.con.execute(sql, (path,))
831
        self.con.commit()
832 867
    
833 868
    def _del_sharing(self, path):
834 869
        sql = 'delete from permissions where name = ?'
835 870
        self.con.execute(sql, (path,))
836 871
        sql = 'delete from public where name = ?'
837 872
        self.con.execute(sql, (path,))
838
        self.con.commit()
839 873
    
840 874
    def _is_allowed(self, user, account, container, name, op='read'):
841 875
        if user == account:

Also available in: Unified diff