Browse Source

simpler spec autosave/backup

Darren Ranalli 22 years ago
parent
commit
a9aaed8d15
2 changed files with 60 additions and 47 deletions
  1. 28 21
      direct/src/level/DistributedLevelAI.py
  2. 32 26
      direct/src/level/LevelSpec.py

+ 28 - 21
direct/src/level/DistributedLevelAI.py

@@ -20,7 +20,6 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
         self.zoneId = zoneId
         if __debug__:
             self.modified = 0
-            self.makeBackup = 1
 
     def generate(self, levelSpec):
         self.notify.debug('generate')
@@ -41,7 +40,7 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
     def delete(self):
         self.notify.debug('delete')
         if __debug__:
-            self.saveSpec()
+            self.removeBackupTask()
         self.destroyLevel()
         DistributedObjectAI.DistributedObjectAI.delete(self)
 
@@ -103,35 +102,43 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
             self.levelSpec.setAttribChange(entId, attribName, value, username)
 
             self.modified = 1
-            self.scheduleSave()
+            self.scheduleAutosave()
 
-        SavePeriod = simbase.config.GetInt('factory-save-period', 10)
-        BackupPeriod = simbase.config.GetInt('factory-backup-period-minutes',5)
+        # backups are made every N minutes, starting from the time that
+        # the first edit is made
+        AutosavePeriod = simbase.config.GetFloat(
+            'level-autosave-period-minutes', 5)
 
-        def scheduleSave(self):
-            if hasattr(self, 'saveTask'):
+        def scheduleAutosave(self):
+            if hasattr(self, 'autosaveTask'):
                 return
-            self.saveTask = taskMgr.doMethodLater(
-                DistributedLevelAI.SavePeriod,
-                self.saveSpec,
-                self.uniqueName('saveSpec'))
+            self.autosaveTaskName = self.uniqueName('saveSpec')
+            self.autosaveTask = taskMgr.doMethodLater(
+                DistributedLevelAI.AutosavePeriod * 60,
+                self.autosaveSpec,
+                self.autosaveTaskName)
+
+        def removeAutosaveTask(self):
+            if hasattr(self, 'autosaveTask'):
+                taskMgr.remove(self.autosaveTaskName)
+                del self.autosaveTask
+
+        def autosaveSpec(self, task=None):
+            self.removeAutosaveTask()
+            if self.modified:
+                DistributedLevelAI.notify.info('autosaving spec')
+                filename = self.levelSpec.getFilename()
+                filename = '%s.autosave' % filename
+                self.levelSpec.saveToDisk(filename, makeBackup=0)
 
         def saveSpec(self, task=None):
             DistributedLevelAI.notify.info('saving spec')
-            if hasattr(self, 'saveTask'):
-                del self.saveTask
+            self.removeAutosaveTask()
             if not self.modified:
                 DistributedLevelAI.notify.info('no changes to save')
                 return
-            self.levelSpec.saveToDisk(createBackup=self.makeBackup)
+            self.levelSpec.saveToDisk()
             self.modified = 0
-            self.makeBackup = 0
-            def setMakeBackup(task, self=self):
-                self.makeBackup = 1
-            self.backupTask = taskMgr.doMethodLater(
-                DistributedLevelAI.BackupPeriod * 60,
-                setMakeBackup,
-                self.uniqueName('setMakeBackup'))
 
         def requestCurrentLevelSpec(self, specHash, entTypeRegHash):
             senderId = self.air.msgSender

+ 32 - 26
direct/src/level/LevelSpec.py

@@ -3,6 +3,8 @@
 import DirectNotifyGlobal
 from PythonUtil import list2dict, uniqueElements
 import string
+if __debug__:
+    import os
 
 class LevelSpec:
     """contains spec data for a level, is responsible for handing the data
@@ -138,42 +140,32 @@ class LevelSpec:
             # name of module that should be imported by spec py file
             return 'SpecImports'
 
-        def saveToDisk(self, filename=None, createBackup=1):
-            """returns zero on failure"""
-            import os
+        def getFilename(self):
+            return self.filename
+
+        def privGetBackupFilename(self):
+            return '%s.bak' % self.getFilename()
 
+        def saveToDisk(self, filename=None, makeBackup=1):
+            """returns zero on failure"""
             if filename is None:
                 filename = self.filename
 
-            if createBackup:
+            if makeBackup and self.privFileExists(filename):
                 # create a backup
                 try:
-                    # does the file exist?
-                    exists = 0
-                    try:
-                        os.stat(filename)
-                        exists = 1
-                    except OSError:
-                        pass
-                    if exists:
-                        def getBackupFilename(num, filename=filename):
-                            return '%s.%03i' % (filename, num)
-                        numBackups = 200
-                        try:
-                            os.unlink(getBackupFilename(numBackups-1))
-                        except OSError:
-                            pass
-                        for i in range(numBackups-1,0,-1):
-                            try:
-                                os.rename(getBackupFilename(i-1),
-                                          getBackupFilename(i))
-                            except OSError:
-                                pass
-                        os.rename(filename, getBackupFilename(0))
+                    backupFilename = self.privGetBackupFilename()
+                    self.privRemoveFile(backupFilename)
+                    os.rename(filename, backupFilename)
                 except OSError, e:
                     LevelSpec.notify.warning(
                         'error during backup: %s' % str(e))
 
+            self.privRemoveFile(filename)
+            self.privSaveToDisk(filename)
+
+        def privSaveToDisk(self, filename):
+            """internal. saves spec to file. returns zero on failure"""
             retval = 1
             # wb to create a UNIX-format file
             f = file(filename, 'wb')
@@ -184,6 +176,20 @@ class LevelSpec:
             f.close()
             return retval
 
+        def privFileExists(self, filename):
+            try:
+                os.stat(filename)
+                return 1
+            except OSError:
+                return 0
+
+        def privRemoveFile(self, filename):
+            try:
+                os.remove(filename)
+                return 1
+            except OSError:
+                return 0
+
         def getPrettyString(self):
             """Returns a string that contains the spec data, nicely formatted.
             This should be used when writing the spec out to file."""