Skip to content

Conversation

@mlwelles
Copy link
Contributor

@mlwelles mlwelles commented Jan 25, 2026

DO NOT MERGE

POC/Experiment for review / discussion purposes only.

This is a proof-of-concept implementation for label-based predicate sharding. It is intended for review and testing purposes only.


Summary

Add @label(name) directive to predicates, allowing them to be pinned to specific alpha groups that share the same label. This creates implicit sub-clusters for data isolation.

Key Changes

  • Add label field to Member, Tablet, and SchemaUpdate protos
  • Parse @label(X) directive in schema (schema/parse.go)
  • Route labeled predicates to matching labeled groups in Zero
  • Require explicit label parameter in Tablet(), BelongsTo(), ForceTablet()
  • /moveTablet validates label compatibility: blocks moves when destination group label differs from predicate label
  • Prevent unlabeled predicates from being assigned to labeled groups

Label Routing Flow

1. Alpha with --label=X registers with Zero, Member.Label is set
2. Schema with @label(X) is parsed, SchemaUpdate.Label is set
3. Zero routes tablet to group where Member.Label matches
4. Rebalancer skips tablets with non-empty Label

Example Usage

# Start alphas with labels:
#   alpha1: (no label) - serves unlabeled predicates
#   alpha2: --label=secret
#   alpha3: --label=top_secret

# Schema:
name: string @index(term) .                    # -> group 1 (unlabeled)
codename: string @index(term) @label(secret) . # -> group 2 (secret)
alias: string @index(term) @label(top_secret) .# -> group 3 (top_secret)

Testing Instructions

Prerequisites

  1. Docker must be running
  2. For macOS, build the Linux binary:
    GOOS=linux make install
    cp $GOPATH/bin/linux_arm64/dgraph $GOPATH/bin/dgraph

Run the Tests

# Build test runner and run label sharding tests
cd t && go build . && ./t --pkg=systest/label

# Run with verbose output
./t --pkg=systest/label -v

# Keep containers running after tests for debugging
./t --pkg=systest/label --keep

# Run a specific test
./t --pkg=systest/label --test=TestLabeledPredicateRouting

Test Cluster Configuration

The tests spin up a Docker cluster with:

Container Group Label Purpose
zero1 - - Cluster coordinator
alpha1 1 (none) Serves unlabeled predicates
alpha2 2 secret Serves @label(secret) predicates
alpha3 3 top_secret Serves @label(top_secret) predicates

What the Tests Verify

Test What It Verifies
TestLabeledAlphaRegistration Alphas started with --label=X correctly register their label with Zero. Verifies Member.Label is set in cluster state.
TestLabeledPredicateRouting Predicates with @label(X) are assigned to the group whose alpha has matching label. Verifies tablet assignments in Zero's /state endpoint.
TestLabeledPredicateDataIsolation Data mutations and queries work correctly across predicates served by different labeled groups. Inserts data using all predicate types and queries it back.
TestLabeledPredicateCannotBeMoved The /moveTablet API validates label compatibility. Attempting to move a labeled predicate to a group with a different (or no) label returns an error. This ensures predicates stay within their designated label boundary.
TestUnlabeledPredicateNotOnLabeledGroup Unlabeled predicates are never assigned to groups that have a label. Prevents data leakage into labeled sub-clusters.
TestMissingLabelGroupError Applying a schema with @label(nonexistent) returns a clear error when no alpha has that label.

Test Plan

  • TestLabeledAlphaRegistration
  • TestLabeledPredicateRouting
  • TestLabeledPredicateDataIsolation
  • TestLabeledPredicateCannotBeMoved
  • TestUnlabeledPredicateNotOnLabeledGroup
  • TestMissingLabelGroupError

All 6 integration tests pass.

Add @Label(name) directive to predicates, allowing them to be pinned
to specific alpha groups that share the same label. This creates
implicit sub-clusters for data isolation.

Key changes:
- Add label field to Member, Tablet, and SchemaUpdate protos
- Parse @Label(X) directive in schema (schema/parse.go)
- Route labeled predicates to matching labeled groups in Zero
- Require explicit label parameter in Tablet(), BelongsTo(), ForceTablet()
- Block moveTablet for labeled predicates
- Prevent unlabeled predicates from being assigned to labeled groups

Label routing flow:
1. Alpha with --label=X registers with Zero, Member.Label is set
2. Schema with @Label(X) is parsed, SchemaUpdate.Label is set
3. Zero routes tablet to group where Member.Label matches
4. Rebalancer skips tablets with non-empty Label

All tablet lookup functions now require explicit label parameter to
ensure correct routing for new predicates during schema mutations.
@mlwelles mlwelles changed the title DO NOT MERGE: feat(sharding): add label-driven predicate routing (DGR-157) DO NOT MERGE: feat(sharding): add label-driven predicate routing Jan 25, 2026
- Update trunk go runtime from 1.24.3 to 1.25.6 to match go.mod
- Fix trailing newline formatting in label test files
- Use closure with defer for RLock/RUnlock in Inform() to prevent
  lock leaks on error paths
- Add getGroupLabel() helper that handles its own locking, keeping
  groupLabel() for callers that already hold the lock
- Move checkSchemaTablet function closer to its usage in proposeAndWait
- Add tablet_label span attribute for better observability
Rename for consistency - drop redundant 'Id' suffix since return
types already indicate the value type:
- labelGroupId → labelGroup
- isLabeledGroupId → isLabeledGroup
- firstUnlabeledGroupId → firstUnlabeledGroup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant