From 024a1b013827e408ba6e8f556b5a71e4a1f315a6 Mon Sep 17 00:00:00 2001 From: Daylon Wilkins Date: Tue, 18 Oct 2022 08:21:08 -0700 Subject: [PATCH] Rewrote branch control persistence to use flatbuffers --- go/cmd/dolt/commands/sql.go | 2 +- go/gen/fb/serial/branchcontrol.go | 1133 +++++++++++++++++ go/gen/fb/serial/fileidentifiers.go | 1 + .../doltcore/branch_control/access.go | 194 +-- .../doltcore/branch_control/binlog.go | 161 +-- .../doltcore/branch_control/branch_control.go | 42 +- .../doltcore/branch_control/expr_parser.go | 58 +- .../doltcore/branch_control/namespace.go | 185 +-- go/serial/branchcontrol.fbs | 71 ++ go/serial/fileidentifiers.go | 1 + go/serial/generate.sh | 1 + 11 files changed, 1523 insertions(+), 326 deletions(-) create mode 100644 go/gen/fb/serial/branchcontrol.go create mode 100644 go/serial/branchcontrol.fbs diff --git a/go/cmd/dolt/commands/sql.go b/go/cmd/dolt/commands/sql.go index 39a59ee51a..3a6469f931 100644 --- a/go/cmd/dolt/commands/sql.go +++ b/go/cmd/dolt/commands/sql.go @@ -259,7 +259,7 @@ func (cmd SqlCmd) Exec(ctx context.Context, commandStr string, args []string, dE } } - // If no privilege filepath specified, default to doltcfg directory + // If no branch control file path is specified, default to doltcfg directory branchControlFilePath, hasBCFilePath := apr.GetValue(BranchCtrlPathFlag) if !hasBCFilePath { branchControlFilePath, err = dEnv.FS.Abs(filepath.Join(cfgDirPath, DefaultBranchCtrlName)) diff --git a/go/gen/fb/serial/branchcontrol.go b/go/gen/fb/serial/branchcontrol.go new file mode 100644 index 0000000000..99a6b0e763 --- /dev/null +++ b/go/gen/fb/serial/branchcontrol.go @@ -0,0 +1,1133 @@ +// Copyright 2022 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package serial + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type BranchControl struct { + _tab flatbuffers.Table +} + +func InitBranchControlRoot(o *BranchControl, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControl(buf []byte, offset flatbuffers.UOffsetT) (*BranchControl, error) { + x := &BranchControl{} + return x, InitBranchControlRoot(x, buf, offset) +} + +func GetRootAsBranchControl(buf []byte, offset flatbuffers.UOffsetT) *BranchControl { + x := &BranchControl{} + InitBranchControlRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControl(buf []byte, offset flatbuffers.UOffsetT) (*BranchControl, error) { + x := &BranchControl{} + return x, InitBranchControlRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControl(buf []byte, offset flatbuffers.UOffsetT) *BranchControl { + x := &BranchControl{} + InitBranchControlRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControl) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControl) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControl) AccessTbl(obj *BranchControlAccess) *BranchControlAccess { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlAccess) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func (rcv *BranchControl) TryAccessTbl(obj *BranchControlAccess) (*BranchControlAccess, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlAccess) + } + obj.Init(rcv._tab.Bytes, x) + if BranchControlAccessNumFields < obj.Table().NumFields() { + return nil, flatbuffers.ErrTableHasUnknownFields + } + return obj, nil + } + return nil, nil +} + +func (rcv *BranchControl) NamespaceTbl(obj *BranchControlNamespace) *BranchControlNamespace { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlNamespace) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func (rcv *BranchControl) TryNamespaceTbl(obj *BranchControlNamespace) (*BranchControlNamespace, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlNamespace) + } + obj.Init(rcv._tab.Bytes, x) + if BranchControlNamespaceNumFields < obj.Table().NumFields() { + return nil, flatbuffers.ErrTableHasUnknownFields + } + return obj, nil + } + return nil, nil +} + +const BranchControlNumFields = 2 + +func BranchControlStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlNumFields) +} +func BranchControlAddAccessTbl(builder *flatbuffers.Builder, accessTbl flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(accessTbl), 0) +} +func BranchControlAddNamespaceTbl(builder *flatbuffers.Builder, namespaceTbl flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(namespaceTbl), 0) +} +func BranchControlEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlAccess struct { + _tab flatbuffers.Table +} + +func InitBranchControlAccessRoot(o *BranchControlAccess, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlAccessNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlAccess(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlAccess, error) { + x := &BranchControlAccess{} + return x, InitBranchControlAccessRoot(x, buf, offset) +} + +func GetRootAsBranchControlAccess(buf []byte, offset flatbuffers.UOffsetT) *BranchControlAccess { + x := &BranchControlAccess{} + InitBranchControlAccessRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlAccess(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlAccess, error) { + x := &BranchControlAccess{} + return x, InitBranchControlAccessRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlAccess(buf []byte, offset flatbuffers.UOffsetT) *BranchControlAccess { + x := &BranchControlAccess{} + InitBranchControlAccessRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlAccess) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlAccess) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlAccess) Binlog(obj *BranchControlBinlog) *BranchControlBinlog { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlBinlog) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func (rcv *BranchControlAccess) TryBinlog(obj *BranchControlBinlog) (*BranchControlBinlog, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlBinlog) + } + obj.Init(rcv._tab.Bytes, x) + if BranchControlBinlogNumFields < obj.Table().NumFields() { + return nil, flatbuffers.ErrTableHasUnknownFields + } + return obj, nil + } + return nil, nil +} + +func (rcv *BranchControlAccess) Branches(obj *BranchControlMatchExpression, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlAccess) TryBranches(obj *BranchControlMatchExpression, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlMatchExpressionNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlAccess) BranchesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlAccess) Users(obj *BranchControlMatchExpression, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlAccess) TryUsers(obj *BranchControlMatchExpression, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlMatchExpressionNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlAccess) UsersLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlAccess) Hosts(obj *BranchControlMatchExpression, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlAccess) TryHosts(obj *BranchControlMatchExpression, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlMatchExpressionNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlAccess) HostsLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlAccess) Values(obj *BranchControlAccessValue, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlAccess) TryValues(obj *BranchControlAccessValue, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlAccessValueNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlAccess) ValuesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +const BranchControlAccessNumFields = 5 + +func BranchControlAccessStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlAccessNumFields) +} +func BranchControlAccessAddBinlog(builder *flatbuffers.Builder, binlog flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(binlog), 0) +} +func BranchControlAccessAddBranches(builder *flatbuffers.Builder, branches flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(branches), 0) +} +func BranchControlAccessStartBranchesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlAccessAddUsers(builder *flatbuffers.Builder, users flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(users), 0) +} +func BranchControlAccessStartUsersVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlAccessAddHosts(builder *flatbuffers.Builder, hosts flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(hosts), 0) +} +func BranchControlAccessStartHostsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlAccessAddValues(builder *flatbuffers.Builder, values flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(4, flatbuffers.UOffsetT(values), 0) +} +func BranchControlAccessStartValuesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlAccessEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlAccessValue struct { + _tab flatbuffers.Table +} + +func InitBranchControlAccessValueRoot(o *BranchControlAccessValue, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlAccessValueNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlAccessValue(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlAccessValue, error) { + x := &BranchControlAccessValue{} + return x, InitBranchControlAccessValueRoot(x, buf, offset) +} + +func GetRootAsBranchControlAccessValue(buf []byte, offset flatbuffers.UOffsetT) *BranchControlAccessValue { + x := &BranchControlAccessValue{} + InitBranchControlAccessValueRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlAccessValue(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlAccessValue, error) { + x := &BranchControlAccessValue{} + return x, InitBranchControlAccessValueRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlAccessValue(buf []byte, offset flatbuffers.UOffsetT) *BranchControlAccessValue { + x := &BranchControlAccessValue{} + InitBranchControlAccessValueRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlAccessValue) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlAccessValue) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlAccessValue) Branch() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlAccessValue) User() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlAccessValue) Host() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlAccessValue) Permissions() uint64 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + return rcv._tab.GetUint64(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *BranchControlAccessValue) MutatePermissions(n uint64) bool { + return rcv._tab.MutateUint64Slot(10, n) +} + +const BranchControlAccessValueNumFields = 4 + +func BranchControlAccessValueStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlAccessValueNumFields) +} +func BranchControlAccessValueAddBranch(builder *flatbuffers.Builder, branch flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(branch), 0) +} +func BranchControlAccessValueAddUser(builder *flatbuffers.Builder, user flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(user), 0) +} +func BranchControlAccessValueAddHost(builder *flatbuffers.Builder, host flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(host), 0) +} +func BranchControlAccessValueAddPermissions(builder *flatbuffers.Builder, permissions uint64) { + builder.PrependUint64Slot(3, permissions, 0) +} +func BranchControlAccessValueEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlNamespace struct { + _tab flatbuffers.Table +} + +func InitBranchControlNamespaceRoot(o *BranchControlNamespace, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlNamespaceNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlNamespace(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlNamespace, error) { + x := &BranchControlNamespace{} + return x, InitBranchControlNamespaceRoot(x, buf, offset) +} + +func GetRootAsBranchControlNamespace(buf []byte, offset flatbuffers.UOffsetT) *BranchControlNamespace { + x := &BranchControlNamespace{} + InitBranchControlNamespaceRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlNamespace(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlNamespace, error) { + x := &BranchControlNamespace{} + return x, InitBranchControlNamespaceRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlNamespace(buf []byte, offset flatbuffers.UOffsetT) *BranchControlNamespace { + x := &BranchControlNamespace{} + InitBranchControlNamespaceRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlNamespace) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlNamespace) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlNamespace) Binlog(obj *BranchControlBinlog) *BranchControlBinlog { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlBinlog) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func (rcv *BranchControlNamespace) TryBinlog(obj *BranchControlBinlog) (*BranchControlBinlog, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(BranchControlBinlog) + } + obj.Init(rcv._tab.Bytes, x) + if BranchControlBinlogNumFields < obj.Table().NumFields() { + return nil, flatbuffers.ErrTableHasUnknownFields + } + return obj, nil + } + return nil, nil +} + +func (rcv *BranchControlNamespace) Branches(obj *BranchControlMatchExpression, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlNamespace) TryBranches(obj *BranchControlMatchExpression, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlMatchExpressionNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlNamespace) BranchesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlNamespace) Users(obj *BranchControlMatchExpression, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlNamespace) TryUsers(obj *BranchControlMatchExpression, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlMatchExpressionNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlNamespace) UsersLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlNamespace) Hosts(obj *BranchControlMatchExpression, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlNamespace) TryHosts(obj *BranchControlMatchExpression, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlMatchExpressionNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlNamespace) HostsLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlNamespace) Values(obj *BranchControlNamespaceValue, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlNamespace) TryValues(obj *BranchControlNamespaceValue, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlNamespaceValueNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlNamespace) ValuesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +const BranchControlNamespaceNumFields = 5 + +func BranchControlNamespaceStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlNamespaceNumFields) +} +func BranchControlNamespaceAddBinlog(builder *flatbuffers.Builder, binlog flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(binlog), 0) +} +func BranchControlNamespaceAddBranches(builder *flatbuffers.Builder, branches flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(branches), 0) +} +func BranchControlNamespaceStartBranchesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlNamespaceAddUsers(builder *flatbuffers.Builder, users flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(users), 0) +} +func BranchControlNamespaceStartUsersVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlNamespaceAddHosts(builder *flatbuffers.Builder, hosts flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(hosts), 0) +} +func BranchControlNamespaceStartHostsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlNamespaceAddValues(builder *flatbuffers.Builder, values flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(4, flatbuffers.UOffsetT(values), 0) +} +func BranchControlNamespaceStartValuesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlNamespaceEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlNamespaceValue struct { + _tab flatbuffers.Table +} + +func InitBranchControlNamespaceValueRoot(o *BranchControlNamespaceValue, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlNamespaceValueNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlNamespaceValue(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlNamespaceValue, error) { + x := &BranchControlNamespaceValue{} + return x, InitBranchControlNamespaceValueRoot(x, buf, offset) +} + +func GetRootAsBranchControlNamespaceValue(buf []byte, offset flatbuffers.UOffsetT) *BranchControlNamespaceValue { + x := &BranchControlNamespaceValue{} + InitBranchControlNamespaceValueRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlNamespaceValue(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlNamespaceValue, error) { + x := &BranchControlNamespaceValue{} + return x, InitBranchControlNamespaceValueRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlNamespaceValue(buf []byte, offset flatbuffers.UOffsetT) *BranchControlNamespaceValue { + x := &BranchControlNamespaceValue{} + InitBranchControlNamespaceValueRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlNamespaceValue) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlNamespaceValue) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlNamespaceValue) Branch() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlNamespaceValue) User() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlNamespaceValue) Host() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +const BranchControlNamespaceValueNumFields = 3 + +func BranchControlNamespaceValueStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlNamespaceValueNumFields) +} +func BranchControlNamespaceValueAddBranch(builder *flatbuffers.Builder, branch flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(branch), 0) +} +func BranchControlNamespaceValueAddUser(builder *flatbuffers.Builder, user flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(user), 0) +} +func BranchControlNamespaceValueAddHost(builder *flatbuffers.Builder, host flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(host), 0) +} +func BranchControlNamespaceValueEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlBinlog struct { + _tab flatbuffers.Table +} + +func InitBranchControlBinlogRoot(o *BranchControlBinlog, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlBinlogNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlBinlog(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlBinlog, error) { + x := &BranchControlBinlog{} + return x, InitBranchControlBinlogRoot(x, buf, offset) +} + +func GetRootAsBranchControlBinlog(buf []byte, offset flatbuffers.UOffsetT) *BranchControlBinlog { + x := &BranchControlBinlog{} + InitBranchControlBinlogRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlBinlog(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlBinlog, error) { + x := &BranchControlBinlog{} + return x, InitBranchControlBinlogRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlBinlog(buf []byte, offset flatbuffers.UOffsetT) *BranchControlBinlog { + x := &BranchControlBinlog{} + InitBranchControlBinlogRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlBinlog) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlBinlog) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlBinlog) Rows(obj *BranchControlBinlogRow, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *BranchControlBinlog) TryRows(obj *BranchControlBinlogRow, j int) (bool, error) { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + if BranchControlBinlogRowNumFields < obj.Table().NumFields() { + return false, flatbuffers.ErrTableHasUnknownFields + } + return true, nil + } + return false, nil +} + +func (rcv *BranchControlBinlog) RowsLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +const BranchControlBinlogNumFields = 1 + +func BranchControlBinlogStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlBinlogNumFields) +} +func BranchControlBinlogAddRows(builder *flatbuffers.Builder, rows flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(rows), 0) +} +func BranchControlBinlogStartRowsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlBinlogEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlBinlogRow struct { + _tab flatbuffers.Table +} + +func InitBranchControlBinlogRowRoot(o *BranchControlBinlogRow, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlBinlogRowNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlBinlogRow(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlBinlogRow, error) { + x := &BranchControlBinlogRow{} + return x, InitBranchControlBinlogRowRoot(x, buf, offset) +} + +func GetRootAsBranchControlBinlogRow(buf []byte, offset flatbuffers.UOffsetT) *BranchControlBinlogRow { + x := &BranchControlBinlogRow{} + InitBranchControlBinlogRowRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlBinlogRow(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlBinlogRow, error) { + x := &BranchControlBinlogRow{} + return x, InitBranchControlBinlogRowRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlBinlogRow(buf []byte, offset flatbuffers.UOffsetT) *BranchControlBinlogRow { + x := &BranchControlBinlogRow{} + InitBranchControlBinlogRowRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlBinlogRow) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlBinlogRow) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlBinlogRow) IsInsert() bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.GetBool(o + rcv._tab.Pos) + } + return false +} + +func (rcv *BranchControlBinlogRow) MutateIsInsert(n bool) bool { + return rcv._tab.MutateBoolSlot(4, n) +} + +func (rcv *BranchControlBinlogRow) Branch() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlBinlogRow) User() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlBinlogRow) Host() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *BranchControlBinlogRow) Permissions() uint64 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(12)) + if o != 0 { + return rcv._tab.GetUint64(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *BranchControlBinlogRow) MutatePermissions(n uint64) bool { + return rcv._tab.MutateUint64Slot(12, n) +} + +const BranchControlBinlogRowNumFields = 5 + +func BranchControlBinlogRowStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlBinlogRowNumFields) +} +func BranchControlBinlogRowAddIsInsert(builder *flatbuffers.Builder, isInsert bool) { + builder.PrependBoolSlot(0, isInsert, false) +} +func BranchControlBinlogRowAddBranch(builder *flatbuffers.Builder, branch flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(branch), 0) +} +func BranchControlBinlogRowAddUser(builder *flatbuffers.Builder, user flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(user), 0) +} +func BranchControlBinlogRowAddHost(builder *flatbuffers.Builder, host flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(host), 0) +} +func BranchControlBinlogRowAddPermissions(builder *flatbuffers.Builder, permissions uint64) { + builder.PrependUint64Slot(4, permissions, 0) +} +func BranchControlBinlogRowEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} + +type BranchControlMatchExpression struct { + _tab flatbuffers.Table +} + +func InitBranchControlMatchExpressionRoot(o *BranchControlMatchExpression, buf []byte, offset flatbuffers.UOffsetT) error { + n := flatbuffers.GetUOffsetT(buf[offset:]) + o.Init(buf, n+offset) + if BranchControlMatchExpressionNumFields < o.Table().NumFields() { + return flatbuffers.ErrTableHasUnknownFields + } + return nil +} + +func TryGetRootAsBranchControlMatchExpression(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlMatchExpression, error) { + x := &BranchControlMatchExpression{} + return x, InitBranchControlMatchExpressionRoot(x, buf, offset) +} + +func GetRootAsBranchControlMatchExpression(buf []byte, offset flatbuffers.UOffsetT) *BranchControlMatchExpression { + x := &BranchControlMatchExpression{} + InitBranchControlMatchExpressionRoot(x, buf, offset) + return x +} + +func TryGetSizePrefixedRootAsBranchControlMatchExpression(buf []byte, offset flatbuffers.UOffsetT) (*BranchControlMatchExpression, error) { + x := &BranchControlMatchExpression{} + return x, InitBranchControlMatchExpressionRoot(x, buf, offset+flatbuffers.SizeUint32) +} + +func GetSizePrefixedRootAsBranchControlMatchExpression(buf []byte, offset flatbuffers.UOffsetT) *BranchControlMatchExpression { + x := &BranchControlMatchExpression{} + InitBranchControlMatchExpressionRoot(x, buf, offset+flatbuffers.SizeUint32) + return x +} + +func (rcv *BranchControlMatchExpression) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *BranchControlMatchExpression) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *BranchControlMatchExpression) Index() uint32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.GetUint32(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *BranchControlMatchExpression) MutateIndex(n uint32) bool { + return rcv._tab.MutateUint32Slot(4, n) +} + +func (rcv *BranchControlMatchExpression) SortOrders(j int) int32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + a := rcv._tab.Vector(o) + return rcv._tab.GetInt32(a + flatbuffers.UOffsetT(j*4)) + } + return 0 +} + +func (rcv *BranchControlMatchExpression) SortOrdersLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *BranchControlMatchExpression) MutateSortOrders(j int, n int32) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + a := rcv._tab.Vector(o) + return rcv._tab.MutateInt32(a+flatbuffers.UOffsetT(j*4), n) + } + return false +} + +const BranchControlMatchExpressionNumFields = 2 + +func BranchControlMatchExpressionStart(builder *flatbuffers.Builder) { + builder.StartObject(BranchControlMatchExpressionNumFields) +} +func BranchControlMatchExpressionAddIndex(builder *flatbuffers.Builder, index uint32) { + builder.PrependUint32Slot(0, index, 0) +} +func BranchControlMatchExpressionAddSortOrders(builder *flatbuffers.Builder, sortOrders flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(sortOrders), 0) +} +func BranchControlMatchExpressionStartSortOrdersVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func BranchControlMatchExpressionEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/go/gen/fb/serial/fileidentifiers.go b/go/gen/fb/serial/fileidentifiers.go index e5099ee63d..66eb49bab4 100644 --- a/go/gen/fb/serial/fileidentifiers.go +++ b/go/gen/fb/serial/fileidentifiers.go @@ -36,6 +36,7 @@ const TableSchemaFileID = "DSCH" const ForeignKeyCollectionFileID = "DFKC" const MergeArtifactsFileID = "ARTM" const BlobFileID = "BLOB" +const BranchControlFileID = "BRCL" const MessageTypesKind int = 27 diff --git a/go/libraries/doltcore/branch_control/access.go b/go/libraries/doltcore/branch_control/access.go index 8d24e04c48..56b07a4cbf 100644 --- a/go/libraries/doltcore/branch_control/access.go +++ b/go/libraries/doltcore/branch_control/access.go @@ -15,12 +15,13 @@ package branch_control import ( - "bytes" - "encoding/binary" "fmt" "sync" "github.com/dolthub/go-mysql-server/sql" + flatbuffers "github.com/google/flatbuffers/go" + + "github.com/dolthub/dolt/go/gen/fb/serial" ) // Permissions are a set of flags that denote a user's allowed functionality on a branch. @@ -31,10 +32,6 @@ const ( Permissions_Write // Permissions_Write allows for all modifying operations on a branch, but does not allow modification of table entries ) -const ( - currentAccessVersion = uint16(1) -) - // Access contains all of the expressions that comprise the "dolt_branch_control" table, which handles write Access to // branches, along with write access to the branch control system tables. type Access struct { @@ -107,62 +104,118 @@ func (tbl *Access) GetIndex(branchExpr string, userExpr string, hostExpr string) return -1 } -// Serialize writes the table to the given buffer. All encoded integers are big-endian. -func (tbl *Access) Serialize(buffer *bytes.Buffer) { +// Serialize returns the offset for the Access table written to the given builder. +func (tbl *Access) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { tbl.RWMutex.RLock() defer tbl.RWMutex.RUnlock() - // Write the version bytes - writeUint16(buffer, currentAccessVersion) - // Write the number of entries - numOfEntries := uint32(len(tbl.Values)) - writeUint32(buffer, numOfEntries) - - // Write the rows - for _, matchExpr := range tbl.Branches { - matchExpr.Serialize(buffer) + // Serialize the binlog + binlog := tbl.binlog.Serialize(b) + // Initialize field offset slices + branchOffsets := make([]flatbuffers.UOffsetT, len(tbl.Branches)) + userOffsets := make([]flatbuffers.UOffsetT, len(tbl.Users)) + hostOffsets := make([]flatbuffers.UOffsetT, len(tbl.Hosts)) + valueOffsets := make([]flatbuffers.UOffsetT, len(tbl.Values)) + // Get field offsets + for i, matchExpr := range tbl.Branches { + branchOffsets[i] = matchExpr.Serialize(b) } - for _, matchExpr := range tbl.Users { - matchExpr.Serialize(buffer) + for i, matchExpr := range tbl.Users { + userOffsets[i] = matchExpr.Serialize(b) } - for _, matchExpr := range tbl.Hosts { - matchExpr.Serialize(buffer) + for i, matchExpr := range tbl.Hosts { + hostOffsets[i] = matchExpr.Serialize(b) } - for _, val := range tbl.Values { - val.Serialize(buffer) + for i, val := range tbl.Values { + valueOffsets[i] = val.Serialize(b) } - // Write the binlog - _ = tbl.binlog.Serialize(buffer) + // Get the field vectors + serial.BranchControlAccessStartBranchesVector(b, len(branchOffsets)) + for i := len(branchOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(branchOffsets[i]) + } + branches := b.EndVector(len(branchOffsets)) + serial.BranchControlAccessStartUsersVector(b, len(userOffsets)) + for i := len(userOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(userOffsets[i]) + } + users := b.EndVector(len(userOffsets)) + serial.BranchControlAccessStartHostsVector(b, len(hostOffsets)) + for i := len(hostOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(hostOffsets[i]) + } + hosts := b.EndVector(len(hostOffsets)) + serial.BranchControlAccessStartValuesVector(b, len(valueOffsets)) + for i := len(valueOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(valueOffsets[i]) + } + values := b.EndVector(len(valueOffsets)) + // Write the table + serial.BranchControlAccessStart(b) + serial.BranchControlAccessAddBinlog(b, binlog) + serial.BranchControlAccessAddBranches(b, branches) + serial.BranchControlAccessAddUsers(b, users) + serial.BranchControlAccessAddHosts(b, hosts) + serial.BranchControlAccessAddValues(b, values) + return serial.BranchControlAccessEnd(b) } -// Deserialize populates the table with the given data. Returns an error if the data cannot be deserialized, or if the -// table has already been written to. Deserialize must be called on an empty table. -func (tbl *Access) Deserialize(data []byte, position *uint64) error { +// Deserialize populates the table with the data from the flatbuffers representation. +func (tbl *Access) Deserialize(fb *serial.BranchControlAccess) error { tbl.RWMutex.Lock() defer tbl.RWMutex.Unlock() + // Verify that the table is empty if len(tbl.Values) != 0 { return fmt.Errorf("cannot deserialize to a non-empty access table") } - // Read the version - version := binary.BigEndian.Uint16(data[*position:]) - *position += 2 - if version != currentAccessVersion { - // If we ever increment the access version, this will instead handle the conversion from previous versions - return fmt.Errorf(`cannot deserialize an access table with version "%d"`, version) + // Verify that all fields have the same length + if fb.BranchesLength() != fb.UsersLength() || fb.UsersLength() != fb.HostsLength() || fb.HostsLength() != fb.ValuesLength() { + return fmt.Errorf("cannot deserialize an access table with differing field lengths") } - // Read the number of entries - numOfEntries := binary.BigEndian.Uint32(data[*position:]) - *position += 4 - // Read the rows - tbl.Branches = deserializeMatchExpressions(numOfEntries, data, position) - tbl.Users = deserializeMatchExpressions(numOfEntries, data, position) - tbl.Hosts = deserializeMatchExpressions(numOfEntries, data, position) - tbl.Values = make([]AccessValue, numOfEntries) - for i := uint32(0); i < numOfEntries; i++ { - tbl.Values[i] = deserializeAccessValue(data, position) + // Read the binlog + binlog, err := fb.TryBinlog(nil) + if err != nil { + return err } - return tbl.binlog.Deserialize(data, position) + if err = tbl.binlog.Deserialize(binlog); err != nil { + return err + } + // Initialize every slice + tbl.Branches = make([]MatchExpression, fb.BranchesLength()) + tbl.Users = make([]MatchExpression, fb.UsersLength()) + tbl.Hosts = make([]MatchExpression, fb.HostsLength()) + tbl.Values = make([]AccessValue, fb.ValuesLength()) + // Read the branches + for i := 0; i < fb.BranchesLength(); i++ { + serialMatchExpr := &serial.BranchControlMatchExpression{} + fb.Branches(serialMatchExpr, i) + tbl.Branches[i] = deserializeMatchExpression(serialMatchExpr) + } + // Read the users + for i := 0; i < fb.UsersLength(); i++ { + serialMatchExpr := &serial.BranchControlMatchExpression{} + fb.Users(serialMatchExpr, i) + tbl.Users[i] = deserializeMatchExpression(serialMatchExpr) + } + // Read the hosts + for i := 0; i < fb.HostsLength(); i++ { + serialMatchExpr := &serial.BranchControlMatchExpression{} + fb.Hosts(serialMatchExpr, i) + tbl.Hosts[i] = deserializeMatchExpression(serialMatchExpr) + } + // Read the values + for i := 0; i < fb.ValuesLength(); i++ { + serialAccessValue := &serial.BranchControlAccessValue{} + fb.Values(serialAccessValue, i) + tbl.Values[i] = AccessValue{ + Branch: string(serialAccessValue.Branch()), + User: string(serialAccessValue.User()), + Host: string(serialAccessValue.Host()), + Permissions: Permissions(serialAccessValue.Permissions()), + } + } + return nil } // filterBranches returns all branches that match the given collection indexes. @@ -210,45 +263,16 @@ func (tbl *Access) gatherPermissions(collectionIndexes []uint32) Permissions { return perms } -// Serialize writes the value to the given buffer. All encoded integers are big-endian. -func (val *AccessValue) Serialize(buffer *bytes.Buffer) { - // Write the branch - branchLen := uint16(len(val.Branch)) - writeUint16(buffer, branchLen) - buffer.WriteString(val.Branch) - // Write the user - userLen := uint16(len(val.User)) - writeUint16(buffer, userLen) - buffer.WriteString(val.User) - // Write the host - hostLen := uint16(len(val.Host)) - writeUint16(buffer, hostLen) - buffer.WriteString(val.Host) - // Write the permissions - writeUint64(buffer, uint64(val.Permissions)) -} +// Serialize returns the offset for the AccessValue written to the given builder. +func (val *AccessValue) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { + branch := b.CreateString(val.Branch) + user := b.CreateString(val.User) + host := b.CreateString(val.Host) -// deserializeAccessValue returns a AccessValue from the data at the given position. Assumes that the given data's -// encoded integers are big-endian. -func deserializeAccessValue(data []byte, position *uint64) AccessValue { - val := AccessValue{} - // Read the branch - branchLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - val.Branch = string(data[*position : *position+branchLen]) - *position += branchLen - // Read the user - userLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - val.User = string(data[*position : *position+userLen]) - *position += userLen - // Read the host - hostLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - val.Host = string(data[*position : *position+hostLen]) - *position += hostLen - // Read the permissions - val.Permissions = Permissions(binary.BigEndian.Uint64(data[*position:])) - *position += 8 - return val + serial.BranchControlAccessValueStart(b) + serial.BranchControlAccessValueAddBranch(b, branch) + serial.BranchControlAccessValueAddUser(b, user) + serial.BranchControlAccessValueAddHost(b, host) + serial.BranchControlAccessValueAddPermissions(b, uint64(val.Permissions)) + return serial.BranchControlAccessValueEnd(b) } diff --git a/go/libraries/doltcore/branch_control/binlog.go b/go/libraries/doltcore/branch_control/binlog.go index 2c7356c9d0..56e03538bb 100644 --- a/go/libraries/doltcore/branch_control/binlog.go +++ b/go/libraries/doltcore/branch_control/binlog.go @@ -15,14 +15,12 @@ package branch_control import ( - "bytes" - "encoding/binary" "fmt" "sync" -) -const ( - currentBinlogVersion = uint16(1) + flatbuffers "github.com/google/flatbuffers/go" + + "github.com/dolthub/dolt/go/gen/fb/serial" ) //TODO: add stored procedure functions for modifying the binlog @@ -88,51 +86,51 @@ func NewNamespaceBinlog(vals []NamespaceValue) *Binlog { } } -// Serialize returns the Binlog as a byte slice. Writes to the given buffer if one is provided, else allocates a -// temporary buffer. All encoded integers are big-endian. -func (binlog *Binlog) Serialize(buffer *bytes.Buffer) []byte { +// Serialize returns the offset for the Binlog written to the given builder. +func (binlog *Binlog) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { binlog.RWMutex.RLock() defer binlog.RWMutex.RUnlock() - if buffer == nil { - buffer = &bytes.Buffer{} + // Initialize row offset slice + rowOffsets := make([]flatbuffers.UOffsetT, len(binlog.rows)) + // Get each row's offset + for i, row := range binlog.rows { + rowOffsets[i] = row.Serialize(b) } - // Write the version bytes - writeUint16(buffer, currentBinlogVersion) - // Write the number of entries - binlogSize := uint64(len(binlog.rows)) - writeUint64(buffer, binlogSize) - - // Write the rows - for _, binlogRow := range binlog.rows { - binlogRow.Serialize(buffer) + // Get the row vector + serial.BranchControlBinlogStartRowsVector(b, len(binlog.rows)) + for i := len(rowOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(rowOffsets[i]) } - return buffer.Bytes() + rows := b.EndVector(len(binlog.rows)) + // Write the binlog + serial.BranchControlBinlogStart(b) + serial.BranchControlBinlogAddRows(b, rows) + return serial.BranchControlBinlogEnd(b) } -// Deserialize populates the binlog with the given data. Returns an error if the data cannot be deserialized, or if the -// Binlog has already been written to. Deserialize must be called on an empty Binlog. -func (binlog *Binlog) Deserialize(data []byte, position *uint64) error { +// Deserialize populates the binlog with the data from the flatbuffers representation. +func (binlog *Binlog) Deserialize(fb *serial.BranchControlBinlog) error { binlog.RWMutex.Lock() defer binlog.RWMutex.Unlock() + // Verify that the binlog is empty if len(binlog.rows) != 0 { return fmt.Errorf("cannot deserialize to a non-empty binlog") } - // Read the version - version := binary.BigEndian.Uint16(data[*position:]) - *position += 2 - if version != currentBinlogVersion { - // If we ever increment the binlog version, this will instead handle the conversion from previous versions - return fmt.Errorf(`cannot deserialize a binlog with version "%d"`, version) - } - // Read the number of entries - binlogSize := binary.BigEndian.Uint64(data[*position:]) - *position += 8 + // Initialize the rows + binlog.rows = make([]BinlogRow, fb.RowsLength()) // Read the rows - binlog.rows = make([]BinlogRow, binlogSize) - for i := uint64(0); i < binlogSize; i++ { - binlog.rows[i] = deserializeBinlogRow(data, position) + for i := 0; i < fb.RowsLength(); i++ { + serialBinlogRow := &serial.BranchControlBinlogRow{} + fb.Rows(serialBinlogRow, i) + binlog.rows[i] = BinlogRow{ + IsInsert: serialBinlogRow.IsInsert(), + Branch: string(serialBinlogRow.Branch()), + User: string(serialBinlogRow.User()), + Host: string(serialBinlogRow.Host()), + Permissions: serialBinlogRow.Permissions(), + } } return nil } @@ -197,60 +195,19 @@ func (binlog *Binlog) Rows() []BinlogRow { return binlog.rows } -// Serialize writes the row to the given buffer. All encoded integers are big-endian. -func (row *BinlogRow) Serialize(buffer *bytes.Buffer) { - // Write whether this was an insertion or deletion - if row.IsInsert { - buffer.WriteByte(1) - } else { - buffer.WriteByte(0) - } - // Write the branch - branchLen := uint16(len(row.Branch)) - writeUint16(buffer, branchLen) - buffer.WriteString(row.Branch) - // Write the user - userLen := uint16(len(row.User)) - writeUint16(buffer, userLen) - buffer.WriteString(row.User) - // Write the host - hostLen := uint16(len(row.Host)) - writeUint16(buffer, hostLen) - buffer.WriteString(row.Host) - // Write the permissions - writeUint64(buffer, row.Permissions) -} +// Serialize returns the offset for the BinlogRow written to the given builder. +func (row *BinlogRow) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { + branch := b.CreateString(row.Branch) + user := b.CreateString(row.User) + host := b.CreateString(row.Host) -// deserializeBinlogRow returns a BinlogRow from the data at the given position. Assumes that the given data's encoded -// integers are big-endian. -func deserializeBinlogRow(data []byte, position *uint64) BinlogRow { - binlogRow := BinlogRow{} - // Read whether this was an insert or write - if data[*position] == 1 { - binlogRow.IsInsert = true - } else { - binlogRow.IsInsert = false - } - *position += 1 - // Read the branch - branchLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - binlogRow.Branch = string(data[*position : *position+branchLen]) - *position += branchLen - // Read the user - userLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - binlogRow.User = string(data[*position : *position+userLen]) - *position += userLen - // Read the host - hostLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - binlogRow.Host = string(data[*position : *position+hostLen]) - *position += hostLen - // Read the permissions - binlogRow.Permissions = binary.BigEndian.Uint64(data[*position:]) - *position += 8 - return binlogRow + serial.BranchControlBinlogRowStart(b) + serial.BranchControlBinlogRowAddIsInsert(b, row.IsInsert) + serial.BranchControlBinlogRowAddBranch(b, branch) + serial.BranchControlBinlogRowAddUser(b, user) + serial.BranchControlBinlogRowAddHost(b, host) + serial.BranchControlBinlogRowAddPermissions(b, row.Permissions) + return serial.BranchControlBinlogRowEnd(b) } // Insert adds an insert entry to the BinlogOverlay. @@ -274,29 +231,3 @@ func (overlay *BinlogOverlay) Delete(branch string, user string, host string, pe Permissions: permissions, }) } - -// writeUint64 writes an uint64 into the buffer. -func writeUint64(buffer *bytes.Buffer, val uint64) { - buffer.WriteByte(byte(val >> 56)) - buffer.WriteByte(byte(val >> 48)) - buffer.WriteByte(byte(val >> 40)) - buffer.WriteByte(byte(val >> 32)) - buffer.WriteByte(byte(val >> 24)) - buffer.WriteByte(byte(val >> 16)) - buffer.WriteByte(byte(val >> 8)) - buffer.WriteByte(byte(val)) -} - -// writeUint32 writes an uint32 into the buffer. -func writeUint32(buffer *bytes.Buffer, val uint32) { - buffer.WriteByte(byte(val >> 24)) - buffer.WriteByte(byte(val >> 16)) - buffer.WriteByte(byte(val >> 8)) - buffer.WriteByte(byte(val)) -} - -// writeUint16 writes an uint16 into the buffer. -func writeUint16(buffer *bytes.Buffer, val uint16) { - buffer.WriteByte(byte(val >> 8)) - buffer.WriteByte(byte(val)) -} diff --git a/go/libraries/doltcore/branch_control/branch_control.go b/go/libraries/doltcore/branch_control/branch_control.go index 1e9088fdc6..a38024ba6c 100644 --- a/go/libraries/doltcore/branch_control/branch_control.go +++ b/go/libraries/doltcore/branch_control/branch_control.go @@ -15,14 +15,16 @@ package branch_control import ( - "bytes" "context" goerrors "errors" + "fmt" "os" + "github.com/dolthub/go-mysql-server/sql" + flatbuffers "github.com/google/flatbuffers/go" "gopkg.in/src-d/go-errors.v1" - "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/dolt/go/gen/fb/serial" ) var ( @@ -101,12 +103,27 @@ func LoadData(ctx context.Context, branchControlFilePath string, doltConfigDirPa if len(data) == 0 { return nil } - position := uint64(0) - // The Deserialize functions acquire write locks, so we don't acquire them here - if err = StaticController.Access.Deserialize(data, &position); err != nil { + // Load the tables + if serial.GetFileID(data) != serial.BranchControlFileID { + return fmt.Errorf("unable to deserialize branch controller, unknown file ID `%s`", serial.GetFileID(data)) + } + bc, err := serial.TryGetRootAsBranchControl(data, serial.MessagePrefixSz) + if err != nil { return err } - if err = StaticController.Namespace.Deserialize(data, &position); err != nil { + access, err := bc.TryAccessTbl(nil) + if err != nil { + return err + } + namespace, err := bc.TryNamespaceTbl(nil) + if err != nil { + return err + } + // The Deserialize functions acquire write locks, so we don't acquire them here + if err = StaticController.Access.Deserialize(access); err != nil { + return err + } + if err = StaticController.Namespace.Deserialize(namespace); err != nil { return err } return nil @@ -133,11 +150,16 @@ func SaveData(ctx context.Context) error { return err } } - buffer := bytes.Buffer{} + b := flatbuffers.NewBuilder(1024) // The Serialize functions acquire read locks, so we don't acquire them here - StaticController.Access.Serialize(&buffer) - StaticController.Namespace.Serialize(&buffer) - return os.WriteFile(StaticController.branchControlFilePath, buffer.Bytes(), 0777) + accessOffset := StaticController.Access.Serialize(b) + namespaceOffset := StaticController.Namespace.Serialize(b) + serial.BranchControlStart(b) + serial.BranchControlAddAccessTbl(b, accessOffset) + serial.BranchControlAddNamespaceTbl(b, namespaceOffset) + root := serial.BranchControlEnd(b) + data := serial.FinishMessage(b, root, []byte(serial.BranchControlFileID)) + return os.WriteFile(StaticController.branchControlFilePath, data, 0777) } // Reset is a temporary function just for testing. Once the controller is in the context, this will be unnecessary. diff --git a/go/libraries/doltcore/branch_control/expr_parser.go b/go/libraries/doltcore/branch_control/expr_parser.go index 585aa6ef63..d288a9a7d2 100644 --- a/go/libraries/doltcore/branch_control/expr_parser.go +++ b/go/libraries/doltcore/branch_control/expr_parser.go @@ -15,13 +15,14 @@ package branch_control import ( - "bytes" - "encoding/binary" "math" "sync" "unicode/utf8" "github.com/dolthub/go-mysql-server/sql" + flatbuffers "github.com/google/flatbuffers/go" + + "github.com/dolthub/dolt/go/gen/fb/serial" ) const ( @@ -254,43 +255,28 @@ func (matchExpr MatchExpression) IsAtEnd() bool { return len(matchExpr.SortOrders) == 0 || (len(matchExpr.SortOrders) == 1 && matchExpr.SortOrders[0] == anyMatch) } -// Serialize writes the MatchExpression to the given buffer. All encoded integers are big-endian. -func (matchExpr MatchExpression) Serialize(buffer *bytes.Buffer) { - // Write the length - sortOrderLen := uint16(len(matchExpr.SortOrders)) - writeUint16(buffer, sortOrderLen) - // Write the sort orders - for _, sortOrder := range matchExpr.SortOrders { - // We can convert to an uint32 on write and convert back to an int32 on read - writeUint32(buffer, uint32(sortOrder)) +// Serialize returns the offset for the MatchExpression written to the given builder. +func (matchExpr MatchExpression) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { + _ = serial.BranchControlMatchExpressionStartSortOrdersVector(b, len(matchExpr.SortOrders)) + for i := len(matchExpr.SortOrders) - 1; i >= 0; i-- { + b.PrependInt32(matchExpr.SortOrders[i]) } + sortOrdersOffset := b.EndVector(len(matchExpr.SortOrders)) + + serial.BranchControlMatchExpressionStart(b) + serial.BranchControlMatchExpressionAddIndex(b, matchExpr.CollectionIndex) + serial.BranchControlMatchExpressionAddSortOrders(b, sortOrdersOffset) + return serial.BranchControlMatchExpressionEnd(b) } -// deserializeMatchExpression returns a MatchExpression from the data at the given position. Assumes that the given -// data's encoded integers are big-endian. -func deserializeMatchExpression(collectionIndex uint32, data []byte, position *uint64) MatchExpression { - matchExpr := MatchExpression{CollectionIndex: collectionIndex} - // Read the length - sortOrderLen := binary.BigEndian.Uint16(data[*position:]) - *position += 2 - // Create the sort order slice - matchExpr.SortOrders = make([]int32, sortOrderLen) - // Read the sort orders - for i := uint16(0); i < sortOrderLen; i++ { - matchExpr.SortOrders[i] = int32(binary.BigEndian.Uint32(data[*position:])) - *position += 4 +// deserializeMatchExpression populates the MatchExpression with the data from the flatbuffers representation. +func deserializeMatchExpression(fb *serial.BranchControlMatchExpression) MatchExpression { + matchExpr := MatchExpression{ + CollectionIndex: fb.Index(), + SortOrders: make([]int32, fb.SortOrdersLength()), + } + for i := 0; i < fb.SortOrdersLength(); i++ { + matchExpr.SortOrders[i] = fb.SortOrders(i) } return matchExpr } - -// deserializeMatchExpressions returns a []MatchExpression from the data at the given position. Assumes that the given -// data's encoded integers are big-endian. -func deserializeMatchExpressions(matchExprsLen uint32, data []byte, position *uint64) []MatchExpression { - // Create the slice - matchExprs := make([]MatchExpression, matchExprsLen) - // Read each match expression - for i := uint32(0); i < matchExprsLen; i++ { - matchExprs[i] = deserializeMatchExpression(i, data, position) - } - return matchExprs -} diff --git a/go/libraries/doltcore/branch_control/namespace.go b/go/libraries/doltcore/branch_control/namespace.go index 23272a53ce..e4f467168e 100644 --- a/go/libraries/doltcore/branch_control/namespace.go +++ b/go/libraries/doltcore/branch_control/namespace.go @@ -15,16 +15,13 @@ package branch_control import ( - "bytes" - "encoding/binary" "fmt" "sync" "github.com/dolthub/go-mysql-server/sql" -) + flatbuffers "github.com/google/flatbuffers/go" -const ( - currentNamespaceVersion = uint16(1) + "github.com/dolthub/dolt/go/gen/fb/serial" ) // Namespace contains all of the expressions that comprise the "dolt_branch_namespace_control" table, which controls @@ -125,62 +122,117 @@ func (tbl *Namespace) Access() *Access { return tbl.access } -// Serialize writes the table to the given buffer. All encoded integers are big-endian. -func (tbl *Namespace) Serialize(buffer *bytes.Buffer) { +// Serialize returns the offset for the Namespace table written to the given builder. +func (tbl *Namespace) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { tbl.RWMutex.RLock() defer tbl.RWMutex.RUnlock() - // Write the version bytes - writeUint16(buffer, currentNamespaceVersion) - // Write the number of entries - numOfEntries := uint32(len(tbl.Values)) - writeUint32(buffer, numOfEntries) - - // Write the rows - for _, matchExpr := range tbl.Branches { - matchExpr.Serialize(buffer) + // Serialize the binlog + binlog := tbl.binlog.Serialize(b) + // Initialize field offset slices + branchOffsets := make([]flatbuffers.UOffsetT, len(tbl.Branches)) + userOffsets := make([]flatbuffers.UOffsetT, len(tbl.Users)) + hostOffsets := make([]flatbuffers.UOffsetT, len(tbl.Hosts)) + valueOffsets := make([]flatbuffers.UOffsetT, len(tbl.Values)) + // Get field offsets + for i, matchExpr := range tbl.Branches { + branchOffsets[i] = matchExpr.Serialize(b) } - for _, matchExpr := range tbl.Users { - matchExpr.Serialize(buffer) + for i, matchExpr := range tbl.Users { + userOffsets[i] = matchExpr.Serialize(b) } - for _, matchExpr := range tbl.Hosts { - matchExpr.Serialize(buffer) + for i, matchExpr := range tbl.Hosts { + hostOffsets[i] = matchExpr.Serialize(b) } - for _, val := range tbl.Values { - val.Serialize(buffer) + for i, val := range tbl.Values { + valueOffsets[i] = val.Serialize(b) } - // Write the binlog - _ = tbl.binlog.Serialize(buffer) + // Get the field vectors + serial.BranchControlNamespaceStartBranchesVector(b, len(branchOffsets)) + for i := len(branchOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(branchOffsets[i]) + } + branches := b.EndVector(len(branchOffsets)) + serial.BranchControlNamespaceStartUsersVector(b, len(userOffsets)) + for i := len(userOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(userOffsets[i]) + } + users := b.EndVector(len(userOffsets)) + serial.BranchControlNamespaceStartHostsVector(b, len(hostOffsets)) + for i := len(hostOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(hostOffsets[i]) + } + hosts := b.EndVector(len(hostOffsets)) + serial.BranchControlNamespaceStartValuesVector(b, len(valueOffsets)) + for i := len(valueOffsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(valueOffsets[i]) + } + values := b.EndVector(len(valueOffsets)) + // Write the table + serial.BranchControlNamespaceStart(b) + serial.BranchControlNamespaceAddBinlog(b, binlog) + serial.BranchControlNamespaceAddBranches(b, branches) + serial.BranchControlNamespaceAddUsers(b, users) + serial.BranchControlNamespaceAddHosts(b, hosts) + serial.BranchControlNamespaceAddValues(b, values) + return serial.BranchControlNamespaceEnd(b) } -// Deserialize populates the table with the given data. Returns an error if the data cannot be deserialized, or if the -// table has already been written to. Deserialize must be called on an empty table. -func (tbl *Namespace) Deserialize(data []byte, position *uint64) error { +// Deserialize populates the table with the data from the flatbuffers representation. +func (tbl *Namespace) Deserialize(fb *serial.BranchControlNamespace) error { tbl.RWMutex.Lock() defer tbl.RWMutex.Unlock() + // Verify that the table is empty if len(tbl.Values) != 0 { return fmt.Errorf("cannot deserialize to a non-empty namespace table") } - // Read the version - version := binary.BigEndian.Uint16(data[*position:]) - *position += 2 - if version != currentNamespaceVersion { - // If we ever increment the namespace version, this will instead handle the conversion from previous versions - return fmt.Errorf(`cannot deserialize an namespace table with version "%d"`, version) + // Verify that all fields have the same length + if fb.BranchesLength() != fb.UsersLength() || fb.UsersLength() != fb.HostsLength() || fb.HostsLength() != fb.ValuesLength() { + return fmt.Errorf("cannot deserialize a namespace table with differing field lengths") } - // Read the number of entries - numOfEntries := binary.BigEndian.Uint32(data[*position:]) - *position += 4 - // Read the rows - tbl.Branches = deserializeMatchExpressions(numOfEntries, data, position) - tbl.Users = deserializeMatchExpressions(numOfEntries, data, position) - tbl.Hosts = deserializeMatchExpressions(numOfEntries, data, position) - tbl.Values = make([]NamespaceValue, numOfEntries) - for i := uint32(0); i < numOfEntries; i++ { - tbl.Values[i] = deserializeNamespaceValue(data, position) + // Read the binlog + binlog, err := fb.TryBinlog(nil) + if err != nil { + return err } - return tbl.binlog.Deserialize(data, position) + if err = tbl.binlog.Deserialize(binlog); err != nil { + return err + } + // Initialize every slice + tbl.Branches = make([]MatchExpression, fb.BranchesLength()) + tbl.Users = make([]MatchExpression, fb.UsersLength()) + tbl.Hosts = make([]MatchExpression, fb.HostsLength()) + tbl.Values = make([]NamespaceValue, fb.ValuesLength()) + // Read the branches + for i := 0; i < fb.BranchesLength(); i++ { + serialMatchExpr := &serial.BranchControlMatchExpression{} + fb.Branches(serialMatchExpr, i) + tbl.Branches[i] = deserializeMatchExpression(serialMatchExpr) + } + // Read the users + for i := 0; i < fb.UsersLength(); i++ { + serialMatchExpr := &serial.BranchControlMatchExpression{} + fb.Users(serialMatchExpr, i) + tbl.Users[i] = deserializeMatchExpression(serialMatchExpr) + } + // Read the hosts + for i := 0; i < fb.HostsLength(); i++ { + serialMatchExpr := &serial.BranchControlMatchExpression{} + fb.Hosts(serialMatchExpr, i) + tbl.Hosts[i] = deserializeMatchExpression(serialMatchExpr) + } + // Read the values + for i := 0; i < fb.ValuesLength(); i++ { + serialNamespaceValue := &serial.BranchControlNamespaceValue{} + fb.Values(serialNamespaceValue, i) + tbl.Values[i] = NamespaceValue{ + Branch: string(serialNamespaceValue.Branch()), + User: string(serialNamespaceValue.User()), + Host: string(serialNamespaceValue.Host()), + } + } + return nil } // filterBranches returns all branches that match the given collection indexes. @@ -219,40 +271,15 @@ func (tbl *Namespace) filterHosts(filters []uint32) []MatchExpression { return matchExprs } -// Serialize writes the value to the given buffer. All encoded integers are big-endian. -func (val *NamespaceValue) Serialize(buffer *bytes.Buffer) { - // Write the branch - branchLen := uint16(len(val.Branch)) - writeUint16(buffer, branchLen) - buffer.WriteString(val.Branch) - // Write the user - userLen := uint16(len(val.User)) - writeUint16(buffer, userLen) - buffer.WriteString(val.User) - // Write the host - hostLen := uint16(len(val.Host)) - writeUint16(buffer, hostLen) - buffer.WriteString(val.Host) -} +// Serialize returns the offset for the NamespaceValue written to the given builder. +func (val *NamespaceValue) Serialize(b *flatbuffers.Builder) flatbuffers.UOffsetT { + branch := b.CreateString(val.Branch) + user := b.CreateString(val.User) + host := b.CreateString(val.Host) -// deserializeNamespaceValue returns a NamespaceValue from the data at the given position. Also returns the new -// position. Assumes that the given data's encoded integers are big-endian. -func deserializeNamespaceValue(data []byte, position *uint64) NamespaceValue { - val := NamespaceValue{} - // Read the branch - branchLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - val.Branch = string(data[*position : *position+branchLen]) - *position += branchLen - // Read the user - userLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - val.User = string(data[*position : *position+userLen]) - *position += userLen - // Read the host - hostLen := uint64(binary.BigEndian.Uint16(data[*position:])) - *position += 2 - val.Host = string(data[*position : *position+hostLen]) - *position += hostLen - return val + serial.BranchControlNamespaceValueStart(b) + serial.BranchControlNamespaceValueAddBranch(b, branch) + serial.BranchControlNamespaceValueAddUser(b, user) + serial.BranchControlNamespaceValueAddHost(b, host) + return serial.BranchControlNamespaceValueEnd(b) } diff --git a/go/serial/branchcontrol.fbs b/go/serial/branchcontrol.fbs new file mode 100644 index 0000000000..dfc01343f4 --- /dev/null +++ b/go/serial/branchcontrol.fbs @@ -0,0 +1,71 @@ +// Copyright 2022 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace serial; + +table BranchControl { + access_tbl: BranchControlAccess; + namespace_tbl: BranchControlNamespace; +} + +table BranchControlAccess { + binlog: BranchControlBinlog; + branches: [BranchControlMatchExpression]; + users: [BranchControlMatchExpression]; + hosts: [BranchControlMatchExpression]; + values: [BranchControlAccessValue]; +} + +table BranchControlAccessValue { + branch: string; + user: string; + host: string; + permissions: uint64; +} + +table BranchControlNamespace { + binlog: BranchControlBinlog; + branches: [BranchControlMatchExpression]; + users: [BranchControlMatchExpression]; + hosts: [BranchControlMatchExpression]; + values: [BranchControlNamespaceValue]; +} + +table BranchControlNamespaceValue { + branch: string; + user: string; + host: string; +} + +table BranchControlBinlog { + rows: [BranchControlBinlogRow]; +} + +table BranchControlBinlogRow { + is_insert: bool; + branch: string; + user: string; + host: string; + permissions: uint64; +} + +table BranchControlMatchExpression { + index: uint32; + sort_orders: [int32]; +} + +// KEEP THIS IN SYNC WITH fileidentifiers.go +file_identifier "BRCL"; + +root_type BranchControl; diff --git a/go/serial/fileidentifiers.go b/go/serial/fileidentifiers.go index e5099ee63d..66eb49bab4 100644 --- a/go/serial/fileidentifiers.go +++ b/go/serial/fileidentifiers.go @@ -36,6 +36,7 @@ const TableSchemaFileID = "DSCH" const ForeignKeyCollectionFileID = "DFKC" const MergeArtifactsFileID = "ARTM" const BlobFileID = "BLOB" +const BranchControlFileID = "BRCL" const MessageTypesKind int = 27 diff --git a/go/serial/generate.sh b/go/serial/generate.sh index b896e86a86..10b1e5f9fb 100755 --- a/go/serial/generate.sh +++ b/go/serial/generate.sh @@ -21,6 +21,7 @@ fi "$FLATC" -o $GEN_DIR --gen-onefile --filename-suffix "" --gen-mutable --go-namespace "serial" --go \ addressmap.fbs \ blob.fbs \ + branchcontrol.fbs \ collation.fbs \ commit.fbs \ commitclosure.fbs \