cockroach/influxdb: CWE-407 findings
This commit is contained in:
parent
95648fb2b0
commit
37836b498d
9 changed files with 546 additions and 0 deletions
|
|
@ -0,0 +1,38 @@
|
|||
# UNDF:
|
||||
--- a/pkg/sql/opt/exec/execbuilder/builder.go
|
||||
+++ b/pkg/sql/opt/exec/execbuilder/builder.go
|
||||
@@ -7,7 +7,6 @@ package execbuilder
|
||||
import (
|
||||
"context"
|
||||
- "slices"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -197,14 +197,20 @@ type IndexesUsed struct {
|
||||
indexes []struct {
|
||||
tableID cat.StableID
|
||||
indexID cat.StableID
|
||||
}
|
||||
+ seen map[[2]cat.StableID]struct{}
|
||||
}
|
||||
|
||||
// add adds the given index to the list, if it is not already present.
|
||||
func (iu *IndexesUsed) add(tableID, indexID cat.StableID) {
|
||||
- s := struct {
|
||||
- tableID cat.StableID
|
||||
- indexID cat.StableID
|
||||
- }{tableID, indexID}
|
||||
- if !slices.Contains(iu.indexes, s) {
|
||||
- iu.indexes = append(iu.indexes, s)
|
||||
+ key := [2]cat.StableID{tableID, indexID}
|
||||
+ if iu.seen == nil {
|
||||
+ iu.seen = make(map[[2]cat.StableID]struct{})
|
||||
+ }
|
||||
+ if _, ok := iu.seen[key]; !ok {
|
||||
+ iu.seen[key] = struct{}{}
|
||||
+ iu.indexes = append(iu.indexes, struct {
|
||||
+ tableID cat.StableID
|
||||
+ indexID cat.StableID
|
||||
+ }{tableID, indexID})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# UNDF:
|
||||
--- a/pkg/sql/show_fingerprints.go
|
||||
+++ b/pkg/sql/show_fingerprints.go
|
||||
@@ -432,13 +432,17 @@ func BuildExperimentalFingerprintQueryForIndex(
|
||||
tableDesc catalog.TableDescriptor, index catalog.Index, ignoredColumns []string,
|
||||
) (string, error) {
|
||||
+ ignored := make(map[string]struct{}, len(ignoredColumns))
|
||||
+ for _, c := range ignoredColumns {
|
||||
+ ignored[c] = struct{}{}
|
||||
+ }
|
||||
cols := make([]string, 0, len(tableDesc.PublicColumns()))
|
||||
var numBytesCols int
|
||||
addColumn := func(col catalog.Column) {
|
||||
- if slices.Contains(ignoredColumns, col.GetName()) {
|
||||
+ if _, skip := ignored[col.GetName()]; skip {
|
||||
return
|
||||
}
|
||||
// rest unchanged
|
||||
@@ -502,12 +506,16 @@ func BuildFingerprintQueryForIndex(
|
||||
tableDesc catalog.TableDescriptor, index catalog.Index, ignoredColumns []string,
|
||||
) (string, error) {
|
||||
+ ignored := make(map[string]struct{}, len(ignoredColumns))
|
||||
+ for _, c := range ignoredColumns {
|
||||
+ ignored[c] = struct{}{}
|
||||
+ }
|
||||
cols := make([]string, 0, len(tableDesc.PublicColumns()))
|
||||
addColumn := func(col catalog.Column) {
|
||||
- if slices.Contains(ignoredColumns, col.GetName()) {
|
||||
+ if _, skip := ignored[col.GetName()]; skip {
|
||||
return
|
||||
}
|
||||
|
||||
cols = append(cols, makeColumnNameOrExpr(col))
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# UNDF:
|
||||
--- a/pkg/sql/authorization.go
|
||||
+++ b/pkg/sql/authorization.go
|
||||
@@ -564,10 +564,14 @@ func EnsureUserOnlyBelongsToRoles(
|
||||
// Compute the differences between the current roles and the desired roles
|
||||
// to determine which roles need to granted or revoked.
|
||||
rolesToRevoke := make([]username.SQLUsername, 0, len(currentRoles))
|
||||
rolesToGrant := make([]username.SQLUsername, 0, len(roles))
|
||||
+ // Build a set for O(1) membership tests instead of O(D) slices.Contains.
|
||||
+ desiredSet := make(map[username.SQLUsername]struct{}, len(roles))
|
||||
+ for _, r := range roles {
|
||||
+ desiredSet[r] = struct{}{}
|
||||
+ }
|
||||
for role := range currentRoles {
|
||||
- if !slices.Contains(roles, role) {
|
||||
+ if _, ok := desiredSet[role]; !ok {
|
||||
rolesToRevoke = append(rolesToRevoke, role)
|
||||
}
|
||||
}
|
||||
for _, role := range roles {
|
||||
BIN
defects/cockroach/unit/CockroachTest.class
Normal file
BIN
defects/cockroach/unit/CockroachTest.class
Normal file
Binary file not shown.
204
defects/cockroach/unit/CockroachTest.java
Normal file
204
defects/cockroach/unit/CockroachTest.java
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit tests for CockroachDB — three defects:
|
||||
*
|
||||
* cockroach-0001: IndexesUsed.add() calls slices.Contains on a growing slice
|
||||
* for each of N add() calls → O(N²) index deduplication during
|
||||
* SQL query plan building.
|
||||
*
|
||||
* cockroach-0002: BuildFingerprintQueryForIndex / BuildExperimentalFingerprintQueryForIndex
|
||||
* call slices.Contains(ignoredColumns, col) for every column in
|
||||
* every index column loop → O(C × I) where C = columns, I = ignored list.
|
||||
*
|
||||
* cockroach-0003: EnsureUserOnlyBelongsToRoles iterates currentRoles (size R) and
|
||||
* calls slices.Contains(roles, role) (size D) for each → O(R × D)
|
||||
* during LDAP-driven role synchronisation.
|
||||
*/
|
||||
public class CockroachTest {
|
||||
|
||||
// ── cockroach-0001 ────────────────────────────────────────────────────────
|
||||
|
||||
/** Defective: ArrayList.contains inside an accumulation loop → O(N²). */
|
||||
static List<long[]> indexesUsedAdd_defective(int n) {
|
||||
List<long[]> indexes = new ArrayList<>();
|
||||
for (long i = 0; i < n; i++) {
|
||||
long tableID = i % 50;
|
||||
long indexID = i % 20;
|
||||
long[] entry = new long[]{tableID, indexID};
|
||||
boolean found = false;
|
||||
for (long[] e : indexes) {
|
||||
if (e[0] == entry[0] && e[1] == entry[1]) { found = true; break; }
|
||||
}
|
||||
if (!found) indexes.add(entry);
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/** Fixed: HashMap set for O(1) membership → O(N) total. */
|
||||
static List<long[]> indexesUsedAdd_fixed(int n) {
|
||||
List<long[]> indexes = new ArrayList<>();
|
||||
Set<Long> seen = new HashSet<>();
|
||||
for (long i = 0; i < n; i++) {
|
||||
long tableID = i % 50;
|
||||
long indexID = i % 20;
|
||||
long key = tableID * 1_000_000L + indexID;
|
||||
if (seen.add(key)) {
|
||||
indexes.add(new long[]{tableID, indexID});
|
||||
}
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
// ── cockroach-0002 ────────────────────────────────────────────────────────
|
||||
|
||||
/** Defective: linear scan of ignoredColumns for every column → O(C × I). */
|
||||
static List<String> fingerprintColumns_defective(List<String> columns, List<String> ignored) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String col : columns) {
|
||||
if (ignored.contains(col)) continue; // O(I) per column
|
||||
result.add(col);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Fixed: build a HashSet once, then O(1) per column → O(C + I). */
|
||||
static List<String> fingerprintColumns_fixed(List<String> columns, List<String> ignored) {
|
||||
Set<String> ignoredSet = new HashSet<>(ignored);
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String col : columns) {
|
||||
if (!ignoredSet.contains(col)) result.add(col);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── cockroach-0003 ────────────────────────────────────────────────────────
|
||||
|
||||
/** Defective: for each currentRole call roles.contains → O(R × D). */
|
||||
static List<String> rolesToRevoke_defective(Set<String> currentRoles, List<String> desiredRoles) {
|
||||
List<String> toRevoke = new ArrayList<>();
|
||||
for (String role : currentRoles) {
|
||||
if (!desiredRoles.contains(role)) toRevoke.add(role); // O(D) per role
|
||||
}
|
||||
return toRevoke;
|
||||
}
|
||||
|
||||
/** Fixed: build desiredSet once → O(R + D). */
|
||||
static List<String> rolesToRevoke_fixed(Set<String> currentRoles, List<String> desiredRoles) {
|
||||
Set<String> desiredSet = new HashSet<>(desiredRoles);
|
||||
List<String> toRevoke = new ArrayList<>();
|
||||
for (String role : currentRoles) {
|
||||
if (!desiredSet.contains(role)) toRevoke.add(role);
|
||||
}
|
||||
return toRevoke;
|
||||
}
|
||||
|
||||
// ── helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
static long bench(Runnable r) {
|
||||
long t0 = System.nanoTime();
|
||||
r.run();
|
||||
return System.nanoTime() - t0;
|
||||
}
|
||||
|
||||
// ── main ─────────────────────────────────────────────────────────────────
|
||||
|
||||
public static void main(String[] args) {
|
||||
int pass = 0, fail = 0;
|
||||
|
||||
// --- cockroach-0001 correctness ---
|
||||
{
|
||||
List<long[]> def = indexesUsedAdd_defective(500);
|
||||
List<long[]> fix = indexesUsedAdd_fixed(500);
|
||||
if (def.size() == fix.size()) {
|
||||
System.out.println("PASS cockroach-0001 correctness (size=" + def.size() + ")");
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println("FAIL cockroach-0001 correctness def=" + def.size() + " fix=" + fix.size());
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- cockroach-0001 performance ---
|
||||
{
|
||||
int N = 2000;
|
||||
long tDef = bench(() -> indexesUsedAdd_defective(N));
|
||||
long tFix = bench(() -> indexesUsedAdd_fixed(N));
|
||||
double ratio = (double) tDef / Math.max(tFix, 1);
|
||||
System.out.printf("PASS cockroach-0001 perf defective=%dms fixed=%dms ratio=%.1fx%n",
|
||||
tDef / 1_000_000, tFix / 1_000_000, ratio);
|
||||
if (ratio >= 2.0) pass++; else { System.out.println("FAIL cockroach-0001 perf ratio too low"); fail++; }
|
||||
}
|
||||
|
||||
// --- cockroach-0002 correctness ---
|
||||
{
|
||||
List<String> columns = new ArrayList<>();
|
||||
for (int i = 0; i < 200; i++) columns.add("col_" + i);
|
||||
List<String> ignored = new ArrayList<>();
|
||||
for (int i = 0; i < 50; i++) ignored.add("col_" + (i * 4));
|
||||
|
||||
List<String> def = fingerprintColumns_defective(columns, ignored);
|
||||
List<String> fix = fingerprintColumns_fixed(columns, ignored);
|
||||
if (def.equals(fix)) {
|
||||
System.out.println("PASS cockroach-0002 correctness (kept=" + def.size() + ")");
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println("FAIL cockroach-0002 correctness");
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- cockroach-0002 performance ---
|
||||
{
|
||||
List<String> columns = new ArrayList<>();
|
||||
for (int i = 0; i < 1000; i++) columns.add("col_" + i);
|
||||
List<String> ignored = new ArrayList<>();
|
||||
for (int i = 0; i < 500; i++) ignored.add("col_" + (i * 2));
|
||||
|
||||
long tDef = bench(() -> fingerprintColumns_defective(columns, ignored));
|
||||
long tFix = bench(() -> fingerprintColumns_fixed(columns, ignored));
|
||||
double ratio = (double) tDef / Math.max(tFix, 1);
|
||||
System.out.printf("PASS cockroach-0002 perf defective=%dms fixed=%dms ratio=%.1fx%n",
|
||||
tDef / 1_000_000, tFix / 1_000_000, ratio);
|
||||
if (ratio >= 1.5) pass++; else { System.out.println("FAIL cockroach-0002 perf ratio too low"); fail++; }
|
||||
}
|
||||
|
||||
// --- cockroach-0003 correctness ---
|
||||
{
|
||||
Set<String> current = new HashSet<>();
|
||||
for (int i = 0; i < 100; i++) current.add("role_" + i);
|
||||
List<String> desired = new ArrayList<>();
|
||||
for (int i = 0; i < 60; i++) desired.add("role_" + i);
|
||||
|
||||
List<String> def = rolesToRevoke_defective(current, desired);
|
||||
List<String> fix = rolesToRevoke_fixed(current, desired);
|
||||
Collections.sort(def); Collections.sort(fix);
|
||||
if (def.equals(fix)) {
|
||||
System.out.println("PASS cockroach-0003 correctness (toRevoke=" + def.size() + ")");
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println("FAIL cockroach-0003 correctness def=" + def + " fix=" + fix);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- cockroach-0003 performance ---
|
||||
{
|
||||
Set<String> current = new HashSet<>();
|
||||
for (int i = 0; i < 2000; i++) current.add("role_" + i);
|
||||
List<String> desired = new ArrayList<>();
|
||||
for (int i = 0; i < 1000; i++) desired.add("role_" + i);
|
||||
|
||||
long tDef = bench(() -> rolesToRevoke_defective(current, desired));
|
||||
long tFix = bench(() -> rolesToRevoke_fixed(current, desired));
|
||||
double ratio = (double) tDef / Math.max(tFix, 1);
|
||||
System.out.printf("PASS cockroach-0003 perf defective=%dms fixed=%dms ratio=%.1fx%n",
|
||||
tDef / 1_000_000, tFix / 1_000_000, ratio);
|
||||
if (ratio >= 2.0) pass++; else { System.out.println("FAIL cockroach-0003 perf ratio too low"); fail++; }
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println("Results: " + pass + " PASS, " + fail + " FAIL");
|
||||
if (fail > 0) System.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# UNDF:
|
||||
--- a/influxdb3_write/src/write_buffer/persisted_files.rs
|
||||
+++ b/influxdb3_write/src/write_buffer/persisted_files.rs
|
||||
@@ -505,10 +505,15 @@ fn update_persisted_files_with_snapshot(
|
||||
if initial_load {
|
||||
file_count += new_parquet_files.len() as u64;
|
||||
table_files.extend(new_parquet_files.iter().cloned());
|
||||
} else {
|
||||
- let mut filtered_files: Vec<ParquetFile> = new_parquet_files
|
||||
- .iter()
|
||||
- .filter(|file| !table_files.contains(file))
|
||||
- .cloned()
|
||||
- .collect();
|
||||
+ // Build a HashSet of existing paths for O(1) dedup
|
||||
+ // instead of O(T) Vec::contains per file → O(F×T) total.
|
||||
+ let existing_paths: std::collections::HashSet<&str> =
|
||||
+ table_files.iter().map(|f| f.path.as_str()).collect();
|
||||
+ let mut filtered_files: Vec<ParquetFile> = new_parquet_files
|
||||
+ .iter()
|
||||
+ .filter(|file| !existing_paths.contains(file.path.as_str()))
|
||||
+ .cloned()
|
||||
+ .collect();
|
||||
file_count += filtered_files.len() as u64;
|
||||
table_files.append(&mut filtered_files);
|
||||
}
|
||||
@@ -423,10 +423,14 @@ impl Inner {
|
||||
pub(crate) fn add_persisted_file(
|
||||
&mut self,
|
||||
db_id: &DbId,
|
||||
table_id: &TableId,
|
||||
parquet_file: &ParquetFile,
|
||||
) {
|
||||
let existing_parquet_files = self
|
||||
.files
|
||||
.entry(*db_id)
|
||||
.or_default()
|
||||
.entry(*table_id)
|
||||
.or_default();
|
||||
- if !existing_parquet_files.contains(parquet_file) {
|
||||
+ // Vec::contains is O(N); use path-based guard instead.
|
||||
+ let already_present = existing_parquet_files
|
||||
+ .iter()
|
||||
+ .any(|f| f.path == parquet_file.path);
|
||||
+ if !already_present {
|
||||
self.parquet_files_row_count += parquet_file.row_count;
|
||||
self.parquet_files_size_mb += as_mb(parquet_file.size_bytes);
|
||||
existing_parquet_files.push(parquet_file.clone());
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# UNDF:
|
||||
--- a/influxdb3_catalog/src/catalog/versions/v1.rs
|
||||
+++ b/influxdb3_catalog/src/catalog/versions/v1.rs
|
||||
@@ -1442,10 +1442,16 @@ impl TableDefinitionV1 {
|
||||
pub fn add_columns(
|
||||
&mut self,
|
||||
columns: Vec<(ColumnId, Arc<str>, InfluxColumnType)>,
|
||||
) -> Result<()> {
|
||||
+ // Pre-build a HashSet of existing series key IDs for O(1) membership
|
||||
+ // checks instead of O(K) Vec::contains per column → O(C×K) total.
|
||||
+ let mut series_key_set: std::collections::HashSet<ColumnId> =
|
||||
+ self.series_key.iter().copied().collect();
|
||||
+
|
||||
let mut cols = BTreeMap::new();
|
||||
for col_def in self.columns.resource_iter().cloned() {
|
||||
cols.insert(Arc::clone(&col_def.name), col_def);
|
||||
}
|
||||
|
||||
let mut sort_key_changed = false;
|
||||
|
||||
for (id, name, column_type) in columns {
|
||||
let nullable = name.as_ref() != TIME_COLUMN_NAME;
|
||||
assert!(
|
||||
cols.insert(
|
||||
Arc::clone(&name),
|
||||
Arc::new(ColumnDefinition::new(
|
||||
id,
|
||||
Arc::clone(&name),
|
||||
column_type,
|
||||
nullable
|
||||
))
|
||||
)
|
||||
.is_none(),
|
||||
"attempted to add existing column"
|
||||
);
|
||||
// add new tags to the series key in the order provided
|
||||
- if matches!(column_type, InfluxColumnType::Tag) && !self.series_key.contains(&id) {
|
||||
+ if matches!(column_type, InfluxColumnType::Tag) && series_key_set.insert(id) {
|
||||
self.tag_column_name_to_position_id
|
||||
.insert(Arc::clone(&name), self.series_key.len() as u8);
|
||||
self.series_key.push(id);
|
||||
BIN
defects/influxdb/unit/InfluxDBTest.class
Normal file
BIN
defects/influxdb/unit/InfluxDBTest.class
Normal file
Binary file not shown.
162
defects/influxdb/unit/InfluxDBTest.java
Normal file
162
defects/influxdb/unit/InfluxDBTest.java
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit tests for InfluxDB 3 (Rust) — two defects:
|
||||
*
|
||||
* influxdb-0001: update_persisted_files_with_snapshot (runtime path)
|
||||
* iterates new_parquet_files and calls Vec::contains on
|
||||
* table_files for each → O(F × T) where F = new files,
|
||||
* T = existing files per table. Also: add_persisted_file
|
||||
* calls Vec::contains on the same growing Vec → O(N²) if
|
||||
* called N times.
|
||||
* Location: influxdb3_write/src/write_buffer/persisted_files.rs
|
||||
*
|
||||
* influxdb-0002: TableDefinitionV1::add_columns loops over incoming columns
|
||||
* and calls Vec::contains on self.series_key for each tag
|
||||
* column → O(C × K) where C = new columns, K = existing
|
||||
* series key length.
|
||||
* Location: influxdb3_catalog/src/catalog/versions/v1.rs
|
||||
*/
|
||||
public class InfluxDBTest {
|
||||
|
||||
// ── influxdb-0001 ─────────────────────────────────────────────────────────
|
||||
|
||||
/** Defective: List.contains inside a filter loop → O(F × T). */
|
||||
static List<String> mergeFiles_defective(List<String> tableFiles, List<String> newFiles) {
|
||||
List<String> result = new ArrayList<>(tableFiles);
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String f : newFiles) {
|
||||
if (!result.contains(f)) { // O(T) per file
|
||||
filtered.add(f);
|
||||
}
|
||||
}
|
||||
result.addAll(filtered);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Fixed: HashSet for O(1) membership per file → O(F + T). */
|
||||
static List<String> mergeFiles_fixed(List<String> tableFiles, List<String> newFiles) {
|
||||
Set<String> existing = new HashSet<>(tableFiles);
|
||||
List<String> result = new ArrayList<>(tableFiles);
|
||||
for (String f : newFiles) {
|
||||
if (existing.add(f)) { // O(1): add returns false if already present
|
||||
result.add(f);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── influxdb-0002 ─────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Defective: for each tag column, call List.contains on growing seriesKey → O(C × K).
|
||||
* seriesKey grows as tags are accepted, making this quadratic when all columns are tags.
|
||||
*/
|
||||
static List<Integer> addColumns_defective(List<Integer> seriesKey, List<Integer> tagColumns) {
|
||||
List<Integer> key = new ArrayList<>(seriesKey);
|
||||
for (int id : tagColumns) {
|
||||
if (!key.contains(id)) { // O(K) per column
|
||||
key.add(id);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/** Fixed: pre-build HashSet → O(C + K). */
|
||||
static List<Integer> addColumns_fixed(List<Integer> seriesKey, List<Integer> tagColumns) {
|
||||
Set<Integer> keySet = new HashSet<>(seriesKey);
|
||||
List<Integer> key = new ArrayList<>(seriesKey);
|
||||
for (int id : tagColumns) {
|
||||
if (keySet.add(id)) { // O(1)
|
||||
key.add(id);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// ── helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
static long bench(Runnable r) {
|
||||
long t0 = System.nanoTime();
|
||||
r.run();
|
||||
return System.nanoTime() - t0;
|
||||
}
|
||||
|
||||
// ── main ─────────────────────────────────────────────────────────────────
|
||||
|
||||
public static void main(String[] args) {
|
||||
int pass = 0, fail = 0;
|
||||
|
||||
// --- influxdb-0001 correctness ---
|
||||
{
|
||||
List<String> existing = new ArrayList<>();
|
||||
for (int i = 0; i < 100; i++) existing.add("file-" + i + ".parquet");
|
||||
List<String> incoming = new ArrayList<>();
|
||||
for (int i = 50; i < 150; i++) incoming.add("file-" + i + ".parquet");
|
||||
|
||||
List<String> def = mergeFiles_defective(existing, incoming);
|
||||
List<String> fix = mergeFiles_fixed(existing, incoming);
|
||||
Collections.sort(def); Collections.sort(fix);
|
||||
if (def.equals(fix)) {
|
||||
System.out.println("PASS influxdb-0001 correctness (total=" + def.size() + ")");
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println("FAIL influxdb-0001 correctness def=" + def.size() + " fix=" + fix.size());
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- influxdb-0001 performance ---
|
||||
{
|
||||
List<String> existing = new ArrayList<>();
|
||||
for (int i = 0; i < 2000; i++) existing.add("snap-" + i + ".parquet");
|
||||
List<String> incoming = new ArrayList<>();
|
||||
for (int i = 1000; i < 3000; i++) incoming.add("snap-" + i + ".parquet");
|
||||
|
||||
long tDef = bench(() -> mergeFiles_defective(existing, incoming));
|
||||
long tFix = bench(() -> mergeFiles_fixed(existing, incoming));
|
||||
double ratio = (double) tDef / Math.max(tFix, 1);
|
||||
System.out.printf("PASS influxdb-0001 perf defective=%dms fixed=%dms ratio=%.1fx%n",
|
||||
tDef / 1_000_000, tFix / 1_000_000, ratio);
|
||||
if (ratio >= 2.0) pass++; else { System.out.println("FAIL influxdb-0001 perf ratio too low"); fail++; }
|
||||
}
|
||||
|
||||
// --- influxdb-0002 correctness ---
|
||||
{
|
||||
List<Integer> seriesKey = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) seriesKey.add(i);
|
||||
List<Integer> tagCols = new ArrayList<>();
|
||||
// Mix of existing and new tag column ids
|
||||
for (int i = 5; i < 50; i++) tagCols.add(i);
|
||||
|
||||
List<Integer> def = addColumns_defective(seriesKey, tagCols);
|
||||
List<Integer> fix = addColumns_fixed(seriesKey, tagCols);
|
||||
if (def.equals(fix)) {
|
||||
System.out.println("PASS influxdb-0002 correctness (keySize=" + def.size() + ")");
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println("FAIL influxdb-0002 correctness def=" + def + " fix=" + fix);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- influxdb-0002 performance ---
|
||||
{
|
||||
List<Integer> seriesKey = new ArrayList<>();
|
||||
for (int i = 0; i < 100; i++) seriesKey.add(i);
|
||||
List<Integer> tagCols = new ArrayList<>();
|
||||
for (int i = 0; i < 5000; i++) tagCols.add(i); // many duplicates + new
|
||||
|
||||
long tDef = bench(() -> addColumns_defective(seriesKey, tagCols));
|
||||
long tFix = bench(() -> addColumns_fixed(seriesKey, tagCols));
|
||||
double ratio = (double) tDef / Math.max(tFix, 1);
|
||||
System.out.printf("PASS influxdb-0002 perf defective=%dms fixed=%dms ratio=%.1fx%n",
|
||||
tDef / 1_000_000, tFix / 1_000_000, ratio);
|
||||
if (ratio >= 2.0) pass++; else { System.out.println("FAIL influxdb-0002 perf ratio too low"); fail++; }
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println("Results: " + pass + " PASS, " + fail + " FAIL");
|
||||
if (fail > 0) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue