github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/datas/database.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // This file incorporates work covered by the following copyright and 16 // permission notice: 17 // 18 // Copyright 2016 Attic Labs, Inc. All rights reserved. 19 // Licensed under the Apache License, version 2.0: 20 // http://www.apache.org/licenses/LICENSE-2.0 21 22 // Package datas defines and implements the database layer used in Noms. 23 package datas 24 25 import ( 26 "context" 27 "io" 28 29 "github.com/dolthub/dolt/go/store/hash" 30 "github.com/dolthub/dolt/go/store/nbs" 31 32 "github.com/dolthub/dolt/go/store/chunks" 33 "github.com/dolthub/dolt/go/store/types" 34 ) 35 36 // Database provides versioned storage for noms values. While Values can be 37 // directly read and written from a Database, it is generally more appropriate 38 // to read data by inspecting the Head of a Dataset and write new data by 39 // updating the Head of a Dataset via Commit() or similar. Particularly, new 40 // data is not guaranteed to be persistent until after a Commit (Delete, 41 // SetHeadToCommit, or FastForward) operation completes. 42 // The Database API is stateful, meaning that calls to GetDataset() or 43 // Datasets() occurring after a call to Commit() (et al) will represent the 44 // result of the Commit(). 45 type Database interface { 46 // To implement types.ValueWriter, Database implementations provide 47 // WriteValue(). WriteValue() writes v to this Database, though v is not 48 // guaranteed to be be persistent until after a subsequent Commit(). The 49 // return value is the Ref of v. 50 // Written values won't be persisted until a commit-alike 51 types.ValueReadWriter 52 53 // Close must have no side-effects 54 io.Closer 55 56 // Datasets returns the root of the database which is a 57 // Map<String, Ref<Commit>> where string is a datasetID. 58 Datasets(ctx context.Context) (types.Map, error) 59 60 // GetDataset returns a Dataset struct containing the current mapping of 61 // datasetID in the above Datasets Map. 62 GetDataset(ctx context.Context, datasetID string) (Dataset, error) 63 64 // Rebase brings this Database's view of the world inline with upstream. 65 Rebase(ctx context.Context) error 66 67 // Commit updates the Commit that ds.ID() in this database points at. All 68 // Values that have been written to this Database are guaranteed to be 69 // persistent after Commit() returns. 70 // The new Commit struct is constructed using v, opts.Parents, and 71 // opts.Meta. If opts.Parents is the zero value (types.Set{}) then 72 // the current head is used. If opts.Meta is the zero value 73 // (types.Struct{}) then a fully initialized empty Struct is passed to 74 // NewCommit. 75 // The returned Dataset is always the newest snapshot, regardless of 76 // success or failure, and Datasets() is updated to match backing storage 77 // upon return as well. If the update cannot be performed, e.g., because 78 // of a conflict, Commit returns an 'ErrMergeNeeded' error. 79 Commit(ctx context.Context, ds Dataset, v types.Value, opts CommitOptions) (Dataset, error) 80 81 // CommitDangling creates a new commit that is unreferenced by any Dataset. 82 // This method is used in the course of programmatic updates such as Rebase 83 // All Values that have been written to this Database are guaranteed to be 84 // persistent after CommitDangling() returns. 85 // The new Commit struct is of the same form as structs created by Commit() 86 CommitDangling(ctx context.Context, v types.Value, opts CommitOptions) (types.Struct, error) 87 88 // CommitValue updates the Commit that ds.ID() in this database points at. 89 // All Values that have been written to this Database are guaranteed to be 90 // persistent after Commit(). 91 // The new Commit struct is constructed using `v`, and the current Head of 92 // `ds` as the lone Parent. 93 // The returned Dataset is always the newest snapshot, regardless of 94 // success or failure, and Datasets() is updated to match backing storage 95 // upon return as well. If the update cannot be performed, e.g., because 96 // of a conflict, Commit returns an 'ErrMergeNeeded' error. 97 CommitValue(ctx context.Context, ds Dataset, v types.Value) (Dataset, error) 98 99 // Tag stores an immutable reference to a Value. It takes a Ref and a Dataset 100 // whose head must be nil (ie a newly created Dataset). 101 // The new Tag struct is constructed with `ref` and metadata about the tag 102 // contained in the struct `opts.Meta`. 103 // The returned Dataset is always the newest snapshot, regardless of 104 // success or failure, and Datasets() is updated to match backing storage 105 // upon return as well. 106 Tag(ctx context.Context, ds Dataset, ref types.Ref, opts TagOptions) (Dataset, error) 107 108 // UpdateWorkingSet updates the dataset given, setting its value to a new 109 // working set value object with the ref and meta given. If the dataset given 110 // already had a value, it must match the hash given or this method returns 111 // ErrOptimisticLockFailed and the caller must retry. 112 // The returned Dataset is always the newest snapshot, regardless of 113 // success or failure, and Datasets() is updated to match backing storage 114 // upon return as well. 115 UpdateWorkingSet(ctx context.Context, ds Dataset, workingSetValue types.Ref, meta WorkingSetMeta, prevHash hash.Hash) (Dataset, error) 116 117 // Delete removes the Dataset named ds.ID() from the map at the root of 118 // the Database. The Dataset data is not necessarily cleaned up at this 119 // time, but may be garbage collected in the future. 120 // The returned Dataset is always the newest snapshot, regardless of 121 // success or failure, and Datasets() is updated to match backing storage 122 // upon return as well. If the update cannot be performed, e.g., because 123 // of a conflict, Delete returns an 'ErrMergeNeeded' error. 124 Delete(ctx context.Context, ds Dataset) (Dataset, error) 125 126 // SetHead ignores any lineage constraints (e.g. the current Head being in 127 // commit’s Parent set) and force-sets a mapping from datasetID: commit in 128 // this database. 129 // All Values that have been written to this Database are guaranteed to be 130 // persistent after SetHead(). If the update cannot be performed, e.g., 131 // because another process moved the current Head out from under you, 132 // error will be non-nil. 133 // The newest snapshot of the Dataset is always returned, so the caller an 134 // easily retry using the latest. 135 // Regardless, Datasets() is updated to match backing storage upon return. 136 SetHead(ctx context.Context, ds Dataset, newHeadRef types.Ref) (Dataset, error) 137 138 // FastForward takes a types.Ref to a Commit object and makes it the new 139 // Head of ds iff it is a descendant of the current Head. Intended to be 140 // used e.g. after a call to Pull(). If the update cannot be performed, 141 // e.g., because another process moved the current Head out from under 142 // you, err will be non-nil. 143 // The newest snapshot of the Dataset is always returned, so the caller 144 // can easily retry using the latest. 145 // Regardless, Datasets() is updated to match backing storage upon return. 146 FastForward(ctx context.Context, ds Dataset, newHeadRef types.Ref) (Dataset, error) 147 148 // Stats may return some kind of struct that reports statistics about the 149 // ChunkStore that backs this Database instance. The type is 150 // implementation-dependent, and impls may return nil 151 Stats() interface{} 152 153 // StatsSummary may return a string containing summarized statistics for 154 // the ChunkStore that backs this Database. It must return "Unsupported" 155 // if this operation is not supported. 156 StatsSummary() string 157 158 Flush(ctx context.Context) error 159 160 // chunkStore returns the ChunkStore used to read and write 161 // groups of values to the database efficiently. This interface is a low- 162 // level detail of the database that should infrequently be needed by 163 // clients. 164 chunkStore() chunks.ChunkStore 165 } 166 167 func NewDatabase(cs chunks.ChunkStore) Database { 168 return newDatabase(cs) 169 } 170 171 // GarbageCollector provides a method to 172 // remove unreferenced data from a store. 173 type GarbageCollector interface { 174 types.ValueReadWriter 175 176 // GC traverses the database starting at the Root and removes 177 // all unreferenced data from persistent storage. 178 GC(ctx context.Context) error 179 } 180 181 // CanUsePuller returns true if a datas.Puller can be used to pull data from one Database into another. Not all 182 // Databases support this yet. 183 func CanUsePuller(db Database) bool { 184 cs := db.chunkStore() 185 if tfs, ok := cs.(nbs.TableFileStore); ok { 186 ops := tfs.SupportedOperations() 187 return ops.CanRead && ops.CanWrite 188 } 189 return false 190 } 191 192 func GetCSStatSummaryForDB(db Database) string { 193 cs := db.chunkStore() 194 return cs.StatsSummary() 195 }