Merge "Handle DB creation race condition"
This commit is contained in:
commit
5501a4031f
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)')
|
||||
|
Loading…
Reference in New Issue
Block a user