183 lines
6.2 KiB
Python
183 lines
6.2 KiB
Python
##############################################################################
|
|
#
|
|
# Copyright (c) 2008 Zope Foundation and Contributors.
|
|
# All Rights Reserved.
|
|
#
|
|
# This software is subject to the provisions of the Zope Public License,
|
|
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
|
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
|
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
|
# FOR A PARTICULAR PURPOSE.
|
|
#
|
|
##############################################################################
|
|
"""Oracle adapter for RelStorage."""
|
|
from __future__ import absolute_import
|
|
|
|
|
|
from .._abstract_drivers import _select_driver
|
|
from ..dbiter import HistoryFreeDatabaseIterator
|
|
from ..dbiter import HistoryPreservingDatabaseIterator
|
|
from ..interfaces import IRelStorageAdapter
|
|
from ..poller import Poller
|
|
|
|
from . import drivers
|
|
from .batch import OracleRowBatcher
|
|
from .connmanager import CXOracleConnectionManager
|
|
from .locker import OracleLocker
|
|
from .mover import OracleObjectMover
|
|
from .oidallocator import OracleOIDAllocator
|
|
from .packundo import OracleHistoryFreePackUndo
|
|
from .packundo import OracleHistoryPreservingPackUndo
|
|
from .schema import OracleSchemaInstaller
|
|
from .scriptrunner import CXOracleScriptRunner
|
|
from .stats import OracleStats
|
|
from .txncontrol import OracleTransactionControl
|
|
|
|
from relstorage.options import Options
|
|
from zope.interface import implementer
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
def select_driver(options=None):
|
|
return _select_driver(options or Options(), drivers)
|
|
|
|
@implementer(IRelStorageAdapter)
|
|
class OracleAdapter(object):
|
|
"""Oracle adapter for RelStorage."""
|
|
# pylint:disable=too-many-instance-attributes
|
|
def __init__(self, user, password, dsn, commit_lock_id=0,
|
|
twophase=False, options=None):
|
|
"""Create an Oracle adapter.
|
|
|
|
The user, password, and dsn parameters are provided to cx_Oracle
|
|
at connection time.
|
|
|
|
If twophase is true, all commits go through an Oracle-level two-phase
|
|
commit process. This is disabled by default. Even when this option
|
|
is disabled, the ZODB two-phase commit is still in effect.
|
|
"""
|
|
# pylint:disable=unused-argument
|
|
self._user = user
|
|
self._password = password
|
|
self._dsn = dsn
|
|
self._twophase = twophase
|
|
if options is None:
|
|
options = Options()
|
|
self.options = options
|
|
self.keep_history = options.keep_history
|
|
|
|
driver = select_driver(options)
|
|
log.debug("Using driver %s", driver)
|
|
|
|
self.connmanager = CXOracleConnectionManager(
|
|
driver,
|
|
user=user,
|
|
password=password,
|
|
dsn=dsn,
|
|
twophase=twophase,
|
|
options=options,
|
|
)
|
|
self.runner = CXOracleScriptRunner(driver)
|
|
self.locker = OracleLocker(
|
|
options=self.options,
|
|
lock_exceptions=driver.lock_exceptions,
|
|
inputsize_NUMBER=driver.NUMBER,
|
|
)
|
|
self.schema = OracleSchemaInstaller(
|
|
connmanager=self.connmanager,
|
|
runner=self.runner,
|
|
keep_history=self.keep_history,
|
|
)
|
|
inputsizes = {
|
|
'blobdata': driver.BLOB,
|
|
'rawdata': driver.BINARY,
|
|
'oid': driver.NUMBER,
|
|
'tid': driver.NUMBER,
|
|
'prev_tid': driver.NUMBER,
|
|
'chunk_num': driver.NUMBER,
|
|
'md5sum': driver.STRING,
|
|
}
|
|
self.mover = OracleObjectMover(
|
|
database_type='oracle',
|
|
options=options,
|
|
runner=self.runner,
|
|
Binary=driver.Binary,
|
|
batcher_factory=lambda cursor, row_limit: OracleRowBatcher(cursor, inputsizes, row_limit),
|
|
)
|
|
self.mover.inputsizes = inputsizes
|
|
self.connmanager.set_on_store_opened(self.mover.on_store_opened)
|
|
self.oidallocator = OracleOIDAllocator(
|
|
connmanager=self.connmanager,
|
|
)
|
|
self.txncontrol = OracleTransactionControl(
|
|
keep_history=self.keep_history,
|
|
Binary=driver.Binary,
|
|
twophase=twophase,
|
|
)
|
|
|
|
if self.keep_history:
|
|
poll_query = "SELECT MAX(tid) FROM transaction"
|
|
else:
|
|
poll_query = "SELECT MAX(tid) FROM object_state"
|
|
self.poller = Poller(
|
|
poll_query=poll_query,
|
|
keep_history=self.keep_history,
|
|
runner=self.runner,
|
|
revert_when_stale=options.revert_when_stale,
|
|
)
|
|
|
|
# pylint:disable=redefined-variable-type
|
|
if self.keep_history:
|
|
self.packundo = OracleHistoryPreservingPackUndo(
|
|
database_type='oracle',
|
|
connmanager=self.connmanager,
|
|
runner=self.runner,
|
|
locker=self.locker,
|
|
options=options,
|
|
)
|
|
self.dbiter = HistoryPreservingDatabaseIterator(
|
|
database_type='oracle',
|
|
runner=self.runner,
|
|
)
|
|
else:
|
|
self.packundo = OracleHistoryFreePackUndo(
|
|
database_type='oracle',
|
|
connmanager=self.connmanager,
|
|
runner=self.runner,
|
|
locker=self.locker,
|
|
options=options,
|
|
)
|
|
self.dbiter = HistoryFreeDatabaseIterator(
|
|
database_type='oracle',
|
|
runner=self.runner,
|
|
)
|
|
|
|
self.stats = OracleStats(
|
|
connmanager=self.connmanager,
|
|
)
|
|
|
|
def new_instance(self):
|
|
# This adapter and its components are stateless, so it's
|
|
# safe to share it between threads.
|
|
return OracleAdapter(
|
|
user=self._user,
|
|
password=self._password,
|
|
dsn=self._dsn,
|
|
twophase=self._twophase,
|
|
options=self.options,
|
|
)
|
|
|
|
def __str__(self):
|
|
parts = [self.__class__.__name__]
|
|
if self.keep_history:
|
|
parts.append('history preserving')
|
|
else:
|
|
parts.append('history free')
|
|
parts.append('user=%r' % self._user)
|
|
parts.append('dsn=%r' % self._dsn)
|
|
parts.append('twophase=%r' % self._twophase)
|
|
return ", ".join(parts)
|