~seif/zeitgeist/tuples

« back to all changes in this revision

Viewing changes to _zeitgeist/engine/sql.py

  • Committer: Siegfried-Angel Gevatter Pujals
  • Date: 2011-05-18 20:48:13 UTC
  • mfrom: (1759.1.6 zeitgeist)
  • Revision ID: rainct@ubuntu.com-20110518204813-rl0znoeo1cuujelt
Merge J.P. Lacerda's branch introducing database backup
before schema upgrades.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
# Copyright © 2009 Mikkel Kamstrup Erlandsen <mikkel.kamstrup@gmail.com>
7
7
# Copyright © 2009-2011 Markus Korn <thekorn@gmx.net>
8
8
# Copyright © 2009 Seif Lotfy <seif@lotfy.com>
 
9
# Copyright © 2011 J.P. Lacerda <jpaflacerda@gmail.com>
9
10
# Copyright © 2011 Collabora Ltd.
10
11
#             By Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>
11
12
#
26
27
import logging
27
28
import time
28
29
import os
 
30
import shutil
29
31
 
30
32
from _zeitgeist.engine import constants
31
33
 
112
114
        named '_zeitgeist.engine.upgrades.$schema_name_$(i)_$(i+1)' and executing 
113
115
        the run(cursor) method of those modules until new_version is reached
114
116
        """
 
117
        _do_schema_backup()
 
118
        _set_schema_version(cursor, schema_name, -1)
115
119
        for i in xrange(old_version, new_version):
116
 
                # Fire of the right upgrade module
117
 
                log.info("Upgrading database '%s' from version %s to %s. This may take a while" %
118
 
                         (schema_name, i, i+1))
 
120
                # Fire off the right upgrade module
 
121
                log.info("Upgrading database '%s' from version %s to %s. "
 
122
                        "This may take a while" % (schema_name, i, i+1))
119
123
                upgrader_name = "%s_%s_%s" % (schema_name, i, i+1)
120
124
                module = __import__ ("_zeitgeist.engine.upgrades.%s" % upgrader_name)
121
125
                eval("module.engine.upgrades.%s.run(cursor)" % upgrader_name)
122
126
                
123
 
                # Update the schema version
124
 
                _set_schema_version(cursor, schema_name, i+1)
 
127
        # Update the schema version
 
128
        _set_schema_version(cursor, schema_name, new_version)
 
129
 
125
130
        log.info("Upgrade succesful")
126
131
 
127
132
def _check_core_schema_upgrade (cursor):
128
 
        """Return True if the schema is good and no setup needs to be run"""
 
133
        """
 
134
        Checks whether the schema is good or, if it is outdated, triggers any
 
135
        necessary upgrade scripts. This method will also attempt to restore a
 
136
        database backup in case a previous upgrade was cancelled midway.
 
137
        
 
138
        It returns a boolean indicating whether the schema was good and the
 
139
        database cursor (which will have changed if the database was restored).
 
