syntax = "proto3"; package frost.fs.object; import "refs/types.proto"; import "session/types.proto"; // Type of the object payload content. Only `REGULAR` type objects can be split, // hence `TOMBSTONE` and `LOCK` payload is limited by the // maximum object size. // // String presentation of object type is the same as definition: // * REGULAR // * TOMBSTONE // * LOCK enum ObjectType { // Just a normal object REGULAR = 0; // Used internally to identify deleted objects TOMBSTONE = 1; // Unused (previously storageGroup information) // _ = 2; // Object lock LOCK = 3; } // Type of match expression enum MatchType { // Unknown. Not used MATCH_TYPE_UNSPECIFIED = 0; // Full string match STRING_EQUAL = 1; // Full string mismatch STRING_NOT_EQUAL = 2; // Lack of key NOT_PRESENT = 3; // String prefix match COMMON_PREFIX = 4; } // Short header fields message ShortHeader { // Object format version. Effectively, the version of API library used to // create particular object. frost.fs.refs.Version version = 1 [ json_name = "version" ]; // Epoch when the object was created uint64 creation_epoch = 2 [ json_name = "creationEpoch" ]; // Object's owner frost.fs.refs.OwnerID owner_id = 3 [ json_name = "ownerID" ]; // Type of the object payload content ObjectType object_type = 4 [ json_name = "objectType" ]; // Size of payload in bytes. // `0xFFFFFFFFFFFFFFFF` means `payload_length` is unknown uint64 payload_length = 5 [ json_name = "payloadLength" ]; // Hash of payload bytes frost.fs.refs.Checksum payload_hash = 6 [ json_name = "payloadHash" ]; // Homomorphic hash of the object payload frost.fs.refs.Checksum homomorphic_hash = 7 [ json_name = "homomorphicHash" ]; } // Object Header message Header { // Object format version. Effectively, the version of API library used to // create particular object frost.fs.refs.Version version = 1 [ json_name = "version" ]; // Object's container frost.fs.refs.ContainerID container_id = 2 [ json_name = "containerID" ]; // Object's owner frost.fs.refs.OwnerID owner_id = 3 [ json_name = "ownerID" ]; // Object creation Epoch uint64 creation_epoch = 4 [ json_name = "creationEpoch" ]; // Size of payload in bytes. // `0xFFFFFFFFFFFFFFFF` means `payload_length` is unknown. uint64 payload_length = 5 [ json_name = "payloadLength" ]; // Hash of payload bytes frost.fs.refs.Checksum payload_hash = 6 [ json_name = "payloadHash" ]; // Type of the object payload content ObjectType object_type = 7 [ json_name = "objectType" ]; // Homomorphic hash of the object payload frost.fs.refs.Checksum homomorphic_hash = 8 [ json_name = "homomorphicHash" ]; // Session token, if it was used during Object creation. Need it to verify // integrity and authenticity out of Request scope. frost.fs.session.SessionToken session_token = 9 [ json_name = "sessionToken" ]; // `Attribute` is a user-defined Key-Value metadata pair attached to an // object. // // Key name must be an object-unique valid UTF-8 string. Value can't be empty. // Objects with duplicated attribute names or attributes with empty values // will be considered invalid. // // There are some "well-known" attributes starting with `__SYSTEM__` // prefix that affect system behaviour: // // * [ __SYSTEM__UPLOAD_ID ] \ // Marks smaller parts of a split bigger object // * [ __SYSTEM__EXPIRATION_EPOCH ] \ // The epoch after which object with no LOCKs on it becomes unavailable. // Locked object continues to be available until each of the LOCKs expire. // * [ __SYSTEM__TICK_EPOCH ] \ // Decimal number that defines what epoch must produce // object notification with UTF-8 object address in a // body (`0` value produces notification right after // object put) // * [ __SYSTEM__TICK_TOPIC ] \ // UTF-8 string topic ID that is used for object notification // // And some well-known attributes used by applications only: // // * Name \ // Human-friendly name // * FileName \ // File name to be associated with the object on saving // * FilePath \ // Full path to be associated with the object on saving. Should start with a // '/' and use '/' as a delimiting symbol. Trailing '/' should be // interpreted as a virtual directory marker. If an object has conflicting // FilePath and FileName, FilePath should have higher priority, because it // is used to construct the directory tree. FilePath with trailing '/' and // non-empty FileName attribute should not be used together. // * Timestamp \ // User-defined local time of object creation in Unix Timestamp format // * Content-Type \ // MIME Content Type of object's payload // // For detailed description of each well-known attribute please see the // corresponding section in FrostFS Technical Specification. message Attribute { // string key to the object attribute string key = 1 [ json_name = "key" ]; // string value of the object attribute string value = 2 [ json_name = "value" ]; } // User-defined object attributes repeated Attribute attributes = 10 [ json_name = "attributes" ]; // Bigger objects can be split into a chain of smaller objects. Information // about inter-dependencies between spawned objects and how to re-construct // the original one is in the `Split` headers. Parent and children objects // must be within the same container. message Split { // Identifier of the origin object. Known only to the minor child. frost.fs.refs.ObjectID parent = 1 [ json_name = "parent" ]; // Identifier of the left split neighbor frost.fs.refs.ObjectID previous = 2 [ json_name = "previous" ]; // `signature` field of the parent object. Used to reconstruct parent. frost.fs.refs.Signature parent_signature = 3 [ json_name = "parentSignature" ]; // `header` field of the parent object. Used to reconstruct parent. Header parent_header = 4 [ json_name = "parentHeader" ]; // List of identifiers of the objects generated by splitting current one. repeated frost.fs.refs.ObjectID children = 5 [ json_name = "children" ]; // 16 byte UUIDv4 used to identify the split object hierarchy parts. Must be // unique inside container. All objects participating in the split must have // the same `split_id` value. bytes split_id = 6 [ json_name = "splitID" ]; } // Position of the object in the split hierarchy Split split = 11 [ json_name = "split" ]; // Erasure code can be applied to any object. // Information about encoded object structure is stored in `EC` header. // All objects belonging to a single EC group have the same `parent` field. message EC { // Identifier of the origin object. Known to all chunks. frost.fs.refs.ObjectID parent = 1 [ json_name = "parent" ]; // Index of this chunk. uint32 index = 2 [ json_name = "index" ]; // Total number of chunks in this split. uint32 total = 3 [ json_name = "total" ]; // Total length of a parent header. Used to trim padding zeroes. uint32 header_length = 4 [ json_name = "headerLength" ]; // Chunk of a parent header. bytes header = 5 [ json_name = "header" ]; // As the origin object is EC-splitted its identifier is known to all // chunks as parent. But parent itself can be a part of Split (does not // relate to EC-split). In this case parent_split_id should be set. bytes parent_split_id = 6 [ json_name = "parentSplitID" ]; // EC-parent's parent ID. parent_split_parent_id is set if EC-parent, // itself, is a part of Split and if an object ID of its parent is // presented. The field allows to determine how EC-chunk is placed in Split // hierarchy. frost.fs.refs.ObjectID parent_split_parent_id = 7 [ json_name = "parentSplitParentID" ]; // EC parent's attributes. repeated Attribute parent_attributes = 8 [ json_name = "parentAttributes" ]; } // Erasure code chunk information. EC ec = 12 [ json_name = "ec" ]; } // Object structure. Object is immutable and content-addressed. It means // `ObjectID` will change if the header or the payload changes. It's calculated // as a hash of header field which contains hash of the object's payload. // // For non-regular object types payload format depends on object type specified // in the header. message Object { // Object's unique identifier. frost.fs.refs.ObjectID object_id = 1 [ json_name = "objectID" ]; // Signed object_id frost.fs.refs.Signature signature = 2 [ json_name = "signature" ]; // Object metadata headers Header header = 3 [ json_name = "header" ]; // Payload bytes bytes payload = 4 [ json_name = "payload" ]; } // Meta information of split hierarchy for object assembly. With the last part // one can traverse linked list of split hierarchy back to the first part and // assemble the original object. With a linking object one can assemble an // object right from the object parts. message SplitInfo { // 16 byte UUID used to identify the split object hierarchy parts. bytes split_id = 1; // The identifier of the last object in split hierarchy parts. It contains // split header with the original object header. frost.fs.refs.ObjectID last_part = 2; // The identifier of a linking object for split hierarchy parts. It contains // split header with the original object header and a sorted list of // object parts. frost.fs.refs.ObjectID link = 3; } // Meta information for the erasure-encoded object. message ECInfo { message Chunk { // Object ID of the chunk. frost.fs.refs.ObjectID id = 1; // Index of the chunk. uint32 index = 2; // Total number of chunks in this split. uint32 total = 3; } // Chunk stored on the node. repeated Chunk chunks = 1; }