Files
seaweedfs/weed/storage/blockvol/csi/snapshot_ids.go
T
Ping QiuandClaude Opus 4.6 979a9b496c feat: Phase 8 CP8-1/2/3/4 -- ops control plane, multi-replica, CSI snapshots, observability
CP8-1: HTTP REST API (create/delete/lookup/list/assign/servers), blockapi Go
client with multi-master failover, 5 shell commands, HTML dashboard at /block/.

CP8-2: RF=2/RF=3 multi-replica support -- ShipperGroup fan-out, distributed
sync, health scoring, segment-based scrub, gated promotion (heartbeat
freshness + WAL LSN + role checks), failover/rebuild for N>2 replicas.

CP8-3: CSI snapshot + expansion -- CreateSnapshot/DeleteSnapshot/ListSnapshots
RPCs, NodeExpandVolume with iSCSI rescan, snapshot ID helpers, 20 adversarial
tests covering concurrent ops, edge cases, and error injection.

CP8-4: Observability -- EngineMetrics atomic counters for flusher/group-commit/
WAL-shipper/scrub, 10 new Prometheus metrics, barrier_lag_lsn SLO gauge,
failover/promotion/rebuild counters, request ID correlation in master gRPC
logs, baseline regression framework with 7 hard-fail conditions.

Total: 63 files, ~11.2K LOC, 160+ new tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 00:05:17 -08:00

45 lines
1.2 KiB
Go

package csi
import (
"fmt"
"hash/fnv"
"strconv"
"strings"
)
// FormatSnapshotID creates a CSI-standard snapshot ID: "snap-{volumeID}-{snapID}".
func FormatSnapshotID(volumeID string, snapID uint32) string {
return fmt.Sprintf("snap-%s-%d", volumeID, snapID)
}
// ParseSnapshotID reverses FormatSnapshotID, returning volumeID and snapID.
// The volumeID may contain dashes, so we split on the last dash.
func ParseSnapshotID(csiSnapID string) (string, uint32, error) {
if !strings.HasPrefix(csiSnapID, "snap-") {
return "", 0, fmt.Errorf("invalid snapshot ID format: missing snap- prefix")
}
rest := csiSnapID[len("snap-"):]
lastDash := strings.LastIndex(rest, "-")
if lastDash < 0 || lastDash == 0 {
return "", 0, fmt.Errorf("invalid snapshot ID format: no volume/snap separator")
}
volumeID := rest[:lastDash]
numStr := rest[lastDash+1:]
id, err := strconv.ParseUint(numStr, 10, 32)
if err != nil {
return "", 0, fmt.Errorf("invalid snapshot ID format: %w", err)
}
return volumeID, uint32(id), nil
}
// snapshotNameToID converts a snapshot name to a deterministic uint32 via FNV-32a hash.
func snapshotNameToID(name string) uint32 {
h := fnv.New32a()
h.Write([]byte(name))
return h.Sum32()
}