2024-09-27 10:19:39 +00:00
import logging
2021-03-11 17:48:47 +00:00
import os
import os . path as p
import time
2024-09-27 10:19:39 +00:00
import pytest
2021-03-11 17:48:47 +00:00
from helpers . cluster import ClickHouseCluster , run_and_check
cluster = ClickHouseCluster ( __file__ )
2021-03-26 07:05:25 +00:00
instance = cluster . add_instance (
" instance " ,
2021-07-30 14:20:57 +00:00
dictionaries = [ " configs/dictionaries/dict1.xml " ] ,
main_configs = [ " configs/config.d/config.xml " ] ,
stay_alive = True ,
2024-10-31 12:34:53 +00:00
# WA for the problem with zombie processes inside the docker container.
# This is important here because we are checking that there are no zombie processes
# after craches inside the library bridge.
# https://forums.docker.com/t/what-the-latest-with-the-zombie-process-reaping-problem/50758/2
use_docker_init_flag = True ,
2021-07-30 14:20:57 +00:00
)
2023-01-02 13:31:19 +00:00
def create_dict_simple ( ch_instance ) :
ch_instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
ch_instance . query (
2022-03-22 16:39:58 +00:00
"""
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
2024-11-05 15:49:01 +00:00
def check_no_zombie_processes ( instance ) :
res = instance . exec_in_container (
[ " bash " , " -c " , " ps ax -ostat,pid | grep -e ' [zZ] ' | wc -l " ] , user = " root "
)
assert res == " 0 \n "
2021-03-11 17:48:47 +00:00
@pytest.fixture ( scope = " module " )
def ch_cluster ( ) :
try :
cluster . start ( )
instance . query ( " CREATE DATABASE test " )
container_lib_path = (
" /etc/clickhouse-server/config.d/dictionarites_lib/dict_lib.cpp "
2022-03-22 16:39:58 +00:00
)
2021-03-11 17:48:47 +00:00
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 " ,
)
instance . query ( " SYSTEM RELOAD CONFIG " )
instance . exec_in_container (
[
" 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-08-18 14:14:53 +00:00
instance . exec_in_container (
[
" 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 (
2022-03-22 16:39:58 +00:00
[
2021-08-18 14:14:53 +00:00
" bash " ,
" -c " ,
" ln -s /dict_lib_copy.so /etc/clickhouse-server/config.d/dictionaries_lib/dict_lib_symlink.so " ,
2022-03-22 16:39:58 +00:00
]
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 " )
2021-08-18 14:14:53 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict " )
2021-03-11 17:48:47 +00:00
instance . query (
2022-03-22 16:39:58 +00:00
"""
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
)
result = instance . query ( " SELECT * FROM lib_dict ORDER BY key " )
expected = (
" 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 "
)
2021-03-26 07:05:25 +00:00
instance . query ( " SYSTEM RELOAD DICTIONARY dict1 " )
2021-03-12 21:22:46 +00:00
instance . query ( " DROP DICTIONARY lib_dict " )
2021-03-11 17:48:47 +00:00
assert result == expected
2022-03-22 16:39:58 +00:00
2021-03-26 07:05:25 +00:00
instance . query (
"""
CREATE TABLE IF NOT EXISTS ` dict1_table ` (
key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64
) ENGINE = Dictionary ( dict1 )
"""
)
result = instance . query ( " SELECT * FROM dict1_table ORDER BY key " )
assert result == expected
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 " )
2021-08-07 09:35:59 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
2021-03-11 17:48:47 +00:00
instance . query (
2022-03-22 16:39:58 +00:00
"""
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
)
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(0)); """ )
2021-03-11 18:10:12 +00:00
assert result . strip ( ) == " 100 "
2021-08-01 08:51:40 +00:00
# Just check bridge is ok with a large vector of random ids
2021-08-01 09:56:48 +00:00
instance . query (
""" select number, dictGet(lib_dict_c, ' value1 ' , toUInt64(rand())) from numbers(1000); """
)
2021-08-01 08:51:40 +00:00
2021-03-24 07:53:15 +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 " )
2021-08-18 14:14:53 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_ckc " )
2021-03-11 17:48:47 +00:00
instance . query (
2022-03-22 16:39:58 +00:00
"""
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
)
2021-03-24 07:53:15 +00:00
result = instance . query (
""" select dictGet(lib_dict_ckc, ' value1 ' , tuple(toUInt64(0))); """
)
assert result . strip ( ) == " 100 "
2021-03-12 14:07:20 +00:00
result = instance . query (
""" select dictGet(lib_dict_ckc, ' value2 ' , tuple(toUInt64(0))); """
2021-03-11 18:10:12 +00:00
)
assert result . strip ( ) == " 200 "
2021-03-24 07:53:15 +00:00
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 ]
2021-08-18 14:14:53 +00:00
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict " )
2021-03-12 21:22:46 +00:00
for num in num_rows :
instance . query (
2022-03-22 16:39:58 +00:00
"""
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 )
""" .format(
num
)
2022-03-22 16:39:58 +00:00
)
2021-03-12 21:22:46 +00:00
result = instance . query ( " SELECT * FROM lib_dict ORDER BY key " )
expected = instance . query (
" SELECT number, number, number, number FROM numbers( {} ) " . format ( num )
2022-03-22 16:39:58 +00:00
)
2021-03-12 21:22:46 +00:00
instance . query ( " DROP DICTIONARY lib_dict " )
assert result == expected
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 " )
2021-04-05 13:13:07 +00:00
instance . query ( " SYSTEM RELOAD DICTIONARY dict2 " )
instance . query (
"""
CREATE TABLE IF NOT EXISTS ` dict2_table ` (
key UInt64 , value1 UInt64 , value2 UInt64 , value3 UInt64
) ENGINE = Dictionary ( dict2 )
"""
)
result = instance . query ( " SELECT * FROM dict2_table ORDER BY key " )
expected = " 0 \t 12 \t 12 \t 12 \n "
assert result == expected
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 " )
2023-01-02 13:31:19 +00:00
create_dict_simple ( instance )
2021-07-30 14:20:57 +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 "
instance . exec_in_container (
[ " bash " , " -c " , " kill -9 `pidof clickhouse-library-bridge` " ] , user = " root "
)
instance . query ( " SYSTEM RELOAD DICTIONARY lib_dict_c " )
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 "
instance . exec_in_container (
[ " bash " , " -c " , " kill -9 `pidof clickhouse-library-bridge` " ] , user = " root "
)
2024-10-31 12:34:53 +00:00
2024-11-05 15:49:01 +00:00
check_no_zombie_processes ( instance )
2021-07-30 14:20:57 +00:00
instance . query ( " DROP DICTIONARY lib_dict_c " )
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 " )
2023-01-02 13:31:19 +00:00
create_dict_simple ( instance )
2021-07-30 14:20:57 +00:00
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
instance . restart_clickhouse ( )
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
instance . exec_in_container (
[ " bash " , " -c " , " kill -9 `pidof clickhouse-library-bridge` " ] , user = " root "
)
instance . restart_clickhouse ( )
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
2024-11-05 15:49:01 +00:00
check_no_zombie_processes ( instance )
2021-07-30 14:20:57 +00:00
instance . query ( " DROP DICTIONARY lib_dict_c " )
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 " )
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
instance . query (
2022-03-22 16:39:58 +00:00
"""
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
)
result = instance . query ( """ select dictGet(lib_dict_c, ' value1 ' , toUInt64(1)); """ )
assert result . strip ( ) == " 101 "
instance . query ( " DROP DICTIONARY IF EXISTS lib_dict_c " )
instance . query (
2022-03-22 16:39:58 +00:00
"""
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
"""
2021-08-18 14:14:53 +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
2022-03-22 16:39:58 +00:00
)
2021-03-11 17:48:47 +00:00
if __name__ == " __main__ " :
cluster . start ( )
input ( " Cluster created, press any key to destroy... " )
cluster . shutdown ( )