| | 399 | # LockingShelveSessionStore contributed by Julian Cigar <jcigar@ulb.ac.be> |
|---|
| | 400 | |
|---|
| | 401 | LOCK_TIMEOUT = 60 |
|---|
| | 402 | |
|---|
| | 403 | class FileLock(object): |
|---|
| | 404 | |
|---|
| | 405 | def __init__(self, lock_file): |
|---|
| | 406 | self._lock_file = lock_file |
|---|
| | 407 | |
|---|
| | 408 | def acquireLock(self, timeout=LOCK_TIMEOUT): |
|---|
| | 409 | |
|---|
| | 410 | for i in xrange(1, timeout*10): |
|---|
| | 411 | try: |
|---|
| | 412 | os.open(self._lock_file, os.O_WRONLY | os.O_CREAT | os.O_EXCL, |
|---|
| | 413 | 0660) |
|---|
| | 414 | return True |
|---|
| | 415 | except: |
|---|
| | 416 | time.sleep(0.1) |
|---|
| | 417 | continue |
|---|
| | 418 | |
|---|
| | 419 | try: |
|---|
| | 420 | self.isStale() and self.releaseLock() |
|---|
| | 421 | except: |
|---|
| | 422 | pass |
|---|
| | 423 | |
|---|
| | 424 | return False |
|---|
| | 425 | |
|---|
| | 426 | def isStale(self): |
|---|
| | 427 | try: |
|---|
| | 428 | return os.stat(self._lock_file).st_mtime < time.time() - 3600 |
|---|
| | 429 | except OSError: |
|---|
| | 430 | return False |
|---|
| | 431 | |
|---|
| | 432 | def releaseLock(self): |
|---|
| | 433 | os.path.isfile(self._lock_file) and os.unlink(self._lock_file) |
|---|
| | 434 | |
|---|
| | 435 | def withLock(self, self_, fct, args): |
|---|
| | 436 | if self.acquireLock(): |
|---|
| | 437 | try: |
|---|
| | 438 | return fct(self_, *args) |
|---|
| | 439 | finally: |
|---|
| | 440 | self.releaseLock() |
|---|
| | 441 | else: |
|---|
| | 442 | raise IOError('Cannot acquire lock') |
|---|
| | 443 | |
|---|
| | 444 | def with_lock(fct): |
|---|
| | 445 | return lambda self, *args: self.lock.withLock(self, fct, args) |
|---|
| | 446 | |
|---|
| | 447 | class LockingShelveSessionStore(SessionStore): |
|---|
| | 448 | def __init__(self, storeFile='sessions', *a, **kw): |
|---|
| | 449 | super(LockingShelveSessionStore, self).__init__(*a, **kw) |
|---|
| | 450 | |
|---|
| | 451 | self.storeFile = storeFile |
|---|
| | 452 | lock_file = os.path.join(os.path.dirname(self.storeFile), '.lock') |
|---|
| | 453 | self.lock = FileLock(lock_file) |
|---|
| | 454 | |
|---|
| | 455 | def _createSession(self, identifier): |
|---|
| | 456 | secondaryStore = shelve.open(self.storeFile) |
|---|
| | 457 | try: |
|---|
| | 458 | if secondaryStore.has_key(identifier): |
|---|
| | 459 | return None |
|---|
| | 460 | sess = self._sessionClass(identifier) |
|---|
| | 461 | secondaryStore[sess.identifier] = sess |
|---|
| | 462 | return sess |
|---|
| | 463 | finally: |
|---|
| | 464 | secondaryStore.close() |
|---|
| | 465 | _createSession = with_lock(_createSession) |
|---|
| | 466 | |
|---|
| | 467 | def _loadSession(self, identifier): |
|---|
| | 468 | secondaryStore = shelve.open(self.storeFile) |
|---|
| | 469 | try: |
|---|
| | 470 | return secondaryStore.get(identifier, None) |
|---|
| | 471 | finally: |
|---|
| | 472 | secondaryStore.close() |
|---|
| | 473 | _loadSession = with_lock(_loadSession) |
|---|
| | 474 | |
|---|
| | 475 | def _saveSession(self, session): |
|---|
| | 476 | secondaryStore = shelve.open(self.storeFile) |
|---|
| | 477 | try: |
|---|
| | 478 | secondaryStore[session.identifier] = session |
|---|
| | 479 | finally: |
|---|
| | 480 | secondaryStore.close() |
|---|
| | 481 | _saveSession = with_lock(_saveSession) |
|---|
| | 482 | |
|---|
| | 483 | def _deleteSession(self, identifier): |
|---|
| | 484 | secondaryStore = shelve.open(self.storeFile) |
|---|
| | 485 | try: |
|---|
| | 486 | if secondaryStore.has_key(identifier): |
|---|
| | 487 | del secondaryStore[identifier] |
|---|
| | 488 | finally: |
|---|
| | 489 | secondaryStore.close() |
|---|
| | 490 | _deleteSession = with_lock(_deleteSession) |
|---|
| | 491 | |
|---|
| | 492 | def _periodic(self): |
|---|
| | 493 | secondaryStore = shelve.open(self.storeFile) |
|---|
| | 494 | try: |
|---|
| | 495 | now = time.time() |
|---|
| | 496 | for key,sess in secondaryStore.items(): |
|---|
| | 497 | if self._isSessionTimedout(sess, now): |
|---|
| | 498 | del secondaryStore[key] |
|---|
| | 499 | finally: |
|---|
| | 500 | secondaryStore.close() |
|---|
| | 501 | _periodic = with_lock(_periodic) |
|---|
| | 502 | |
|---|
| | 503 | def _shutdown(self): |
|---|
| | 504 | pass |
|---|
| | 505 | |
|---|