github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/merge/mutable_secondary_index.go (about) 1 // Copyright 2022 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 package merge 16 17 import ( 18 "context" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 22 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 23 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 24 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/index" 25 "github.com/dolthub/dolt/go/store/prolly" 26 "github.com/dolthub/dolt/go/store/val" 27 ) 28 29 // GetMutableSecondaryIdxs returns a MutableSecondaryIdx for each secondary index in |indexes|. 30 func GetMutableSecondaryIdxs(ctx *sql.Context, sch schema.Schema, tableName string, indexes durable.IndexSet) ([]MutableSecondaryIdx, error) { 31 mods := make([]MutableSecondaryIdx, sch.Indexes().Count()) 32 for i, index := range sch.Indexes().AllIndexes() { 33 idx, err := indexes.GetIndex(ctx, sch, index.Name()) 34 if err != nil { 35 return nil, err 36 } 37 m := durable.ProllyMapFromIndex(idx) 38 if schema.IsKeyless(sch) { 39 m = prolly.ConvertToSecondaryKeylessIndex(m) 40 } 41 mods[i], err = NewMutableSecondaryIdx(ctx, m, sch, tableName, index) 42 if err != nil { 43 return nil, err 44 } 45 } 46 return mods, nil 47 } 48 49 // GetMutableSecondaryIdxsWithPending returns a MutableSecondaryIdx for each secondary index in |indexes|. If an index 50 // is listed in the given |sch|, but does not exist in the given |indexes|, then it is skipped. This is useful when 51 // merging a schema that has a new index, but the index does not exist on the index set being modified. 52 func GetMutableSecondaryIdxsWithPending(ctx *sql.Context, sch schema.Schema, tableName string, indexes durable.IndexSet, pendingSize int) ([]MutableSecondaryIdx, error) { 53 mods := make([]MutableSecondaryIdx, 0, sch.Indexes().Count()) 54 for _, index := range sch.Indexes().AllIndexes() { 55 56 // If an index isn't found on the left side, we know it must be a new index added on the right side, 57 // so just skip it, and we'll rebuild the full index at the end of merging when we notice it's missing. 58 // TODO: GetMutableSecondaryIdxs should get this same treatment, or we should have a flag that 59 // allows skipping over missing indexes. Seems like we could refactor this code to remove 60 // the duplication. 61 hasIndex, err := indexes.HasIndex(ctx, index.Name()) 62 if err != nil { 63 return nil, err 64 } 65 if !hasIndex { 66 continue 67 } 68 69 idx, err := indexes.GetIndex(ctx, sch, index.Name()) 70 if err != nil { 71 return nil, err 72 } 73 m := durable.ProllyMapFromIndex(idx) 74 75 // If the schema has changed, don't reuse the index. 76 // TODO: This isn't technically required, but correctly handling updating secondary indexes when only some 77 // of the table's rows have been updated is difficult to get right. 78 // Dropping the index is potentially slower but guarenteed to be correct. 79 if !m.KeyDesc().Equals(index.Schema().GetKeyDescriptorWithNoConversion()) { 80 continue 81 } 82 83 if !m.ValDesc().Equals(index.Schema().GetValueDescriptor()) { 84 continue 85 } 86 87 if schema.IsKeyless(sch) { 88 m = prolly.ConvertToSecondaryKeylessIndex(m) 89 } 90 newMutableSecondaryIdx, err := NewMutableSecondaryIdx(ctx, m, sch, tableName, index) 91 if err != nil { 92 return nil, err 93 } 94 95 newMutableSecondaryIdx.mut = newMutableSecondaryIdx.mut.WithMaxPending(pendingSize) 96 mods = append(mods, newMutableSecondaryIdx) 97 } 98 return mods, nil 99 } 100 101 // MutableSecondaryIdx wraps a prolly.MutableMap of a secondary table index. It 102 // provides the InsertEntry, UpdateEntry, and DeleteEntry functions which can be 103 // used to modify the index based on a modification to corresponding primary row. 104 type MutableSecondaryIdx struct { 105 Name string 106 mut *prolly.MutableMap 107 builder index.SecondaryKeyBuilder 108 } 109 110 // NewMutableSecondaryIdx returns a MutableSecondaryIdx. |m| is the secondary idx data. 111 func NewMutableSecondaryIdx(ctx *sql.Context, idx prolly.Map, sch schema.Schema, tableName string, def schema.Index) (MutableSecondaryIdx, error) { 112 b, err := index.NewSecondaryKeyBuilder(ctx, tableName, sch, def, idx.KeyDesc(), idx.Pool(), idx.NodeStore()) 113 if err != nil { 114 return MutableSecondaryIdx{}, err 115 } 116 117 return MutableSecondaryIdx{ 118 Name: def.Name(), 119 mut: idx.Mutate(), 120 builder: b, 121 }, nil 122 } 123 124 // InsertEntry inserts a secondary index entry given the key and new value 125 // of the primary row. 126 func (m MutableSecondaryIdx) InsertEntry(ctx context.Context, key, newValue val.Tuple) error { 127 newKey, err := m.builder.SecondaryKeyFromRow(ctx, key, newValue) 128 if err != nil { 129 return err 130 } 131 132 // secondary indexes only use their key tuple 133 err = m.mut.Put(ctx, newKey, val.EmptyTuple) 134 if err != nil { 135 return err 136 } 137 return nil 138 } 139 140 // UpdateEntry modifies the corresponding secondary index entry given the key 141 // and curr/new values of the primary row. 142 func (m MutableSecondaryIdx) UpdateEntry(ctx context.Context, key, currValue, newValue val.Tuple) error { 143 currKey, err := m.builder.SecondaryKeyFromRow(ctx, key, currValue) 144 if err != nil { 145 return err 146 } 147 148 newKey, err := m.builder.SecondaryKeyFromRow(ctx, key, newValue) 149 if err != nil { 150 return err 151 } 152 153 err = m.mut.Delete(ctx, currKey) 154 if err != nil { 155 return err 156 } 157 return m.mut.Put(ctx, newKey, val.EmptyTuple) 158 } 159 160 // DeleteEntry deletes a secondary index entry given they key and value of the primary row. 161 func (m MutableSecondaryIdx) DeleteEntry(ctx context.Context, key val.Tuple, value val.Tuple) error { 162 currKey, err := m.builder.SecondaryKeyFromRow(ctx, key, value) 163 if err != nil { 164 return err 165 } 166 167 return m.mut.Delete(ctx, currKey) 168 } 169 170 // Map returns the finalized prolly.Map of the underlying prolly.MutableMap. 171 func (m MutableSecondaryIdx) Map(ctx context.Context) (prolly.Map, error) { 172 return m.mut.Map(ctx) 173 }