diff --git a/swift/account/server.py b/swift/account/server.py index 4c08fc1e78..bb7c170d25 100644 --- a/swift/account/server.py +++ b/swift/account/server.py @@ -113,8 +113,11 @@ class AccountController(object): broker.pending_timeout = 3 if account.startswith(self.auto_create_account_prefix) and \ not os.path.exists(broker.db_file): - broker.initialize(normalize_timestamp( - req.headers.get('x-timestamp') or time.time())) + try: + broker.initialize(normalize_timestamp( + req.headers.get('x-timestamp') or time.time())) + except swift.common.db.DatabaseAlreadyExists: + pass if req.headers.get('x-account-override-deleted', 'no').lower() != \ 'yes' and broker.is_deleted(): return HTTPNotFound(request=req) @@ -130,8 +133,11 @@ class AccountController(object): else: # put account timestamp = normalize_timestamp(req.headers['x-timestamp']) if not os.path.exists(broker.db_file): - broker.initialize(timestamp) - created = True + try: + broker.initialize(timestamp) + created = True + except swift.common.db.DatabaseAlreadyExists: + pass elif broker.is_status_deleted(): return HTTPForbidden(request=req, body='Recently deleted') else: diff --git a/swift/common/db.py b/swift/common/db.py index bffdb2e1ef..f8b4314e79 100644 --- a/swift/common/db.py +++ b/swift/common/db.py @@ -70,6 +70,16 @@ class DatabaseConnectionError(sqlite3.DatabaseError): self.path, self.timeout, self.msg) +class DatabaseAlreadyExists(sqlite3.DatabaseError): + """More friendly error messages for DB Errors.""" + + def __init__(self, path): + self.path = path + + def __str__(self): + return 'DB %s already exists' % self.path + + class GreenDBConnection(sqlite3.Connection): """SQLite DB Connection handler that plays well with eventlet.""" @@ -247,9 +257,7 @@ class DatabaseBroker(object): if os.path.exists(self.db_file): # It's as if there was a "condition" where different parts # of the system were "racing" each other. - raise DatabaseConnectionError( - self.db_file, - 'DB created by someone else while working?') + raise DatabaseAlreadyExists(self.db_file) renamer(tmp_db_file, self.db_file) self.conn = get_db_connection(self.db_file, self.timeout) else: diff --git a/swift/container/server.py b/swift/container/server.py index 6aee0045ac..0a7e7324b0 100644 --- a/swift/container/server.py +++ b/swift/container/server.py @@ -198,8 +198,11 @@ class ContainerController(object): broker = self._get_container_broker(drive, part, account, container) if account.startswith(self.auto_create_account_prefix) and obj and \ not os.path.exists(broker.db_file): - broker.initialize(normalize_timestamp( - req.headers.get('x-timestamp') or time.time())) + try: + broker.initialize(normalize_timestamp( + req.headers.get('x-timestamp') or time.time())) + except swift.common.db.DatabaseAlreadyExists: + pass if not os.path.exists(broker.db_file): return HTTPNotFound() if obj: # delete object @@ -247,7 +250,10 @@ class ContainerController(object): if obj: # put container object if account.startswith(self.auto_create_account_prefix) and \ not os.path.exists(broker.db_file): - broker.initialize(timestamp) + try: + broker.initialize(timestamp) + except swift.common.db.DatabaseAlreadyExists: + pass if not os.path.exists(broker.db_file): return HTTPNotFound() broker.put_object(obj, timestamp, int(req.headers['x-size']), @@ -256,8 +262,11 @@ class ContainerController(object): return HTTPCreated(request=req) else: # put container if not os.path.exists(broker.db_file): - broker.initialize(timestamp) - created = True + try: + broker.initialize(timestamp) + created = True + except swift.common.db.DatabaseAlreadyExists: + pass else: created = broker.is_deleted() broker.update_put_timestamp(timestamp) diff --git a/test/unit/common/test_db.py b/test/unit/common/test_db.py index c86d679c4c..1ae44927cc 100644 --- a/test/unit/common/test_db.py +++ b/test/unit/common/test_db.py @@ -25,6 +25,7 @@ from uuid import uuid4 import simplejson import sqlite3 +from mock import patch import swift.common.db from swift.common.db import AccountBroker, chexor, ContainerBroker, \ @@ -99,6 +100,7 @@ class TestDatabaseBroker(unittest.TestCase): def test_DB_PREALLOCATION_setting(self): u = uuid4().hex b = DatabaseBroker(u) + swift.common.db.DB_PREALLOCATION = False b._preallocate() swift.common.db.DB_PREALLOCATION = True self.assertRaises(OSError, b._preallocate) @@ -147,6 +149,15 @@ class TestDatabaseBroker(unittest.TestCase): conn.execute('SELECT * FROM outgoing_sync') conn.execute('SELECT * FROM incoming_sync') + def my_exists(*a, **kw): + return True + + with patch('os.path.exists', my_exists): + broker = DatabaseBroker(os.path.join(self.testdir, '1.db')) + broker._initialize = stub + self.assertRaises(swift.common.db.DatabaseAlreadyExists, + broker.initialize, normalize_timestamp('1')) + def test_delete_db(self): def init_stub(conn, put_timestamp): conn.execute('CREATE TABLE test (one TEXT)')