Source code for relstorage.adapters.mysql.mover

##############################################################################
#
# Copyright (c) 2009 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.
#
##############################################################################
"""IObjectMover implementation.
"""
from __future__ import absolute_import
from __future__ import print_function

from zope.interface import implementer

from relstorage.adapters.interfaces import IObjectMover

from ..schema import Schema
from ..mover import AbstractObjectMover
from ..mover import metricmethod_sampled


[docs] @implementer(IObjectMover) class MySQLObjectMover(AbstractObjectMover): _create_temp_store = Schema.temp_store.create()
[docs] @metricmethod_sampled def on_store_opened(self, cursor, restart=False): """Create the temporary table for storing objects""" if restart: # TRUNCATE is a DDL statement, even against a temporary # table, and as such does an implicit transaction commit. # Normally we want to avoid that, but here its OK since # this method is called between transactions, as it were. # TRUNCATE benchmarks (zodbshoot add) substantially faster # (10157) than a DELETE (75xx) and moderately faster than # a DROP/CREATE (9457). TRUNCATE is in the replication # logs like a DROP/CREATE. (DROP TEMPORARY TABLE is *not* # DDL and not transaction ending). # We are up to 4 temp tables, doing this with a call to a stored # proc saves round trips. # # It's possible that the DDL lock that TRUNCATE takes can be a bottleneck # in some places, though? self.driver.callproc_no_result( cursor, "clean_temp_state(false)" ) else: # InnoDB tables benchmark much faster for concurrency=2 # and 6 than MyISAM tables under both MySQL 5.5 and 5.7, # at least on OS X 10.12. The OS X filesystem is single # threaded, though, so the effects of flushing MyISAM tables # to disk on every operation are probably magnified. # note that the md5 column is not used if self.keep_history == False. self._create_temp_store.execute(cursor) stmt = """ CREATE TEMPORARY TABLE temp_read_current ( zoid BIGINT UNSIGNED NOT NULL PRIMARY KEY, tid BIGINT UNSIGNED NOT NULL ) ENGINE InnoDB """ cursor.execute(stmt) stmt = """ CREATE TEMPORARY TABLE temp_blob_chunk ( zoid BIGINT UNSIGNED NOT NULL, chunk_num BIGINT UNSIGNED NOT NULL, PRIMARY KEY (zoid, chunk_num), chunk LONGBLOB ) ENGINE InnoDB """ cursor.execute(stmt) stmt = """ CREATE TEMPORARY TABLE IF NOT EXISTS temp_locked_zoid ( zoid BIGINT UNSIGNED NOT NULL PRIMARY KEY ) ENGINE InnoDB """ cursor.execute(stmt) AbstractObjectMover.on_store_opened(self, cursor, restart=restart)
[docs] @metricmethod_sampled def restore(self, cursor, batcher, oid, tid, data): """Store an object directly, without conflict detection. Used for copying transactions into this database. """ if self.version_detector.requires_values_upsert_alias(cursor): alias = 'AS NEW' def VALUES(col): return 'NEW.' + col else: alias = '' def VALUES(col): return f'VALUES({col})' if self.keep_history: suffix = f""" {alias} ON DUPLICATE KEY UPDATE tid = {VALUES('tid')}, prev_tid = {VALUES('prev_tid')}, md5 = {VALUES('md5')}, state_size = {VALUES('state_size')}, state = {VALUES('state')} """ else: suffix = f""" {alias} ON DUPLICATE KEY UPDATE tid = {VALUES('tid')}, state_size = {VALUES('state_size')}, state = {VALUES('state')} """ self._generic_restore(batcher, oid, tid, data, command='INSERT', suffix=suffix)
# Override this query from the superclass. The MySQL optimizer, up # through at least 5.7.17 doesn't like actual subqueries in a DELETE # statement. See https://github.com/zodb/relstorage/issues/175 _move_from_temp_hf_delete_blob_chunk_query = """ DELETE bc FROM blob_chunk bc INNER JOIN (SELECT zoid FROM temp_store) sq ON bc.zoid = sq.zoid """ # We UPSERT for hf movement; no need to do a delete. _move_from_temp_hf_delete_query = ''