ClickHouse-Encoder

 view release on metacpan or  search on metacpan

bench/complex_insert_benchmark.pl  view on Meta::CPAN

system("clickhouse-client --port $PORT --query 'create table bench_complex (
    id UInt32,
    name String,
    tags Array(String),
    coords Tuple(Float64, Float64),
    optional Nullable(UInt64)
) engine = Null'");

# Benchmark function
sub bench_insert {
    my ($format, $data, $iterations) = @_;
    my @times;

    for my $i (1 .. $iterations) {
        my $t0 = time();
        open my $fh, '|-', "clickhouse-client --port $PORT --query 'insert into bench_complex format $format' 2>/dev/null"
            or die "Cannot run clickhouse-client: $!";
        binmode $fh;
        print $fh $data;
        close $fh;
        my $elapsed = time() - $t0;
        push @times, $elapsed;
    }

bench/insert_benchmark.pl  view on Meta::CPAN


# Create test table
print "\nSetting up test table...\n";
system("clickhouse-client --port $PORT --query 'drop table if exists bench_native'");
system("clickhouse-client --port $PORT --query 'drop table if exists bench_csv'");
system("clickhouse-client --port $PORT --query 'create table bench_native (id UInt32, bignum UInt64, value Float64, name String) engine = Null'");
system("clickhouse-client --port $PORT --query 'create table bench_csv (id UInt32, bignum UInt64, value Float64, name String) engine = Null'");

# Benchmark function
sub bench_insert {
    my ($table, $format, $data, $iterations) = @_;
    my @times;

    for my $i (1 .. $iterations) {
        my $t0 = time();
        open my $fh, '|-', "clickhouse-client --port $PORT --query 'insert into $table format $format' 2>/dev/null"
            or die "Cannot run clickhouse-client: $!";
        binmode $fh;
        print $fh $data;
        close $fh;
        my $elapsed = time() - $t0;
        push @times, $elapsed;
    }

bench/wide_table_benchmark.pl  view on Meta::CPAN

print "\n", "=" x 70, "\n";
print "INSERT Benchmark\n";
print "=" x 70, "\n\n";

print "Setting up test table...\n";
system("clickhouse-client --port $PORT --query 'drop table if exists bench_wide'");
system("clickhouse-client --port $PORT --query 'create table bench_wide (\n    $col_defs\n) engine = Null'");

# Benchmark function
sub bench_insert {
    my ($format, $data, $iterations) = @_;
    my @times;

    for my $i (1 .. $iterations) {
        my $t0 = time();
        open my $fh, '|-', "clickhouse-client --port $PORT --query 'insert into bench_wide format $format' 2>/dev/null"
            or die "Cannot run clickhouse-client: $!";
        binmode $fh;
        print $fh $data;
        close $fh;
        my $elapsed = time() - $t0;
        push @times, $elapsed;
        printf "  Run %d: %.3f sec\n", $i, $elapsed;
    }

    return @times;
}

# Warmup
print "Warming up...\n";
bench_insert('Native', $native_data, 1);
bench_insert('TabSeparated', $csv_data, 1);

# Benchmark
print "\nBenchmarking Native format ($ITERATIONS iterations)...\n";
my @native_times = bench_insert('Native', $native_data, $ITERATIONS);

print "\nBenchmarking TabSeparated format ($ITERATIONS iterations)...\n";
my @csv_times = bench_insert('TabSeparated', $csv_data, $ITERATIONS);

# Calculate statistics
sub stats {
    my @times = @_;
    my $sum = 0;
    $sum += $_ for @times;
    my $avg = $sum / @times;
    my $min = (sort { $a <=> $b } @times)[0];
    return ($avg, $min);

xt/fuzz-decoder.t  view on Meta::CPAN

        2 * 1024 * 1024 * 1024,
        2 * 1024 * 1024 * 1024);
    1;
};
plan skip_all => 'BSD::Resource not available; skipping unbounded fuzz'
    unless $cap_ok;

srand($ENV{FUZZ_DECODER_SEED} // 19937);

# 150 is the empirical safe ceiling under RLIMIT_AS=2 GiB with the
# default seed: enough iterations to exercise each seed shape several
# times without the cumulative Perl arena footprint plus a worst-case
# bounded allocation tripping the cap. Bump FUZZ_DECODER_ITERS in CI
# when adding more aggressive fuzz patterns.
my $iters = $ENV{FUZZ_DECODER_ITERS} // 150;

# Build a known-good seed block for each interesting type, then
# mutate. Both fully-random and surgically-perturbed inputs exercise
# different decoder paths.
my @seeds;

xt/fuzz-decoder.t  view on Meta::CPAN

        }
        else {
            # Append trailing garbage.
            $bytes .= join '', map chr(int rand 256), 1..int(rand 32);
        }
    }
    next unless _looks_safe($bytes);
    # Wrap in a fresh sub call so the decoder's return value and any
    # mortal SVs created during decode are reclaimed before the next
    # iteration. Without this, mortals can pile up across hundreds
    # of iterations until the test process's heap is exhausted.
    eval { _try_decode($bytes); 1 };
    # "Out of memory" / "Killed" from RLIMIT_AS aborts the test process
    # and never returns to this branch - but catching the symbolic text
    # in $@ surfaces a real allocation gap if the eval somehow recovered
    # without the process dying.
    if ($@ && $@ =~ /Segmentation|stack overflow|Out of memory|Killed/i) {
        $crashed++;
        diag "CRASH at iter $i: $@";
    } else {
        $survived++;
    }
}

sub _try_decode {
    ClickHouse::Encoder->decode_block($_[0]);
    return;
}

is($crashed, 0, "$iters fuzz iterations: 0 crashes ($survived survived)");

done_testing();



( run in 0.929 second using v1.01-cache-2.11-cpan-96521ef73a4 )