140
        """
129
141
        # See if we have the right schema version, and try an upgrade if needed
130
142
        core_schema_version = _get_schema_version(cursor, constants.CORE_SCHEMA)
131
 
        if core_schema_version is not None:
132
 
                if core_schema_version >= constants.CORE_SCHEMA_VERSION:
133
 
                        return True
134
 
                else:
135
 
                        try:
136
 
                                _do_schema_upgrade (cursor,
137
 
                                                    constants.CORE_SCHEMA,
138
 
                                                    core_schema_version,
139
 
                                                    constants.CORE_SCHEMA_VERSION)
140
 
                                # Don't return here. The upgrade process might depend on the
141
 
                                # tables, indexes, and views being set up (to avoid code dup)
142
 
                                log.info("Running post upgrade setup")
143
 
                                return False
144
 
                        except Exception, e:
145
 
                                log.exception("Failed to upgrade database '%s' from version %s to %s: %s" %
146
 
                                          (constants.CORE_SCHEMA, core_schema_version, constants.CORE_SCHEMA_VERSION, e))
147
 
                                raise SystemExit(27)
 
143
        if core_schema_version >= constants.CORE_SCHEMA_VERSION:
 
144
                return True, cursor
148
145
        else:
149
 
                return False
150
 
 
 
146
                try:
 
147
                        if core_schema_version <= -1:
 
148
                                cursor.connection.commit()
 
149
                                cursor.connection.close()
 
150
                                _do_schema_restore()
 
151
                                cursor = _connect_to_db(constants.DATABASE_FILE)
 
152
                                core_schema_version = _get_schema_version(cursor,
 
153
                                        constants.CORE_SCHEMA)
 
154
                                log.exception("Database corrupted at upgrade -- "
 
155
                                        "upgrading from version %s" % core_schema_version)
 
156
 
 
157
                        _do_schema_upgrade (cursor,
 
158
                                constants.CORE_SCHEMA,
 
159
                                core_schema_version,
 
160
                                constants.CORE_SCHEMA_VERSION)
 
161
 
 
162
                        # Don't return here. The upgrade process might depend on the
 
163
                        # tables, indexes, and views being set up (to avoid code dup)
 
164
                        log.info("Running post upgrade setup")
 
165
                        return False, cursor
 
166
                except sqlite3.OperationalError:
 
167
                        # Something went wrong while applying the upgrade -- this is
 
168
                        # probably due to a non existing table (this occurs when 
 
169
                        # applying core_3_4, for example). We just need to fall through
 
170
                        # the rest of create_db to fix this...
 
171
                        log.exception("Database corrupted -- proceeding")
 
172
                        return False, cursor
 
173
                except Exception, e:
 
174
                        log.exception(
 
175
                                "Failed to upgrade database '%s' from version %s to %s: %s" % \
 
176
                                (constants.CORE_SCHEMA, core_schema_version,
 
177
                                constants.CORE_SCHEMA_VERSION, e))
 
178
                        raise SystemExit(27)
 
179
 
 
180
def _do_schema_backup ():
 
181
        shutil.copyfile(constants.DATABASE_FILE, constants.DATABASE_FILE_BACKUP)
 
182
 
 
183
def _do_schema_restore ():
 
184
        shutil.move(constants.DATABASE_FILE_BACKUP, constants.DATABASE_FILE)
 
185
 
 
186
def _connect_to_db(file_path):
 
187
        conn = sqlite3.connect(file_path)
 
188
        conn.row_factory = sqlite3.Row
 
189
        cursor = conn.cursor(UnicodeCursor)
 
190
        return cursor
151
191
 
152
192
def create_db(file_path):
153
193
        """Create the database and return a default cursor for it"""
154
194
        start = time.time()
155
195
        log.info("Using database: %s" % file_path)
156
196
        new_database = not os.path.exists(file_path)
157
 
        conn = sqlite3.connect(file_path)
158
 
        conn.row_factory = sqlite3.Row
159
 
        cursor = conn.cursor(UnicodeCursor)
 
197
        cursor = _connect_to_db(file_path)
160
198
 
161
199
        # Seif: as result of the optimization story (LP: #639737) we are setting
162
200
        # journal_mode to WAL if possible, this change is irreversible but
179
217
        cursor.execute("CREATE TEMP TABLE _fix_cache (table_name VARCHAR, id INTEGER)")
180
218
        
181
219
        # Always assume that temporary memory backed DBs have good schemas
182
 
        if constants.DATABASE_FILE != ":memory:":
183
 
                if not new_database and _check_core_schema_upgrade(cursor):
 
220
        if constants.DATABASE_FILE != ":memory:" and not new_database:
 
221
                do_upgrade, cursor = _check_core_schema_upgrade(cursor)
 
222
                if do_upgrade:
184
223
                        _time = (time.time() - start)*1000
185
224
                        log.debug("Core schema is good. DB loaded in %sms" % _time)
186
225
                        return cursor