www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit d3bc693dabf72c39aad84156f495f32b11334a7a
parent 9a0457b43e984e5d83ef5382bc5c15e7a8d09865
Author: Dan Stillman <dstillman@zotero.org>
Date:   Tue,  1 Aug 2006 23:10:31 +0000

Closes #77, maintain database backups

The Scholar database is backed up on browser close. On startup, if the main database is damaged, the extension saves a copy of the damaged file and tries to restore from the last automatic backup. If it fails, it creates a new database file.

New methods:

Scholar.getScholarDatabase(string [ext])
Scholar.backupDatabase()
Scholar.moveToUnique(file, newFile) -- find a unique filename using the leafName of newFile as the suggested name (using the built-in Mozilla functionality) and move the file there
Scholar.Date.getFileDateString(file)
Scholar.Date.getFileTimeString(file)



Diffstat:
Mchrome/chromeFiles/content/scholar/xpcom/db.js | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mchrome/chromeFiles/content/scholar/xpcom/scholar.js | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mchrome/chromeFiles/locale/en-US/scholar/scholar.properties | 8++++++--
3 files changed, 164 insertions(+), 9 deletions(-)

diff --git a/chrome/chromeFiles/content/scholar/xpcom/db.js b/chrome/chromeFiles/content/scholar/xpcom/db.js @@ -7,7 +7,6 @@ Scholar.DB = new function(){ var _transactionRollback; var _transactionNestingLevel = 0; - // Privileged methods this.query = query; this.valueQuery = valueQuery; this.rowQuery = rowQuery; @@ -359,13 +358,80 @@ Scholar.DB = new function(){ var store = Components.classes["@mozilla.org/storage/service;1"]. getService(Components.interfaces.mozIStorageService); - // Get the storage directory - var file = Scholar.getScholarDirectory(); - - // This makes file point to PROFILE_DIR/<scholar dir>/<scholar database file> - file.append(SCHOLAR_CONFIG['DB_FILE']); + var file = Scholar.getScholarDatabase(); + var backupFile = Scholar.getScholarDatabase('bak'); - _connection = store.openDatabase(file); + catchBlock: try { + _connection = store.openDatabase(file); + } + catch (e){ + if (e.name=='NS_ERROR_FILE_CORRUPTED'){ + Scholar.debug('Database file corrupted', 1); + + // No backup file! Eek! + if (!backupFile.exists()){ + Scholar.debug('No backup file exists', 1); + + // Save damaged filed + Scholar.debug('Saving damaged DB file with .damaged extension', 1); + var damagedFile = Scholar.getScholarDatabase('damaged'); + Scholar.moveToUnique(file, damagedFile); + + // Create new main database + var file = Scholar.getScholarDatabase(); + _connection = store.openDatabase(file); + + alert(Scholar.getString('db.dbCorruptedNoBackup')); + break catchBlock; + } + + // Save damaged file + Scholar.debug('Saving damaged DB file with .damaged extension', 1); + var damagedFile = Scholar.getScholarDatabase('damaged'); + Scholar.moveToUnique(file, damagedFile); + + // Test the backup file + try { + _connection = store.openDatabase(backupFile); + } + // Can't open backup either + catch (e){ + // Create new main database + var file = Scholar.getScholarDatabase(); + _connection = store.openDatabase(file); + + alert(Scholar.getString('db.dbRestoreFailed')); + break catchBlock; + } + + _connection = undefined; + + // Copy backup file to main DB file + Scholar.debug('Restoring main database from backup file', 1); + try { + backupFile.copyTo(backupFile.parent, SCHOLAR_CONFIG['DB_FILE']); + } + catch (e){ + // TODO: deal with low disk space + throw (e); + } + + // Open restored database + var file = Scholar.getScholarDirectory(); + file.append(SCHOLAR_CONFIG['DB_FILE']); + _connection = store.openDatabase(file); + Scholar.debug('Database restored', 1); + var msg = Scholar.getString('db.dbRestored'); + msg = msg.replace('%1', Scholar.Date.getFileDateString(backupFile)) + msg = msg.replace('%2', Scholar.Date.getFileTimeString(backupFile)) + alert(msg); + + break catchBlock; + } + + // Some other error that we don't yet know how to deal with + throw (e); + } return _connection; } diff --git a/chrome/chromeFiles/content/scholar/xpcom/scholar.js b/chrome/chromeFiles/content/scholar/xpcom/scholar.js @@ -23,6 +23,8 @@ var Scholar = new function(){ this.getProfileDirectory = getProfileDirectory; this.getScholarDirectory = getScholarDirectory; this.getStorageDirectory = getStorageDirectory; + this.getScholarDatabase = getScholarDatabase; + this.backupDatabase = backupDatabase; this.debug = debug; this.varDump = varDump; this.getString = getString; @@ -32,6 +34,7 @@ var Scholar = new function(){ this.arraySearch = arraySearch; this.randomString = randomString; this.getRandomID = getRandomID; + this.moveToUnique = moveToUnique; // Public properties this.version; @@ -93,6 +96,10 @@ var Scholar = new function(){ } _shutdown = true; + + Scholar.backupDatabase(); + + return true; } @@ -126,6 +133,57 @@ var Scholar = new function(){ return file; } + function getScholarDatabase(ext){ + ext = ext ? '.' + ext : ''; + + var file = Scholar.getScholarDirectory(); + file.append(SCHOLAR_CONFIG['DB_FILE'] + ext); + return file; + } + + + /* + * Back up the main database file + * + * This could probably create a corrupt file fairly easily if all changes + * haven't been flushed to disk -- proceed with caution + */ + function backupDatabase(){ + if (Scholar.DB.transactionInProgress()){ + Scholar.debug('Transaction in progress--skipping DB backup', 2); + return false; + } + + Scholar.debug('Backing up database'); + + var file = Scholar.getScholarDatabase(); + var backupFile = Scholar.getScholarDatabase('bak'); + + // Copy via a temporary file so we don't run into disk space issues + // after deleting the old backup file + var tmpFile = Scholar.getScholarDatabase('tmp'); + if (tmpFile.exists()){ + tmpFile.remove(null); + } + + try { + file.copyTo(file.parent, tmpFile.leafName); + } + catch (e){ + // TODO: deal with low disk space + throw (e); + } + + // Remove old backup file + if (backupFile.exists()){ + backupFile.remove(null); + } + + tmpFile.moveTo(tmpFile.parent, backupFile.leafName); + + return true; + } + /* * Debug logging function @@ -342,6 +400,17 @@ var Scholar = new function(){ return rnd; } + + + function moveToUnique(file, newFile){ + newFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644); + var newName = newFile.leafName; + newFile.remove(null); + + // Move file to unique name + file.moveTo(newFile.parent, newName); + return file; + } }; @@ -519,6 +588,8 @@ Scholar.Hash.prototype.has = function(in_key){ Scholar.Date = new function(){ this.sqlToDate = sqlToDate; + this.getFileDateString = getFileDateString; + this.getFileTimeString = getFileTimeString; /** * Convert an SQL date in the form '2006-06-13 11:03:05' into a JS Date object @@ -543,6 +614,20 @@ Scholar.Date = new function(){ return false; } } + + + function getFileDateString(file){ + var date = new Date(); + date.setTime(file.lastModifiedTime); + return date.toLocaleDateString(); + } + + + function getFileTimeString(file){ + var date = new Date(); + date.setTime(file.lastModifiedTime); + return date.toLocaleTimeString(); + } } Scholar.Browser = new function() { diff --git a/chrome/chromeFiles/locale/en-US/scholar/scholar.properties b/chrome/chromeFiles/locale/en-US/scholar/scholar.properties @@ -79,4 +79,8 @@ creatorTypes.translator = Translator ingester.scraping = Saving Item... ingester.scrapeComplete = Item Saved. ingester.scrapeError = Could Not Save Item. -ingester.scrapeErrorDescription = An error occurred while saving this item. Please try again. If this error persists, contact the translator author. -\ No newline at end of file +ingester.scrapeErrorDescription = An error occurred while saving this item. Please try again. If this error persists, contact the translator author. + +db.dbCorruptedNoBackup = The Scholar database appears to have become corrupted, and no automatic backup is available.\n\nA new database file has been created. The damaged file was saved in your Scholar directory. +db.dbRestored = The Scholar database appears to have become corrupted.\n\nYour data was restored from the last automatic backup made on %1 at %2. The damaged file was saved in your Scholar directory. +db.dbRestoreFailed = The Scholar database appears to have become corrupted, and an attempt to restore from the last automatic backup failed.\n\nA new database file has been created. The damaged file was saved in your Scholar directory. +\ No newline at end of file