snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
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
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
This commit is contained in:
378
weed/mq/offset/manager.go
Normal file
378
weed/mq/offset/manager.go
Normal file
@@ -0,0 +1,378 @@
|
||||
package offset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
)
|
||||
|
||||
// PartitionOffsetManager manages sequential offset assignment for a single partition
|
||||
type PartitionOffsetManager struct {
|
||||
mu sync.RWMutex
|
||||
namespace string
|
||||
topicName string
|
||||
partition *schema_pb.Partition
|
||||
nextOffset int64
|
||||
|
||||
// Checkpointing for recovery
|
||||
lastCheckpoint int64
|
||||
lastCheckpointedOffset int64
|
||||
storage OffsetStorage
|
||||
|
||||
// Background checkpointing
|
||||
stopCheckpoint chan struct{}
|
||||
}
|
||||
|
||||
// OffsetStorage interface for persisting offset state
|
||||
type OffsetStorage interface {
|
||||
// SaveCheckpoint persists the current offset state for recovery
|
||||
// Takes topic information along with partition to determine the correct storage location
|
||||
SaveCheckpoint(namespace, topicName string, partition *schema_pb.Partition, offset int64) error
|
||||
|
||||
// LoadCheckpoint retrieves the last saved offset state
|
||||
LoadCheckpoint(namespace, topicName string, partition *schema_pb.Partition) (int64, error)
|
||||
|
||||
// GetHighestOffset scans storage to find the highest assigned offset
|
||||
GetHighestOffset(namespace, topicName string, partition *schema_pb.Partition) (int64, error)
|
||||
}
|
||||
|
||||
// NewPartitionOffsetManager creates a new offset manager for a partition
|
||||
func NewPartitionOffsetManager(namespace, topicName string, partition *schema_pb.Partition, storage OffsetStorage) (*PartitionOffsetManager, error) {
|
||||
manager := &PartitionOffsetManager{
|
||||
namespace: namespace,
|
||||
topicName: topicName,
|
||||
partition: partition,
|
||||
storage: storage,
|
||||
stopCheckpoint: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Recover offset state
|
||||
if err := manager.recover(); err != nil {
|
||||
return nil, fmt.Errorf("failed to recover offset state: %w", err)
|
||||
}
|
||||
|
||||
// Start background checkpoint goroutine
|
||||
go manager.runPeriodicCheckpoint()
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
// Close stops the background checkpoint goroutine and performs a final checkpoint
|
||||
func (m *PartitionOffsetManager) Close() error {
|
||||
close(m.stopCheckpoint)
|
||||
|
||||
// Perform final checkpoint
|
||||
m.mu.RLock()
|
||||
currentOffset := m.nextOffset - 1 // Last assigned offset
|
||||
lastCheckpointed := m.lastCheckpointedOffset
|
||||
m.mu.RUnlock()
|
||||
|
||||
if currentOffset >= 0 && currentOffset > lastCheckpointed {
|
||||
return m.storage.SaveCheckpoint(m.namespace, m.topicName, m.partition, currentOffset)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssignOffset assigns the next sequential offset
|
||||
func (m *PartitionOffsetManager) AssignOffset() int64 {
|
||||
m.mu.Lock()
|
||||
offset := m.nextOffset
|
||||
m.nextOffset++
|
||||
m.mu.Unlock()
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
// AssignOffsets assigns a batch of sequential offsets
|
||||
func (m *PartitionOffsetManager) AssignOffsets(count int64) (baseOffset int64, lastOffset int64) {
|
||||
m.mu.Lock()
|
||||
baseOffset = m.nextOffset
|
||||
lastOffset = m.nextOffset + count - 1
|
||||
m.nextOffset += count
|
||||
m.mu.Unlock()
|
||||
|
||||
return baseOffset, lastOffset
|
||||
}
|
||||
|
||||
// GetNextOffset returns the next offset that will be assigned
|
||||
func (m *PartitionOffsetManager) GetNextOffset() int64 {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
return m.nextOffset
|
||||
}
|
||||
|
||||
// GetHighWaterMark returns the high water mark (next offset)
|
||||
func (m *PartitionOffsetManager) GetHighWaterMark() int64 {
|
||||
return m.GetNextOffset()
|
||||
}
|
||||
|
||||
// recover restores offset state from storage
|
||||
func (m *PartitionOffsetManager) recover() error {
|
||||
var checkpointOffset int64 = -1
|
||||
var highestOffset int64 = -1
|
||||
|
||||
// Try to load checkpoint
|
||||
if offset, err := m.storage.LoadCheckpoint(m.namespace, m.topicName, m.partition); err == nil && offset >= 0 {
|
||||
checkpointOffset = offset
|
||||
}
|
||||
|
||||
// Try to scan storage for highest offset
|
||||
if offset, err := m.storage.GetHighestOffset(m.namespace, m.topicName, m.partition); err == nil && offset >= 0 {
|
||||
highestOffset = offset
|
||||
}
|
||||
|
||||
// Use the higher of checkpoint or storage scan
|
||||
if checkpointOffset >= 0 && highestOffset >= 0 {
|
||||
if highestOffset > checkpointOffset {
|
||||
m.nextOffset = highestOffset + 1
|
||||
m.lastCheckpoint = highestOffset
|
||||
m.lastCheckpointedOffset = highestOffset
|
||||
} else {
|
||||
m.nextOffset = checkpointOffset + 1
|
||||
m.lastCheckpoint = checkpointOffset
|
||||
m.lastCheckpointedOffset = checkpointOffset
|
||||
}
|
||||
} else if checkpointOffset >= 0 {
|
||||
m.nextOffset = checkpointOffset + 1
|
||||
m.lastCheckpoint = checkpointOffset
|
||||
m.lastCheckpointedOffset = checkpointOffset
|
||||
} else if highestOffset >= 0 {
|
||||
m.nextOffset = highestOffset + 1
|
||||
m.lastCheckpoint = highestOffset
|
||||
m.lastCheckpointedOffset = highestOffset
|
||||
} else {
|
||||
// No data exists, start from 0
|
||||
m.nextOffset = 0
|
||||
m.lastCheckpoint = -1
|
||||
m.lastCheckpointedOffset = -1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// runPeriodicCheckpoint runs in the background and checkpoints every 2 seconds if the offset changed
|
||||
func (m *PartitionOffsetManager) runPeriodicCheckpoint() {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
m.performCheckpointIfChanged()
|
||||
case <-m.stopCheckpoint:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// performCheckpointIfChanged saves checkpoint only if offset has changed since last checkpoint
|
||||
func (m *PartitionOffsetManager) performCheckpointIfChanged() {
|
||||
m.mu.RLock()
|
||||
currentOffset := m.nextOffset - 1 // Last assigned offset
|
||||
lastCheckpointed := m.lastCheckpointedOffset
|
||||
m.mu.RUnlock()
|
||||
|
||||
// Skip if no messages have been assigned, or no change since last checkpoint
|
||||
if currentOffset < 0 || currentOffset == lastCheckpointed {
|
||||
return
|
||||
}
|
||||
|
||||
// Perform checkpoint
|
||||
if err := m.storage.SaveCheckpoint(m.namespace, m.topicName, m.partition, currentOffset); err != nil {
|
||||
// Log error but don't fail - checkpointing is for optimization
|
||||
fmt.Printf("Failed to checkpoint offset %d for %s/%s: %v\n", currentOffset, m.namespace, m.topicName, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Update last checkpointed offset
|
||||
m.mu.Lock()
|
||||
m.lastCheckpointedOffset = currentOffset
|
||||
m.lastCheckpoint = currentOffset
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// PartitionOffsetRegistry manages offset managers for multiple partitions
|
||||
type PartitionOffsetRegistry struct {
|
||||
mu sync.RWMutex
|
||||
managers map[string]*PartitionOffsetManager
|
||||
storage OffsetStorage
|
||||
}
|
||||
|
||||
// NewPartitionOffsetRegistry creates a new registry
|
||||
func NewPartitionOffsetRegistry(storage OffsetStorage) *PartitionOffsetRegistry {
|
||||
return &PartitionOffsetRegistry{
|
||||
managers: make(map[string]*PartitionOffsetManager),
|
||||
storage: storage,
|
||||
}
|
||||
}
|
||||
|
||||
// GetManager returns the offset manager for a partition, creating it if needed
|
||||
func (r *PartitionOffsetRegistry) GetManager(namespace, topicName string, partition *schema_pb.Partition) (*PartitionOffsetManager, error) {
|
||||
// CRITICAL FIX: Use TopicPartitionKey to ensure each topic has its own offset manager
|
||||
key := TopicPartitionKey(namespace, topicName, partition)
|
||||
|
||||
r.mu.RLock()
|
||||
manager, exists := r.managers[key]
|
||||
r.mu.RUnlock()
|
||||
|
||||
if exists {
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
// Create new manager
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
// Double-check after acquiring write lock
|
||||
if manager, exists := r.managers[key]; exists {
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
manager, err := NewPartitionOffsetManager(namespace, topicName, partition, r.storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.managers[key] = manager
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
// AssignOffset assigns an offset for the given partition
|
||||
func (r *PartitionOffsetRegistry) AssignOffset(namespace, topicName string, partition *schema_pb.Partition) (int64, error) {
|
||||
manager, err := r.GetManager(namespace, topicName, partition)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
assignedOffset := manager.AssignOffset()
|
||||
|
||||
return assignedOffset, nil
|
||||
}
|
||||
|
||||
// AssignOffsets assigns a batch of offsets for the given partition
|
||||
func (r *PartitionOffsetRegistry) AssignOffsets(namespace, topicName string, partition *schema_pb.Partition, count int64) (baseOffset, lastOffset int64, err error) {
|
||||
manager, err := r.GetManager(namespace, topicName, partition)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
baseOffset, lastOffset = manager.AssignOffsets(count)
|
||||
return baseOffset, lastOffset, nil
|
||||
}
|
||||
|
||||
// GetHighWaterMark returns the high water mark for a partition
|
||||
func (r *PartitionOffsetRegistry) GetHighWaterMark(namespace, topicName string, partition *schema_pb.Partition) (int64, error) {
|
||||
manager, err := r.GetManager(namespace, topicName, partition)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return manager.GetHighWaterMark(), nil
|
||||
}
|
||||
|
||||
// Close stops all partition managers and performs final checkpoints
|
||||
func (r *PartitionOffsetRegistry) Close() error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
var firstErr error
|
||||
for _, manager := range r.managers {
|
||||
if err := manager.Close(); err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
}
|
||||
}
|
||||
|
||||
return firstErr
|
||||
}
|
||||
|
||||
// TopicPartitionKey generates a unique key for a topic-partition combination
|
||||
// This is the canonical key format used across the offset management system
|
||||
func TopicPartitionKey(namespace, topicName string, partition *schema_pb.Partition) string {
|
||||
return fmt.Sprintf("%s/%s/ring:%d:range:%d-%d",
|
||||
namespace, topicName,
|
||||
partition.RingSize, partition.RangeStart, partition.RangeStop)
|
||||
}
|
||||
|
||||
// PartitionKey generates a unique key for a partition (without topic context)
|
||||
// Note: UnixTimeNs is intentionally excluded from the key because it represents
|
||||
// partition creation time, not partition identity. Using it would cause offset
|
||||
// tracking to reset whenever a partition is recreated or looked up again.
|
||||
// DEPRECATED: Use TopicPartitionKey for production code to avoid key collisions
|
||||
func PartitionKey(partition *schema_pb.Partition) string {
|
||||
return fmt.Sprintf("ring:%d:range:%d-%d",
|
||||
partition.RingSize, partition.RangeStart, partition.RangeStop)
|
||||
}
|
||||
|
||||
// partitionKey is the internal lowercase version for backward compatibility within this package
|
||||
func partitionKey(partition *schema_pb.Partition) string {
|
||||
return PartitionKey(partition)
|
||||
}
|
||||
|
||||
// OffsetAssignment represents an assigned offset with metadata
|
||||
type OffsetAssignment struct {
|
||||
Offset int64
|
||||
Timestamp int64
|
||||
Partition *schema_pb.Partition
|
||||
}
|
||||
|
||||
// BatchOffsetAssignment represents a batch of assigned offsets
|
||||
type BatchOffsetAssignment struct {
|
||||
BaseOffset int64
|
||||
LastOffset int64
|
||||
Count int64
|
||||
Timestamp int64
|
||||
Partition *schema_pb.Partition
|
||||
}
|
||||
|
||||
// AssignmentResult contains the result of offset assignment
|
||||
type AssignmentResult struct {
|
||||
Assignment *OffsetAssignment
|
||||
Batch *BatchOffsetAssignment
|
||||
Error error
|
||||
}
|
||||
|
||||
// OffsetAssigner provides high-level offset assignment operations
|
||||
type OffsetAssigner struct {
|
||||
registry *PartitionOffsetRegistry
|
||||
}
|
||||
|
||||
// AssignSingleOffset assigns a single offset with timestamp
|
||||
func (a *OffsetAssigner) AssignSingleOffset(namespace, topicName string, partition *schema_pb.Partition) *AssignmentResult {
|
||||
offset, err := a.registry.AssignOffset(namespace, topicName, partition)
|
||||
if err != nil {
|
||||
return &AssignmentResult{Error: err}
|
||||
}
|
||||
|
||||
return &AssignmentResult{
|
||||
Assignment: &OffsetAssignment{
|
||||
Offset: offset,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
Partition: partition,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AssignBatchOffsets assigns a batch of offsets with timestamp
|
||||
func (a *OffsetAssigner) AssignBatchOffsets(namespace, topicName string, partition *schema_pb.Partition, count int64) *AssignmentResult {
|
||||
baseOffset, lastOffset, err := a.registry.AssignOffsets(namespace, topicName, partition, count)
|
||||
if err != nil {
|
||||
return &AssignmentResult{Error: err}
|
||||
}
|
||||
|
||||
return &AssignmentResult{
|
||||
Batch: &BatchOffsetAssignment{
|
||||
BaseOffset: baseOffset,
|
||||
LastOffset: lastOffset,
|
||||
Count: count,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
Partition: partition,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetHighWaterMark returns the high water mark for a partition
|
||||
func (a *OffsetAssigner) GetHighWaterMark(namespace, topicName string, partition *schema_pb.Partition) (int64, error) {
|
||||
return a.registry.GetHighWaterMark(namespace, topicName, partition)
|
||||
}
|
||||
Reference in New Issue
Block a user