filer: add structured error codes to CreateEntryResponse (#8767)
* filer: add FilerError enum and error_code field to CreateEntryResponse Add a machine-readable error code alongside the existing string error field. This follows the precedent set by PublishMessageResponse in the MQ broker proto. The string field is kept for human readability and backward compatibility. Defined codes: OK, ENTRY_NAME_TOO_LONG, PARENT_IS_FILE, EXISTING_IS_DIRECTORY, EXISTING_IS_FILE, ENTRY_ALREADY_EXISTS. * filer: add sentinel errors and error code mapping in filer_pb Define sentinel errors (ErrEntryNameTooLong, ErrParentIsFile, etc.) in the filer_pb package so both the filer and consumers can reference them without circular imports. Add FilerErrorToSentinel() to map proto error codes to sentinels, and update CreateEntryWithResponse() to check error_code first, falling back to the string-based path for backward compatibility with old servers. * filer: return wrapped sentinel errors and set proto error codes Replace fmt.Errorf string errors in filer.CreateEntry, UpdateEntry, and ensureParentDirectoryEntry with wrapped filer_pb sentinel errors (using %w). This preserves errors.Is() traversal on the server side. In the gRPC CreateEntry handler, map sentinel errors to the corresponding FilerError proto codes using errors.Is(), setting both resp.Error (string, for backward compat) and resp.ErrorCode (enum). * S3: use errors.Is() with filer sentinels instead of string matching Replace fragile string-based error matching in filerErrorToS3Error and other S3 API consumers with errors.Is() checks against filer_pb sentinel errors. This works because the updated CreateEntryWithResponse helper reconstructs sentinel errors from the proto FilerError code. Update iceberg stage_create and metadata_files to check resp.ErrorCode instead of parsing resp.Error strings. Update SSE-S3 to use errors.Is() for the already-exists check. String matching is retained only for non-filer errors (gRPC transport errors, checksum validation) that don't go through CreateEntryResponse. * filer: remove backward-compat string fallbacks for error codes Clients and servers are always deployed together, so there is no need for backward-compatibility fallback paths that parse resp.Error strings when resp.ErrorCode is unset. Simplify all consumers to rely solely on the structured error code. * iceberg: ensure unknown non-OK error codes are not silently ignored When FilerErrorToSentinel returns nil for an unrecognized error code, return an error including the code and message rather than falling through to return nil. * filer: fix redundant error message and restore error wrapping in helper Use request path instead of resp.Error in the sentinel error format string to avoid duplicating the sentinel message (e.g. "entry already exists: entry already exists"). Restore %w wrapping with errors.New() in the fallback paths so callers can use errors.Is()/errors.As(). * filer: promote file to directory on path conflict instead of erroring S3 allows both "foo/bar" (object) and "foo/bar/xyzzy" (another object) to coexist because S3 has a flat key space. When ensureParentDirectoryEntry finds a parent path that is a file instead of a directory, promote it to a directory by setting ModeDir while preserving the original content and chunks. Use Store.UpdateEntry directly to bypass the Filer.UpdateEntry type-change guard. This fixes the S3 compatibility test failures where creating overlapping keys (e.g. "foo/bar" then "foo/bar/xyzzy") returned ExistingObjectIsFile.
This commit is contained in:
@@ -203,9 +203,21 @@ message CreateEntryRequest {
|
||||
bool skip_check_parent_directory = 6;
|
||||
}
|
||||
|
||||
// Structured error codes for filer entry operations.
|
||||
// Values are stable — do not reorder or reuse numbers.
|
||||
enum FilerError {
|
||||
OK = 0;
|
||||
ENTRY_NAME_TOO_LONG = 1; // name exceeds max_file_name_length
|
||||
PARENT_IS_FILE = 2; // parent path component is a file, not a directory
|
||||
EXISTING_IS_DIRECTORY = 3; // cannot overwrite directory with file
|
||||
EXISTING_IS_FILE = 4; // cannot overwrite file with directory
|
||||
ENTRY_ALREADY_EXISTS = 5; // O_EXCL and entry already exists
|
||||
}
|
||||
|
||||
message CreateEntryResponse {
|
||||
string error = 1;
|
||||
string error = 1; // kept for human readability + backward compat
|
||||
SubscribeMetadataResponse metadata_event = 2;
|
||||
FilerError error_code = 3; // machine-readable error code
|
||||
}
|
||||
|
||||
message UpdateEntryRequest {
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/log_buffer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/wdclient"
|
||||
"golang.org/x/sync/singleflight"
|
||||
@@ -204,7 +203,7 @@ func (f *Filer) CreateEntry(ctx context.Context, entry *Entry, o_excl bool, isFr
|
||||
}
|
||||
|
||||
if entry.FullPath.IsLongerFileName(maxFilenameLength) {
|
||||
return fmt.Errorf(constants.ErrMsgEntryNameTooLong)
|
||||
return filer_pb.ErrEntryNameTooLong
|
||||
}
|
||||
|
||||
if entry.IsDirectory() {
|
||||
@@ -238,7 +237,7 @@ func (f *Filer) CreateEntry(ctx context.Context, entry *Entry, o_excl bool, isFr
|
||||
} else {
|
||||
if o_excl {
|
||||
glog.V(3).InfofCtx(ctx, "EEXIST: entry %s already exists", entry.FullPath)
|
||||
return fmt.Errorf("EEXIST: entry %s already exists", entry.FullPath)
|
||||
return fmt.Errorf("%s: %w", entry.FullPath, filer_pb.ErrEntryAlreadyExists)
|
||||
}
|
||||
glog.V(4).InfofCtx(ctx, "UpdateEntry %s: old entry: %v", entry.FullPath, oldEntry.Name())
|
||||
if err := f.UpdateEntry(ctx, oldEntry, entry); err != nil {
|
||||
@@ -324,8 +323,16 @@ func (f *Filer) ensureParentDirectoryEntry(ctx context.Context, entry *Entry, di
|
||||
}
|
||||
|
||||
} else if !dirEntry.IsDirectory() {
|
||||
glog.ErrorfCtx(ctx, "CreateEntry %s: %s should be a directory", entry.FullPath, dirPath)
|
||||
return fmt.Errorf("%s%s", dirPath, constants.ErrMsgIsAFile)
|
||||
// S3 allows both "foo/bar" (object) and "foo/bar/xyzzy" (another
|
||||
// object) to coexist because S3 has a flat key space. Promote the
|
||||
// existing file to a directory, preserving its content/chunks so
|
||||
// the original object data remains accessible.
|
||||
glog.V(2).InfofCtx(ctx, "promoting %s from file to directory for %s", dirPath, entry.FullPath)
|
||||
dirEntry.Attr.Mode |= os.ModeDir | 0111
|
||||
if updateErr := f.Store.UpdateEntry(ctx, dirEntry); updateErr != nil {
|
||||
return fmt.Errorf("promote %s to directory: %v", dirPath, updateErr)
|
||||
}
|
||||
f.NotifyUpdateEvent(ctx, nil, dirEntry, false, isFromOtherCluster, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -336,11 +343,11 @@ func (f *Filer) UpdateEntry(ctx context.Context, oldEntry, entry *Entry) (err er
|
||||
entry.Attr.Crtime = oldEntry.Attr.Crtime
|
||||
if oldEntry.IsDirectory() && !entry.IsDirectory() {
|
||||
glog.ErrorfCtx(ctx, "existing %s is a directory", oldEntry.FullPath)
|
||||
return fmt.Errorf("%s%s%s", constants.ErrMsgExistingPrefix, oldEntry.FullPath, constants.ErrMsgIsADirectory)
|
||||
return fmt.Errorf("%s: %w", oldEntry.FullPath, filer_pb.ErrExistingIsDirectory)
|
||||
}
|
||||
if !oldEntry.IsDirectory() && entry.IsDirectory() {
|
||||
glog.ErrorfCtx(ctx, "existing %s is a file", oldEntry.FullPath)
|
||||
return fmt.Errorf("%s%s%s", constants.ErrMsgExistingPrefix, oldEntry.FullPath, constants.ErrMsgIsAFile)
|
||||
return fmt.Errorf("%s: %w", oldEntry.FullPath, filer_pb.ErrExistingIsFile)
|
||||
}
|
||||
}
|
||||
return f.Store.UpdateEntry(ctx, entry)
|
||||
|
||||
@@ -203,9 +203,21 @@ message CreateEntryRequest {
|
||||
bool skip_check_parent_directory = 6;
|
||||
}
|
||||
|
||||
// Structured error codes for filer entry operations.
|
||||
// Values are stable — do not reorder or reuse numbers.
|
||||
enum FilerError {
|
||||
OK = 0;
|
||||
ENTRY_NAME_TOO_LONG = 1; // name exceeds max_file_name_length
|
||||
PARENT_IS_FILE = 2; // parent path component is a file, not a directory
|
||||
EXISTING_IS_DIRECTORY = 3; // cannot overwrite directory with file
|
||||
EXISTING_IS_FILE = 4; // cannot overwrite file with directory
|
||||
ENTRY_ALREADY_EXISTS = 5; // O_EXCL and entry already exists
|
||||
}
|
||||
|
||||
message CreateEntryResponse {
|
||||
string error = 1;
|
||||
string error = 1; // kept for human readability + backward compat
|
||||
SubscribeMetadataResponse metadata_event = 2;
|
||||
FilerError error_code = 3; // machine-readable error code
|
||||
}
|
||||
|
||||
message UpdateEntryRequest {
|
||||
|
||||
@@ -73,6 +73,66 @@ func (SSEType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_filer_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// Structured error codes for filer entry operations.
|
||||
// Values are stable — do not reorder or reuse numbers.
|
||||
type FilerError int32
|
||||
|
||||
const (
|
||||
FilerError_OK FilerError = 0
|
||||
FilerError_ENTRY_NAME_TOO_LONG FilerError = 1 // name exceeds max_file_name_length
|
||||
FilerError_PARENT_IS_FILE FilerError = 2 // parent path component is a file, not a directory
|
||||
FilerError_EXISTING_IS_DIRECTORY FilerError = 3 // cannot overwrite directory with file
|
||||
FilerError_EXISTING_IS_FILE FilerError = 4 // cannot overwrite file with directory
|
||||
FilerError_ENTRY_ALREADY_EXISTS FilerError = 5 // O_EXCL and entry already exists
|
||||
)
|
||||
|
||||
// Enum value maps for FilerError.
|
||||
var (
|
||||
FilerError_name = map[int32]string{
|
||||
0: "OK",
|
||||
1: "ENTRY_NAME_TOO_LONG",
|
||||
2: "PARENT_IS_FILE",
|
||||
3: "EXISTING_IS_DIRECTORY",
|
||||
4: "EXISTING_IS_FILE",
|
||||
5: "ENTRY_ALREADY_EXISTS",
|
||||
}
|
||||
FilerError_value = map[string]int32{
|
||||
"OK": 0,
|
||||
"ENTRY_NAME_TOO_LONG": 1,
|
||||
"PARENT_IS_FILE": 2,
|
||||
"EXISTING_IS_DIRECTORY": 3,
|
||||
"EXISTING_IS_FILE": 4,
|
||||
"ENTRY_ALREADY_EXISTS": 5,
|
||||
}
|
||||
)
|
||||
|
||||
func (x FilerError) Enum() *FilerError {
|
||||
p := new(FilerError)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x FilerError) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (FilerError) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_filer_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (FilerError) Type() protoreflect.EnumType {
|
||||
return &file_filer_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x FilerError) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FilerError.Descriptor instead.
|
||||
func (FilerError) EnumDescriptor() ([]byte, []int) {
|
||||
return file_filer_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type LookupDirectoryEntryRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"`
|
||||
@@ -1119,8 +1179,9 @@ func (x *CreateEntryRequest) GetSkipCheckParentDirectory() bool {
|
||||
|
||||
type CreateEntryResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
|
||||
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` // kept for human readability + backward compat
|
||||
MetadataEvent *SubscribeMetadataResponse `protobuf:"bytes,2,opt,name=metadata_event,json=metadataEvent,proto3" json:"metadata_event,omitempty"`
|
||||
ErrorCode FilerError `protobuf:"varint,3,opt,name=error_code,json=errorCode,proto3,enum=filer_pb.FilerError" json:"error_code,omitempty"` // machine-readable error code
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -1169,6 +1230,13 @@ func (x *CreateEntryResponse) GetMetadataEvent() *SubscribeMetadataResponse {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CreateEntryResponse) GetErrorCode() FilerError {
|
||||
if x != nil {
|
||||
return x.ErrorCode
|
||||
}
|
||||
return FilerError_OK
|
||||
}
|
||||
|
||||
type UpdateEntryRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"`
|
||||
@@ -4571,10 +4639,12 @@ const file_filer_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"signatures\x18\x05 \x03(\x05R\n" +
|
||||
"signatures\x12=\n" +
|
||||
"\x1bskip_check_parent_directory\x18\x06 \x01(\bR\x18skipCheckParentDirectory\"w\n" +
|
||||
"\x1bskip_check_parent_directory\x18\x06 \x01(\bR\x18skipCheckParentDirectory\"\xac\x01\n" +
|
||||
"\x13CreateEntryResponse\x12\x14\n" +
|
||||
"\x05error\x18\x01 \x01(\tR\x05error\x12J\n" +
|
||||
"\x0emetadata_event\x18\x02 \x01(\v2#.filer_pb.SubscribeMetadataResponseR\rmetadataEvent\"\xd2\x02\n" +
|
||||
"\x0emetadata_event\x18\x02 \x01(\v2#.filer_pb.SubscribeMetadataResponseR\rmetadataEvent\x123\n" +
|
||||
"\n" +
|
||||
"error_code\x18\x03 \x01(\x0e2\x14.filer_pb.FilerErrorR\terrorCode\"\xd2\x02\n" +
|
||||
"\x12UpdateEntryRequest\x12\x1c\n" +
|
||||
"\tdirectory\x18\x01 \x01(\tR\tdirectory\x12%\n" +
|
||||
"\x05entry\x18\x02 \x01(\v2\x0f.filer_pb.EntryR\x05entry\x121\n" +
|
||||
@@ -4851,7 +4921,15 @@ const file_filer_proto_rawDesc = "" +
|
||||
"\x05SSE_C\x10\x01\x12\v\n" +
|
||||
"\aSSE_KMS\x10\x02\x12\n" +
|
||||
"\n" +
|
||||
"\x06SSE_S3\x10\x032\xf7\x10\n" +
|
||||
"\x06SSE_S3\x10\x03*\x8c\x01\n" +
|
||||
"\n" +
|
||||
"FilerError\x12\x06\n" +
|
||||
"\x02OK\x10\x00\x12\x17\n" +
|
||||
"\x13ENTRY_NAME_TOO_LONG\x10\x01\x12\x12\n" +
|
||||
"\x0ePARENT_IS_FILE\x10\x02\x12\x19\n" +
|
||||
"\x15EXISTING_IS_DIRECTORY\x10\x03\x12\x14\n" +
|
||||
"\x10EXISTING_IS_FILE\x10\x04\x12\x18\n" +
|
||||
"\x14ENTRY_ALREADY_EXISTS\x10\x052\xf7\x10\n" +
|
||||
"\fSeaweedFiler\x12g\n" +
|
||||
"\x14LookupDirectoryEntry\x12%.filer_pb.LookupDirectoryEntryRequest\x1a&.filer_pb.LookupDirectoryEntryResponse\"\x00\x12N\n" +
|
||||
"\vListEntries\x12\x1c.filer_pb.ListEntriesRequest\x1a\x1d.filer_pb.ListEntriesResponse\"\x000\x01\x12L\n" +
|
||||
@@ -4894,171 +4972,173 @@ func file_filer_proto_rawDescGZIP() []byte {
|
||||
return file_filer_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_filer_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_filer_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_filer_proto_msgTypes = make([]protoimpl.MessageInfo, 71)
|
||||
var file_filer_proto_goTypes = []any{
|
||||
(SSEType)(0), // 0: filer_pb.SSEType
|
||||
(*LookupDirectoryEntryRequest)(nil), // 1: filer_pb.LookupDirectoryEntryRequest
|
||||
(*LookupDirectoryEntryResponse)(nil), // 2: filer_pb.LookupDirectoryEntryResponse
|
||||
(*ListEntriesRequest)(nil), // 3: filer_pb.ListEntriesRequest
|
||||
(*ListEntriesResponse)(nil), // 4: filer_pb.ListEntriesResponse
|
||||
(*RemoteEntry)(nil), // 5: filer_pb.RemoteEntry
|
||||
(*Entry)(nil), // 6: filer_pb.Entry
|
||||
(*FullEntry)(nil), // 7: filer_pb.FullEntry
|
||||
(*EventNotification)(nil), // 8: filer_pb.EventNotification
|
||||
(*FileChunk)(nil), // 9: filer_pb.FileChunk
|
||||
(*FileChunkManifest)(nil), // 10: filer_pb.FileChunkManifest
|
||||
(*FileId)(nil), // 11: filer_pb.FileId
|
||||
(*FuseAttributes)(nil), // 12: filer_pb.FuseAttributes
|
||||
(*CreateEntryRequest)(nil), // 13: filer_pb.CreateEntryRequest
|
||||
(*CreateEntryResponse)(nil), // 14: filer_pb.CreateEntryResponse
|
||||
(*UpdateEntryRequest)(nil), // 15: filer_pb.UpdateEntryRequest
|
||||
(*UpdateEntryResponse)(nil), // 16: filer_pb.UpdateEntryResponse
|
||||
(*AppendToEntryRequest)(nil), // 17: filer_pb.AppendToEntryRequest
|
||||
(*AppendToEntryResponse)(nil), // 18: filer_pb.AppendToEntryResponse
|
||||
(*DeleteEntryRequest)(nil), // 19: filer_pb.DeleteEntryRequest
|
||||
(*DeleteEntryResponse)(nil), // 20: filer_pb.DeleteEntryResponse
|
||||
(*AtomicRenameEntryRequest)(nil), // 21: filer_pb.AtomicRenameEntryRequest
|
||||
(*AtomicRenameEntryResponse)(nil), // 22: filer_pb.AtomicRenameEntryResponse
|
||||
(*StreamRenameEntryRequest)(nil), // 23: filer_pb.StreamRenameEntryRequest
|
||||
(*StreamRenameEntryResponse)(nil), // 24: filer_pb.StreamRenameEntryResponse
|
||||
(*AssignVolumeRequest)(nil), // 25: filer_pb.AssignVolumeRequest
|
||||
(*AssignVolumeResponse)(nil), // 26: filer_pb.AssignVolumeResponse
|
||||
(*LookupVolumeRequest)(nil), // 27: filer_pb.LookupVolumeRequest
|
||||
(*Locations)(nil), // 28: filer_pb.Locations
|
||||
(*Location)(nil), // 29: filer_pb.Location
|
||||
(*LookupVolumeResponse)(nil), // 30: filer_pb.LookupVolumeResponse
|
||||
(*Collection)(nil), // 31: filer_pb.Collection
|
||||
(*CollectionListRequest)(nil), // 32: filer_pb.CollectionListRequest
|
||||
(*CollectionListResponse)(nil), // 33: filer_pb.CollectionListResponse
|
||||
(*DeleteCollectionRequest)(nil), // 34: filer_pb.DeleteCollectionRequest
|
||||
(*DeleteCollectionResponse)(nil), // 35: filer_pb.DeleteCollectionResponse
|
||||
(*StatisticsRequest)(nil), // 36: filer_pb.StatisticsRequest
|
||||
(*StatisticsResponse)(nil), // 37: filer_pb.StatisticsResponse
|
||||
(*PingRequest)(nil), // 38: filer_pb.PingRequest
|
||||
(*PingResponse)(nil), // 39: filer_pb.PingResponse
|
||||
(*GetFilerConfigurationRequest)(nil), // 40: filer_pb.GetFilerConfigurationRequest
|
||||
(*GetFilerConfigurationResponse)(nil), // 41: filer_pb.GetFilerConfigurationResponse
|
||||
(*SubscribeMetadataRequest)(nil), // 42: filer_pb.SubscribeMetadataRequest
|
||||
(*SubscribeMetadataResponse)(nil), // 43: filer_pb.SubscribeMetadataResponse
|
||||
(*TraverseBfsMetadataRequest)(nil), // 44: filer_pb.TraverseBfsMetadataRequest
|
||||
(*TraverseBfsMetadataResponse)(nil), // 45: filer_pb.TraverseBfsMetadataResponse
|
||||
(*LogEntry)(nil), // 46: filer_pb.LogEntry
|
||||
(*KeepConnectedRequest)(nil), // 47: filer_pb.KeepConnectedRequest
|
||||
(*KeepConnectedResponse)(nil), // 48: filer_pb.KeepConnectedResponse
|
||||
(*LocateBrokerRequest)(nil), // 49: filer_pb.LocateBrokerRequest
|
||||
(*LocateBrokerResponse)(nil), // 50: filer_pb.LocateBrokerResponse
|
||||
(*KvGetRequest)(nil), // 51: filer_pb.KvGetRequest
|
||||
(*KvGetResponse)(nil), // 52: filer_pb.KvGetResponse
|
||||
(*KvPutRequest)(nil), // 53: filer_pb.KvPutRequest
|
||||
(*KvPutResponse)(nil), // 54: filer_pb.KvPutResponse
|
||||
(*FilerConf)(nil), // 55: filer_pb.FilerConf
|
||||
(*CacheRemoteObjectToLocalClusterRequest)(nil), // 56: filer_pb.CacheRemoteObjectToLocalClusterRequest
|
||||
(*CacheRemoteObjectToLocalClusterResponse)(nil), // 57: filer_pb.CacheRemoteObjectToLocalClusterResponse
|
||||
(*LockRequest)(nil), // 58: filer_pb.LockRequest
|
||||
(*LockResponse)(nil), // 59: filer_pb.LockResponse
|
||||
(*UnlockRequest)(nil), // 60: filer_pb.UnlockRequest
|
||||
(*UnlockResponse)(nil), // 61: filer_pb.UnlockResponse
|
||||
(*FindLockOwnerRequest)(nil), // 62: filer_pb.FindLockOwnerRequest
|
||||
(*FindLockOwnerResponse)(nil), // 63: filer_pb.FindLockOwnerResponse
|
||||
(*Lock)(nil), // 64: filer_pb.Lock
|
||||
(*TransferLocksRequest)(nil), // 65: filer_pb.TransferLocksRequest
|
||||
(*TransferLocksResponse)(nil), // 66: filer_pb.TransferLocksResponse
|
||||
nil, // 67: filer_pb.Entry.ExtendedEntry
|
||||
nil, // 68: filer_pb.UpdateEntryRequest.ExpectedExtendedEntry
|
||||
nil, // 69: filer_pb.LookupVolumeResponse.LocationsMapEntry
|
||||
(*LocateBrokerResponse_Resource)(nil), // 70: filer_pb.LocateBrokerResponse.Resource
|
||||
(*FilerConf_PathConf)(nil), // 71: filer_pb.FilerConf.PathConf
|
||||
(FilerError)(0), // 1: filer_pb.FilerError
|
||||
(*LookupDirectoryEntryRequest)(nil), // 2: filer_pb.LookupDirectoryEntryRequest
|
||||
(*LookupDirectoryEntryResponse)(nil), // 3: filer_pb.LookupDirectoryEntryResponse
|
||||
(*ListEntriesRequest)(nil), // 4: filer_pb.ListEntriesRequest
|
||||
(*ListEntriesResponse)(nil), // 5: filer_pb.ListEntriesResponse
|
||||
(*RemoteEntry)(nil), // 6: filer_pb.RemoteEntry
|
||||
(*Entry)(nil), // 7: filer_pb.Entry
|
||||
(*FullEntry)(nil), // 8: filer_pb.FullEntry
|
||||
(*EventNotification)(nil), // 9: filer_pb.EventNotification
|
||||
(*FileChunk)(nil), // 10: filer_pb.FileChunk
|
||||
(*FileChunkManifest)(nil), // 11: filer_pb.FileChunkManifest
|
||||
(*FileId)(nil), // 12: filer_pb.FileId
|
||||
(*FuseAttributes)(nil), // 13: filer_pb.FuseAttributes
|
||||
(*CreateEntryRequest)(nil), // 14: filer_pb.CreateEntryRequest
|
||||
(*CreateEntryResponse)(nil), // 15: filer_pb.CreateEntryResponse
|
||||
(*UpdateEntryRequest)(nil), // 16: filer_pb.UpdateEntryRequest
|
||||
(*UpdateEntryResponse)(nil), // 17: filer_pb.UpdateEntryResponse
|
||||
(*AppendToEntryRequest)(nil), // 18: filer_pb.AppendToEntryRequest
|
||||
(*AppendToEntryResponse)(nil), // 19: filer_pb.AppendToEntryResponse
|
||||
(*DeleteEntryRequest)(nil), // 20: filer_pb.DeleteEntryRequest
|
||||
(*DeleteEntryResponse)(nil), // 21: filer_pb.DeleteEntryResponse
|
||||
(*AtomicRenameEntryRequest)(nil), // 22: filer_pb.AtomicRenameEntryRequest
|
||||
(*AtomicRenameEntryResponse)(nil), // 23: filer_pb.AtomicRenameEntryResponse
|
||||
(*StreamRenameEntryRequest)(nil), // 24: filer_pb.StreamRenameEntryRequest
|
||||
(*StreamRenameEntryResponse)(nil), // 25: filer_pb.StreamRenameEntryResponse
|
||||
(*AssignVolumeRequest)(nil), // 26: filer_pb.AssignVolumeRequest
|
||||
(*AssignVolumeResponse)(nil), // 27: filer_pb.AssignVolumeResponse
|
||||
(*LookupVolumeRequest)(nil), // 28: filer_pb.LookupVolumeRequest
|
||||
(*Locations)(nil), // 29: filer_pb.Locations
|
||||
(*Location)(nil), // 30: filer_pb.Location
|
||||
(*LookupVolumeResponse)(nil), // 31: filer_pb.LookupVolumeResponse
|
||||
(*Collection)(nil), // 32: filer_pb.Collection
|
||||
(*CollectionListRequest)(nil), // 33: filer_pb.CollectionListRequest
|
||||
(*CollectionListResponse)(nil), // 34: filer_pb.CollectionListResponse
|
||||
(*DeleteCollectionRequest)(nil), // 35: filer_pb.DeleteCollectionRequest
|
||||
(*DeleteCollectionResponse)(nil), // 36: filer_pb.DeleteCollectionResponse
|
||||
(*StatisticsRequest)(nil), // 37: filer_pb.StatisticsRequest
|
||||
(*StatisticsResponse)(nil), // 38: filer_pb.StatisticsResponse
|
||||
(*PingRequest)(nil), // 39: filer_pb.PingRequest
|
||||
(*PingResponse)(nil), // 40: filer_pb.PingResponse
|
||||
(*GetFilerConfigurationRequest)(nil), // 41: filer_pb.GetFilerConfigurationRequest
|
||||
(*GetFilerConfigurationResponse)(nil), // 42: filer_pb.GetFilerConfigurationResponse
|
||||
(*SubscribeMetadataRequest)(nil), // 43: filer_pb.SubscribeMetadataRequest
|
||||
(*SubscribeMetadataResponse)(nil), // 44: filer_pb.SubscribeMetadataResponse
|
||||
(*TraverseBfsMetadataRequest)(nil), // 45: filer_pb.TraverseBfsMetadataRequest
|
||||
(*TraverseBfsMetadataResponse)(nil), // 46: filer_pb.TraverseBfsMetadataResponse
|
||||
(*LogEntry)(nil), // 47: filer_pb.LogEntry
|
||||
(*KeepConnectedRequest)(nil), // 48: filer_pb.KeepConnectedRequest
|
||||
(*KeepConnectedResponse)(nil), // 49: filer_pb.KeepConnectedResponse
|
||||
(*LocateBrokerRequest)(nil), // 50: filer_pb.LocateBrokerRequest
|
||||
(*LocateBrokerResponse)(nil), // 51: filer_pb.LocateBrokerResponse
|
||||
(*KvGetRequest)(nil), // 52: filer_pb.KvGetRequest
|
||||
(*KvGetResponse)(nil), // 53: filer_pb.KvGetResponse
|
||||
(*KvPutRequest)(nil), // 54: filer_pb.KvPutRequest
|
||||
(*KvPutResponse)(nil), // 55: filer_pb.KvPutResponse
|
||||
(*FilerConf)(nil), // 56: filer_pb.FilerConf
|
||||
(*CacheRemoteObjectToLocalClusterRequest)(nil), // 57: filer_pb.CacheRemoteObjectToLocalClusterRequest
|
||||
(*CacheRemoteObjectToLocalClusterResponse)(nil), // 58: filer_pb.CacheRemoteObjectToLocalClusterResponse
|
||||
(*LockRequest)(nil), // 59: filer_pb.LockRequest
|
||||
(*LockResponse)(nil), // 60: filer_pb.LockResponse
|
||||
(*UnlockRequest)(nil), // 61: filer_pb.UnlockRequest
|
||||
(*UnlockResponse)(nil), // 62: filer_pb.UnlockResponse
|
||||
(*FindLockOwnerRequest)(nil), // 63: filer_pb.FindLockOwnerRequest
|
||||
(*FindLockOwnerResponse)(nil), // 64: filer_pb.FindLockOwnerResponse
|
||||
(*Lock)(nil), // 65: filer_pb.Lock
|
||||
(*TransferLocksRequest)(nil), // 66: filer_pb.TransferLocksRequest
|
||||
(*TransferLocksResponse)(nil), // 67: filer_pb.TransferLocksResponse
|
||||
nil, // 68: filer_pb.Entry.ExtendedEntry
|
||||
nil, // 69: filer_pb.UpdateEntryRequest.ExpectedExtendedEntry
|
||||
nil, // 70: filer_pb.LookupVolumeResponse.LocationsMapEntry
|
||||
(*LocateBrokerResponse_Resource)(nil), // 71: filer_pb.LocateBrokerResponse.Resource
|
||||
(*FilerConf_PathConf)(nil), // 72: filer_pb.FilerConf.PathConf
|
||||
}
|
||||
var file_filer_proto_depIdxs = []int32{
|
||||
6, // 0: filer_pb.LookupDirectoryEntryResponse.entry:type_name -> filer_pb.Entry
|
||||
6, // 1: filer_pb.ListEntriesResponse.entry:type_name -> filer_pb.Entry
|
||||
9, // 2: filer_pb.Entry.chunks:type_name -> filer_pb.FileChunk
|
||||
12, // 3: filer_pb.Entry.attributes:type_name -> filer_pb.FuseAttributes
|
||||
67, // 4: filer_pb.Entry.extended:type_name -> filer_pb.Entry.ExtendedEntry
|
||||
5, // 5: filer_pb.Entry.remote_entry:type_name -> filer_pb.RemoteEntry
|
||||
6, // 6: filer_pb.FullEntry.entry:type_name -> filer_pb.Entry
|
||||
6, // 7: filer_pb.EventNotification.old_entry:type_name -> filer_pb.Entry
|
||||
6, // 8: filer_pb.EventNotification.new_entry:type_name -> filer_pb.Entry
|
||||
11, // 9: filer_pb.FileChunk.fid:type_name -> filer_pb.FileId
|
||||
11, // 10: filer_pb.FileChunk.source_fid:type_name -> filer_pb.FileId
|
||||
7, // 0: filer_pb.LookupDirectoryEntryResponse.entry:type_name -> filer_pb.Entry
|
||||
7, // 1: filer_pb.ListEntriesResponse.entry:type_name -> filer_pb.Entry
|
||||
10, // 2: filer_pb.Entry.chunks:type_name -> filer_pb.FileChunk
|
||||
13, // 3: filer_pb.Entry.attributes:type_name -> filer_pb.FuseAttributes
|
||||
68, // 4: filer_pb.Entry.extended:type_name -> filer_pb.Entry.ExtendedEntry
|
||||
6, // 5: filer_pb.Entry.remote_entry:type_name -> filer_pb.RemoteEntry
|
||||
7, // 6: filer_pb.FullEntry.entry:type_name -> filer_pb.Entry
|
||||
7, // 7: filer_pb.EventNotification.old_entry:type_name -> filer_pb.Entry
|
||||
7, // 8: filer_pb.EventNotification.new_entry:type_name -> filer_pb.Entry
|
||||
12, // 9: filer_pb.FileChunk.fid:type_name -> filer_pb.FileId
|
||||
12, // 10: filer_pb.FileChunk.source_fid:type_name -> filer_pb.FileId
|
||||
0, // 11: filer_pb.FileChunk.sse_type:type_name -> filer_pb.SSEType
|
||||
9, // 12: filer_pb.FileChunkManifest.chunks:type_name -> filer_pb.FileChunk
|
||||
6, // 13: filer_pb.CreateEntryRequest.entry:type_name -> filer_pb.Entry
|
||||
43, // 14: filer_pb.CreateEntryResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
6, // 15: filer_pb.UpdateEntryRequest.entry:type_name -> filer_pb.Entry
|
||||
68, // 16: filer_pb.UpdateEntryRequest.expected_extended:type_name -> filer_pb.UpdateEntryRequest.ExpectedExtendedEntry
|
||||
43, // 17: filer_pb.UpdateEntryResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
9, // 18: filer_pb.AppendToEntryRequest.chunks:type_name -> filer_pb.FileChunk
|
||||
43, // 19: filer_pb.DeleteEntryResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
8, // 20: filer_pb.StreamRenameEntryResponse.event_notification:type_name -> filer_pb.EventNotification
|
||||
29, // 21: filer_pb.AssignVolumeResponse.location:type_name -> filer_pb.Location
|
||||
29, // 22: filer_pb.Locations.locations:type_name -> filer_pb.Location
|
||||
69, // 23: filer_pb.LookupVolumeResponse.locations_map:type_name -> filer_pb.LookupVolumeResponse.LocationsMapEntry
|
||||
31, // 24: filer_pb.CollectionListResponse.collections:type_name -> filer_pb.Collection
|
||||
8, // 25: filer_pb.SubscribeMetadataResponse.event_notification:type_name -> filer_pb.EventNotification
|
||||
6, // 26: filer_pb.TraverseBfsMetadataResponse.entry:type_name -> filer_pb.Entry
|
||||
70, // 27: filer_pb.LocateBrokerResponse.resources:type_name -> filer_pb.LocateBrokerResponse.Resource
|
||||
71, // 28: filer_pb.FilerConf.locations:type_name -> filer_pb.FilerConf.PathConf
|
||||
6, // 29: filer_pb.CacheRemoteObjectToLocalClusterResponse.entry:type_name -> filer_pb.Entry
|
||||
43, // 30: filer_pb.CacheRemoteObjectToLocalClusterResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
64, // 31: filer_pb.TransferLocksRequest.locks:type_name -> filer_pb.Lock
|
||||
28, // 32: filer_pb.LookupVolumeResponse.LocationsMapEntry.value:type_name -> filer_pb.Locations
|
||||
1, // 33: filer_pb.SeaweedFiler.LookupDirectoryEntry:input_type -> filer_pb.LookupDirectoryEntryRequest
|
||||
3, // 34: filer_pb.SeaweedFiler.ListEntries:input_type -> filer_pb.ListEntriesRequest
|
||||
13, // 35: filer_pb.SeaweedFiler.CreateEntry:input_type -> filer_pb.CreateEntryRequest
|
||||
15, // 36: filer_pb.SeaweedFiler.UpdateEntry:input_type -> filer_pb.UpdateEntryRequest
|
||||
17, // 37: filer_pb.SeaweedFiler.AppendToEntry:input_type -> filer_pb.AppendToEntryRequest
|
||||
19, // 38: filer_pb.SeaweedFiler.DeleteEntry:input_type -> filer_pb.DeleteEntryRequest
|
||||
21, // 39: filer_pb.SeaweedFiler.AtomicRenameEntry:input_type -> filer_pb.AtomicRenameEntryRequest
|
||||
23, // 40: filer_pb.SeaweedFiler.StreamRenameEntry:input_type -> filer_pb.StreamRenameEntryRequest
|
||||
25, // 41: filer_pb.SeaweedFiler.AssignVolume:input_type -> filer_pb.AssignVolumeRequest
|
||||
27, // 42: filer_pb.SeaweedFiler.LookupVolume:input_type -> filer_pb.LookupVolumeRequest
|
||||
32, // 43: filer_pb.SeaweedFiler.CollectionList:input_type -> filer_pb.CollectionListRequest
|
||||
34, // 44: filer_pb.SeaweedFiler.DeleteCollection:input_type -> filer_pb.DeleteCollectionRequest
|
||||
36, // 45: filer_pb.SeaweedFiler.Statistics:input_type -> filer_pb.StatisticsRequest
|
||||
38, // 46: filer_pb.SeaweedFiler.Ping:input_type -> filer_pb.PingRequest
|
||||
40, // 47: filer_pb.SeaweedFiler.GetFilerConfiguration:input_type -> filer_pb.GetFilerConfigurationRequest
|
||||
44, // 48: filer_pb.SeaweedFiler.TraverseBfsMetadata:input_type -> filer_pb.TraverseBfsMetadataRequest
|
||||
42, // 49: filer_pb.SeaweedFiler.SubscribeMetadata:input_type -> filer_pb.SubscribeMetadataRequest
|
||||
42, // 50: filer_pb.SeaweedFiler.SubscribeLocalMetadata:input_type -> filer_pb.SubscribeMetadataRequest
|
||||
51, // 51: filer_pb.SeaweedFiler.KvGet:input_type -> filer_pb.KvGetRequest
|
||||
53, // 52: filer_pb.SeaweedFiler.KvPut:input_type -> filer_pb.KvPutRequest
|
||||
56, // 53: filer_pb.SeaweedFiler.CacheRemoteObjectToLocalCluster:input_type -> filer_pb.CacheRemoteObjectToLocalClusterRequest
|
||||
58, // 54: filer_pb.SeaweedFiler.DistributedLock:input_type -> filer_pb.LockRequest
|
||||
60, // 55: filer_pb.SeaweedFiler.DistributedUnlock:input_type -> filer_pb.UnlockRequest
|
||||
62, // 56: filer_pb.SeaweedFiler.FindLockOwner:input_type -> filer_pb.FindLockOwnerRequest
|
||||
65, // 57: filer_pb.SeaweedFiler.TransferLocks:input_type -> filer_pb.TransferLocksRequest
|
||||
2, // 58: filer_pb.SeaweedFiler.LookupDirectoryEntry:output_type -> filer_pb.LookupDirectoryEntryResponse
|
||||
4, // 59: filer_pb.SeaweedFiler.ListEntries:output_type -> filer_pb.ListEntriesResponse
|
||||
14, // 60: filer_pb.SeaweedFiler.CreateEntry:output_type -> filer_pb.CreateEntryResponse
|
||||
16, // 61: filer_pb.SeaweedFiler.UpdateEntry:output_type -> filer_pb.UpdateEntryResponse
|
||||
18, // 62: filer_pb.SeaweedFiler.AppendToEntry:output_type -> filer_pb.AppendToEntryResponse
|
||||
20, // 63: filer_pb.SeaweedFiler.DeleteEntry:output_type -> filer_pb.DeleteEntryResponse
|
||||
22, // 64: filer_pb.SeaweedFiler.AtomicRenameEntry:output_type -> filer_pb.AtomicRenameEntryResponse
|
||||
24, // 65: filer_pb.SeaweedFiler.StreamRenameEntry:output_type -> filer_pb.StreamRenameEntryResponse
|
||||
26, // 66: filer_pb.SeaweedFiler.AssignVolume:output_type -> filer_pb.AssignVolumeResponse
|
||||
30, // 67: filer_pb.SeaweedFiler.LookupVolume:output_type -> filer_pb.LookupVolumeResponse
|
||||
33, // 68: filer_pb.SeaweedFiler.CollectionList:output_type -> filer_pb.CollectionListResponse
|
||||
35, // 69: filer_pb.SeaweedFiler.DeleteCollection:output_type -> filer_pb.DeleteCollectionResponse
|
||||
37, // 70: filer_pb.SeaweedFiler.Statistics:output_type -> filer_pb.StatisticsResponse
|
||||
39, // 71: filer_pb.SeaweedFiler.Ping:output_type -> filer_pb.PingResponse
|
||||
41, // 72: filer_pb.SeaweedFiler.GetFilerConfiguration:output_type -> filer_pb.GetFilerConfigurationResponse
|
||||
45, // 73: filer_pb.SeaweedFiler.TraverseBfsMetadata:output_type -> filer_pb.TraverseBfsMetadataResponse
|
||||
43, // 74: filer_pb.SeaweedFiler.SubscribeMetadata:output_type -> filer_pb.SubscribeMetadataResponse
|
||||
43, // 75: filer_pb.SeaweedFiler.SubscribeLocalMetadata:output_type -> filer_pb.SubscribeMetadataResponse
|
||||
52, // 76: filer_pb.SeaweedFiler.KvGet:output_type -> filer_pb.KvGetResponse
|
||||
54, // 77: filer_pb.SeaweedFiler.KvPut:output_type -> filer_pb.KvPutResponse
|
||||
57, // 78: filer_pb.SeaweedFiler.CacheRemoteObjectToLocalCluster:output_type -> filer_pb.CacheRemoteObjectToLocalClusterResponse
|
||||
59, // 79: filer_pb.SeaweedFiler.DistributedLock:output_type -> filer_pb.LockResponse
|
||||
61, // 80: filer_pb.SeaweedFiler.DistributedUnlock:output_type -> filer_pb.UnlockResponse
|
||||
63, // 81: filer_pb.SeaweedFiler.FindLockOwner:output_type -> filer_pb.FindLockOwnerResponse
|
||||
66, // 82: filer_pb.SeaweedFiler.TransferLocks:output_type -> filer_pb.TransferLocksResponse
|
||||
58, // [58:83] is the sub-list for method output_type
|
||||
33, // [33:58] is the sub-list for method input_type
|
||||
33, // [33:33] is the sub-list for extension type_name
|
||||
33, // [33:33] is the sub-list for extension extendee
|
||||
0, // [0:33] is the sub-list for field type_name
|
||||
10, // 12: filer_pb.FileChunkManifest.chunks:type_name -> filer_pb.FileChunk
|
||||
7, // 13: filer_pb.CreateEntryRequest.entry:type_name -> filer_pb.Entry
|
||||
44, // 14: filer_pb.CreateEntryResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
1, // 15: filer_pb.CreateEntryResponse.error_code:type_name -> filer_pb.FilerError
|
||||
7, // 16: filer_pb.UpdateEntryRequest.entry:type_name -> filer_pb.Entry
|
||||
69, // 17: filer_pb.UpdateEntryRequest.expected_extended:type_name -> filer_pb.UpdateEntryRequest.ExpectedExtendedEntry
|
||||
44, // 18: filer_pb.UpdateEntryResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
10, // 19: filer_pb.AppendToEntryRequest.chunks:type_name -> filer_pb.FileChunk
|
||||
44, // 20: filer_pb.DeleteEntryResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
9, // 21: filer_pb.StreamRenameEntryResponse.event_notification:type_name -> filer_pb.EventNotification
|
||||
30, // 22: filer_pb.AssignVolumeResponse.location:type_name -> filer_pb.Location
|
||||
30, // 23: filer_pb.Locations.locations:type_name -> filer_pb.Location
|
||||
70, // 24: filer_pb.LookupVolumeResponse.locations_map:type_name -> filer_pb.LookupVolumeResponse.LocationsMapEntry
|
||||
32, // 25: filer_pb.CollectionListResponse.collections:type_name -> filer_pb.Collection
|
||||
9, // 26: filer_pb.SubscribeMetadataResponse.event_notification:type_name -> filer_pb.EventNotification
|
||||
7, // 27: filer_pb.TraverseBfsMetadataResponse.entry:type_name -> filer_pb.Entry
|
||||
71, // 28: filer_pb.LocateBrokerResponse.resources:type_name -> filer_pb.LocateBrokerResponse.Resource
|
||||
72, // 29: filer_pb.FilerConf.locations:type_name -> filer_pb.FilerConf.PathConf
|
||||
7, // 30: filer_pb.CacheRemoteObjectToLocalClusterResponse.entry:type_name -> filer_pb.Entry
|
||||
44, // 31: filer_pb.CacheRemoteObjectToLocalClusterResponse.metadata_event:type_name -> filer_pb.SubscribeMetadataResponse
|
||||
65, // 32: filer_pb.TransferLocksRequest.locks:type_name -> filer_pb.Lock
|
||||
29, // 33: filer_pb.LookupVolumeResponse.LocationsMapEntry.value:type_name -> filer_pb.Locations
|
||||
2, // 34: filer_pb.SeaweedFiler.LookupDirectoryEntry:input_type -> filer_pb.LookupDirectoryEntryRequest
|
||||
4, // 35: filer_pb.SeaweedFiler.ListEntries:input_type -> filer_pb.ListEntriesRequest
|
||||
14, // 36: filer_pb.SeaweedFiler.CreateEntry:input_type -> filer_pb.CreateEntryRequest
|
||||
16, // 37: filer_pb.SeaweedFiler.UpdateEntry:input_type -> filer_pb.UpdateEntryRequest
|
||||
18, // 38: filer_pb.SeaweedFiler.AppendToEntry:input_type -> filer_pb.AppendToEntryRequest
|
||||
20, // 39: filer_pb.SeaweedFiler.DeleteEntry:input_type -> filer_pb.DeleteEntryRequest
|
||||
22, // 40: filer_pb.SeaweedFiler.AtomicRenameEntry:input_type -> filer_pb.AtomicRenameEntryRequest
|
||||
24, // 41: filer_pb.SeaweedFiler.StreamRenameEntry:input_type -> filer_pb.StreamRenameEntryRequest
|
||||
26, // 42: filer_pb.SeaweedFiler.AssignVolume:input_type -> filer_pb.AssignVolumeRequest
|
||||
28, // 43: filer_pb.SeaweedFiler.LookupVolume:input_type -> filer_pb.LookupVolumeRequest
|
||||
33, // 44: filer_pb.SeaweedFiler.CollectionList:input_type -> filer_pb.CollectionListRequest
|
||||
35, // 45: filer_pb.SeaweedFiler.DeleteCollection:input_type -> filer_pb.DeleteCollectionRequest
|
||||
37, // 46: filer_pb.SeaweedFiler.Statistics:input_type -> filer_pb.StatisticsRequest
|
||||
39, // 47: filer_pb.SeaweedFiler.Ping:input_type -> filer_pb.PingRequest
|
||||
41, // 48: filer_pb.SeaweedFiler.GetFilerConfiguration:input_type -> filer_pb.GetFilerConfigurationRequest
|
||||
45, // 49: filer_pb.SeaweedFiler.TraverseBfsMetadata:input_type -> filer_pb.TraverseBfsMetadataRequest
|
||||
43, // 50: filer_pb.SeaweedFiler.SubscribeMetadata:input_type -> filer_pb.SubscribeMetadataRequest
|
||||
43, // 51: filer_pb.SeaweedFiler.SubscribeLocalMetadata:input_type -> filer_pb.SubscribeMetadataRequest
|
||||
52, // 52: filer_pb.SeaweedFiler.KvGet:input_type -> filer_pb.KvGetRequest
|
||||
54, // 53: filer_pb.SeaweedFiler.KvPut:input_type -> filer_pb.KvPutRequest
|
||||
57, // 54: filer_pb.SeaweedFiler.CacheRemoteObjectToLocalCluster:input_type -> filer_pb.CacheRemoteObjectToLocalClusterRequest
|
||||
59, // 55: filer_pb.SeaweedFiler.DistributedLock:input_type -> filer_pb.LockRequest
|
||||
61, // 56: filer_pb.SeaweedFiler.DistributedUnlock:input_type -> filer_pb.UnlockRequest
|
||||
63, // 57: filer_pb.SeaweedFiler.FindLockOwner:input_type -> filer_pb.FindLockOwnerRequest
|
||||
66, // 58: filer_pb.SeaweedFiler.TransferLocks:input_type -> filer_pb.TransferLocksRequest
|
||||
3, // 59: filer_pb.SeaweedFiler.LookupDirectoryEntry:output_type -> filer_pb.LookupDirectoryEntryResponse
|
||||
5, // 60: filer_pb.SeaweedFiler.ListEntries:output_type -> filer_pb.ListEntriesResponse
|
||||
15, // 61: filer_pb.SeaweedFiler.CreateEntry:output_type -> filer_pb.CreateEntryResponse
|
||||
17, // 62: filer_pb.SeaweedFiler.UpdateEntry:output_type -> filer_pb.UpdateEntryResponse
|
||||
19, // 63: filer_pb.SeaweedFiler.AppendToEntry:output_type -> filer_pb.AppendToEntryResponse
|
||||
21, // 64: filer_pb.SeaweedFiler.DeleteEntry:output_type -> filer_pb.DeleteEntryResponse
|
||||
23, // 65: filer_pb.SeaweedFiler.AtomicRenameEntry:output_type -> filer_pb.AtomicRenameEntryResponse
|
||||
25, // 66: filer_pb.SeaweedFiler.StreamRenameEntry:output_type -> filer_pb.StreamRenameEntryResponse
|
||||
27, // 67: filer_pb.SeaweedFiler.AssignVolume:output_type -> filer_pb.AssignVolumeResponse
|
||||
31, // 68: filer_pb.SeaweedFiler.LookupVolume:output_type -> filer_pb.LookupVolumeResponse
|
||||
34, // 69: filer_pb.SeaweedFiler.CollectionList:output_type -> filer_pb.CollectionListResponse
|
||||
36, // 70: filer_pb.SeaweedFiler.DeleteCollection:output_type -> filer_pb.DeleteCollectionResponse
|
||||
38, // 71: filer_pb.SeaweedFiler.Statistics:output_type -> filer_pb.StatisticsResponse
|
||||
40, // 72: filer_pb.SeaweedFiler.Ping:output_type -> filer_pb.PingResponse
|
||||
42, // 73: filer_pb.SeaweedFiler.GetFilerConfiguration:output_type -> filer_pb.GetFilerConfigurationResponse
|
||||
46, // 74: filer_pb.SeaweedFiler.TraverseBfsMetadata:output_type -> filer_pb.TraverseBfsMetadataResponse
|
||||
44, // 75: filer_pb.SeaweedFiler.SubscribeMetadata:output_type -> filer_pb.SubscribeMetadataResponse
|
||||
44, // 76: filer_pb.SeaweedFiler.SubscribeLocalMetadata:output_type -> filer_pb.SubscribeMetadataResponse
|
||||
53, // 77: filer_pb.SeaweedFiler.KvGet:output_type -> filer_pb.KvGetResponse
|
||||
55, // 78: filer_pb.SeaweedFiler.KvPut:output_type -> filer_pb.KvPutResponse
|
||||
58, // 79: filer_pb.SeaweedFiler.CacheRemoteObjectToLocalCluster:output_type -> filer_pb.CacheRemoteObjectToLocalClusterResponse
|
||||
60, // 80: filer_pb.SeaweedFiler.DistributedLock:output_type -> filer_pb.LockResponse
|
||||
62, // 81: filer_pb.SeaweedFiler.DistributedUnlock:output_type -> filer_pb.UnlockResponse
|
||||
64, // 82: filer_pb.SeaweedFiler.FindLockOwner:output_type -> filer_pb.FindLockOwnerResponse
|
||||
67, // 83: filer_pb.SeaweedFiler.TransferLocks:output_type -> filer_pb.TransferLocksResponse
|
||||
59, // [59:84] is the sub-list for method output_type
|
||||
34, // [34:59] is the sub-list for method input_type
|
||||
34, // [34:34] is the sub-list for extension type_name
|
||||
34, // [34:34] is the sub-list for extension extendee
|
||||
0, // [0:34] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_filer_proto_init() }
|
||||
@@ -5071,7 +5151,7 @@ func file_filer_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_filer_proto_rawDesc), len(file_filer_proto_rawDesc)),
|
||||
NumEnums: 1,
|
||||
NumEnums: 2,
|
||||
NumMessages: 71,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
|
||||
@@ -145,6 +145,13 @@ func CreateEntryWithResponse(ctx context.Context, client SeaweedFilerClient, req
|
||||
glog.V(1).InfofCtx(ctx, "create entry %s/%s %v: %v", request.Directory, request.Entry.Name, request.OExcl, err)
|
||||
return nil, fmt.Errorf("CreateEntry: %w", err)
|
||||
}
|
||||
if resp.ErrorCode != FilerError_OK {
|
||||
glog.V(1).InfofCtx(ctx, "create entry %s/%s %v: %v (code %v)", request.Directory, request.Entry.Name, request.OExcl, resp.Error, resp.ErrorCode)
|
||||
if sentinel := FilerErrorToSentinel(resp.ErrorCode); sentinel != nil {
|
||||
return nil, fmt.Errorf("CreateEntry %s/%s: %w", request.Directory, request.Entry.Name, sentinel)
|
||||
}
|
||||
return nil, fmt.Errorf("CreateEntry: %w", errors.New(resp.Error))
|
||||
}
|
||||
if resp.Error != "" {
|
||||
glog.V(1).InfofCtx(ctx, "create entry %s/%s %v: %v", request.Directory, request.Entry.Name, request.OExcl, resp.Error)
|
||||
return nil, fmt.Errorf("CreateEntry: %w", errors.New(resp.Error))
|
||||
@@ -183,6 +190,37 @@ func LookupEntry(ctx context.Context, client SeaweedFilerClient, request *Lookup
|
||||
|
||||
var ErrNotFound = errors.New("filer: no entry is found in filer store")
|
||||
|
||||
// Sentinel errors for filer entry operations.
|
||||
// These are set by the filer and reconstructed from FilerError codes after
|
||||
// crossing the gRPC boundary, so consumers can use errors.Is() instead of
|
||||
// parsing error strings.
|
||||
var (
|
||||
ErrEntryNameTooLong = errors.New("entry name too long")
|
||||
ErrParentIsFile = errors.New("parent path is a file")
|
||||
ErrExistingIsDirectory = errors.New("existing entry is a directory")
|
||||
ErrExistingIsFile = errors.New("existing entry is a file")
|
||||
ErrEntryAlreadyExists = errors.New("entry already exists")
|
||||
)
|
||||
|
||||
// FilerErrorToSentinel maps a proto FilerError code to its sentinel error.
|
||||
// Returns nil for OK or unknown codes.
|
||||
func FilerErrorToSentinel(code FilerError) error {
|
||||
switch code {
|
||||
case FilerError_ENTRY_NAME_TOO_LONG:
|
||||
return ErrEntryNameTooLong
|
||||
case FilerError_PARENT_IS_FILE:
|
||||
return ErrParentIsFile
|
||||
case FilerError_EXISTING_IS_DIRECTORY:
|
||||
return ErrExistingIsDirectory
|
||||
case FilerError_EXISTING_IS_FILE:
|
||||
return ErrExistingIsFile
|
||||
case FilerError_ENTRY_ALREADY_EXISTS:
|
||||
return ErrEntryAlreadyExists
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func IsEmpty(event *SubscribeMetadataResponse) bool {
|
||||
return event.EventNotification.NewEntry == nil && event.EventNotification.OldEntry == nil
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (s *Server) saveMetadataFile(ctx context.Context, bucketName, tablePath, me
|
||||
if createErr != nil {
|
||||
return fmt.Errorf("failed to create %s: %w", errorContext, createErr)
|
||||
}
|
||||
if resp.Error != "" && !strings.Contains(resp.Error, "exist") {
|
||||
if resp.ErrorCode != filer_pb.FilerError_OK && resp.ErrorCode != filer_pb.FilerError_ENTRY_ALREADY_EXISTS {
|
||||
return fmt.Errorf("failed to create %s: %s", errorContext, resp.Error)
|
||||
}
|
||||
return nil
|
||||
@@ -104,8 +104,11 @@ func (s *Server) saveMetadataFile(ctx context.Context, bucketName, tablePath, me
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write metadata file: %w", err)
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return fmt.Errorf("failed to write metadata file: %s", resp.Error)
|
||||
if resp.ErrorCode != filer_pb.FilerError_OK {
|
||||
if sentinel := filer_pb.FilerErrorToSentinel(resp.ErrorCode); sentinel != nil {
|
||||
return fmt.Errorf("failed to write metadata file: %w", sentinel)
|
||||
}
|
||||
return fmt.Errorf("failed to write metadata file: code=%v %s", resp.ErrorCode, resp.Error)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -198,7 +198,7 @@ func (s *Server) writeStageCreateMarker(ctx context.Context, bucketName string,
|
||||
if createErr != nil {
|
||||
return fmt.Errorf("failed to create %s: %w", errorContext, createErr)
|
||||
}
|
||||
if resp.Error != "" && !strings.Contains(resp.Error, "exist") {
|
||||
if resp.ErrorCode != filer_pb.FilerError_OK && resp.ErrorCode != filer_pb.FilerError_ENTRY_ALREADY_EXISTS {
|
||||
return fmt.Errorf("failed to create %s: %s", errorContext, resp.Error)
|
||||
}
|
||||
return nil
|
||||
@@ -236,8 +236,11 @@ func (s *Server) writeStageCreateMarker(ctx context.Context, bucketName string,
|
||||
if createErr != nil {
|
||||
return createErr
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return errors.New(resp.Error)
|
||||
if resp.ErrorCode != filer_pb.FilerError_OK {
|
||||
if sentinel := filer_pb.FilerErrorToSentinel(resp.ErrorCode); sentinel != nil {
|
||||
return fmt.Errorf("create stage marker: %w", sentinel)
|
||||
}
|
||||
return fmt.Errorf("create stage marker: code=%v %s", resp.ErrorCode, resp.Error)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
mathrand "math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -359,8 +358,8 @@ func (km *SSES3KeyManager) generateAndSaveSuperKeyToFiler() error {
|
||||
// Set appropriate permissions for the directory
|
||||
entry.Attributes.FileMode = uint32(0700 | os.ModeDir)
|
||||
}); err != nil {
|
||||
// Only ignore "file exists" errors.
|
||||
if !strings.Contains(err.Error(), "file exists") {
|
||||
// Only ignore "already exists" errors.
|
||||
if !errors.Is(err, filer_pb.ErrEntryAlreadyExists) {
|
||||
return fmt.Errorf("failed to create KEK directory %s: %w", SSES3KEKDirectory, err)
|
||||
}
|
||||
glog.V(3).Infof("Parent directory %s already exists, continuing.", SSES3KEKDirectory)
|
||||
|
||||
@@ -793,21 +793,25 @@ func filerErrorToS3Error(err error) s3err.ErrorCode {
|
||||
return s3err.ErrNone
|
||||
}
|
||||
|
||||
errString := err.Error()
|
||||
// Filer sentinel errors — matched via errors.Is() after crossing gRPC boundary
|
||||
switch {
|
||||
case errors.Is(err, filer_pb.ErrEntryNameTooLong):
|
||||
return s3err.ErrKeyTooLongError
|
||||
case errors.Is(err, filer_pb.ErrParentIsFile), errors.Is(err, filer_pb.ErrExistingIsFile):
|
||||
return s3err.ErrExistingObjectIsFile
|
||||
case errors.Is(err, filer_pb.ErrExistingIsDirectory):
|
||||
return s3err.ErrExistingObjectIsDirectory
|
||||
case errors.Is(err, weed_server.ErrReadOnly):
|
||||
return s3err.ErrAccessDenied
|
||||
}
|
||||
|
||||
// Non-filer errors that don't go through CreateEntryResponse — string matching required
|
||||
errString := err.Error()
|
||||
switch {
|
||||
case errString == constants.ErrMsgBadDigest:
|
||||
return s3err.ErrBadDigest
|
||||
case errors.Is(err, weed_server.ErrReadOnly):
|
||||
return s3err.ErrAccessDenied
|
||||
case strings.Contains(errString, "context canceled") || strings.Contains(errString, "code = Canceled"):
|
||||
return s3err.ErrInvalidRequest
|
||||
case strings.Contains(errString, constants.ErrMsgExistingPrefix) && strings.HasSuffix(errString, constants.ErrMsgIsADirectory):
|
||||
return s3err.ErrExistingObjectIsDirectory
|
||||
case strings.HasSuffix(errString, constants.ErrMsgIsAFile):
|
||||
return s3err.ErrExistingObjectIsFile
|
||||
case strings.Contains(errString, constants.ErrMsgEntryNameTooLong):
|
||||
return s3err.ErrKeyTooLongError
|
||||
default:
|
||||
return s3err.ErrInternalError
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
weed_server "github.com/seaweedfs/seaweedfs/weed/server"
|
||||
@@ -53,28 +54,28 @@ func TestFilerErrorToS3Error(t *testing.T) {
|
||||
expectedErr: s3err.ErrInvalidRequest,
|
||||
},
|
||||
{
|
||||
name: "Directory exists error",
|
||||
err: errors.New("existing /path/to/file is a directory"),
|
||||
name: "Directory exists error (sentinel)",
|
||||
err: fmt.Errorf("CreateEntry /path: %w", filer_pb.ErrExistingIsDirectory),
|
||||
expectedErr: s3err.ErrExistingObjectIsDirectory,
|
||||
},
|
||||
{
|
||||
name: "Directory exists error (CreateEntry-wrapped)",
|
||||
err: errors.New("CreateEntry: existing /path/to/file is a directory"),
|
||||
expectedErr: s3err.ErrExistingObjectIsDirectory,
|
||||
},
|
||||
{
|
||||
name: "File exists error",
|
||||
err: errors.New("/path/to/file is a file"),
|
||||
name: "Parent is file error (sentinel)",
|
||||
err: fmt.Errorf("CreateEntry /path: %w", filer_pb.ErrParentIsFile),
|
||||
expectedErr: s3err.ErrExistingObjectIsFile,
|
||||
},
|
||||
{
|
||||
name: "Entry name too long error",
|
||||
err: errors.New("CreateEntry: entry name too long"),
|
||||
name: "Existing is file error (sentinel)",
|
||||
err: fmt.Errorf("CreateEntry /path: %w", filer_pb.ErrExistingIsFile),
|
||||
expectedErr: s3err.ErrExistingObjectIsFile,
|
||||
},
|
||||
{
|
||||
name: "Entry name too long (sentinel)",
|
||||
err: fmt.Errorf("CreateEntry: %w", filer_pb.ErrEntryNameTooLong),
|
||||
expectedErr: s3err.ErrKeyTooLongError,
|
||||
},
|
||||
{
|
||||
name: "Entry name too long error (unwrapped)",
|
||||
err: errors.New("entry name too long"),
|
||||
name: "Entry name too long (bare sentinel)",
|
||||
err: filer_pb.ErrEntryNameTooLong,
|
||||
expectedErr: s3err.ErrKeyTooLongError,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ package weed_server
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -191,6 +192,18 @@ func (fs *FilerServer) CreateEntry(ctx context.Context, req *filer_pb.CreateEntr
|
||||
} else {
|
||||
glog.V(3).InfofCtx(ctx, "CreateEntry %s: %v", filepath.Join(req.Directory, req.Entry.Name), createErr)
|
||||
resp.Error = createErr.Error()
|
||||
switch {
|
||||
case errors.Is(createErr, filer_pb.ErrEntryNameTooLong):
|
||||
resp.ErrorCode = filer_pb.FilerError_ENTRY_NAME_TOO_LONG
|
||||
case errors.Is(createErr, filer_pb.ErrParentIsFile):
|
||||
resp.ErrorCode = filer_pb.FilerError_PARENT_IS_FILE
|
||||
case errors.Is(createErr, filer_pb.ErrExistingIsDirectory):
|
||||
resp.ErrorCode = filer_pb.FilerError_EXISTING_IS_DIRECTORY
|
||||
case errors.Is(createErr, filer_pb.ErrExistingIsFile):
|
||||
resp.ErrorCode = filer_pb.FilerError_EXISTING_IS_FILE
|
||||
case errors.Is(createErr, filer_pb.ErrEntryAlreadyExists):
|
||||
resp.ErrorCode = filer_pb.FilerError_ENTRY_ALREADY_EXISTS
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user