github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/objstorage/remote/storage.go (about) 1 // Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package remote 6 7 import ( 8 "context" 9 "io" 10 11 "github.com/cockroachdb/redact" 12 ) 13 14 // Locator is an opaque string identifying a remote.Storage implementation. 15 // 16 // The Locator must not contain secrets (like authentication keys). Locators are 17 // stored on disk in the shared object catalog and are passed around as part of 18 // RemoteObjectBacking; they can also appear in error messages. 19 type Locator string 20 21 // SafeFormat implements redact.SafeFormatter. 22 func (l Locator) SafeFormat(w redact.SafePrinter, _ rune) { 23 w.Printf("%s", redact.SafeString(l)) 24 } 25 26 // StorageFactory is used to return Storage implementations based on locators. A 27 // Pebble store that uses shared storage is configured with a StorageFactory. 28 type StorageFactory interface { 29 CreateStorage(locator Locator) (Storage, error) 30 } 31 32 // SharedLevelsStart denotes the highest (i.e. lowest numbered) level that will 33 // have sstables shared across Pebble instances when doing skip-shared 34 // iteration (see db.ScanInternal) or shared file ingestion (see 35 // db.IngestAndExcise). 36 const SharedLevelsStart = 5 37 38 // CreateOnSharedStrategy specifies what table files should be created on shared 39 // storage. For use with CreateOnShared in options. 40 type CreateOnSharedStrategy int 41 42 const ( 43 // CreateOnSharedNone denotes no files being created on shared storage. 44 CreateOnSharedNone CreateOnSharedStrategy = iota 45 // CreateOnSharedLower denotes the creation of files in lower levels of the 46 // LSM (specifically, L5 and L6 as they're below SharedLevelsStart) on 47 // shared storage, and higher levels on local storage. 48 CreateOnSharedLower 49 // CreateOnSharedAll denotes the creation of all sstables on shared storage. 50 CreateOnSharedAll 51 ) 52 53 // ShouldCreateShared returns whether new table files at the specified level 54 // should be created on shared storage. 55 func ShouldCreateShared(strategy CreateOnSharedStrategy, level int) bool { 56 switch strategy { 57 case CreateOnSharedAll: 58 return true 59 case CreateOnSharedNone: 60 return false 61 case CreateOnSharedLower: 62 return level >= SharedLevelsStart 63 default: 64 panic("unexpected CreateOnSharedStrategy value") 65 } 66 } 67 68 // Storage is an interface for a blob storage driver. This is lower-level 69 // than an FS-like interface, however FS/File-like abstractions can be built on 70 // top of these methods. 71 // 72 // TODO(bilal): Consider pushing shared file obsoletion as well as path 73 // generation behind this interface. 74 type Storage interface { 75 io.Closer 76 77 // ReadObject returns an ObjectReader that can be used to perform reads on an 78 // object, along with the total size of the object. 79 ReadObject(ctx context.Context, objName string) (_ ObjectReader, objSize int64, _ error) 80 81 // CreateObject returns a writer for the object at the request name. A new 82 // empty object is created if CreateObject is called on an existing object. 83 // 84 // A Writer *must* be closed via either Close, and if closing returns a 85 // non-nil error, that error should be handled or reported to the user -- an 86 // implementation may buffer written data until Close and only then return 87 // an error, or Write may return an opaque io.EOF with the underlying cause 88 // returned by the subsequent Close(). 89 // 90 // TODO(radu): if we encounter some unrelated error while writing to the 91 // WriteCloser, we'd want to abort the whole thing rather than letting Close 92 // finalize the upload. 93 CreateObject(objName string) (io.WriteCloser, error) 94 95 // List enumerates files within the supplied prefix, returning a list of 96 // objects within that prefix. If delimiter is non-empty, names which have the 97 // same prefix, prior to the delimiter but after the prefix, are grouped into a 98 // single result which is that prefix. The order that results are returned is 99 // undefined. If a prefix is specified, the prefix is trimmed from the result 100 // list. 101 // 102 // An example would be, if the storage contains objects a, b/4, b/5 and b/6, 103 // these would be the return values: 104 // List("", "") -> ["a", "b/4", "b/5", "b/6"] 105 // List("", "/") -> ["a", "b"] 106 // List("b", "/") -> ["4", "5", "6"] 107 // List("b", "") -> ["/4", "/5", "/6"] 108 List(prefix, delimiter string) ([]string, error) 109 110 // Delete removes the named object from the store. 111 Delete(objName string) error 112 113 // Size returns the length of the named object in bytesWritten. 114 Size(objName string) (int64, error) 115 116 // IsNotExistError returns true if the given error (returned by a method in 117 // this interface) indicates that the object does not exist. 118 IsNotExistError(err error) bool 119 } 120 121 // ObjectReader is used to perform reads on an object. 122 type ObjectReader interface { 123 // ReadAt reads len(p) bytes into p starting at offset off. 124 // 125 // Does not return partial results; if offset + len(p) is past the end of the 126 // object, an error is returned. 127 // 128 // Clients of ReadAt can execute parallel ReadAt calls on the same 129 // ObjectReader. 130 ReadAt(ctx context.Context, p []byte, offset int64) error 131 132 Close() error 133 }