mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge branch 'master' of github.com:ClickHouse/ClickHouse
This commit is contained in:
commit
3cc3bd2fea
@ -221,7 +221,8 @@ void MySQLHandler::authenticate(const String & user_name, const String & auth_pl
|
||||
{
|
||||
// For compatibility with JavaScript MySQL client, Native41 authentication plugin is used when possible (if password is specified using double SHA1). Otherwise SHA256 plugin is used.
|
||||
auto user = connection_context.getUser(user_name);
|
||||
if (user->authentication.getType() != DB::Authentication::DOUBLE_SHA1_PASSWORD)
|
||||
const DB::Authentication::Type user_auth_type = user->authentication.getType();
|
||||
if (user_auth_type != DB::Authentication::DOUBLE_SHA1_PASSWORD && user_auth_type != DB::Authentication::PLAINTEXT_PASSWORD && user_auth_type != DB::Authentication::NO_PASSWORD)
|
||||
{
|
||||
authPluginSSL();
|
||||
}
|
||||
|
@ -160,6 +160,35 @@ void Authentication::setPasswordHashBinary(const Digest & hash)
|
||||
}
|
||||
|
||||
|
||||
Digest Authentication::getPasswordDoubleSHA1() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NO_PASSWORD:
|
||||
{
|
||||
Poco::SHA1Engine engine;
|
||||
return engine.digest();
|
||||
}
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
{
|
||||
Poco::SHA1Engine engine;
|
||||
engine.update(getPassword());
|
||||
const Digest & first_sha1 = engine.digest();
|
||||
engine.update(first_sha1.data(), first_sha1.size());
|
||||
return engine.digest();
|
||||
}
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
throw Exception("Cannot get password double SHA1 for user with 'SHA256_PASSWORD' authentication.", ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
case DOUBLE_SHA1_PASSWORD:
|
||||
return password_hash;
|
||||
}
|
||||
throw Exception("Unknown authentication type: " + std::to_string(static_cast<int>(type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
bool Authentication::isCorrectPassword(const String & password_) const
|
||||
{
|
||||
switch (type)
|
||||
@ -168,7 +197,14 @@ bool Authentication::isCorrectPassword(const String & password_) const
|
||||
return true;
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
return password_ == StringRef{reinterpret_cast<const char *>(password_hash.data()), password_hash.size()};
|
||||
{
|
||||
if (password_ == StringRef{reinterpret_cast<const char *>(password_hash.data()), password_hash.size()})
|
||||
return true;
|
||||
|
||||
// For compatibility with MySQL clients which support only native authentication plugin, SHA1 can be passed instead of password.
|
||||
auto password_sha1 = encodeSHA1(password_hash);
|
||||
return password_ == StringRef{reinterpret_cast<const char *>(password_sha1.data()), password_sha1.size()};
|
||||
}
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
return encodeSHA256(password_) == password_hash;
|
||||
|
@ -49,6 +49,10 @@ public:
|
||||
void setPasswordHashBinary(const Digest & hash);
|
||||
const Digest & getPasswordHashBinary() const { return password_hash; }
|
||||
|
||||
/// Returns SHA1(SHA1(password)) used by MySQL compatibility server for authentication.
|
||||
/// Allowed to use for Type::NO_PASSWORD, Type::PLAINTEXT_PASSWORD, Type::DOUBLE_SHA1_PASSWORD.
|
||||
Digest getPasswordDoubleSHA1() const;
|
||||
|
||||
/// Checks if the provided password is correct. Returns false if not.
|
||||
bool isCorrectPassword(const String & password) const;
|
||||
|
||||
|
@ -953,10 +953,7 @@ public:
|
||||
|
||||
auto user = context.getUser(user_name);
|
||||
|
||||
if (user->authentication.getType() != DB::Authentication::DOUBLE_SHA1_PASSWORD)
|
||||
throw Exception("Cannot use " + getName() + " auth plugin for user " + user_name + " since its password isn't specified using double SHA1.", ErrorCodes::UNKNOWN_EXCEPTION);
|
||||
|
||||
Poco::SHA1Engine::Digest double_sha1_value = user->authentication.getPasswordHashBinary();
|
||||
Poco::SHA1Engine::Digest double_sha1_value = user->authentication.getPasswordDoubleSHA1();
|
||||
assert(double_sha1_value.size() == Poco::SHA1Engine::DIGEST_SIZE);
|
||||
|
||||
Poco::SHA1Engine engine;
|
||||
|
@ -8,18 +8,18 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <ext/range.h>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Calculates the distance between two geographical locations.
|
||||
* There are two variants:
|
||||
* greatCircleDistance: calculates the distance on a sphere: https://en.wikipedia.org/wiki/Great-circle_distance
|
||||
* geoDistance: calculates the distance on WGS-84 ellipsoid.
|
||||
* There are three variants:
|
||||
* greatCircleAngle: calculates the distance on a sphere in degrees: https://en.wikipedia.org/wiki/Great-circle_distance
|
||||
* greatCircleDistance: calculates the distance on a sphere in meters.
|
||||
* geoDistance: calculates the distance on WGS-84 ellipsoid in meters.
|
||||
*
|
||||
* The function calculates distance in meters between two points on Earth specified by longitude and latitude in degrees.
|
||||
* The function calculates distance between two points on Earth specified by longitude and latitude in degrees.
|
||||
*
|
||||
* Latitude must be in [-90, 90], longitude must be [-180, 180].
|
||||
*
|
||||
@ -42,36 +42,19 @@ constexpr size_t COS_LUT_SIZE = 1024; // maxerr 0.00063%
|
||||
constexpr size_t ASIN_SQRT_LUT_SIZE = 512;
|
||||
constexpr size_t METRIC_LUT_SIZE = 1024;
|
||||
|
||||
/** We use "WGS-84 ellipsoidal quadratic mean radius of Earth" as the approximation to calculate distances on sphere.
|
||||
* The motivation for it is explained here: https://math.wikia.org/wiki/Ellipsoidal_quadratic_mean_radius
|
||||
*
|
||||
* Brief explanation:
|
||||
* - the radius of sphere is choosen to minimize the difference between distance on that sphere and distance on WGS-84 ellipsoid between two points,
|
||||
* averaged uniformly (?) by all angles (?) between points.
|
||||
* This sounds not clear enough for me: what set we are averaging and by what measure?
|
||||
*
|
||||
* The value should be calculated this way:
|
||||
* WITH 6378137.0 AS a, 6356752.314245 AS b SELECT sqrt(3 * a * a + b * b) / 2
|
||||
*
|
||||
* But for unknown reason, slightly different value is used.
|
||||
* This constant may be changed in future with a note about backward incompatible change in the changelog.
|
||||
*
|
||||
* See also:
|
||||
* https://github.com/Project-OSRM/osrm-backend/blob/bb1f4a025a3cefd3598a38b9d3e55485d1080ec5/third_party/libosmium/include/osmium/geom/haversine.hpp#L58-L59
|
||||
* https://github.com/Project-OSRM/osrm-backend/issues/5051
|
||||
* https://github.com/mapbox/turf-swift/issues/26
|
||||
* https://github.com/Project-OSRM/osrm-backend/pull/5041
|
||||
* https://en.wikipedia.org/wiki/Talk:Great-circle_distance/Archive_1
|
||||
/** Earth radius in meters using WGS84 authalic radius.
|
||||
* We use this value to be consistent with H3 library.
|
||||
*/
|
||||
constexpr float EARTH_RADIUS = 6372797.560856;
|
||||
constexpr float EARTH_RADIUS = 6371007.180918475;
|
||||
constexpr float EARTH_DIAMETER = 2 * EARTH_RADIUS;
|
||||
|
||||
|
||||
float cos_lut[COS_LUT_SIZE + 1]; /// cos(x) table
|
||||
float asin_sqrt_lut[ASIN_SQRT_LUT_SIZE + 1]; /// asin(sqrt(x)) * earth_diameter table
|
||||
|
||||
float sphere_metric_lut[METRIC_LUT_SIZE + 1]; /// sphere metric: the distance for one degree across longitude depending on latitude
|
||||
float wgs84_metric_lut[2 * (METRIC_LUT_SIZE + 1)]; /// ellipsoid metric: the distance across one degree latitude/longitude depending on latitude
|
||||
float sphere_metric_lut[METRIC_LUT_SIZE + 1]; /// sphere metric, unitless: the distance in degrees for one degree across longitude depending on latitude
|
||||
float sphere_metric_meters_lut[METRIC_LUT_SIZE + 1]; /// sphere metric: the distance in meters for one degree across longitude depending on latitude
|
||||
float wgs84_metric_meters_lut[2 * (METRIC_LUT_SIZE + 1)]; /// ellipsoid metric: the distance in meters across one degree latitude/longitude depending on latitude
|
||||
|
||||
|
||||
inline double sqr(double v)
|
||||
@ -90,7 +73,7 @@ void geodistInit()
|
||||
cos_lut[i] = static_cast<float>(cos(2 * PI * i / COS_LUT_SIZE)); // [0, 2 * pi] -> [0, COS_LUT_SIZE]
|
||||
|
||||
for (size_t i = 0; i <= ASIN_SQRT_LUT_SIZE; ++i)
|
||||
asin_sqrt_lut[i] = static_cast<float>(EARTH_DIAMETER * asin(
|
||||
asin_sqrt_lut[i] = static_cast<float>(asin(
|
||||
sqrt(static_cast<double>(i) / ASIN_SQRT_LUT_SIZE))); // [0, 1] -> [0, ASIN_SQRT_LUT_SIZE]
|
||||
|
||||
for (size_t i = 0; i <= METRIC_LUT_SIZE; ++i)
|
||||
@ -100,10 +83,13 @@ void geodistInit()
|
||||
/// Squared metric coefficients (for the distance in meters) on a tangent plane, for latitude and longitude (in degrees),
|
||||
/// depending on the latitude (in radians).
|
||||
|
||||
wgs84_metric_lut[i * 2] = static_cast<float>(sqr(111132.09 - 566.05 * cos(2 * latitude) + 1.20 * cos(4 * latitude)));
|
||||
wgs84_metric_lut[i * 2 + 1] = static_cast<float>(sqr(111415.13 * cos(latitude) - 94.55 * cos(3 * latitude) + 0.12 * cos(5 * latitude)));
|
||||
/// https://github.com/mapbox/cheap-ruler/blob/master/index.js#L67
|
||||
wgs84_metric_meters_lut[i * 2] = static_cast<float>(sqr(111132.09 - 566.05 * cos(2 * latitude) + 1.20 * cos(4 * latitude)));
|
||||
wgs84_metric_meters_lut[i * 2 + 1] = static_cast<float>(sqr(111415.13 * cos(latitude) - 94.55 * cos(3 * latitude) + 0.12 * cos(5 * latitude)));
|
||||
|
||||
sphere_metric_lut[i] = static_cast<float>(sqr((EARTH_DIAMETER * PI / 360) * cos(latitude)));
|
||||
sphere_metric_meters_lut[i] = static_cast<float>(sqr((EARTH_DIAMETER * PI / 360) * cos(latitude)));
|
||||
|
||||
sphere_metric_lut[i] = cosf(latitude);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +129,7 @@ inline float geodistFastAsinSqrt(float x)
|
||||
{
|
||||
// distance under 4546 km, Taylor error under 0.00072%
|
||||
float y = sqrtf(x);
|
||||
return EARTH_DIAMETER * (y + x * y * 0.166666666666666f + x * x * y * 0.075f + x * x * x * y * 0.044642857142857f);
|
||||
return y + x * y * 0.166666666666666f + x * x * y * 0.075f + x * x * x * y * 0.044642857142857f;
|
||||
}
|
||||
if (x < 0.948f)
|
||||
{
|
||||
@ -158,8 +144,9 @@ inline float geodistFastAsinSqrt(float x)
|
||||
|
||||
enum class Method
|
||||
{
|
||||
SPHERE,
|
||||
WGS84
|
||||
SPHERE_DEGREES,
|
||||
SPHERE_METERS,
|
||||
WGS84_METERS,
|
||||
};
|
||||
|
||||
|
||||
@ -187,20 +174,27 @@ float distance(float lon1deg, float lat1deg, float lon2deg, float lat2deg)
|
||||
float k_lat;
|
||||
float k_lon;
|
||||
|
||||
if constexpr (method == Method::SPHERE)
|
||||
if constexpr (method == Method::SPHERE_DEGREES)
|
||||
{
|
||||
k_lat = sqr(EARTH_DIAMETER * PI / 360);
|
||||
k_lat = 1;
|
||||
|
||||
k_lon = sphere_metric_lut[latitude_midpoint_index]
|
||||
+ (sphere_metric_lut[latitude_midpoint_index + 1] - sphere_metric_lut[latitude_midpoint_index]) * (latitude_midpoint - latitude_midpoint_index);
|
||||
}
|
||||
else if constexpr (method == Method::WGS84)
|
||||
else if constexpr (method == Method::SPHERE_METERS)
|
||||
{
|
||||
k_lat = wgs84_metric_lut[latitude_midpoint_index * 2]
|
||||
+ (wgs84_metric_lut[(latitude_midpoint_index + 1) * 2] - wgs84_metric_lut[latitude_midpoint_index * 2]) * (latitude_midpoint - latitude_midpoint_index);
|
||||
k_lat = sqr(EARTH_DIAMETER * PI / 360);
|
||||
|
||||
k_lon = wgs84_metric_lut[latitude_midpoint_index * 2 + 1]
|
||||
+ (wgs84_metric_lut[(latitude_midpoint_index + 1) * 2 + 1] - wgs84_metric_lut[latitude_midpoint_index * 2 + 1]) * (latitude_midpoint - latitude_midpoint_index);
|
||||
k_lon = sphere_metric_meters_lut[latitude_midpoint_index]
|
||||
+ (sphere_metric_meters_lut[latitude_midpoint_index + 1] - sphere_metric_meters_lut[latitude_midpoint_index]) * (latitude_midpoint - latitude_midpoint_index);
|
||||
}
|
||||
else if constexpr (method == Method::WGS84_METERS)
|
||||
{
|
||||
k_lat = wgs84_metric_meters_lut[latitude_midpoint_index * 2]
|
||||
+ (wgs84_metric_meters_lut[(latitude_midpoint_index + 1) * 2] - wgs84_metric_meters_lut[latitude_midpoint_index * 2]) * (latitude_midpoint - latitude_midpoint_index);
|
||||
|
||||
k_lon = wgs84_metric_meters_lut[latitude_midpoint_index * 2 + 1]
|
||||
+ (wgs84_metric_meters_lut[(latitude_midpoint_index + 1) * 2 + 1] - wgs84_metric_meters_lut[latitude_midpoint_index * 2 + 1]) * (latitude_midpoint - latitude_midpoint_index);
|
||||
}
|
||||
|
||||
/// Metric on a tangent plane: it differs from Euclidean metric only by scale of coordinates.
|
||||
@ -213,7 +207,10 @@ float distance(float lon1deg, float lat1deg, float lon2deg, float lat2deg)
|
||||
float a = sqrf(geodistFastSin(lat_diff * RAD_IN_DEG_HALF))
|
||||
+ geodistFastCos(lat1deg * RAD_IN_DEG) * geodistFastCos(lat2deg * RAD_IN_DEG) * sqrf(geodistFastSin(lon_diff * RAD_IN_DEG_HALF));
|
||||
|
||||
return geodistFastAsinSqrt(a);
|
||||
if constexpr (method == Method::SPHERE_DEGREES)
|
||||
return (360.0f / PI) * geodistFastAsinSqrt(a);
|
||||
else
|
||||
return EARTH_DIAMETER * geodistFastAsinSqrt(a);
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +221,11 @@ template <Method method>
|
||||
class FunctionGeoDistance : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = (method == Method::SPHERE) ? "greatCircleDistance" : "geoDistance";
|
||||
static constexpr auto name =
|
||||
(method == Method::SPHERE_DEGREES) ? "greatCircleAngle"
|
||||
: ((method == Method::SPHERE_METERS) ? "greatCircleDistance"
|
||||
: "geoDistance");
|
||||
|
||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionGeoDistance<method>>(); }
|
||||
|
||||
private:
|
||||
@ -271,8 +272,9 @@ private:
|
||||
void registerFunctionGeoDistance(FunctionFactory & factory)
|
||||
{
|
||||
geodistInit();
|
||||
factory.registerFunction<FunctionGeoDistance<Method::SPHERE>>();
|
||||
factory.registerFunction<FunctionGeoDistance<Method::WGS84>>();
|
||||
factory.registerFunction<FunctionGeoDistance<Method::SPHERE_DEGREES>>();
|
||||
factory.registerFunction<FunctionGeoDistance<Method::SPHERE_METERS>>();
|
||||
factory.registerFunction<FunctionGeoDistance<Method::WGS84_METERS>>();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,6 +96,12 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
const char * DELETE_ON_DESTROY_MARKER_PATH = "delete-on-destroy.txt";
|
||||
}
|
||||
|
||||
|
||||
MergeTreeData::MergeTreeData(
|
||||
const String & database_,
|
||||
const String & table_,
|
||||
@ -801,6 +807,17 @@ void MergeTreeData::loadDataParts(bool skip_sanity_checks)
|
||||
part->relative_path = part_name;
|
||||
bool broken = false;
|
||||
|
||||
Poco::Path part_path(getFullPathOnDisk(part_disk_ptr), part_name);
|
||||
Poco::Path marker_path(part_path, DELETE_ON_DESTROY_MARKER_PATH);
|
||||
if (Poco::File(marker_path).exists())
|
||||
{
|
||||
LOG_WARNING(log, "Detaching stale part " << getFullPathOnDisk(part_disk_ptr) << part_name << ", which should have been deleted after a move. That can only happen after unclean restart of ClickHouse after move of a part having an operation blocking that stale copy of part.");
|
||||
std::lock_guard loading_lock(mutex);
|
||||
broken_parts_to_detach.push_back(part);
|
||||
++suspicious_broken_parts;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
part->loadColumnsChecksumsIndexes(require_part_metadata, true);
|
||||
@ -2515,7 +2532,7 @@ MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(
|
||||
void MergeTreeData::swapActivePart(MergeTreeData::DataPartPtr part_copy)
|
||||
{
|
||||
auto lock = lockParts();
|
||||
for (const auto & original_active_part : getDataPartsStateRange(DataPartState::Committed))
|
||||
for (auto original_active_part : getDataPartsStateRange(DataPartState::Committed))
|
||||
{
|
||||
if (part_copy->name == original_active_part->name)
|
||||
{
|
||||
@ -2528,6 +2545,16 @@ void MergeTreeData::swapActivePart(MergeTreeData::DataPartPtr part_copy)
|
||||
|
||||
auto part_it = data_parts_indexes.insert(part_copy).first;
|
||||
modifyPartState(part_it, DataPartState::Committed);
|
||||
|
||||
Poco::Path marker_path(Poco::Path(original_active_part->getFullPath()), DELETE_ON_DESTROY_MARKER_PATH);
|
||||
try
|
||||
{
|
||||
Poco::File(marker_path).createFile();
|
||||
}
|
||||
catch (Poco::Exception & e)
|
||||
{
|
||||
LOG_ERROR(log, e.what() << " (while creating DeleteOnDestroy marker: " + backQuote(marker_path.toString()) + ")");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -346,6 +346,11 @@ MergeTreeDataPart::~MergeTreeDataPart()
|
||||
}
|
||||
|
||||
dir.remove(true);
|
||||
|
||||
if (state == State::DeleteOnDestroy)
|
||||
{
|
||||
LOG_TRACE(storage.log, "Removed part from old location " << path);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -628,11 +628,11 @@ class ClickHouseInstance:
|
||||
def http_query(self, sql, data=None):
|
||||
return urllib.urlopen("http://" + self.ip_address + ":8123/?query=" + urllib.quote(sql, safe=''), data).read()
|
||||
|
||||
def restart_clickhouse(self, stop_start_wait_sec=5):
|
||||
def restart_clickhouse(self, stop_start_wait_sec=5, kill=False):
|
||||
if not self.stay_alive:
|
||||
raise Exception("clickhouse can be restarted only with stay_alive=True instance")
|
||||
|
||||
self.exec_in_container(["bash", "-c", "pkill clickhouse"], user='root')
|
||||
self.exec_in_container(["bash", "-c", "pkill {} clickhouse".format("-9" if kill else "")], user='root')
|
||||
time.sleep(stop_start_wait_sec)
|
||||
self.exec_in_container(["bash", "-c", "{} --daemon".format(CLICKHOUSE_START_COMMAND)], user=str(os.getuid()))
|
||||
|
||||
|
@ -3,6 +3,7 @@ import pytest
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import threading
|
||||
import time
|
||||
from multiprocessing.dummy import Pool
|
||||
from helpers.client import QueryRuntimeException
|
||||
@ -15,6 +16,7 @@ node1 = cluster.add_instance('node1',
|
||||
config_dir='configs',
|
||||
main_configs=['configs/logs_config.xml'],
|
||||
with_zookeeper=True,
|
||||
stay_alive=True,
|
||||
tmpfs=['/jbod1:size=40M', '/jbod2:size=40M', '/external:size=200M'],
|
||||
macros={"shard": 0, "replica": 1} )
|
||||
|
||||
@ -22,6 +24,7 @@ node2 = cluster.add_instance('node2',
|
||||
config_dir='configs',
|
||||
main_configs=['configs/logs_config.xml'],
|
||||
with_zookeeper=True,
|
||||
stay_alive=True,
|
||||
tmpfs=['/jbod1:size=40M', '/jbod2:size=40M', '/external:size=200M'],
|
||||
macros={"shard": 0, "replica": 2} )
|
||||
|
||||
@ -1028,6 +1031,7 @@ def test_rename(start_cluster):
|
||||
node1.query("DROP TABLE IF EXISTS default.renaming_table1")
|
||||
node1.query("DROP TABLE IF EXISTS test.renaming_table2")
|
||||
|
||||
|
||||
def test_freeze(start_cluster):
|
||||
try:
|
||||
node1.query("""
|
||||
@ -1057,6 +1061,50 @@ def test_freeze(start_cluster):
|
||||
node1.exec_in_container(["bash", "-c", "find /jbod1/shadow -name '*.mrk2' | grep '.*'"])
|
||||
node1.exec_in_container(["bash", "-c", "find /external/shadow -name '*.mrk2' | grep '.*'"])
|
||||
|
||||
|
||||
finally:
|
||||
node1.query("DROP TABLE IF EXISTS default.freezing_table")
|
||||
|
||||
|
||||
def test_kill_while_insert(start_cluster):
|
||||
try:
|
||||
name = "test_kill_while_insert"
|
||||
|
||||
node1.query("DROP TABLE IF EXISTS {name}".format(name=name))
|
||||
|
||||
node1.query("""
|
||||
CREATE TABLE {name} (
|
||||
s String
|
||||
) ENGINE = MergeTree
|
||||
ORDER BY tuple()
|
||||
SETTINGS storage_policy='small_jbod_with_external'
|
||||
""".format(name=name))
|
||||
|
||||
data = []
|
||||
dates = []
|
||||
for i in range(10):
|
||||
data.append(get_random_string(1024 * 1024)) # 1MB value
|
||||
node1.query("INSERT INTO {name} VALUES {}".format(','.join(["('" + s + "')" for s in data]), name=name))
|
||||
|
||||
disks = get_used_disks_for_table(node1, name)
|
||||
assert set(disks) == {"jbod1"}
|
||||
|
||||
start_time = time.time()
|
||||
long_select = threading.Thread(target=node1.query, args=("SELECT sleep(3) FROM {name}".format(name=name),))
|
||||
long_select.start()
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
node1.query("ALTER TABLE {name} MOVE PARTITION tuple() TO DISK 'external'".format(name=name))
|
||||
assert time.time() - start_time < 2
|
||||
node1.restart_clickhouse(kill=True)
|
||||
|
||||
try:
|
||||
long_select.join()
|
||||
except:
|
||||
""""""
|
||||
|
||||
time.sleep(0.5)
|
||||
assert node1.query("SELECT count() FROM {name}".format(name=name)).splitlines() == ["10"]
|
||||
|
||||
finally:
|
||||
"""Don't drop table afterwards to not shadow assertion."""
|
||||
|
@ -6,3 +6,8 @@ services:
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: 1
|
||||
command: --federated --socket /var/run/mysqld/mysqld.sock
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||
interval: 1s
|
||||
timeout: 2s
|
||||
retries: 100
|
||||
|
@ -15,6 +15,16 @@
|
||||
<quota>default</quota>
|
||||
</default>
|
||||
|
||||
<user_with_sha256>
|
||||
<!-- echo -n abacaba | openssl dgst -sha256 !-->
|
||||
<password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
|
||||
<networks incl="networks" replace="replace">
|
||||
<ip>::/0</ip>
|
||||
</networks>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
</user_with_sha256>
|
||||
|
||||
<user_with_double_sha1>
|
||||
<!-- echo -n abacaba | openssl dgst -sha1 -binary | openssl dgst -sha1 !-->
|
||||
<password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
|
||||
|
@ -1,14 +1,14 @@
|
||||
# coding: utf-8
|
||||
|
||||
import docker
|
||||
import datetime
|
||||
import math
|
||||
import os
|
||||
import pytest
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import docker
|
||||
import pymysql.connections
|
||||
|
||||
from docker.models.containers import Container
|
||||
|
||||
from helpers.cluster import ClickHouseCluster
|
||||
@ -39,6 +39,25 @@ def mysql_client():
|
||||
yield docker.from_env().containers.get(cluster.project_name + '_mysql1_1')
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mysql_server(mysql_client):
|
||||
"""Return MySQL container when it is healthy.
|
||||
|
||||
:type mysql_client: Container
|
||||
:rtype: Container
|
||||
"""
|
||||
retries = 30
|
||||
for i in range(retries):
|
||||
info = mysql_client.client.api.inspect_container(mysql_client.name)
|
||||
if info['State']['Health']['Status'] == 'healthy':
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise Exception('Mysql server has not started in %d seconds.' % retries)
|
||||
|
||||
return mysql_client
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def golang_container():
|
||||
docker_compose = os.path.join(SCRIPT_DIR, 'clients', 'golang', 'docker_compose.yml')
|
||||
@ -111,14 +130,14 @@ def test_mysql_client(mysql_client, server_address):
|
||||
|
||||
assert stdout == '\n'.join(['column', '0', '0', '1', '1', '5', '5', 'tmp_column', '0', '1', ''])
|
||||
|
||||
def test_mysql_federated(mysql_client, server_address):
|
||||
|
||||
def test_mysql_federated(mysql_server, server_address):
|
||||
node.query('''DROP DATABASE IF EXISTS mysql_federated''', settings={"password": "123"})
|
||||
node.query('''CREATE DATABASE mysql_federated''', settings={"password": "123"})
|
||||
node.query('''CREATE TABLE mysql_federated.test (col UInt32) ENGINE = Log''', settings={"password": "123"})
|
||||
node.query('''INSERT INTO mysql_federated.test VALUES (0), (1), (5)''', settings={"password": "123"})
|
||||
|
||||
|
||||
code, (_, stderr) = mysql_client.exec_run('''
|
||||
code, (_, stderr) = mysql_server.exec_run('''
|
||||
mysql
|
||||
-e "DROP SERVER IF EXISTS clickhouse;"
|
||||
-e "CREATE SERVER clickhouse FOREIGN DATA WRAPPER mysql OPTIONS (USER 'default', PASSWORD '123', HOST '{host}', PORT {port}, DATABASE 'mysql_federated');"
|
||||
@ -128,7 +147,7 @@ def test_mysql_federated(mysql_client, server_address):
|
||||
|
||||
assert code == 0
|
||||
|
||||
code, (stdout, stderr) = mysql_client.exec_run('''
|
||||
code, (stdout, stderr) = mysql_server.exec_run('''
|
||||
mysql
|
||||
-e "CREATE TABLE mysql_federated.test(`col` int UNSIGNED) ENGINE=FEDERATED CONNECTION='clickhouse';"
|
||||
-e "SELECT * FROM mysql_federated.test ORDER BY col;"
|
||||
@ -136,7 +155,7 @@ def test_mysql_federated(mysql_client, server_address):
|
||||
|
||||
assert stdout == '\n'.join(['col', '0', '1', '5', ''])
|
||||
|
||||
code, (stdout, stderr) = mysql_client.exec_run('''
|
||||
code, (stdout, stderr) = mysql_server.exec_run('''
|
||||
mysql
|
||||
-e "INSERT INTO mysql_federated.test VALUES (0), (1), (5);"
|
||||
-e "SELECT * FROM mysql_federated.test ORDER BY col;"
|
||||
@ -233,13 +252,12 @@ def test_php_client(server_address, php_container):
|
||||
|
||||
|
||||
def test_mysqljs_client(server_address, nodejs_container):
|
||||
code, (_, stderr) = nodejs_container.exec_run('node test.js {host} {port} default 123'.format(host=server_address, port=server_port), demux=True)
|
||||
code, (_, stderr) = nodejs_container.exec_run('node test.js {host} {port} user_with_sha256 abacaba'.format(host=server_address, port=server_port), demux=True)
|
||||
assert code == 1
|
||||
assert 'MySQL is requesting the sha256_password authentication method, which is not supported.' in stderr
|
||||
|
||||
code, (_, stderr) = nodejs_container.exec_run('node test.js {host} {port} user_with_empty_password ""'.format(host=server_address, port=server_port), demux=True)
|
||||
assert code == 1
|
||||
assert 'MySQL is requesting the sha256_password authentication method, which is not supported.' in stderr
|
||||
assert code == 0
|
||||
|
||||
code, (_, _) = nodejs_container.exec_run('node test.js {host} {port} user_with_double_sha1 abacaba'.format(host=server_address, port=server_port), demux=True)
|
||||
assert code == 0
|
||||
|
@ -1,8 +1,8 @@
|
||||
111194.93
|
||||
111194.93
|
||||
111195.05
|
||||
111195.05
|
||||
110567.33
|
||||
111699.25
|
||||
10007543
|
||||
10007543
|
||||
10007543
|
||||
10007554
|
||||
10007554
|
||||
10007554
|
||||
10001780
|
||||
|
@ -0,0 +1,101 @@
|
||||
1
|
||||
-179 -0.06
|
||||
-178 -0.02
|
||||
-177 -0.02
|
||||
-176 -0.01
|
||||
-174 -0.01
|
||||
174 -0.01
|
||||
176 -0.01
|
||||
177 -0.02
|
||||
178 -0.02
|
||||
179 -0.06
|
||||
|
||||
██
|
||||
████
|
||||
██████▏
|
||||
████████▎
|
||||
██████████▎
|
||||
████████████▍
|
||||
██████████████▍
|
||||
████████████████▌
|
||||
██████████████████▌
|
||||
████████████████████▌
|
||||
██████████████████████▋
|
||||
████████████████████████▋
|
||||
██████████████████████████▌
|
||||
████████████████████████████▍
|
||||
██████████████████████████████▍
|
||||
████████████████████████████████▎
|
||||
██████████████████████████████████▎
|
||||
████████████████████████████████████▏
|
||||
██████████████████████████████████████
|
||||
███████████████████████████████████████▊
|
||||
█████████████████████████████████████████▋
|
||||
███████████████████████████████████████████▌
|
||||
█████████████████████████████████████████████▎
|
||||
███████████████████████████████████████████████
|
||||
████████████████████████████████████████████████▋
|
||||
██████████████████████████████████████████████████▌
|
||||
████████████████████████████████████████████████████▏
|
||||
█████████████████████████████████████████████████████▋
|
||||
███████████████████████████████████████████████████████▍
|
||||
█████████████████████████████████████████████████████████
|
||||
██████████████████████████████████████████████████████████▌
|
||||
████████████████████████████████████████████████████████████
|
||||
█████████████████████████████████████████████████████████████▌
|
||||
██████████████████████████████████████████████████████████████▊
|
||||
████████████████████████████████████████████████████████████████▎
|
||||
█████████████████████████████████████████████████████████████████▌
|
||||
██████████████████████████████████████████████████████████████████▋
|
||||
████████████████████████████████████████████████████████████████████
|
||||
█████████████████████████████████████████████████████████████████████▏
|
||||
██████████████████████████████████████████████████████████████████████▎
|
||||
███████████████████████████████████████████████████████████████████████▎
|
||||
████████████████████████████████████████████████████████████████████████▎
|
||||
█████████████████████████████████████████████████████████████████████████▎
|
||||
██████████████████████████████████████████████████████████████████████████▏
|
||||
███████████████████████████████████████████████████████████████████████████
|
||||
███████████████████████████████████████████████████████████████████████████▋
|
||||
████████████████████████████████████████████████████████████████████████████▍
|
||||
█████████████████████████████████████████████████████████████████████████████
|
||||
█████████████████████████████████████████████████████████████████████████████▌
|
||||
█████████████████████████████████████████████████████████████████████████████▊
|
||||
██████████████████████████████████████████████████████████████████████████████▎
|
||||
██████████████████████████████████████████████████████████████████████████████▌
|
||||
██████████████████████████████████████████████████████████████████████████████▋
|
||||
██████████████████████████████████████████████████████████████████████████████▊
|
||||
██████████████████████████████████████████████████████████████████████████████▊
|
||||
██████████████████████████████████████████████████████████████████████████████▋
|
||||
██████████████████████████████████████████████████████████████████████████████▋
|
||||
██████████████████████████████████████████████████████████████████████████████▍
|
||||
██████████████████████████████████████████████████████████████████████████████
|
||||
█████████████████████████████████████████████████████████████████████████████▌
|
||||
█████████████████████████████████████████████████████████████████████████████
|
||||
████████████████████████████████████████████████████████████████████████████▎
|
||||
███████████████████████████████████████████████████████████████████████████▌
|
||||
██████████████████████████████████████████████████████████████████████████▌
|
||||
█████████████████████████████████████████████████████████████████████████▌
|
||||
████████████████████████████████████████████████████████████████████████▎
|
||||
███████████████████████████████████████████████████████████████████████
|
||||
█████████████████████████████████████████████████████████████████████▋
|
||||
████████████████████████████████████████████████████████████████████
|
||||
██████████████████████████████████████████████████████████████████▍
|
||||
████████████████████████████████████████████████████████████████▌
|
||||
██████████████████████████████████████████████████████████████▌
|
||||
████████████████████████████████████████████████████████████▍
|
||||
██████████████████████████████████████████████████████████▏
|
||||
███████████████████████████████████████████████████████▋
|
||||
█████████████████████████████████████████████████████▏
|
||||
██████████████████████████████████████████████████▍
|
||||
███████████████████████████████████████████████▌
|
||||
████████████████████████████████████████████▌
|
||||
█████████████████████████████████████████▎
|
||||
█████████████████████████████████████▊
|
||||
██████████████████████████████████▍
|
||||
██████████████████████████████▋
|
||||
██████████████████████████▋
|
||||
██████████████████████▋
|
||||
██████████████████▌
|
||||
██████████████▏
|
||||
█████████▌
|
||||
████▊
|
@ -0,0 +1,3 @@
|
||||
WITH number - 90 AS lat SELECT DISTINCT greatCircleAngle(0, 0, 0, lat) = abs(lat) FROM numbers(180);
|
||||
WITH number - 180 AS lon SELECT lon, round(greatCircleAngle(0, 0, lon, 0) - abs(lon) AS err, 2) FROM numbers(360) WHERE abs(err) > 0.01;
|
||||
SELECT bar((greatCircleAngle(0, 0, number, number) - number) * 100, 0, 2000, 100) FROM numbers(90);
|
@ -1 +0,0 @@
|
||||
../en/index.md
|
142
docs/ja/index.md
Normal file
142
docs/ja/index.md
Normal file
@ -0,0 +1,142 @@
|
||||
# ClickHouseとは?
|
||||
|
||||
ClickHouseは、クエリのオンライン分析処理(OLAP)用の列指向のデータベース管理システム(DBMS)です。
|
||||
|
||||
「通常の」行指向のDBMSでは、データは次の順序で保存されます。
|
||||
|
||||
| Row | WatchID | JavaEnable | Title | GoodEvent | EventTime |
|
||||
| ------ | ------------------- | ---------- | ------------------ | --------- | ------------------- |
|
||||
| #0 | 89354350662 | 1 | Investor Relations | 1 | 2016-05-18 05:19:20 |
|
||||
| #1 | 90329509958 | 0 | Contact us | 1 | 2016-05-18 08:10:20 |
|
||||
| #2 | 89953706054 | 1 | Mission | 1 | 2016-05-18 07:38:00 |
|
||||
| #N | ... | ... | ... | ... | ... |
|
||||
|
||||
つまり、行に関連するすべての値は物理的に隣り合わせに格納されます。
|
||||
|
||||
行指向のDBMSの例:MySQL, Postgres および MS SQL Server
|
||||
{: .grey }
|
||||
|
||||
列指向のDBMSでは、データは次のように保存されます:
|
||||
|
||||
| Row: | #0 | #1 | #2 | #N |
|
||||
| ----------- | ------------------- | ------------------- | ------------------- | ------------------- |
|
||||
| WatchID: | 89354350662 | 90329509958 | 89953706054 | ... |
|
||||
| JavaEnable: | 1 | 0 | 1 | ... |
|
||||
| Title: | Investor Relations | Contact us | Mission | ... |
|
||||
| GoodEvent: | 1 | 1 | 1 | ... |
|
||||
| EventTime: | 2016-05-18 05:19:20 | 2016-05-18 08:10:20 | 2016-05-18 07:38:00 | ... |
|
||||
|
||||
これらの例は、データが配置される順序のみを示しています。
|
||||
異なる列の値は別々に保存され、同じ列のデータは一緒に保存されます。
|
||||
|
||||
列指向DBMSの例:Vertica, Paraccel (Actian Matrix and Amazon Redshift), Sybase IQ, Exasol, Infobright, InfiniDB, MonetDB (VectorWise and Actian Vector), LucidDB, SAP HANA, Google Dremel, Google PowerDrill, Druid および kdb+
|
||||
{: .grey }
|
||||
|
||||
異なったデータ格納の順序は、異なったシナリオにより適します。
|
||||
データアクセスシナリオとは、クエリの実行内容、頻度、割合を指します。クエリで読み取られるの各種データの量(行、列、バイト)。データの読み取りと更新の関係。作業データのサイズとローカルでの使用方法。トランザクションが使用されるかどうか、およびそれらがどの程度分離されているか。データ複製と論理的整合性の要件。クエリの種類ごとの遅延とスループットの要件など。
|
||||
|
||||
システムの負荷が高いほど、使用シナリオの要件に一致するようにセットアップされたシステムをカスタマイズすることがより重要になり、このカスタマイズはより細かくなります。大きく異なるシナリオに等しく適したシステムはありません。システムがさまざまなシナリオに適応可能である場合、高負荷下では、システムはすべてのシナリオを同等に不十分に処理するか、1つまたはいくつかの可能なシナリオでうまく機能します。
|
||||
|
||||
## OLAPシナリオの主要なプロパティ
|
||||
|
||||
- リクエストの大部分は読み取りアクセス用である。
|
||||
- データは、単一行ではなく、かなり大きなバッチ(> 1000行)で更新されます。または、まったく更新されない。
|
||||
- データはDBに追加されるが、変更されない。
|
||||
- 読み取りの場合、非常に多くの行がDBから抽出されるが、一部の列のみ。
|
||||
- テーブルは「幅が広く」、多数の列が含まれる。
|
||||
- クエリは比較的まれ(通常、サーバーあたり毎秒数百あるいはそれ以下の数のクエリ)。
|
||||
- 単純なクエリでは、約50ミリ秒の遅延が容認される。
|
||||
- 列の値はかなり小さく、数値や短い文字列(たとえば、URLごとに60バイト)。
|
||||
- 単一のクエリを処理する場合、高いスループットが必要(サーバーあたり毎秒最大数十億行)。
|
||||
- トランザクションは必要ない。
|
||||
- データの一貫性の要件が低い。
|
||||
- クエリごとに1つの大きなテーブルがある。 1つを除くすべてのテーブルは小さい。
|
||||
- クエリ結果は、ソースデータよりも大幅に小さくなる。つまり、データはフィルター処理または集計されるため、結果は単一サーバーのRAMに収まる。
|
||||
|
||||
OLAPシナリオは、他の一般的なシナリオ(OLTPやKey-Valueアクセスなど)とは非常に異なることが容易にわかります。 したがって、まともなパフォーマンスを得るには、OLTPまたはKey-Value DBを使用して分析クエリを処理しようとするのは無意味です。 たとえば、分析にMongoDBまたはRedisを使用しようとすると、OLAPデータベースに比べてパフォーマンスが非常に低下します。
|
||||
|
||||
## OLAPシナリオで列指向データベースがよりよく機能する理由
|
||||
|
||||
列指向データベースは、OLAPシナリオにより適しています。ほとんどのクエリの処理が少なくとも100倍高速です。 理由を以下に詳しく説明しますが、その根拠は視覚的に簡単に説明できます:
|
||||
|
||||
**行指向DBMS**
|
||||
|
||||
![Row-oriented](images/row_oriented.gif#)
|
||||
|
||||
**列指向DBMS**
|
||||
|
||||
![Column-oriented](images/column_oriented.gif#)
|
||||
|
||||
違いがわかりましたか?
|
||||
|
||||
### Input/output
|
||||
|
||||
1. 分析クエリでは、少数のテーブル列のみを読み取る必要があります。列指向のデータベースでは、必要なデータのみを読み取ることができます。たとえば、100のうち5つの列が必要な場合、I/Oが20倍削減されることが期待できます。
|
||||
2. データはパケットで読み取られるため、圧縮が容易です。列のデータも圧縮が簡単です。これにより、I/Oボリュームがさらに削減されます。
|
||||
3. I/Oの削減により、より多くのデータがシステムキャッシュに収まります。
|
||||
|
||||
たとえば、「各広告プラットフォームのレコード数をカウントする」クエリでは、1つの「広告プラットフォームID」列を読み取る必要がありますが、これは非圧縮では1バイトの領域を要します。トラフィックのほとんどが広告プラットフォームからのものではない場合、この列は少なくとも10倍の圧縮が期待できます。高速な圧縮アルゴリズムを使用すれば、1秒あたり少なくとも非圧縮データに換算して数ギガバイトの速度でデータを展開できます。つまり、このクエリは、単一のサーバーで1秒あたり約数十億行の速度で処理できます。この速度はまさに実際に達成されます。
|
||||
|
||||
<details markdown="1"><summary>Example</summary>
|
||||
```
|
||||
$ clickhouse-client
|
||||
ClickHouse client version 0.0.52053.
|
||||
Connecting to localhost:9000.
|
||||
Connected to ClickHouse server version 0.0.52053.
|
||||
|
||||
:) SELECT CounterID, count() FROM hits GROUP BY CounterID ORDER BY count() DESC LIMIT 20
|
||||
|
||||
SELECT
|
||||
CounterID,
|
||||
count()
|
||||
FROM hits
|
||||
GROUP BY CounterID
|
||||
ORDER BY count() DESC
|
||||
LIMIT 20
|
||||
|
||||
┌─CounterID─┬──count()─┐
|
||||
│ 114208 │ 56057344 │
|
||||
│ 115080 │ 51619590 │
|
||||
│ 3228 │ 44658301 │
|
||||
│ 38230 │ 42045932 │
|
||||
│ 145263 │ 42042158 │
|
||||
│ 91244 │ 38297270 │
|
||||
│ 154139 │ 26647572 │
|
||||
│ 150748 │ 24112755 │
|
||||
│ 242232 │ 21302571 │
|
||||
│ 338158 │ 13507087 │
|
||||
│ 62180 │ 12229491 │
|
||||
│ 82264 │ 12187441 │
|
||||
│ 232261 │ 12148031 │
|
||||
│ 146272 │ 11438516 │
|
||||
│ 168777 │ 11403636 │
|
||||
│ 4120072 │ 11227824 │
|
||||
│ 10938808 │ 10519739 │
|
||||
│ 74088 │ 9047015 │
|
||||
│ 115079 │ 8837972 │
|
||||
│ 337234 │ 8205961 │
|
||||
└───────────┴──────────┘
|
||||
|
||||
20 rows in set. Elapsed: 0.153 sec. Processed 1.00 billion rows, 4.00 GB (6.53 billion rows/s., 26.10 GB/s.)
|
||||
|
||||
:)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### CPU
|
||||
|
||||
クエリを実行するには大量の行を処理する必要があるため、個別の行ではなくベクター全体のすべての操作をディスパッチするか、ディスパッチコストがほとんどないようにクエリエンジンを実装すると効率的です。 適切なディスクサブシステムでこれを行わないと、クエリインタープリターが必然的にCPUを失速させます。
|
||||
データを列に格納し、可能な場合は列ごとに処理することは理にかなっています。
|
||||
|
||||
これを行うには2つの方法があります:
|
||||
|
||||
1. ベクトルエンジン。 すべての操作は、個別の値ではなく、ベクトルに対して記述されます。 これは、オペレーションを頻繁に呼び出す必要がなく、ディスパッチコストが無視できることを意味します。 操作コードには、最適化された内部サイクルが含まれています。
|
||||
|
||||
2. コード生成。 クエリ用に生成されたコードには、すべての間接的な呼び出しが含まれています。
|
||||
|
||||
これは、単純なクエリを実行する場合には意味がないため、「通常の」データベースでは実行されません。 ただし、例外があります。 たとえば、MemSQLはコード生成を使用して、SQLクエリを処理する際の遅延を減らします。 (比較のために、分析DBMSではレイテンシではなくスループットの最適化が必要です。)
|
||||
|
||||
CPU効率のために、クエリ言語は宣言型(SQLまたはMDX)、または少なくともベクトル(J、K)でなければなりません。 クエリには、最適化を可能にする暗黙的なループのみを含める必要があります。
|
||||
|
||||
[Original article](https://clickhouse.yandex/docs/ja/) <!--hide-->
|
@ -52,11 +52,11 @@
|
||||
|
||||
### 1.8. Перенос между разделами по TTL.
|
||||
|
||||
Делает [Владимир Чеботарёв](https://github.com/excitoon), Altinity.
|
||||
Делает [Владимир Чеботарёв](https://github.com/excitoon), Altinity. Декабрь 2019.
|
||||
|
||||
### 1.9. Использование TTL для прореживания данных.
|
||||
|
||||
В очереди.
|
||||
Будет делать Сорокин Николай, ВШЭ и Яндекс.
|
||||
|
||||
Сейчас пользователь может задать в таблице выражение, которое определяет, сколько времени хранятся данные. Обычно это выражение задаётся относительно значения столбца с датой - например: удалять данные через три месяца. https://clickhouse.yandex/docs/ru/operations/table_engines/mergetree/#table_engine-mergetree-ttl
|
||||
|
||||
@ -160,7 +160,7 @@ ClickHouse использует небольшое подмножество фу
|
||||
|
||||
### 2.9. Логгировние в format-стиле.
|
||||
|
||||
В задаче заинтересован [Александр Кузьменков](https://github.com/akuzm). Нет прогресса.
|
||||
Делает [Иван Лежанкин](https://github.com/abyss7). Низкий приоритет.
|
||||
|
||||
### 2.10. Запрашивать у таблиц не столбцы, а срезы.
|
||||
|
||||
@ -205,7 +205,7 @@ ClickHouse использует небольшое подмножество фу
|
||||
|
||||
### 3.4. Добавить японский язык в документацию.
|
||||
|
||||
Эту задачу сделает [Иван Блинков](https://github.com/blinkov/), до конца ноября 2019.
|
||||
Эту задачу сделает [Иван Блинков](https://github.com/blinkov/), до конца декабря 2019.
|
||||
|
||||
|
||||
## 4. Сетевое взаимодействие.
|
||||
@ -257,7 +257,7 @@ ClickHouse использует небольшое подмножество фу
|
||||
|
||||
### 5.3. Встроенная ручка для Prometheus и, возможно, Solomon.
|
||||
|
||||
Простая задача.
|
||||
Простая задача. https://github.com/Vdimir
|
||||
|
||||
### 5.4. Opt-in сообщать в клиенте, если вышла новая версия.
|
||||
|
||||
@ -270,7 +270,8 @@ ClickHouse использует небольшое подмножество фу
|
||||
|
||||
### 6.1. Исправления сэмплирующего профайлера запросов.
|
||||
|
||||
Михаил Филимонов, Altinity. Ноябрь 2019.
|
||||
Михаил Филимонов, Altinity. Ноябрь 2019. Сделано.
|
||||
Осталось ещё проверить работоспособность профайлера в первом потоке (что важно для INSERT).
|
||||
|
||||
### 6.2. Добавление memory profiler.
|
||||
|
||||
@ -364,6 +365,7 @@ UBSan включен в функциональных тестах, но не в
|
||||
Мы используем -Wall -Wextra -Weverything -Werror.
|
||||
При сборке с clang, -Weverything уже включено. Но в gcc есть уникальные warning-и, отсутствующие в clang.
|
||||
Wolf Kreuzerkrieg. Возможно, его уже не интересует эта задача.
|
||||
Низкий приоритет. Возможно, будет отменено.
|
||||
|
||||
### 7.14. Альтернатива для readline и libedit.
|
||||
|
||||
@ -562,7 +564,7 @@ Fuzzing тестирование - это тестирование случай
|
||||
|
||||
### 8.4. Унификация File, HDFS, S3 под URL.
|
||||
|
||||
### 8.5. Аутентификация в S3.
|
||||
### 8.5. + Аутентификация в S3.
|
||||
|
||||
[Владимир Чеботарёв](https://github.com/excitoon), Altinity.
|
||||
|
||||
@ -570,16 +572,18 @@ Fuzzing тестирование - это тестирование случай
|
||||
|
||||
Андрей Коняев, ArenaData.
|
||||
|
||||
### 8.7. Исправление мелочи HDFS на очень старых ядрах Linux.
|
||||
### 8.7. + Исправление мелочи HDFS на очень старых ядрах Linux.
|
||||
|
||||
В ядрах 2.6 отсутствует один системный вызов, который библиотека hdfs3 использует без необходимости.
|
||||
Тривиально, но исполнителя ещё нет.
|
||||
Сделал Amos Bird.
|
||||
|
||||
### 8.8. Поддержка виртуальных столбцов с именем файла и путём.
|
||||
|
||||
[Ольга Хвостикова](https://github.com/stavrolia).
|
||||
|
||||
### 8.9. Поддержка сжатых файлов (gz, bz) на чтение и запись.
|
||||
### 8.9. + Поддержка сжатых файлов (gz, bz) на чтение и запись.
|
||||
|
||||
Сделал [Andrey Bodrov](https://github.com/apbodrov)
|
||||
|
||||
### 8.10. Запись в табличную функцию ODBC.
|
||||
|
||||
@ -617,7 +621,9 @@ Fuzzing тестирование - это тестирование случай
|
||||
|
||||
Встроенная в ClickHouse возможность работать в качестве реплики MySQL даст преимущества для дальнейшего развития.
|
||||
|
||||
### 8.18. ClickHouse как Federated MySQL.
|
||||
### 8.18. + ClickHouse как Federated MySQL.
|
||||
|
||||
Maxim Fedotov, Wargaming + Yuri Baranov, Яндекс.
|
||||
|
||||
### 8.19. Интеграция с RabbitMQ.
|
||||
|
||||
@ -642,7 +648,7 @@ Fuzzing тестирование - это тестирование случай
|
||||
|
||||
## 9. Безопасность.
|
||||
|
||||
### 9.1. Ограничение на хосты в запросах ко внешним системам.
|
||||
### 9.1. + Ограничение на хосты в запросах ко внешним системам.
|
||||
|
||||
Михаил Коротов.
|
||||
|
||||
@ -760,7 +766,7 @@ ClickHouse предоставляет возможность обратитьс
|
||||
|
||||
### 11.9. Доработки ODBC драйвера.
|
||||
|
||||
Денис Глазачев, Altinity.
|
||||
Денис Глазачев, Altinity. Хороший прогресс по этой задаче.
|
||||
|
||||
### 11.10. Преднастроенные HTTP handlers для запросов.
|
||||
|
||||
@ -873,7 +879,9 @@ zhang2014
|
||||
|
||||
### 14.17. Ввести понятие stateful функций.
|
||||
|
||||
zhang2014.
|
||||
Для runningDifference, neighbour - их учёт в оптимизаторе запросов.
|
||||
В интерфейсе уже сделано. Надо проверить, что учитывается в нужных местах (например, что работает predicate pushdown сквозь ORDER BY, если таких функций нет).
|
||||
|
||||
### 14.18. UNION DISTINCT и возможность включить его по-умолчанию.
|
||||
|
||||
@ -911,7 +919,7 @@ zhang2014
|
||||
|
||||
### 15.5. Использование ключа таблицы для оптимизации merge JOIN.
|
||||
|
||||
### 15.6. SEMI и ANTI JOIN.
|
||||
### 15.6. + SEMI и ANTI JOIN.
|
||||
|
||||
Артём Зуйков.
|
||||
|
||||
@ -954,7 +962,7 @@ ClickHouse не является geospatial СУБД. Тем не менее, в
|
||||
|
||||
Реализовать в ClickHouse типы данных для задач обработки геоинформационных данных: Point, Line, MultiLine, Polygon и операции над ними - проверка вхождения, пересечения. Вариантом минимум будет реализация этих операций в евклидовой системе координат. Дополнительно - на сфере и WGS84.
|
||||
|
||||
### 17.3. Ускорение greatCircleDistance.
|
||||
### 17.3. + Ускорение greatCircleDistance.
|
||||
|
||||
[Ольга Хвостикова](https://github.com/stavrolia), основано на коде Андрея Аксёнова, получено разрешение на использование кода.
|
||||
|
||||
@ -1050,9 +1058,9 @@ Hold. Полезно для заказчиков внутри Яндекса, н
|
||||
|
||||
## 21. Оптимизации производительности.
|
||||
|
||||
### 21.1. Параллельный парсинг форматов.
|
||||
### 21.1. + Параллельный парсинг форматов.
|
||||
|
||||
Начинал Олег Ершов, доделывает Никита Михайлов, помогает [Александр Кузьменков](https://github.com/akuzm). Почти всё готово.
|
||||
Начинал Олег Ершов, доделывает Никита Михайлов, помогает [Александр Кузьменков](https://github.com/akuzm). Готово.
|
||||
|
||||
### 21.2. Параллельное форматирование форматов.
|
||||
|
||||
@ -1100,7 +1108,7 @@ Hold. Полезно для заказчиков внутри Яндекса, н
|
||||
|
||||
[Николай Кочетов](https://github.com/KochetovNicolai). Требует 2.1.
|
||||
|
||||
### 21.10. Улучшение эвристики PREWHERE.
|
||||
### 21.10. + Улучшение эвристики PREWHERE.
|
||||
|
||||
Amos Bird.
|
||||
|
||||
@ -1237,29 +1245,32 @@ zhang2014.
|
||||
|
||||
Требует 6.3., но можно улучшить отдельными хаками. Нужно Метрике и БК.
|
||||
|
||||
### 22.11. Более простая ser/de настроек запросов.
|
||||
### 22.11. + Более простая ser/de настроек запросов.
|
||||
|
||||
[Виталий Баранов](https://github.com/vitlibar), почти всё готово.
|
||||
И пропуск неизвестных настроек. Важно для Метрики для упрощения апгрейда без изменения конфига.
|
||||
[Виталий Баранов](https://github.com/vitlibar), готово.
|
||||
|
||||
### 22.12. Исправление низкой производительности чтения из Kafka.
|
||||
|
||||
[Иван Лежанкин](https://github.com/abyss7).
|
||||
### 22.12. + Исправление низкой производительности чтения из Kafka.
|
||||
|
||||
Для ClickHouse нехарактерно наличие кода, обладающего столь низкой производительностью. Практики разработки не подразумевают, что такой код должен попасть в продакшен без надлежащего тестирования производительности.
|
||||
|
||||
Изначально было назначено на [Ивана Лежанкина](https://github.com/abyss7), но по неизвестной причине было не сделано в течение нескольких месяцев.
|
||||
Сделал Михаил Филимонов, Altinity.
|
||||
|
||||
### 22.13. Посмотреть, почему не работают некоторые collations.
|
||||
|
||||
[Иван Лежанкин](https://github.com/abyss7), совмещается с 7.1.
|
||||
Изначально было назначено на [Ивана Лежанкина](https://github.com/abyss7), но в результате сделал Александр Сапин.
|
||||
|
||||
### 22.14. Посмотреть, почему не работает StorageSet для MergeTree таблиц при некоторых условиях.
|
||||
|
||||
|
||||
### 22.15. Нормализация коммитов в Kafka и идемпотентности операций.
|
||||
|
||||
[Иван Лежанкин](https://github.com/abyss7), если он не сдастся.
|
||||
|
||||
### 22.16. Исправление низкой производительности кодека DoubleDelta.
|
||||
|
||||
Василий Немков, Altinity - временно приостановлено, но намерения остаются в силе.
|
||||
Василий Немков, Altinity - в процессе.
|
||||
|
||||
Мы считаем важным, что код в ClickHouse содержит разумные оптимизации, основанные на анализе производительности. Но иногда бывают досадные исключения.
|
||||
|
||||
@ -1269,11 +1280,11 @@ zhang2014.
|
||||
|
||||
Василий Немков, Altinity.
|
||||
|
||||
### 22.19. Одновременное использование SAMPLE и PREWHERE.
|
||||
### 22.19. + Одновременное использование SAMPLE и PREWHERE.
|
||||
|
||||
Нужно для Метрики. [Николай Кочетов](https://github.com/KochetovNicolai), ноябрь 2019.
|
||||
|
||||
### 22.20. Неправильная работа PREWHERE при некоторых условиях.
|
||||
### 22.20. + Неправильная работа PREWHERE при некоторых условиях.
|
||||
|
||||
[Николай Кочетов](https://github.com/KochetovNicolai), декабрь 2019.
|
||||
|
||||
@ -1310,6 +1321,10 @@ https://github.com/ClickHouse/ClickHouse/issues/2655
|
||||
|
||||
[Иван Лежанкин](https://github.com/abyss7).
|
||||
|
||||
### 22.29. Уязвимость DDL для словарей executable.
|
||||
|
||||
[Александр Сапин](https://github.com/alesapin)
|
||||
|
||||
|
||||
## 23. Default Festival.
|
||||
|
||||
@ -1582,13 +1597,14 @@ Amos Bird, но его решение слишком громоздкое и п
|
||||
|
||||
## 25. DevRel
|
||||
|
||||
### 25.1. Перевод инструкции для начинающих разработчиков.
|
||||
### 25.1. + Перевод инструкции для начинающих разработчиков.
|
||||
|
||||
Александр Казаков, ноябрь 2019.
|
||||
|
||||
### 25.2. Вычитка и выкладка статьи про обфускацию данных на английском.
|
||||
|
||||
Эми, Александр Казаков, Алексей Миловидов, ноябрь 2019.
|
||||
Готово к выкладке.
|
||||
|
||||
### 25.3. Подготовка статьи "Секреты оптимизации производительности ClickHouse".
|
||||
|
||||
@ -1608,7 +1624,7 @@ Amos Bird, но его решение слишком громоздкое и п
|
||||
|
||||
Эми
|
||||
|
||||
### 25.8. Выступление keynote на BDTC.
|
||||
### 25.8. + Выступление keynote на BDTC.
|
||||
|
||||
Алексей Миловидов
|
||||
|
||||
|
@ -45,6 +45,9 @@ def build_for_lang(lang, args):
|
||||
os.environ['SINGLE_PAGE'] = '0'
|
||||
|
||||
config_path = os.path.join(args.docs_dir, 'toc_%s.yml' % lang)
|
||||
if args.is_stable_release and not os.path.exists(config_path):
|
||||
logging.warn('Skipping %s docs, because %s does not exist' % (lang, config_path))
|
||||
return
|
||||
|
||||
try:
|
||||
theme_cfg = {
|
||||
@ -249,6 +252,7 @@ if __name__ == '__main__':
|
||||
arg_parser.add_argument('--output-dir', default='build')
|
||||
arg_parser.add_argument('--enable-stable-releases', action='store_true')
|
||||
arg_parser.add_argument('--version-prefix', type=str, default='')
|
||||
arg_parser.add_argument('--is-stable-release', action='store_true')
|
||||
arg_parser.add_argument('--skip-single-page', action='store_true')
|
||||
arg_parser.add_argument('--skip-pdf', action='store_true')
|
||||
arg_parser.add_argument('--skip-website', action='store_true')
|
||||
@ -260,8 +264,6 @@ if __name__ == '__main__':
|
||||
|
||||
from github import choose_latest_releases
|
||||
args.stable_releases = choose_latest_releases() if args.enable_stable_releases else []
|
||||
|
||||
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG if args.verbose else logging.INFO,
|
||||
|
@ -15,7 +15,7 @@ def choose_latest_releases():
|
||||
candidates = requests.get('https://api.github.com/repos/ClickHouse/ClickHouse/tags?per_page=100').json()
|
||||
for tag in candidates:
|
||||
name = tag.get('name', '')
|
||||
if 'v18' in name or 'stable' not in name:
|
||||
if ('v18' in name) or ('stable' not in name) or ('prestable' in name):
|
||||
continue
|
||||
major_version = '.'.join((name.split('.', 2))[:2])
|
||||
if major_version not in seen:
|
||||
@ -33,6 +33,7 @@ def process_release(args, callback, release):
|
||||
tar.extractall(base_dir)
|
||||
args = copy.deepcopy(args)
|
||||
args.version_prefix = name
|
||||
args.is_stable_release = True
|
||||
args.docs_dir = os.path.join(base_dir, os.listdir(base_dir)[0], 'docs')
|
||||
callback(args)
|
||||
|
||||
|
@ -31,6 +31,9 @@ if (GLIBC_COMPATIBILITY)
|
||||
list(APPEND glibc_compatibility_sources libcxxabi/cxa_thread_atexit.cpp)
|
||||
endif()
|
||||
|
||||
# Need to omit frame pointers to match the performance of glibc
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer")
|
||||
|
||||
add_library(glibc-compatibility STATIC ${glibc_compatibility_sources})
|
||||
|
||||
target_include_directories(glibc-compatibility PRIVATE libcxxabi ${musl_arch_include_dir})
|
||||
|
3
libs/libglibc-compatibility/musl/aarch64/syscall_arch.h
Normal file
3
libs/libglibc-compatibility/musl/aarch64/syscall_arch.h
Normal file
@ -0,0 +1,3 @@
|
||||
#define VDSO_USEFUL
|
||||
#define VDSO_CGT_SYM "__kernel_clock_gettime"
|
||||
#define VDSO_CGT_VER "LINUX_2.6.39"
|
108
libs/libglibc-compatibility/musl/clock_gettime.c
Normal file
108
libs/libglibc-compatibility/musl/clock_gettime.c
Normal file
@ -0,0 +1,108 @@
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include "atomic.h"
|
||||
#include "musl_features.h"
|
||||
#include "syscall.h"
|
||||
|
||||
#ifdef VDSO_CGT_SYM
|
||||
|
||||
static void *volatile vdso_func;
|
||||
|
||||
#ifdef VDSO_CGT32_SYM
|
||||
static void *volatile vdso_func_32;
|
||||
static int cgt_time32_wrap(clockid_t clk, struct timespec *ts)
|
||||
{
|
||||
long ts32[2];
|
||||
int (*f)(clockid_t, long[2]) =
|
||||
(int (*)(clockid_t, long[2]))vdso_func_32;
|
||||
int r = f(clk, ts32);
|
||||
if (!r) {
|
||||
/* Fallback to syscalls if time32 overflowed. Maybe
|
||||
* we lucked out and somehow migrated to a kernel with
|
||||
* time64 syscalls available. */
|
||||
if (ts32[0] < 0) {
|
||||
a_cas_p(&vdso_func, (void *)cgt_time32_wrap, 0);
|
||||
return -ENOSYS;
|
||||
}
|
||||
ts->tv_sec = ts32[0];
|
||||
ts->tv_nsec = ts32[1];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cgt_init(clockid_t clk, struct timespec *ts)
|
||||
{
|
||||
void *p = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM);
|
||||
#ifdef VDSO_CGT32_SYM
|
||||
if (!p) {
|
||||
void *q = __vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM);
|
||||
if (q) {
|
||||
a_cas_p(&vdso_func_32, 0, q);
|
||||
p = cgt_time32_wrap;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int (*f)(clockid_t, struct timespec *) =
|
||||
(int (*)(clockid_t, struct timespec *))p;
|
||||
a_cas_p(&vdso_func, (void *)cgt_init, p);
|
||||
return f ? f(clk, ts) : -ENOSYS;
|
||||
}
|
||||
|
||||
static void *volatile vdso_func = (void *)cgt_init;
|
||||
|
||||
#endif
|
||||
|
||||
int __clock_gettime(clockid_t clk, struct timespec *ts)
|
||||
{
|
||||
int r;
|
||||
|
||||
#ifdef VDSO_CGT_SYM
|
||||
int (*f)(clockid_t, struct timespec *) =
|
||||
(int (*)(clockid_t, struct timespec *))vdso_func;
|
||||
if (f) {
|
||||
r = f(clk, ts);
|
||||
if (!r) return r;
|
||||
if (r == -EINVAL) return __syscall_ret(r);
|
||||
/* Fall through on errors other than EINVAL. Some buggy
|
||||
* vdso implementations return ENOSYS for clocks they
|
||||
* can't handle, rather than making the syscall. This
|
||||
* also handles the case where cgt_init fails to find
|
||||
* a vdso function to use. */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SYS_clock_gettime64
|
||||
r = -ENOSYS;
|
||||
if (sizeof(time_t) > 4)
|
||||
r = __syscall(SYS_clock_gettime64, clk, ts);
|
||||
if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
|
||||
return __syscall_ret(r);
|
||||
long ts32[2];
|
||||
r = __syscall(SYS_clock_gettime, clk, ts32);
|
||||
if (r==-ENOSYS && clk==CLOCK_REALTIME) {
|
||||
r = __syscall(SYS_gettimeofday, ts32, 0);
|
||||
ts32[1] *= 1000;
|
||||
}
|
||||
if (!r) {
|
||||
ts->tv_sec = ts32[0];
|
||||
ts->tv_nsec = ts32[1];
|
||||
return r;
|
||||
}
|
||||
return __syscall_ret(r);
|
||||
#else
|
||||
r = __syscall(SYS_clock_gettime, clk, ts);
|
||||
if (r == -ENOSYS) {
|
||||
if (clk == CLOCK_REALTIME) {
|
||||
__syscall(SYS_gettimeofday, ts, 0);
|
||||
ts->tv_nsec = (int)ts->tv_nsec * 1000;
|
||||
return 0;
|
||||
}
|
||||
r = -EINVAL;
|
||||
}
|
||||
return __syscall_ret(r);
|
||||
#endif
|
||||
}
|
||||
|
||||
weak_alias(__clock_gettime, clock_gettime);
|
27
libs/libglibc-compatibility/musl/clock_nanosleep.c
Normal file
27
libs/libglibc-compatibility/musl/clock_nanosleep.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include "musl_features.h"
|
||||
#include "syscall.h"
|
||||
|
||||
int __clock_nanosleep(clockid_t clk, int flags, const struct timespec * req, struct timespec * rem)
|
||||
{
|
||||
if (clk == CLOCK_THREAD_CPUTIME_ID)
|
||||
return EINVAL;
|
||||
int old_cancel_type;
|
||||
int status;
|
||||
/// We cannot port __syscall_cp because musl has very limited cancellation point implementation.
|
||||
/// For example, c++ destructors won't get called and exception unwinding isn't implemented.
|
||||
/// Instead, we use normal __syscall here and turn on the asynchrous cancel mode to allow
|
||||
/// cancel. This works because nanosleep doesn't contain any resource allocations or
|
||||
/// deallocations.
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_cancel_type);
|
||||
if (clk == CLOCK_REALTIME && !flags)
|
||||
status = -__syscall(SYS_nanosleep, req, rem);
|
||||
else
|
||||
status = -__syscall(SYS_clock_nanosleep, clk, flags, req, rem);
|
||||
pthread_setcanceltype(old_cancel_type, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
weak_alias(__clock_nanosleep, clock_nanosleep);
|
@ -1,14 +1,11 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <syscall.h>
|
||||
#include "syscall.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#ifdef VDSO_GETCPU_SYM
|
||||
|
||||
void *__vdsosym(const char *, const char *);
|
||||
|
||||
static void *volatile vdso_func;
|
||||
|
||||
typedef long (*getcpu_f)(unsigned *, unsigned *, void *);
|
||||
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <syscall_arch.h>
|
||||
|
||||
typedef long syscall_arg_t;
|
||||
|
||||
__attribute__((visibility("hidden")))
|
||||
@ -7,3 +10,6 @@ long __syscall_ret(unsigned long);
|
||||
|
||||
__attribute__((visibility("hidden")))
|
||||
long __syscall(syscall_arg_t, ...);
|
||||
|
||||
__attribute__((visibility("hidden")))
|
||||
void *__vdsosym(const char *, const char *);
|
||||
|
105
libs/libglibc-compatibility/musl/vdso.c
Normal file
105
libs/libglibc-compatibility/musl/vdso.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/auxv.h>
|
||||
#include "syscall.h"
|
||||
|
||||
#ifdef VDSO_USEFUL
|
||||
|
||||
#if ULONG_MAX == 0xffffffff
|
||||
typedef Elf32_Ehdr Ehdr;
|
||||
typedef Elf32_Phdr Phdr;
|
||||
typedef Elf32_Sym Sym;
|
||||
typedef Elf32_Verdef Verdef;
|
||||
typedef Elf32_Verdaux Verdaux;
|
||||
#else
|
||||
typedef Elf64_Ehdr Ehdr;
|
||||
typedef Elf64_Phdr Phdr;
|
||||
typedef Elf64_Sym Sym;
|
||||
typedef Elf64_Verdef Verdef;
|
||||
typedef Elf64_Verdaux Verdaux;
|
||||
#endif
|
||||
|
||||
static int checkver(Verdef *def, int vsym, const char *vername, char *strings)
|
||||
{
|
||||
vsym &= 0x7fff;
|
||||
for (;;) {
|
||||
if (!(def->vd_flags & VER_FLG_BASE)
|
||||
&& (def->vd_ndx & 0x7fff) == vsym)
|
||||
break;
|
||||
if (def->vd_next == 0)
|
||||
return 0;
|
||||
def = (Verdef *)((char *)def + def->vd_next);
|
||||
}
|
||||
Verdaux *aux = (Verdaux *)((char *)def + def->vd_aux);
|
||||
return !strcmp(vername, strings + aux->vda_name);
|
||||
}
|
||||
|
||||
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
|
||||
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
|
||||
|
||||
extern char** environ;
|
||||
static Ehdr *eh = NULL;
|
||||
void *__vdsosym(const char *vername, const char *name);
|
||||
// We don't have libc struct available here. Compute aux vector manually.
|
||||
__attribute__((constructor)) static void auxv_init()
|
||||
{
|
||||
size_t i, *auxv;
|
||||
for (i=0; environ[i]; i++);
|
||||
auxv = (void *)(environ+i+1);
|
||||
for (i=0; auxv[i] != AT_SYSINFO_EHDR; i+=2)
|
||||
if (!auxv[i]) return;
|
||||
if (!auxv[i+1]) return;
|
||||
eh = (void *)auxv[i+1];
|
||||
}
|
||||
|
||||
void *__vdsosym(const char *vername, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
if (!eh) return 0;
|
||||
Phdr *ph = (void *)((char *)eh + eh->e_phoff);
|
||||
size_t *dynv=0, base=-1;
|
||||
for (i=0; i<eh->e_phnum; i++, ph=(void *)((char *)ph+eh->e_phentsize)) {
|
||||
if (ph->p_type == PT_LOAD)
|
||||
base = (size_t)eh + ph->p_offset - ph->p_vaddr;
|
||||
else if (ph->p_type == PT_DYNAMIC)
|
||||
dynv = (void *)((char *)eh + ph->p_offset);
|
||||
}
|
||||
if (!dynv || base==(size_t)-1) return 0;
|
||||
|
||||
char *strings = 0;
|
||||
Sym *syms = 0;
|
||||
Elf_Symndx *hashtab = 0;
|
||||
uint16_t *versym = 0;
|
||||
Verdef *verdef = 0;
|
||||
|
||||
for (i=0; dynv[i]; i+=2) {
|
||||
void *p = (void *)(base + dynv[i+1]);
|
||||
switch(dynv[i]) {
|
||||
case DT_STRTAB: strings = p; break;
|
||||
case DT_SYMTAB: syms = p; break;
|
||||
case DT_HASH: hashtab = p; break;
|
||||
case DT_VERSYM: versym = p; break;
|
||||
case DT_VERDEF: verdef = p; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strings || !syms || !hashtab) return 0;
|
||||
if (!verdef) versym = 0;
|
||||
|
||||
for (i=0; i<hashtab[1]; i++) {
|
||||
if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue;
|
||||
if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue;
|
||||
if (!syms[i].st_shndx) continue;
|
||||
if (strcmp(name, strings+syms[i].st_name)) continue;
|
||||
if (versym && !checkver(verdef, versym[i], vername, strings))
|
||||
continue;
|
||||
return (void *)(base + syms[i].st_value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
5
libs/libglibc-compatibility/musl/x86_64/syscall_arch.h
Normal file
5
libs/libglibc-compatibility/musl/x86_64/syscall_arch.h
Normal file
@ -0,0 +1,5 @@
|
||||
#define VDSO_USEFUL
|
||||
#define VDSO_CGT_SYM "__vdso_clock_gettime"
|
||||
#define VDSO_CGT_VER "LINUX_2.6"
|
||||
#define VDSO_GETCPU_SYM "__vdso_getcpu"
|
||||
#define VDSO_GETCPU_VER "LINUX_2.6"
|
Loading…
Reference in New Issue
Block a user