~divmod-dev/divmod.org/compressed-resources-2747

« back to all changes in this revision

Viewing changes to Imaginary/pottery/persistence.py

  • Committer: exarkun
  • Date: 2006-02-26 02:37:39 UTC
  • Revision ID: svn-v4:866e43f7-fbfc-0310-8f2a-ec88d1da2979:trunk:4991
Merge move-pottery-to-trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
"""Persistence support for Pottery
 
3
 
 
4
For now, this defines a service which holds a reference to the game's
 
5
realm instance.  Periodically, the realm is pickled and written to
 
6
disk.  When the service is created, if an existing pickled realm
 
7
exists on disk, it is loaded and used instead of the realm passed in.
 
8
"""
 
9
 
 
10
 
 
11
import os, errno
 
12
import cPickle as pickle
 
13
 
 
14
from twisted.application import service
 
15
from twisted.internet import task
 
16
from twisted.python import log
 
17
 
 
18
class PersistenceService(service.Service):
 
19
    def __init__(self, fname, realm):
 
20
        self.fname = fname
 
21
        if os.path.exists(fname):
 
22
            realm = self._unpersist()
 
23
        self.realm = realm
 
24
 
 
25
    def startService(self):
 
26
        self.loop = task.LoopingCall(self._persist)
 
27
        self.loop.start(60).addErrback(log.err)
 
28
 
 
29
    def stopService(self):
 
30
        self.loop.stop()
 
31
        self._persist()
 
32
 
 
33
    def _persist(self):
 
34
        # Try to reap the previous persistence child.
 
35
        try:
 
36
            os.waitpid(-1, os.WNOHANG)
 
37
        except OSError, e:
 
38
            if e.errno != errno.ECHILD:
 
39
                raise
 
40
 
 
41
        # Fork and continue normal execution in the parent.  In the child,
 
42
        # try to acquire the persist lock.  If it cannot be acquired,
 
43
        # return.  Otherwise, pickle game state to a new file, move the
 
44
        # entire result over the existing game state file, and release the
 
45
        # lock.
 
46
        pid = os.fork()
 
47
        if pid == 0:
 
48
            try:
 
49
                try:
 
50
                    os.mkdir(self.fname + '.lock')
 
51
                except OSError, e:
 
52
                    if e.errno != errno.EEXIST:
 
53
                        raise
 
54
                else:
 
55
                    try:
 
56
                        fObj = file(self.fname + '.tmp', 'wb')
 
57
                        fObj.write(pickle.dumps(self.realm))
 
58
                        fObj.close()
 
59
                        os.rename(self.fname + '.tmp', self.fname)
 
60
                    finally:
 
61
                        os.rmdir(self.fname + '.lock')
 
62
            finally:
 
63
                os._exit(0)
 
64
 
 
65
    def _unpersist(self):
 
66
        fObj = file(self.fname, 'rb')
 
67
        return pickle.loads(fObj.read())
 
68