Files
upstream-mirror 89f5be005d
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 03:23:42 +05:00

245 lines
9.8 KiB
Python

#!/usr/bin/env python3
"""Drive the SeaweedFS Lance Namespace with LanceDB.
The existing client test uses `lance_namespace` and `pylance` directly, which is
the protocol's reference client. LanceDB is what people actually point at a
catalog: it connects with `connect_namespace("rest", ...)`, lists what is there,
opens a table and searches it. This checks the catalog against that path, the
way the Spark, Trino and ClickHouse suites check the Iceberg one.
Everything it prints is either "PASS" or a line starting with FAIL, so the Go
harness can report the first real failure rather than a stack trace.
"""
import argparse
import sys
import warnings
warnings.filterwarnings("ignore")
import lance
import lance_namespace as ln
import lancedb
import pyarrow as pa
DIM = 8
def sample_rows(count):
"""A vector table, which is the only kind worth putting in Lance."""
return pa.table(
{
"id": pa.array(list(range(count)), type=pa.int64()),
"title": pa.array([f"row-{i}" for i in range(count)]),
"vector": pa.array(
[[float(i) + d for d in range(DIM)] for i in range(count)],
type=pa.list_(pa.float32(), DIM),
),
}
)
def seed_table(namespace_url, storage, bucket, namespace, table, rows):
"""Declares a table through the namespace and writes a dataset into it.
LanceDB reads through the catalog; the writing half is pylance, because the
namespace records where a table lives and does not carry its data.
"""
ns = ln.connect("rest", {"uri": namespace_url})
ns.create_namespace(
ln.CreateNamespaceRequest(id=[bucket], mode="EXIST_OK")
)
ns.create_namespace(
ln.CreateNamespaceRequest(id=[bucket, namespace], mode="EXIST_OK")
)
table_id = [bucket, namespace, table]
declared = ns.declare_table(ln.DeclareTableRequest(id=table_id))
lance.write_dataset(
sample_rows(rows), declared.location, storage_options=storage, mode="overwrite"
)
print(f"seeded {rows} rows at {declared.location}")
return declared.location
def check(condition, message):
if not condition:
print(f"FAIL: {message}", file=sys.stderr)
raise SystemExit(1)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--namespace-url", required=True)
parser.add_argument("--s3-endpoint", required=True)
parser.add_argument("--bucket", required=True)
parser.add_argument("--namespace", default="ml")
parser.add_argument("--table", default="embeddings")
# Enough rows for an IVF_PQ index to be worth building, which is the point
# of step 4: without one, a search is a brute-force scan.
parser.add_argument("--rows", type=int, default=1024)
parser.add_argument("--access-key", default="any")
parser.add_argument("--secret-key", default="any")
args = parser.parse_args()
# The namespace vends an endpoint correct for its own host; a container
# reaches the same gateway by another name, so the endpoint is overridden
# here and the credentials filled in for a deployment without STS.
storage = {
"aws_endpoint": args.s3_endpoint,
"allow_http": "true",
"aws_access_key_id": args.access_key,
"aws_secret_access_key": args.secret_key,
"aws_region": "us-east-1",
}
location = seed_table(
args.namespace_url, storage, args.bucket, args.namespace, args.table, args.rows
)
print(f"lancedb {lancedb.__version__} connecting to {args.namespace_url}")
db = lancedb.connect_namespace(
"rest", {"uri": args.namespace_url}, storage_options=storage
)
# 1. The catalog is browsable: the bucket is a namespace, and the table is
# in it under the name the namespace gave it.
tables = list(db.table_names(namespace_path=[args.bucket, args.namespace], limit=100))
print(f"table_names -> {tables}")
check(
any(args.table in name for name in tables),
f"{args.table} is not listed in {tables}",
)
# 2. Opening it goes through the catalog: LanceDB asks the namespace where
# the table is and reads it from there.
# storage_options is passed per call as well as on the connection: what the
# namespace vends for a table is merged in, and a deployment without STS
# vends no credentials, which is what the client would otherwise be left with.
table = db.open_table(
args.table,
namespace_path=[args.bucket, args.namespace],
storage_options=storage,
)
count = table.count_rows()
print(f"open_table -> {count} rows")
check(count == args.rows, f"read {count} rows, want {args.rows}")
# 3. The schema survived the round trip, vector column included. This is the
# part a catalog that only records a location cannot fake.
names = table.schema.names
print(f"schema -> {names}")
check("vector" in names and "title" in names, f"schema lost columns: {names}")
# 4. Build a vector index, then search it. Both halves matter: an index
# writes files into a directory of the table the S3 door has to admit -
# the layout guard has refused a Lance directory before - and without one
# a search is a brute-force scan that proves nothing about the index path
# the maintenance worker exists to keep in shape.
table.create_index(
metric="l2",
vector_column_name="vector",
index_type="IVF_PQ",
num_partitions=1,
num_sub_vectors=4,
)
indices = table.list_indices()
print(f"create_index -> {indices}")
check(len(indices) >= 1, "no index was created")
# Vectors are laid out so that id N sits near id N+1, so a query built from
# id 1 should come back with its neighbourhood. The assertion is a
# neighbourhood and not an exact id: an IVF_PQ index quantizes, so the
# nearest hit is approximate by construction - with this data it answers 0
# as readily as 1, and both are right.
query = [float(1) + d for d in range(DIM)]
hits = table.search(query).limit(3).to_list()
ids = [hit["id"] for hit in hits]
print(f"search -> {ids}")
check(len(hits) == 3, f"search returned {len(hits)} hits, want 3")
check(
all(i <= 5 for i in ids),
f"search returned {ids}, which is not the neighbourhood of the query",
)
# 5. A filtered scan, so it is not only the ANN path that works.
filtered = table.search().where("id < 5").limit(10).to_list()
print(f"filtered scan -> {len(filtered)} rows")
check(len(filtered) == 5, f"filter returned {len(filtered)} rows, want 5")
# 6. Creating a table. By default LanceDB declares it through the namespace
# and writes the data itself, which is exactly the split this catalog
# serves, so this has to work.
created = db.create_table(
"created_by_lancedb",
data=sample_rows(4),
namespace_path=[args.bucket, args.namespace],
storage_options=storage,
)
check(created.count_rows() == 4, "create_table wrote the wrong number of rows")
listed = list(db.table_names(namespace_path=[args.bucket, args.namespace], limit=100))
check(
any("created_by_lancedb" in name for name in listed),
f"a table created through LanceDB is not listed: {listed}",
)
print(f"create_table -> {created.count_rows()} rows, listed by the catalog")
# 7. The same creation with server-side pushdown, which asks the namespace
# to run CreateTable itself. That operation carries Arrow data and this
# catalog answers the spec's Unsupported for it. What matters is that the
# client is left with something coherent either way - it falls back to
# declare-and-write - rather than a hang, a 404, or a half-made table.
pushdown = lancedb.connect_namespace(
"rest",
{"uri": args.namespace_url},
storage_options=storage,
namespace_client_pushdown_operations=["CreateTable"],
)
pushed_error = None
try:
pushdown.create_table(
"pushed_by_lancedb",
data=sample_rows(2),
namespace_path=[args.bucket, args.namespace],
storage_options=storage,
)
except Exception as err: # noqa: BLE001 - the point is what the client sees
pushed_error = err
after = list(db.table_names(namespace_path=[args.bucket, args.namespace], limit=100))
landed = any("pushed_by_lancedb" in name for name in after)
print(f"create_table with pushdown: error={pushed_error!r}, catalog has it={landed}")
if pushed_error is None:
# The client fell back to declare-and-write, so the table is real and
# has to be readable and complete.
check(landed, "create_table reported success but the catalog has no table")
rows = db.open_table(
"pushed_by_lancedb",
namespace_path=[args.bucket, args.namespace],
storage_options=storage,
).count_rows()
check(rows == 2, f"the pushed table holds {rows} rows, want 2")
else:
# Refused, which is what this catalog answers for a data-plane
# operation. It has to be that refusal and not some other failure, and
# it must not have left a half-made table behind.
message = str(pushed_error).lower()
check(
"unsupported" in message or "501" in message or "not implemented" in message,
f"pushdown failed for an unexpected reason: {pushed_error}",
)
check(not landed, "a refused create left a table behind in the catalog")
# 8. And the dataset is still readable straight off its URI, which is what
# keeps the catalog optional.
direct = lance.dataset(location, storage_options=storage).count_rows()
check(direct == args.rows, f"direct read got {direct} rows, want {args.rows}")
print(f"direct read without the catalog -> {direct} rows")
print("PASS")
return 0
if __name__ == "__main__":
sys.exit(main())