syntax = "proto3"; package volume_server_pb; option go_package = "github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb"; import "remote.proto"; ////////////////////////////////////////////////// // Persistent state for volume servers. message VolumeServerState { // whether the server is in maintenance (i.e. read-only) mode. bool maintenance = 1; // incremental version counter uint32 version = 2; } ////////////////////////////////////////////////// service VolumeServer { //Experts only: takes multiple fid parameters. This function does not propagate deletes to replicas. rpc BatchDelete (BatchDeleteRequest) returns (BatchDeleteResponse) { } rpc VacuumVolumeCheck (VacuumVolumeCheckRequest) returns (VacuumVolumeCheckResponse) { } rpc VacuumVolumeCompact (VacuumVolumeCompactRequest) returns (stream VacuumVolumeCompactResponse) { } rpc VacuumVolumeCommit (VacuumVolumeCommitRequest) returns (VacuumVolumeCommitResponse) { } rpc VacuumVolumeCleanup (VacuumVolumeCleanupRequest) returns (VacuumVolumeCleanupResponse) { } rpc DeleteCollection (DeleteCollectionRequest) returns (DeleteCollectionResponse) { } rpc AllocateVolume (AllocateVolumeRequest) returns (AllocateVolumeResponse) { } rpc VolumeSyncStatus (VolumeSyncStatusRequest) returns (VolumeSyncStatusResponse) { } rpc VolumeIncrementalCopy (VolumeIncrementalCopyRequest) returns (stream VolumeIncrementalCopyResponse) { } rpc VolumeMount (VolumeMountRequest) returns (VolumeMountResponse) { } rpc VolumeUnmount (VolumeUnmountRequest) returns (VolumeUnmountResponse) { } rpc VolumeConsolidateIndex (VolumeConsolidateIndexRequest) returns (VolumeConsolidateIndexResponse) { } rpc VolumeDelete (VolumeDeleteRequest) returns (VolumeDeleteResponse) { } rpc VolumeMarkReadonly (VolumeMarkReadonlyRequest) returns (VolumeMarkReadonlyResponse) { } rpc VolumeMarkWritable (VolumeMarkWritableRequest) returns (VolumeMarkWritableResponse) { } rpc VolumeConfigure (VolumeConfigureRequest) returns (VolumeConfigureResponse) { } rpc VolumeStatus (VolumeStatusRequest) returns (VolumeStatusResponse) { } rpc GetState (GetStateRequest) returns (GetStateResponse) { } rpc SetState (SetStateRequest) returns (SetStateResponse) { } // copy the .idx .dat files, and mount this volume rpc VolumeCopy (VolumeCopyRequest) returns (stream VolumeCopyResponse) { } rpc ReadVolumeFileStatus (ReadVolumeFileStatusRequest) returns (ReadVolumeFileStatusResponse) { } rpc CopyFile (CopyFileRequest) returns (stream CopyFileResponse) { } rpc ReceiveFile (stream ReceiveFileRequest) returns (ReceiveFileResponse) { } rpc ReadNeedleBlob (ReadNeedleBlobRequest) returns (ReadNeedleBlobResponse) { } rpc ReadNeedleMeta (ReadNeedleMetaRequest) returns (ReadNeedleMetaResponse) { } rpc WriteNeedleBlob (WriteNeedleBlobRequest) returns (WriteNeedleBlobResponse) { } rpc ReadAllNeedles (ReadAllNeedlesRequest) returns (stream ReadAllNeedlesResponse) { } rpc VolumeTailSender (VolumeTailSenderRequest) returns (stream VolumeTailSenderResponse) { } rpc VolumeTailReceiver (VolumeTailReceiverRequest) returns (VolumeTailReceiverResponse) { } // erasure coding rpc VolumeEcShardsGenerate (VolumeEcShardsGenerateRequest) returns (VolumeEcShardsGenerateResponse) { } rpc VolumeEcShardsRebuild (VolumeEcShardsRebuildRequest) returns (VolumeEcShardsRebuildResponse) { } rpc VolumeEcShardsCopy (VolumeEcShardsCopyRequest) returns (VolumeEcShardsCopyResponse) { } rpc VolumeEcShardsDelete (VolumeEcShardsDeleteRequest) returns (VolumeEcShardsDeleteResponse) { } rpc VolumeEcShardsMount (VolumeEcShardsMountRequest) returns (VolumeEcShardsMountResponse) { } rpc VolumeEcShardsUnmount (VolumeEcShardsUnmountRequest) returns (VolumeEcShardsUnmountResponse) { } rpc VolumeEcShardRead (VolumeEcShardReadRequest) returns (stream VolumeEcShardReadResponse) { } rpc VolumeEcBlobDelete (VolumeEcBlobDeleteRequest) returns (VolumeEcBlobDeleteResponse) { } rpc VolumeEcShardsToVolume (VolumeEcShardsToVolumeRequest) returns (VolumeEcShardsToVolumeResponse) { } rpc VolumeEcShardsInfo (VolumeEcShardsInfoRequest) returns (VolumeEcShardsInfoResponse) { } // tiered storage rpc VolumeTierMoveDatToRemote (VolumeTierMoveDatToRemoteRequest) returns (stream VolumeTierMoveDatToRemoteResponse) { } rpc VolumeTierMoveDatFromRemote (VolumeTierMoveDatFromRemoteRequest) returns (stream VolumeTierMoveDatFromRemoteResponse) { } rpc VolumeServerStatus (VolumeServerStatusRequest) returns (VolumeServerStatusResponse) { } rpc VolumeServerLeave (VolumeServerLeaveRequest) returns (VolumeServerLeaveResponse) { } // remote storage rpc FetchAndWriteNeedle (FetchAndWriteNeedleRequest) returns (FetchAndWriteNeedleResponse) { } // scrubbing rpc ScrubVolume (ScrubVolumeRequest) returns (ScrubVolumeResponse) { } rpc ScrubEcVolume (ScrubEcVolumeRequest) returns (ScrubEcVolumeResponse) { } // query rpc Query (QueryRequest) returns (stream QueriedStripe) { } rpc VolumeNeedleStatus (VolumeNeedleStatusRequest) returns (VolumeNeedleStatusResponse) { } rpc Ping (PingRequest) returns (PingResponse) { } } ////////////////////////////////////////////////// message BatchDeleteRequest { repeated string file_ids = 1; bool skip_cookie_check = 2; } message BatchDeleteResponse { repeated DeleteResult results = 1; } message DeleteResult { string file_id = 1; int32 status = 2; string error = 3; uint32 size = 4; uint32 version = 5; } message Empty { } message VacuumVolumeCheckRequest { uint32 volume_id = 1; } message VacuumVolumeCheckResponse { double garbage_ratio = 1; } message VacuumVolumeCompactRequest { uint32 volume_id = 1; int64 preallocate = 2; } message VacuumVolumeCompactResponse { int64 processed_bytes = 1; float load_avg_1m = 2; } message VacuumVolumeCommitRequest { uint32 volume_id = 1; } message VacuumVolumeCommitResponse { bool is_read_only = 1; uint64 volume_size = 2; } message VacuumVolumeCleanupRequest { uint32 volume_id = 1; } message VacuumVolumeCleanupResponse { } message DeleteCollectionRequest { string collection = 1; } message DeleteCollectionResponse { } message AllocateVolumeRequest { uint32 volume_id = 1; string collection = 2; int64 preallocate = 3; string replication = 4; string ttl = 5; uint32 memory_map_max_size_mb = 6; string disk_type = 7; uint32 version = 8; } message AllocateVolumeResponse { } message VolumeSyncStatusRequest { uint32 volume_id = 1; } message VolumeSyncStatusResponse { uint32 volume_id = 1; string collection = 2; string replication = 4; string ttl = 5; uint64 tail_offset = 6; uint32 compact_revision = 7; uint64 idx_file_size = 8; uint32 version = 9; } message VolumeIncrementalCopyRequest { uint32 volume_id = 1; uint64 since_ns = 2; } message VolumeIncrementalCopyResponse { bytes file_content = 1; } message VolumeMountRequest { uint32 volume_id = 1; } message VolumeMountResponse { } message VolumeUnmountRequest { uint32 volume_id = 1; } message VolumeUnmountResponse { } message VolumeConsolidateIndexRequest { uint32 volume_id = 1; } message VolumeConsolidateIndexResponse { } message VolumeDeleteRequest { uint32 volume_id = 1; bool only_empty = 2; // when true, do not remove the cloud-tier object backing the volume. // used for moves where another server is taking over the same .vif. bool keep_remote_data = 3; } message VolumeDeleteResponse { } message VolumeMarkReadonlyRequest { uint32 volume_id = 1; bool persist = 2; // reject writes but keep accepting deletes, so expiring data can drain the volume bool can_delete = 3; } message VolumeMarkReadonlyResponse { } message VolumeMarkWritableRequest { uint32 volume_id = 1; } message VolumeMarkWritableResponse { } message VolumeConfigureRequest { uint32 volume_id = 1; string replication = 2; } message VolumeConfigureResponse { string error = 1; } message VolumeStatusRequest { uint32 volume_id = 1; } message VolumeStatusResponse { bool is_read_only = 1; uint64 volume_size = 2; uint64 file_count = 3; uint64 file_deleted_count = 4; } message GetStateRequest { } message GetStateResponse { VolumeServerState state = 1; } message SetStateRequest { // SetState updates *all* volume server flags at once. Retrieve state with GetState(), // modify individual flags as required, then call this RPC to update. VolumeServerState state = 1; } message SetStateResponse { VolumeServerState state = 1; } message VolumeCopyRequest { uint32 volume_id = 1; string collection = 2; string replication = 3; string ttl = 4; string source_data_node = 5; string disk_type = 6; int64 io_byte_per_second = 7; } message VolumeCopyResponse { uint64 last_append_at_ns = 1; int64 processed_bytes = 2; } message CopyFileRequest { uint32 volume_id = 1; string ext = 2; uint32 compaction_revision = 3; uint64 stop_offset = 4; string collection = 5; bool is_ec_volume = 6; bool ignore_source_file_not_found = 7; } message CopyFileResponse { bytes file_content = 1; int64 modified_ts_ns = 2; } message ReceiveFileRequest { oneof data { ReceiveFileInfo info = 1; bytes file_content = 2; } } message ReceiveFileInfo { uint32 volume_id = 1; string ext = 2; string collection = 3; bool is_ec_volume = 4; uint32 shard_id = 5; uint64 file_size = 6; uint32 disk_id = 7; // EC shard disk; 0 = auto-select (see VolumeEcShardsCopyRequest.disk_id) // Field numbers 8-11 are reserved for versioned-EC; disk_type stays at 12. // Staged-new-volume mode (EC decode onto a clean peer): set on a non-EC push // whose volume does not yet exist on this server. The server picks a disk // location of this medium with a free slot and writes .copying, // finalized by VolumeEcShardsToVolume(from_staged). string disk_type = 12; } message ReceiveFileResponse { uint64 bytes_written = 1; string error = 2; } message ReadNeedleBlobRequest { uint32 volume_id = 1; int64 offset = 3; // actual offset int32 size = 4; } message ReadNeedleBlobResponse { bytes needle_blob = 1; } message ReadNeedleMetaRequest { uint32 volume_id = 1; uint64 needle_id = 2; int64 offset = 3; // actual offset int32 size = 4; } message ReadNeedleMetaResponse { uint32 cookie = 1; uint64 last_modified = 2; uint32 crc = 3; string ttl = 4; uint64 append_at_ns = 5; } message WriteNeedleBlobRequest { uint32 volume_id = 1; uint64 needle_id = 2; int32 size = 3; bytes needle_blob = 4; } message WriteNeedleBlobResponse { } message ReadAllNeedlesRequest { repeated uint32 volume_ids = 1; } message ReadAllNeedlesResponse { uint32 volume_id = 1; uint64 needle_id = 2; uint32 cookie = 3; bytes needle_blob = 5; bool needle_blob_compressed = 6; uint64 last_modified = 7; uint32 crc = 8; bytes name = 9; bytes mime = 10; } message VolumeTailSenderRequest { uint32 volume_id = 1; uint64 since_ns = 2; uint32 idle_timeout_seconds = 3; } message VolumeTailSenderResponse { bytes needle_header = 1; bytes needle_body = 2; bool is_last_chunk = 3; uint32 version = 4; } message VolumeTailReceiverRequest { uint32 volume_id = 1; uint64 since_ns = 2; uint32 idle_timeout_seconds = 3; string source_volume_server = 4; } message VolumeTailReceiverResponse { } message VolumeEcShardsGenerateRequest { uint32 volume_id = 1; string collection = 2; } message VolumeEcShardsGenerateResponse { } message VolumeEcShardsRebuildRequest { uint32 volume_id = 1; string collection = 2; bool unsafe_ignore_sidecar = 3; // bypass the bitrot-sidecar fail-closed guard (operator override; distinct from ec.rebuild -force) } message VolumeEcShardsRebuildResponse { repeated uint32 rebuilt_shard_ids = 1; } message VolumeEcShardsCopyRequest { uint32 volume_id = 1; string collection = 2; repeated uint32 shard_ids = 3; bool copy_ecx_file = 4; string source_data_node = 5; bool copy_ecj_file = 6; bool copy_vif_file = 7; uint32 disk_id = 8; // Target disk ID for storing EC shards bool copy_ecsum_file = 9; // copy the bitrot checksum sidecar (.ecsum) when present; tolerant of a missing source (no-op), since this non-2PC path has no Prepare backstop int64 io_byte_per_second = 10; // limit the copy rate; 0 falls back to the server's maintenance rate } message VolumeEcShardsCopyResponse { } message VolumeEcShardsDeleteRequest { uint32 volume_id = 1; string collection = 2; repeated uint32 shard_ids = 3; bool full_teardown = 4; // pre-encode cleanup: wipe every EC artifact + generation for this volume, not just shard_ids int64 encode_ts_ns = 5; // full_teardown generation fence: delete only a disk whose .vif generation is strictly OLDER than this; preserve same-or-newer, generation 0, and an unreadable .vif. 0 => wipe-all (shell pre-encode / pre-upgrade) } message VolumeEcShardsDeleteResponse { bool full_teardown_done = 1; // set by a new server that performed full_teardown; absent from an old server lets the caller detect the silent no-op } message VolumeEcShardsMountRequest { uint32 volume_id = 1; string collection = 2; repeated uint32 shard_ids = 3; string source_disk_type = 4; // disk type of the source volume, applied to the in-memory EC volume so heartbeats report under it (#9423) bool recover_missing_index = 5; // first fetch a missing .ecx index from a peer so on-disk shards without a local index become mountable (#10104) } message VolumeEcShardsMountResponse { } message VolumeEcShardsUnmountRequest { uint32 volume_id = 1; repeated uint32 shard_ids = 3; int64 encode_ts_ns = 4; // generation fence: skip a disk whose mounted EC volume is this generation or newer (0 = unfenced, unmount all) } message VolumeEcShardsUnmountResponse { } message VolumeEcShardReadRequest { uint32 volume_id = 1; uint32 shard_id = 2; int64 offset = 3; int64 size = 4; uint64 file_key = 5; reserved 6; int64 encode_ts_ns = 7; // caller's expected encode time; the server rejects a shard from a different encode run } message VolumeEcShardReadResponse { bytes data = 1; bool is_deleted = 2; int64 encode_ts_ns = 3; // identity of the shard actually served; client rejects a mismatch (0 = pre-upgrade server) } message VolumeEcBlobDeleteRequest { uint32 volume_id = 1; string collection = 2; uint64 file_key = 3; uint32 version = 4; } message VolumeEcBlobDeleteResponse { } message VolumeEcShardsToVolumeRequest { uint32 volume_id = 1; string collection = 2; // Staged mode: the caller already decoded the EC shards off-box and pushed // .dat/.idx/.vif as .copying to this server (ReceiveFile // staged-new-volume mode). Adopt them as a normal volume instead of decoding // local EC shards in place, so is never registered as both EC and // normal on one disk. bool from_staged = 3; string disk_type = 4; // target medium's disk location for the normal volume (staged mode) } message VolumeEcShardsToVolumeResponse { } message VolumeEcShardsInfoRequest { uint32 volume_id = 1; } message VolumeEcShardsInfoResponse { repeated EcShardInfo ec_shard_infos = 1; uint64 volume_size = 2; uint64 file_count = 3; uint64 file_deleted_count = 4; EcShardConfig ec_shard_config = 10; // the layout this holder serves reads through; a binary predating a field reports it as unset } message EcShardInfo { uint32 shard_id = 1; int64 size = 2; string collection = 3; uint32 volume_id = 4; } message ReadVolumeFileStatusRequest { uint32 volume_id = 1; } message ReadVolumeFileStatusResponse { uint32 volume_id = 1; uint64 idx_file_timestamp_seconds = 2; uint64 idx_file_size = 3; uint64 dat_file_timestamp_seconds = 4; uint64 dat_file_size = 5; uint64 file_count = 6; uint32 compaction_revision = 7; string collection = 8; string disk_type = 9; VolumeInfo volume_info = 10; uint32 version = 11; } message DiskStatus { string dir = 1; uint64 all = 2; uint64 used = 3; uint64 free = 4; float percent_free = 5; float percent_used = 6; string disk_type = 7; string error = 8; } message MemStatus { int32 goroutines = 1; uint64 all = 2; uint64 used = 3; uint64 free = 4; uint64 self = 5; uint64 heap = 6; uint64 stack = 7; } // tired storage on volume servers message RemoteFile { string backend_type = 1; string backend_id = 2; string key = 3; uint64 offset = 4; uint64 file_size = 5; uint64 modified_time = 6; string extension = 7; } message VolumeInfo { repeated RemoteFile files = 1; uint32 version = 2; string replication = 3; uint32 bytes_offset = 4; int64 dat_file_size = 5; // store the original dat file size uint64 expire_at_sec = 6; // expiration time of ec volume bool read_only = 7; EcShardConfig ec_shard_config = 8; // EC shard configuration (optional, null = use default 10+4) bool read_only_can_delete = 9; // with read_only: writes are rejected but deletes still land } // EcShardConfig specifies erasure coding shard configuration message EcShardConfig { uint32 data_shards = 1; // Number of data shards (e.g., 10) uint32 parity_shards = 2; // Number of parity shards (e.g., 4) int64 encode_ts_ns = 3; // encode time (unix nanos); a read served from a shard of a different encode run is rejected int64 block_size = 4; // uniform block layout: each shard is a single contiguous block of this many bytes; 0 = legacy 1GiB/1MiB two-tier layout } // EcBitrotProtection is the entire content of a bitrot checksum sidecar // (.ecsum for the legacy generation, .ecsum.v for vacuum // generation N). On disk it is wrapped in a fixed header carrying a CRC32C // over this serialized payload (see weed/storage/erasure_coding/ec_bitrot.go). message EcBitrotProtection { ChecksumAlgorithm algorithm = 1; // CRC32C (Castagnoli) uint32 block_size = 2; // bytes per checksum block; default 16777216 (16 MiB), a power-of-two multiple of 1 MiB uint32 generation = 3; // EC vacuum generation these checksums describe (0 = legacy/fresh); must match the sidecar filename version EcShardConfig ec_shard_config = 4; // data/parity shard counts at encode time repeated EcShardChecksums shards = 5; // one entry per shard id in the active layout bytes encode_uuid = 6; // random per-encode identity, for stale-sidecar detection across in-place re-encodes } message EcShardChecksums { uint32 shard_id = 1; // 0..MaxShardCount-1 (custom EC ratios go up to 32) int64 covered_size = 2; // shard byte length these checksums cover (must equal the on-disk shard length) bytes block_crc32c = 3; // packed little-endian uint32[] = ceil(covered_size/block_size) entries } enum ChecksumAlgorithm { CHECKSUM_NONE = 0; CHECKSUM_CRC32C = 1; } message OldVersionVolumeInfo { repeated RemoteFile files = 1; uint32 version = 2; string replication = 3; uint32 BytesOffset = 4; int64 dat_file_size = 5; // store the original dat file size uint64 DestroyTime = 6; // expiration time of ec volume bool read_only = 7; } // tiered storage message VolumeTierMoveDatToRemoteRequest { uint32 volume_id = 1; string collection = 2; string destination_backend_name = 3; bool keep_local_dat_file = 4; } message VolumeTierMoveDatToRemoteResponse { int64 processed = 1; float processedPercentage = 2; } message VolumeTierMoveDatFromRemoteRequest { uint32 volume_id = 1; string collection = 2; bool keep_remote_dat_file = 3; } message VolumeTierMoveDatFromRemoteResponse { int64 processed = 1; float processedPercentage = 2; } message VolumeServerStatusRequest { } message VolumeServerStatusResponse { repeated DiskStatus disk_statuses = 1; MemStatus memory_status = 2; string version = 3; string data_center = 4; string rack = 5; VolumeServerState state = 6; } message VolumeServerLeaveRequest { } message VolumeServerLeaveResponse { } // remote storage message FetchAndWriteNeedleRequest { uint32 volume_id = 1; uint64 needle_id = 2; uint32 cookie = 3; int64 offset = 4; int64 size = 5; message Replica { string url = 1; string public_url = 2; int32 grpc_port = 3; } repeated Replica replicas = 6; string auth = 7; int32 download_concurrency = 8; // multipart download concurrency if supported by the remote storage client; for S3, 0 = default (5) // remote conf remote_pb.RemoteConf remote_conf = 15; remote_pb.RemoteStorageLocation remote_location = 16; } message FetchAndWriteNeedleResponse { string e_tag = 1; } enum VolumeScrubMode { UNKNOWN = 0; INDEX = 1; FULL = 2; LOCAL = 3; CHECKSUM = 4; // EC only: verify each local shard's raw bytes against the bitrot checksum sidecar READS = 5; // like FULL, but EC intervals no shard can serve are reconstructed from parity } message ScrubVolumeRequest { VolumeScrubMode mode = 1; // optional list of volume IDs to scrub. if empty, all volumes for the server are scrubbed. repeated uint32 volume_ids = 2; bool mark_broken_volumes_readonly = 3; } message ScrubVolumeResponse { uint64 total_volumes = 1; uint64 total_files = 2; repeated uint32 broken_volume_ids = 3; repeated string details = 4; } message ScrubEcVolumeRequest { VolumeScrubMode mode = 1; // optional list of volume IDs to scrub. if empty, all EC volumes for the server are scrubbed. repeated uint32 volume_ids = 2; bool force_deleted_needles_check = 3; // FULL mode only; may report false positives when EC indexes disagree } message ScrubEcVolumeResponse { uint64 total_volumes = 1; uint64 total_files = 2; repeated uint32 broken_volume_ids = 3; repeated EcShardInfo broken_shard_infos = 4; repeated string details = 5; } // select on volume servers message QueryRequest { repeated string selections = 1; repeated string from_file_ids = 2; message Filter { string field = 1; string operand = 2; string value = 3; } Filter filter = 3; message InputSerialization { // NONE | GZIP | BZIP2 string compression_type = 1; message CSVInput { string file_header_info = 1; // Valid values: NONE | USE | IGNORE string record_delimiter = 2; // Default: \n string field_delimiter = 3; // Default: , string quote_character = 4; // Default: " string quote_escape_character = 5; // Default: " string comments = 6; // Default: # // If true, records might contain record delimiters within quote characters bool allow_quoted_record_delimiter = 7; // default False. } message JSONInput { string type = 1; // Valid values: DOCUMENT | LINES } message ParquetInput { } CSVInput csv_input = 2; JSONInput json_input = 3; ParquetInput parquet_input = 4; } InputSerialization input_serialization = 4; message OutputSerialization { message CSVOutput { string quote_fields = 1; // Valid values: ALWAYS | ASNEEDED string record_delimiter = 2; // Default: \n string field_delimiter = 3; // Default: , string quote_character = 4; // Default: " string quote_escape_character = 5; // Default: " } message JSONOutput { string record_delimiter = 1; } CSVOutput csv_output = 2; JSONOutput json_output = 3; } OutputSerialization output_serialization = 5; } message QueriedStripe { bytes records = 1; } message VolumeNeedleStatusRequest { uint32 volume_id = 1; uint64 needle_id = 2; } message VolumeNeedleStatusResponse { uint64 needle_id = 1; uint32 cookie = 2; uint32 size = 3; uint64 last_modified = 4; uint32 crc = 5; string ttl = 6; } message PingRequest { string target = 1; // default to ping itself string target_type = 2; } message PingResponse { int64 start_time_ns = 1; int64 remote_time_ns = 2; int64 stop_time_ns = 3; }