You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.8 KiB
112 lines
3.8 KiB
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2011-2013 Codernity (http://codernity.com)
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
|
|
from threading import RLock
|
|
|
|
from CodernityDB.env import cdb_environment
|
|
|
|
cdb_environment['mode'] = "threads"
|
|
cdb_environment['rlock_obj'] = RLock
|
|
|
|
from database import Database
|
|
|
|
from functools import wraps
|
|
from types import FunctionType, MethodType
|
|
|
|
from CodernityDB.database_safe_shared import th_safe_gen
|
|
|
|
|
|
class SuperLock(type):
|
|
|
|
@staticmethod
|
|
def wrapper(f):
|
|
@wraps(f)
|
|
def _inner(*args, **kwargs):
|
|
db = args[0]
|
|
with db.super_lock:
|
|
# print '=>', f.__name__, repr(args[1:])
|
|
res = f(*args, **kwargs)
|
|
# if db.opened:
|
|
# db.flush()
|
|
# print '<=', f.__name__, repr(args[1:])
|
|
return res
|
|
return _inner
|
|
|
|
def __new__(cls, classname, bases, attr):
|
|
new_attr = {}
|
|
for base in bases:
|
|
for b_attr in dir(base):
|
|
a = getattr(base, b_attr, None)
|
|
if isinstance(a, MethodType) and not b_attr.startswith('_'):
|
|
if b_attr == 'flush' or b_attr == 'flush_indexes':
|
|
pass
|
|
else:
|
|
# setattr(base, b_attr, SuperLock.wrapper(a))
|
|
new_attr[b_attr] = SuperLock.wrapper(a)
|
|
for attr_name, attr_value in attr.iteritems():
|
|
if isinstance(attr_value, FunctionType) and not attr_name.startswith('_'):
|
|
attr_value = SuperLock.wrapper(attr_value)
|
|
new_attr[attr_name] = attr_value
|
|
new_attr['super_lock'] = RLock()
|
|
return type.__new__(cls, classname, bases, new_attr)
|
|
|
|
|
|
class SuperThreadSafeDatabase(Database):
|
|
"""
|
|
Thread safe version that always allows single thread to use db.
|
|
It adds the same lock for all methods, so only one operation can be
|
|
performed in given time. Completely different implementation
|
|
than ThreadSafe version (without super word)
|
|
"""
|
|
|
|
__metaclass__ = SuperLock
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(SuperThreadSafeDatabase, self).__init__(*args, **kwargs)
|
|
|
|
def __patch_index_gens(self, name):
|
|
ind = self.indexes_names[name]
|
|
for c in ('all', 'get_many'):
|
|
m = getattr(ind, c)
|
|
if getattr(ind, c + "_orig", None):
|
|
return
|
|
m_fixed = th_safe_gen.wrapper(m, name, c, self.super_lock)
|
|
setattr(ind, c, m_fixed)
|
|
setattr(ind, c + '_orig', m)
|
|
|
|
def open(self, *args, **kwargs):
|
|
res = super(SuperThreadSafeDatabase, self).open(*args, **kwargs)
|
|
for name in self.indexes_names.iterkeys():
|
|
self.__patch_index_gens(name)
|
|
return res
|
|
|
|
def create(self, *args, **kwargs):
|
|
res = super(SuperThreadSafeDatabase, self).create(*args, **kwargs)
|
|
for name in self.indexes_names.iterkeys():
|
|
self.__patch_index_gens(name)
|
|
return res
|
|
|
|
def add_index(self, *args, **kwargs):
|
|
res = super(SuperThreadSafeDatabase, self).add_index(*args, **kwargs)
|
|
self.__patch_index_gens(res)
|
|
return res
|
|
|
|
def edit_index(self, *args, **kwargs):
|
|
res = super(SuperThreadSafeDatabase, self).edit_index(*args, **kwargs)
|
|
self.__patch_index_gens(res)
|
|
return res
|
|
|