2021-03-11 17:48:47 +00:00
import os
import os . path as p
import pytest
import time
2021-08-03 19:47:59 +00:00
import logging
2021-03-11 17:48:47 +00:00
from helpers . cluster import ClickHouseCluster , run_and_check
cluster = ClickHouseCluster ( __file__ )
2022-03-22 16:39:58 +00:00
instance = cluster . add_instance (
" instance " ,
dictionaries = [ " configs/dictionaries/dict1.xml " ] ,
main_configs = [ " configs/config.d/config.xml " ] ,
stay_alive = True ,
)
2021-07-30 14:20:57 +00:00
def create_dict_simple ( ) :
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
instance . query (
"""
2021-07-30 14:20:57 +00:00
CREATE DICTIONARY lib_dict_c ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
PRIMARY KEY key SOURCE ( library ( PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.so ' ) )
LAYOUT ( CACHE (
SIZE_IN_CELLS 10000000
BLOCK_SIZE 4096
FILE_SIZE 16777216
READ_BUFFER_SIZE 1048576
MAX_STORED_KEYS 1048576 ) )
LIFETIME ( 2 ) ;
2022-03-22 16:39:58 +00:00
"""
)
2021-07-30 14:20:57 +00:00
2021-03-11 17:48:47 +00:00
@pytest.fixture ( scope = " module " )
def ch_cluster ( ) :
try :
cluster . start ( )
2022-03-22 16:39:58 +00:00
instance . query ( " CREATE DATABASE test " )
container_lib_path = (
" /etc/clickhouse-server/config.d/dictionarites_lib/dict_lib.cpp "
)
instance . copy_file_to_container (
os . path . join (
os . path . dirname ( os . path . realpath ( __file__ ) ) , " configs/dict_lib.cpp "
) ,
" /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.cpp " ,
)
2021-03-11 17:48:47 +00:00
instance . query ( " SYSTEM RELOAD CONFIG " )
instance . exec_in_container (
2022-03-22 16:39:58 +00:00
[
" bash " ,
" -c " ,
" /usr/bin/g++ -shared -o /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.so -fPIC /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.cpp " ,
] ,
user = " root " ,
)
2021-03-11 17:48:47 +00:00
2021-08-18 14:14:53 +00:00
instance . exec_in_container (
2022-03-22 16:39:58 +00:00
[
" bash " ,
" -c " ,
" /usr/bin/g++ -shared -o /dict_lib_copy.so -fPIC /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.cpp " ,
] ,
user = " root " ,
)
instance . exec_in_container (
[
" bash " ,
" -c " ,
" ln -s /dict_lib_copy.so /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib_symlink.so " ,
]
)
2021-08-18 14:14:53 +00:00
2021-03-11 17:48:47 +00:00
yield cluster
finally :
cluster . shutdown ( )
@pytest.fixture ( autouse = True )
def setup_teardown ( ) :
yield # run test
def test_load_all ( ch_cluster ) :
2021-04-27 04:02:59 +00:00
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict " )
instance . query (
"""
2021-03-11 17:48:47 +00:00
CREATE DICTIONARY lib_dict ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
PRIMARY KEY key
2021-03-26 07:05:25 +00:00
SOURCE ( library (
PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.so '
SETTINGS ( test_type test_simple ) ) )
2021-03-11 17:48:47 +00:00
LAYOUT ( HASHED ( ) )
LIFETIME ( MIN 0 MAX 10 )
2022-03-22 16:39:58 +00:00
"""
)
2021-03-11 17:48:47 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( " SELECT * FROM lib_dict ORDER BY key " )
2021-03-11 17:48:47 +00:00
expected = (
2022-03-22 16:39:58 +00:00
" 0 \t 10 \t 20 \t 30 \n "
+ " 1 \t 11 \t 21 \t 31 \n "
+ " 2 \t 12 \t 22 \t 32 \n "
+ " 3 \t 13 \t 23 \t 33 \n "
+ " 4 \t 14 \t 24 \t 34 \n "
+ " 5 \t 15 \t 25 \t 35 \n "
+ " 6 \t 16 \t 26 \t 36 \n "
+ " 7 \t 17 \t 27 \t 37 \n "
+ " 8 \t 18 \t 28 \t 38 \n "
+ " 9 \t 19 \t 29 \t 39 \n "
)
instance . query ( " SYSTEM RELOAD DICTIONARY dict1 " )
instance . query ( " DROP DICTIONARY lib_dict " )
assert result == expected
instance . query (
"""
2021-03-26 07:05:25 +00:00
CREATE TABLE IF NOT EXISTS ` dict1_table ` (
key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64
) ENGINE = Dictionary ( dict1 )
2022-03-22 16:39:58 +00:00
"""
)
2021-03-26 07:05:25 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( " SELECT * FROM dict1_table ORDER BY key " )
assert result == expected
2021-03-26 07:05:25 +00:00
2021-03-11 17:48:47 +00:00
def test_load_ids ( ch_cluster ) :
2021-04-27 04:02:59 +00:00
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
instance . query (
"""
2021-03-11 17:48:47 +00:00
CREATE DICTIONARY lib_dict_c ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
2021-03-12 21:22:46 +00:00
PRIMARY KEY key SOURCE ( library ( PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.so ' ) )
2021-03-11 17:48:47 +00:00
LAYOUT ( CACHE (
SIZE_IN_CELLS 10000000
BLOCK_SIZE 4096
FILE_SIZE 16777216
READ_BUFFER_SIZE 1048576
MAX_STORED_KEYS 1048576 ) )
LIFETIME ( 2 ) ;
2022-03-22 16:39:58 +00:00
"""
)
2021-03-11 17:48:47 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(0)); """ )
assert result . strip ( ) == " 100 "
2021-08-01 08:51:40 +00:00
# Just check bridge is ok with a large vector of random ids
2022-03-22 16:39:58 +00:00
instance . query (
""" select number, dictGet(lib_dict_c, ' value1 ' , toUInt64(rand())) from numbers(1000); """
)
2021-08-01 08:51:40 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
instance . query ( " DROP DICTIONARY lib_dict_c " )
2021-03-11 17:48:47 +00:00
def test_load_keys ( ch_cluster ) :
2021-04-27 04:02:59 +00:00
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_ckc " )
instance . query (
"""
2021-03-12 14:07:20 +00:00
CREATE DICTIONARY lib_dict_ckc ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
2021-03-11 17:48:47 +00:00
PRIMARY KEY key
2021-03-12 21:22:46 +00:00
SOURCE ( library ( PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.so ' ) )
2021-03-12 14:07:20 +00:00
LAYOUT ( COMPLEX_KEY_CACHE ( SIZE_IN_CELLS 10000000 ) )
2021-03-11 17:48:47 +00:00
LIFETIME ( 2 ) ;
2022-03-22 16:39:58 +00:00
"""
)
2021-03-11 17:48:47 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query (
""" select dictGet(lib_dict_ckc, ' value1 ' , tuple(toUInt64(0))); """
)
assert result . strip ( ) == " 100 "
result = instance . query (
""" select dictGet(lib_dict_ckc, ' value2 ' , tuple(toUInt64(0))); """
)
assert result . strip ( ) == " 200 "
instance . query ( " DROP DICTIONARY lib_dict_ckc " )
2021-03-11 17:48:47 +00:00
2021-03-12 21:22:46 +00:00
def test_load_all_many_rows ( ch_cluster ) :
2021-04-27 04:02:59 +00:00
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
2021-03-12 21:22:46 +00:00
num_rows = [ 1000 , 10000 , 100000 , 1000000 ]
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict " )
2021-03-12 21:22:46 +00:00
for num in num_rows :
2022-03-22 16:39:58 +00:00
instance . query (
"""
2021-03-12 21:22:46 +00:00
CREATE DICTIONARY lib_dict ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
PRIMARY KEY key
SOURCE ( library (
PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib.so '
2021-03-26 07:05:25 +00:00
SETTINGS ( num_rows { } test_type test_many_rows ) ) )
2021-03-12 21:22:46 +00:00
LAYOUT ( HASHED ( ) )
LIFETIME ( MIN 0 MAX 10 )
2022-03-22 16:39:58 +00:00
""" .format(
num
)
)
2021-03-12 21:22:46 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( " SELECT * FROM lib_dict ORDER BY key " )
expected = instance . query (
" SELECT number, number, number, number FROM numbers( {} ) " . format ( num )
)
instance . query ( " DROP DICTIONARY lib_dict " )
assert result == expected
2021-03-12 21:22:46 +00:00
2021-04-05 13:13:07 +00:00
def test_null_values ( ch_cluster ) :
2021-04-27 04:02:59 +00:00
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
2022-03-22 16:39:58 +00:00
instance . query ( " SYSTEM RELOAD DICTIONARY dict2 " )
instance . query (
"""
2021-04-05 13:13:07 +00:00
CREATE TABLE IF NOT EXISTS ` dict2_table ` (
key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64
) ENGINE = Dictionary ( dict2 )
2022-03-22 16:39:58 +00:00
"""
)
2021-04-05 13:13:07 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( " SELECT * FROM dict2_table ORDER BY key " )
2021-04-05 13:13:07 +00:00
expected = " 0 \t 12 \t 12 \t 12 \n "
2022-03-22 16:39:58 +00:00
assert result == expected
2021-04-05 13:13:07 +00:00
2021-07-30 14:20:57 +00:00
def test_recover_after_bridge_crash ( ch_cluster ) :
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
create_dict_simple ( )
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(0)); """ )
assert result . strip ( ) == " 100 "
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-07-30 14:20:57 +00:00
2022-03-22 16:39:58 +00:00
instance . exec_in_container (
[ " bash " , " -c " , " kill -9 `pidof clickhouse-library-bridge` " ] , user = " root "
)
instance . query ( " SYSTEM RELOAD DICTIONARY lib_dict_c " )
2021-07-30 14:20:57 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(0)); """ )
assert result . strip ( ) == " 100 "
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-07-30 14:20:57 +00:00
2022-03-22 16:39:58 +00:00
instance . exec_in_container (
[ " bash " , " -c " , " kill -9 `pidof clickhouse-library-bridge` " ] , user = " root "
)
instance . query ( " DROP DICTIONARY lib_dict_c " )
2021-07-30 14:20:57 +00:00
def test_server_restart_bridge_might_be_stil_alive ( ch_cluster ) :
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
create_dict_simple ( )
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-07-30 14:20:57 +00:00
instance . restart_clickhouse ( )
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-07-30 14:20:57 +00:00
2022-03-22 16:39:58 +00:00
instance . exec_in_container (
[ " bash " , " -c " , " kill -9 `pidof clickhouse-library-bridge` " ] , user = " root "
)
2021-07-30 14:20:57 +00:00
instance . restart_clickhouse ( )
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-07-30 14:20:57 +00:00
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY lib_dict_c " )
2021-07-30 14:20:57 +00:00
2021-08-01 08:51:40 +00:00
def test_bridge_dies_with_parent ( ch_cluster ) :
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
if instance . is_built_with_address_sanitizer ( ) :
2022-03-22 16:39:58 +00:00
pytest . skip (
" Leak sanitizer falsely reports about a leak of 16 bytes in clickhouse-odbc-bridge "
)
2021-08-01 08:51:40 +00:00
create_dict_simple ( )
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-08-01 08:51:40 +00:00
clickhouse_pid = instance . get_process_pid ( " clickhouse server " )
bridge_pid = instance . get_process_pid ( " library-bridge " )
assert clickhouse_pid is not None
assert bridge_pid is not None
while clickhouse_pid is not None :
try :
2022-03-22 16:39:58 +00:00
instance . exec_in_container (
[ " kill " , str ( clickhouse_pid ) ] , privileged = True , user = " root "
)
2021-08-01 08:51:40 +00:00
except :
pass
clickhouse_pid = instance . get_process_pid ( " clickhouse server " )
time . sleep ( 1 )
for i in range ( 30 ) :
time . sleep ( 1 )
bridge_pid = instance . get_process_pid ( " library-bridge " )
if bridge_pid is None :
break
if bridge_pid :
2022-03-22 16:39:58 +00:00
out = instance . exec_in_container (
[ " gdb " , " -p " , str ( bridge_pid ) , " --ex " , " thread apply all bt " , " --ex " , " q " ] ,
privileged = True ,
user = " root " ,
)
2021-08-01 08:51:40 +00:00
logging . debug ( f " Bridge is running, gdb output: \n { out } " )
assert clickhouse_pid is None
assert bridge_pid is None
instance . start_clickhouse ( 20 )
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY lib_dict_c " )
2021-08-01 08:51:40 +00:00
2021-08-18 14:14:53 +00:00
def test_path_validation ( ch_cluster ) :
if instance . is_built_with_memory_sanitizer ( ) :
pytest . skip ( " Memory Sanitizer cannot work with third-party shared libraries " )
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
instance . query (
"""
2021-08-18 14:14:53 +00:00
CREATE DICTIONARY lib_dict_c ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
PRIMARY KEY key SOURCE ( library ( PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib_symlink.so ' ) )
LAYOUT ( CACHE (
SIZE_IN_CELLS 10000000
BLOCK_SIZE 4096
FILE_SIZE 16777216
READ_BUFFER_SIZE 1048576
MAX_STORED_KEYS 1048576 ) )
LIFETIME ( 2 ) ;
2022-03-22 16:39:58 +00:00
"""
)
2021-08-18 14:14:53 +00:00
2022-03-22 16:39:58 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2021-08-18 14:14:53 +00:00
2022-03-22 16:39:58 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
instance . query (
"""
2021-08-18 14:14:53 +00:00
CREATE DICTIONARY lib_dict_c ( key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64 )
PRIMARY KEY key SOURCE ( library ( PATH ' /etc/clickhouse-server/config.d/dictionaries_lib/../../../../dict_lib_copy.so ' ) )
LAYOUT ( CACHE (
SIZE_IN_CELLS 10000000
BLOCK_SIZE 4096
FILE_SIZE 16777216
READ_BUFFER_SIZE 1048576
MAX_STORED_KEYS 1048576 ) )
LIFETIME ( 2 ) ;
2022-03-22 16:39:58 +00:00
"""
)
result = instance . query_and_get_error (
""" select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """
)
assert (
" DB::Exception: File path /etc/clickhouse-server/config.d/dictionaries_lib/../../../../dict_lib_copy.so is not inside /etc/clickhouse-server/config.d/dictionaries_lib "
in result
)
if __name__ == " __main__ " :
2021-03-11 17:48:47 +00:00
cluster . start ( )
input ( " Cluster created, press any key to destroy... " )
cluster . shutdown ( )