IceLog is a Go + gRPC metadata control plane for lakehouse-style table catalogs. It tracks table schemas, partition files, immutable snapshots, and lightweight transaction state in PostgreSQL, then serves that metadata through a typed gRPC API.
Built to demonstrate backend systems work: concurrency control, snapshot isolation concepts, cache invalidation, durable metadata storage, Dockerized local development, and CI-backed tests.
- gRPC metadata service with protobuf-generated Go clients and server stubs.
- PostgreSQL-backed catalog for tables, schemas, snapshots, partitions, and transactions.
- Immutable snapshot commits with stale-parent conflict detection.
- Point-in-time partition reads by snapshot ID.
- Per-table shared/exclusive locking for concurrent metadata access.
- In-memory LRU cache for hot partition metadata, with invalidation on writes.
- Unit and integration tests, including cache behavior, MVCC lifecycle, schema validation, pagination, and stale snapshot conflicts.
- Docker Compose setup for local PostgreSQL plus GitHub Actions for unit tests, integration tests, and Docker image build.
gRPC clients
|
v
internal/server Request validation, response mapping, MetadataService
|
v
internal/catalog Table lifecycle, schema evolution, snapshots, partitions
|
+--> internal/transaction Active transactions, pinned snapshots, MVCC checks
+--> internal/cache Generic LRU cache for partition metadata
+--> internal/lock Per-table read/write locks
|
v
internal/db PostgreSQL persistence layer
PostgreSQL stores:
tables: table definitions, schema JSON, properties, current snapshot pointerschema_history: versioned schema changessnapshots: immutable snapshot recordspartitions: file-level partition metadata and visibility windowstransactions: transaction lifecycle and read snapshot tracking
Read path
- Resolve the requested snapshot, or use the current table snapshot.
- Check the partition cache for
table:snapshot. - On cache miss, load visible partitions from PostgreSQL.
- Return file paths, row counts, sizes, schema, and table properties.
Write path
- Acquire the table's exclusive metadata lock.
- Validate that the request's parent snapshot is still current.
- Insert a new immutable snapshot and partition changes in one DB transaction.
- Move the table's current snapshot pointer.
- Invalidate cached partition metadata for that table.
The protobuf service is defined in proto/metadata_service.proto.
Main RPC groups:
- Tables:
CreateTable,GetTableMetadata,AlterTable,DropTable,ListTables - Partitions:
GetPartitions,GetPartitionStats - Snapshots:
CommitSnapshot,GetSnapshot,ListSnapshots - Transactions:
BeginTransaction,CommitTransaction,AbortTransaction
cmd/server/ Server entrypoint
internal/server/ gRPC service implementation
internal/catalog/ Catalog, schema, snapshot, and partition logic
internal/transaction/ MVCC and transaction state
internal/db/ PostgreSQL client and models
internal/cache/ Generic LRU cache
internal/lock/ Per-table lock manager
proto/ Protobuf definitions
gen/metadata/ Generated protobuf/gRPC code
tests/ PostgreSQL-backed integration tests
scripts/ DB init SQL and grpcurl payloads
Run PostgreSQL and the gRPC server:
docker compose up --buildThe server listens on:
127.0.0.1:50051
Run only PostgreSQL, then start the server locally:
docker compose up -d --wait postgres
make runEquivalent PowerShell setup:
$env:PG_CONN_STRING="host=127.0.0.1 port=5432 dbname=metadata user=metadata_user password=metadata_pass"
go run ./cmd/serverUnit tests:
make test-unitIntegration tests:
make test-integrationAll tests:
make testWithout Make:
go test -v ./cmd/... ./gen/... ./internal/...
docker compose up -d --wait postgres
go test -v ./testsReflection is enabled:
grpcurl -plaintext 127.0.0.1:50051 list metadata.MetadataServiceCreate a table:
grpcurl -plaintext -d @ 127.0.0.1:50051 metadata.MetadataService/CreateTable < scripts/grpc/create_table.jsonCommit a snapshot:
grpcurl -plaintext -d @ 127.0.0.1:50051 metadata.MetadataService/CommitSnapshot < scripts/grpc/commit_snapshot.jsonRead partition metadata:
grpcurl -plaintext -d @ 127.0.0.1:50051 metadata.MetadataService/GetPartitions < scripts/grpc/get_partitions.jsonMore request payloads are available in scripts/grpc.
Generate protobuf code:
make protoRun the server locally:
make runTidy dependencies:
make tidy- Partition spec evolution is intentionally not implemented yet.
- Transactions are lightweight metadata transactions, not a distributed transaction protocol.
ListTablescomputes visible partition counts per table and can be batch-optimized later.