Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/compiler/src/writers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ const DUCKDB_TEMP_DIRECTORY = join(tmpdir(), "openislands-duckdb");
* /app owned by root in the Docker image: "IO Error: Failed to create directory .tmp").
*/
export function createInMemoryDuckDB(): Promise<InstanceType<typeof DuckDBInstance>> {
return DuckDBInstance.create(":memory:", { temp_directory: DUCKDB_TEMP_DIRECTORY });
return DuckDBInstance.create(":memory:", {
temp_directory: DUCKDB_TEMP_DIRECTORY,
// ponytail: DuckDB caps memory_limit to the cgroup (~80%) but scales threads to HOST cores,
// ignoring the CPU cgroup — 12 threads on an 819 MiB cap OOM at boot ("failed to pin block")
// at ~68 MiB/thread. 4 keeps >125 MiB/thread (DuckDB's floor) and clamps to core count on
// smaller boxes. Raise only for a big-data deployment that also has the RAM for it.
threads: "4",
});
}

/** Where a dataset's rows physically live: its content source, plus the table name when that source is a SQLite database. */
Expand Down
22 changes: 21 additions & 1 deletion packages/compiler/test/writers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { LocalContentStore } from "@openislands/storage";
import { resolveWriter } from "../src/writers.js";
import { createInMemoryDuckDB, resolveWriter } from "../src/writers.js";

function tempDir(): string {
const dir = mkdtempSync(join(tmpdir(), "oi-writers-"));
Expand Down Expand Up @@ -44,3 +44,23 @@ describe("appendLines EOL preservation", () => {
expect(content).not.toContain("\r");
});
});

describe("createInMemoryDuckDB resource bounds", () => {
// Guards the container OOM fix: an unbounded thread count over a cgroup-capped memory_limit
// fails to pin buffers at boot, and a default temp_directory spills to a non-writable cwd.
it("caps threads and sets a writable temp_directory", async () => {
const instance = await createInMemoryDuckDB();
const conn = await instance.connect();
try {
const reader = await conn.runAndReadAll(
"SELECT current_setting('threads') AS threads, current_setting('temp_directory') AS temp_directory",
);
const [row] = reader.getRowObjects();
expect(Number(row.threads)).toBe(4);
expect(String(row.temp_directory)).toContain("openislands-duckdb");
} finally {
conn.closeSync();
instance.closeSync();
}
});
});
Loading