зеркало из https://github.com/github/vitess-gh.git
252 строки
8.8 KiB
Python
Executable File
252 строки
8.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2014, Google Inc. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can
|
|
# be found in the LICENSE file.
|
|
|
|
# This file contains integration tests for the go/vt/binlog package.
|
|
# It sets up filtered replication between two shards and checks how data flows
|
|
# through binlog streamer.
|
|
|
|
import logging
|
|
import unittest
|
|
|
|
from vtdb import keyrange_constants
|
|
from vtdb import update_stream
|
|
|
|
import environment
|
|
import tablet
|
|
import utils
|
|
from mysql_flavor import mysql_flavor
|
|
|
|
src_master = tablet.Tablet()
|
|
src_replica = tablet.Tablet()
|
|
src_rdonly = tablet.Tablet()
|
|
dst_master = tablet.Tablet()
|
|
dst_replica = tablet.Tablet()
|
|
|
|
|
|
def setUpModule():
|
|
try:
|
|
environment.topo_server().setup()
|
|
|
|
setup_procs = [
|
|
src_master.init_mysql(),
|
|
src_replica.init_mysql(),
|
|
src_rdonly.init_mysql(),
|
|
dst_master.init_mysql(),
|
|
dst_replica.init_mysql(),
|
|
]
|
|
utils.Vtctld().start()
|
|
utils.wait_procs(setup_procs)
|
|
|
|
# Set up binlog stream from shard 0 to shard 1.
|
|
# Modeled after initial_sharding.py.
|
|
utils.run_vtctl(['CreateKeyspace', 'test_keyspace'])
|
|
utils.run_vtctl(['SetKeyspaceShardingInfo', '-force', 'test_keyspace',
|
|
'keyspace_id', keyrange_constants.KIT_UINT64])
|
|
|
|
src_master.init_tablet('master', 'test_keyspace', '0')
|
|
src_replica.init_tablet('replica', 'test_keyspace', '0')
|
|
src_rdonly.init_tablet('rdonly', 'test_keyspace', '0')
|
|
|
|
utils.run_vtctl(['RebuildShardGraph', 'test_keyspace/0'])
|
|
utils.validate_topology()
|
|
|
|
for t in [src_master, src_replica, src_rdonly]:
|
|
t.create_db('vt_test_keyspace')
|
|
t.start_vttablet(wait_for_state=None)
|
|
|
|
for t in [src_master, src_replica, src_rdonly]:
|
|
t.wait_for_vttablet_state('SERVING')
|
|
|
|
utils.run_vtctl(['InitShardMaster', 'test_keyspace/0',
|
|
src_master.tablet_alias], auto_log=True)
|
|
|
|
# Create schema
|
|
logging.debug('Creating schema...')
|
|
create_table = '''create table test_table(
|
|
id bigint auto_increment,
|
|
keyspace_id bigint(20) unsigned,
|
|
msg varchar(64),
|
|
primary key (id),
|
|
index by_msg (msg)
|
|
) Engine=InnoDB'''
|
|
|
|
utils.run_vtctl(['ApplySchema',
|
|
'-sql=' + create_table,
|
|
'test_keyspace'], auto_log=True)
|
|
|
|
# run a health check on source replica so it responds to discovery
|
|
# (for binlog players) and on the source rdonlys (for workers)
|
|
utils.run_vtctl(['RunHealthCheck', src_replica.tablet_alias, 'replica'])
|
|
utils.run_vtctl(['RunHealthCheck', src_rdonly.tablet_alias, 'rdonly'])
|
|
|
|
# Create destination shard.
|
|
dst_master.init_tablet('master', 'test_keyspace', '-')
|
|
dst_replica.init_tablet('replica', 'test_keyspace', '-')
|
|
# Start masters with enabled healthcheck (necessary for resolving the
|
|
# destination master).
|
|
dst_master.start_vttablet(wait_for_state='NOT_SERVING',
|
|
target_tablet_type='replica')
|
|
dst_replica.start_vttablet(wait_for_state='NOT_SERVING')
|
|
|
|
utils.run_vtctl(['InitShardMaster', 'test_keyspace/-',
|
|
dst_master.tablet_alias], auto_log=True)
|
|
|
|
# copy the schema
|
|
utils.run_vtctl(['CopySchemaShard', src_replica.tablet_alias,
|
|
'test_keyspace/-'], auto_log=True)
|
|
|
|
# run the clone worked (this is a degenerate case, source and destination
|
|
# both have the full keyrange. Happens to work correctly).
|
|
logging.debug('Running the clone worker to start binlog stream...')
|
|
utils.run_vtworker(['--cell', 'test_nj',
|
|
'SplitClone',
|
|
'--source_reader_count', '10',
|
|
'--min_table_size_for_split', '1',
|
|
'--min_healthy_rdonly_endpoints', '1',
|
|
'test_keyspace/0'],
|
|
auto_log=True)
|
|
dst_master.wait_for_binlog_player_count(1)
|
|
|
|
# Wait for dst_replica to be ready.
|
|
dst_replica.wait_for_binlog_server_state('Enabled')
|
|
except:
|
|
tearDownModule()
|
|
raise
|
|
|
|
|
|
def tearDownModule():
|
|
utils.required_teardown()
|
|
if utils.options.skip_teardown:
|
|
return
|
|
|
|
tablet.kill_tablets([src_master, src_replica, src_rdonly,
|
|
dst_master, dst_replica])
|
|
|
|
teardown_procs = [
|
|
src_master.teardown_mysql(),
|
|
src_replica.teardown_mysql(),
|
|
src_rdonly.teardown_mysql(),
|
|
dst_master.teardown_mysql(),
|
|
dst_replica.teardown_mysql(),
|
|
]
|
|
utils.wait_procs(teardown_procs, raise_on_error=False)
|
|
|
|
environment.topo_server().teardown()
|
|
utils.kill_sub_processes()
|
|
utils.remove_tmp_files()
|
|
|
|
src_master.remove_tree()
|
|
src_replica.remove_tree()
|
|
src_rdonly.remove_tree()
|
|
dst_master.remove_tree()
|
|
dst_replica.remove_tree()
|
|
|
|
|
|
def _get_update_stream(tblt):
|
|
protocol, endpoint = tblt.update_stream_python_endpoint()
|
|
return update_stream.connect(protocol, endpoint, 30)
|
|
|
|
|
|
class TestBinlog(unittest.TestCase):
|
|
|
|
def test_charset(self):
|
|
start_position = mysql_flavor().master_position(dst_replica)
|
|
logging.debug('test_charset: starting @ %s', start_position)
|
|
|
|
# Insert something that will replicate incorrectly if the charset is not
|
|
# propagated through binlog streamer to the destination.
|
|
#
|
|
# Vitess tablets default to using utf8, so we insert something crazy and
|
|
# pretend it's latin1. If the binlog player doesn't also pretend it's
|
|
# latin1, it will be inserted as utf8, which will change its value.
|
|
src_master.mquery(
|
|
'vt_test_keyspace',
|
|
"INSERT INTO test_table (id, keyspace_id, msg) "
|
|
"VALUES (41523, 1, 'Šṛ́rỏé') /* vtgate:: keyspace_id:00000001 */",
|
|
conn_params={'charset': 'latin1'}, write=True)
|
|
|
|
# Wait for it to replicate.
|
|
stream = _get_update_stream(dst_replica)
|
|
for stream_event in stream.stream_update(start_position):
|
|
if stream_event.category == update_stream.StreamEvent.POS:
|
|
break
|
|
stream.close()
|
|
|
|
# Check the value.
|
|
data = dst_master.mquery(
|
|
'vt_test_keyspace',
|
|
'SELECT id, keyspace_id, msg FROM test_table WHERE id=41523 LIMIT 1')
|
|
self.assertEqual(len(data), 1, 'No data replicated.')
|
|
self.assertEqual(len(data[0]), 3, 'Wrong number of columns.')
|
|
self.assertEqual(data[0][2], 'Šṛ́rỏé',
|
|
'Data corrupted due to wrong charset.')
|
|
|
|
def test_checksum_enabled(self):
|
|
start_position = mysql_flavor().master_position(dst_replica)
|
|
logging.debug('test_checksum_enabled: starting @ %s', start_position)
|
|
|
|
# Enable binlog_checksum, which will also force a log rotation that should
|
|
# cause binlog streamer to notice the new checksum setting.
|
|
if not mysql_flavor().enable_binlog_checksum(dst_replica):
|
|
logging.debug(
|
|
'skipping checksum test on flavor without binlog_checksum setting')
|
|
return
|
|
|
|
# Insert something and make sure it comes through intact.
|
|
sql = (
|
|
"INSERT INTO test_table (id, keyspace_id, msg) "
|
|
"VALUES (19283, 1, 'testing checksum enabled') "
|
|
"/* vtgate:: keyspace_id:00000001 */")
|
|
src_master.mquery('vt_test_keyspace', sql, write=True)
|
|
|
|
# Look for it using update stream to see if binlog streamer can talk to
|
|
# dst_replica, which now has binlog_checksum enabled.
|
|
stream = _get_update_stream(dst_replica)
|
|
found = False
|
|
for stream_event in stream.stream_update(start_position):
|
|
if stream_event.category == update_stream.StreamEvent.POS:
|
|
break
|
|
if stream_event.sql == sql:
|
|
found = True
|
|
break
|
|
stream.close()
|
|
self.assertEqual(found, True, 'expected query not found in update stream')
|
|
|
|
def test_checksum_disabled(self):
|
|
# Disable binlog_checksum to make sure we can also talk to a server without
|
|
# checksums enabled, in case they are enabled by default.
|
|
start_position = mysql_flavor().master_position(dst_replica)
|
|
logging.debug('test_checksum_disabled: starting @ %s', start_position)
|
|
|
|
# For flavors that don't support checksums, this is a no-op.
|
|
mysql_flavor().disable_binlog_checksum(dst_replica)
|
|
|
|
# Insert something and make sure it comes through intact.
|
|
sql = (
|
|
"INSERT INTO test_table (id, keyspace_id, msg) "
|
|
"VALUES (58812, 1, 'testing checksum disabled') "
|
|
"/* vtgate:: keyspace_id:00000001 */")
|
|
src_master.mquery(
|
|
'vt_test_keyspace', sql, write=True)
|
|
|
|
# Look for it using update stream to see if binlog streamer can talk to
|
|
# dst_replica, which now has binlog_checksum disabled.
|
|
stream = _get_update_stream(dst_replica)
|
|
found = False
|
|
for stream_event in stream.stream_update(start_position):
|
|
if stream_event.category == update_stream.StreamEvent.POS:
|
|
break
|
|
if stream_event.sql == sql:
|
|
found = True
|
|
break
|
|
stream.close()
|
|
self.assertEqual(found, True, 'expected query not found in update stream')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
utils.main()
|