github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/branch_control/binlog.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 branch_control 16 17 import ( 18 "fmt" 19 "sync" 20 21 flatbuffers "github.com/dolthub/flatbuffers/v23/go" 22 23 "github.com/dolthub/dolt/go/gen/fb/serial" 24 ) 25 26 //TODO: add stored procedure functions for modifying the binlog 27 28 // Binlog is a running log file that tracks changes to tables within branch control. This is used for history purposes, 29 // as well as transactional purposes through the use of the BinlogOverlay. 30 type Binlog struct { 31 rows []BinlogRow 32 RWMutex *sync.RWMutex 33 } 34 35 // BinlogRow is a row within the Binlog. 36 type BinlogRow struct { 37 IsInsert bool 38 Database string 39 Branch string 40 User string 41 Host string 42 Permissions uint64 43 } 44 45 // BinlogOverlay enables transactional use cases over Binlog. Unlike a Binlog, a BinlogOverlay requires external 46 // synchronization. 47 type BinlogOverlay struct { 48 parentLength int 49 rows []BinlogRow 50 } 51 52 // NewAccessBinlog returns a new Binlog that represents the construction of the given Access values. May be used to 53 // truncate the Binlog's history. 54 func NewAccessBinlog(vals []AccessRow) *Binlog { 55 rows := make([]BinlogRow, len(vals)) 56 for i, val := range vals { 57 rows[i] = BinlogRow{ 58 IsInsert: true, 59 Database: val.Database, 60 Branch: val.Branch, 61 User: val.User, 62 Host: val.Host, 63 Permissions: uint64(val.Permissions), 64 } 65 } 66 return &Binlog{ 67 rows: rows, 68 RWMutex: &sync.RWMutex{}, 69 } 70 } 71 72 // NewNamespaceBinlog returns a new Binlog that represents the construction of the given Namespace values. May be used 73 // to truncate the Binlog's history. 74 func NewNamespaceBinlog(vals []NamespaceValue) *Binlog { 75 rows := make([]BinlogRow, len(vals)) 76 for i, val := range vals { 77 rows[i] = BinlogRow{ 78 IsInsert: true, 79 Database: val.Database, 80 Branch: val.Branch, 81 User: val.User, 82 Host: val.Host, 83 Permissions: 0, 84 } 85 } 86 return &Binlog{ 87 rows: rows, 88 RWMutex: &sync.RWMutex{}, 89 } 90 } 91 92 // Serialize returns the offset for the Binlog written to the given builder. 93 func (binlog *Binlog) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { 94 binlog.RWMutex.RLock() 95 defer binlog.RWMutex.RUnlock() 96 97 // Initialize row offset slice 98 rowOffsets := make([]flatbuffers.UOffsetT, len(binlog.rows)) 99 // Get each row's offset 100 for i, row := range binlog.rows { 101 rowOffsets[i] = row.Serialize(b) 102 } 103 // Get the row vector 104 serial.BranchControlBinlogStartRowsVector(b, len(binlog.rows)) 105 for i := len(rowOffsets) - 1; i >= 0; i-- { 106 b.PrependUOffsetT(rowOffsets[i]) 107 } 108 rows := b.EndVector(len(binlog.rows)) 109 // Write the binlog 110 serial.BranchControlBinlogStart(b) 111 serial.BranchControlBinlogAddRows(b, rows) 112 return serial.BranchControlBinlogEnd(b) 113 } 114 115 // Deserialize populates the binlog with the data from the flatbuffers representation. 116 func (binlog *Binlog) Deserialize(fb *serial.BranchControlBinlog) error { 117 binlog.RWMutex.Lock() 118 defer binlog.RWMutex.Unlock() 119 120 // Verify that the binlog is empty 121 if len(binlog.rows) != 0 { 122 return fmt.Errorf("cannot deserialize to a non-empty binlog") 123 } 124 // Initialize the rows 125 binlog.rows = make([]BinlogRow, fb.RowsLength()) 126 // Read the rows 127 for i := 0; i < fb.RowsLength(); i++ { 128 serialBinlogRow := &serial.BranchControlBinlogRow{} 129 _, err := fb.TryRows(serialBinlogRow, i) 130 if err != nil { 131 return fmt.Errorf("cannot deserialize binlog, it was created with a later version of Dolt") 132 } 133 binlog.rows[i] = BinlogRow{ 134 IsInsert: serialBinlogRow.IsInsert(), 135 Database: string(serialBinlogRow.Database()), 136 Branch: string(serialBinlogRow.Branch()), 137 User: string(serialBinlogRow.User()), 138 Host: string(serialBinlogRow.Host()), 139 Permissions: serialBinlogRow.Permissions(), 140 } 141 } 142 return nil 143 } 144 145 // Insert adds an insert entry to the Binlog. 146 func (binlog *Binlog) Insert(database string, branch string, user string, host string, permissions uint64) { 147 binlog.RWMutex.Lock() 148 defer binlog.RWMutex.Unlock() 149 150 binlog.rows = append(binlog.rows, BinlogRow{ 151 IsInsert: true, 152 Database: database, 153 Branch: branch, 154 User: user, 155 Host: host, 156 Permissions: permissions, 157 }) 158 } 159 160 // Delete adds a delete entry to the Binlog. 161 func (binlog *Binlog) Delete(database string, branch string, user string, host string, permissions uint64) { 162 binlog.RWMutex.Lock() 163 defer binlog.RWMutex.Unlock() 164 165 binlog.rows = append(binlog.rows, BinlogRow{ 166 IsInsert: false, 167 Database: database, 168 Branch: branch, 169 User: user, 170 Host: host, 171 Permissions: permissions, 172 }) 173 } 174 175 // Rows returns the underlying rows. 176 func (binlog *Binlog) Rows() []BinlogRow { 177 return binlog.rows 178 } 179 180 // Serialize returns the offset for the BinlogRow written to the given builder. 181 func (row *BinlogRow) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { 182 database := b.CreateSharedString(row.Database) 183 branch := b.CreateSharedString(row.Branch) 184 user := b.CreateSharedString(row.User) 185 host := b.CreateSharedString(row.Host) 186 187 serial.BranchControlBinlogRowStart(b) 188 serial.BranchControlBinlogRowAddIsInsert(b, row.IsInsert) 189 serial.BranchControlBinlogRowAddDatabase(b, database) 190 serial.BranchControlBinlogRowAddBranch(b, branch) 191 serial.BranchControlBinlogRowAddUser(b, user) 192 serial.BranchControlBinlogRowAddHost(b, host) 193 serial.BranchControlBinlogRowAddPermissions(b, row.Permissions) 194 return serial.BranchControlBinlogRowEnd(b) 195 }