mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-09 09:35:03 +09:00
Add doc tree
This commit is contained in:
parent
660f8d839b
commit
e4ad5b6485
6 changed files with 272 additions and 133 deletions
|
@ -30,7 +30,7 @@ type AddResult struct {
|
|||
Summary AddResultSummary
|
||||
}
|
||||
|
||||
type TreeUpdateListener interface {
|
||||
type ACLTreeUpdateListener interface {
|
||||
Update(tree ACLTree)
|
||||
Rebuild(tree ACLTree)
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ type ACLTree interface {
|
|||
type aclTree struct {
|
||||
treeStorage treestorage.TreeStorage
|
||||
accountData *account.AccountData
|
||||
updateListener TreeUpdateListener
|
||||
updateListener ACLTreeUpdateListener
|
||||
|
||||
id string
|
||||
header *treepb.TreeHeader
|
||||
|
@ -86,7 +86,7 @@ type aclTree struct {
|
|||
sync.RWMutex
|
||||
}
|
||||
|
||||
func BuildACLTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountData, listener TreeUpdateListener) (ACLTree, error) {
|
||||
func BuildACLTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountData, listener ACLTreeUpdateListener) (ACLTree, error) {
|
||||
treeBuilder := newTreeBuilder(t, acc.Decoder)
|
||||
aclStateBuilder := newACLStateBuilderWithIdentity(acc.Decoder, acc)
|
||||
changeBuilder := newACLChangeBuilder()
|
||||
|
@ -127,7 +127,7 @@ func BuildACLTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountDat
|
|||
return aclTree, nil
|
||||
}
|
||||
|
||||
func BuildACLTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener TreeUpdateListener) (ACLTree, error) {
|
||||
func BuildACLTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener ACLTreeUpdateListener) (ACLTree, error) {
|
||||
treeBuilder := newTreeBuilder(t, decoder)
|
||||
aclStateBuilder := newACLStateBuilder()
|
||||
changeBuilder := newACLChangeBuilder()
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
package tree
|
||||
|
||||
type ChangeValidator interface {
|
||||
ValidateChange(change *Change) error
|
||||
type DocTreeValidator interface {
|
||||
ValidateTree(tree *Tree, aclTree ACLTree) error
|
||||
}
|
||||
|
||||
type defChangeValidator struct {
|
||||
aclTree ACLTree
|
||||
}
|
||||
type docTreeValidator struct{}
|
||||
|
||||
func NewDefChangeValidator(aclTree ACLTree) ChangeValidator {
|
||||
return &defChangeValidator{}
|
||||
func newTreeValidator() DocTreeValidator {
|
||||
return &docTreeValidator{}
|
||||
}
|
||||
|
||||
func (c *defChangeValidator) ValidateChange(change *Change) error {
|
||||
func (v *docTreeValidator) ValidateTree(tree *Tree, aclTree ACLTree) error {
|
||||
// TODO: add validation logic where we check that the change refers to correct acl heads
|
||||
// that means that more recent changes should refer to more recent acl heads
|
||||
return nil
|
||||
|
|
|
@ -12,6 +12,14 @@ type DescriptionParser interface {
|
|||
ParseChange(*Change) ([]string, error)
|
||||
}
|
||||
|
||||
var NoOpDescriptionParser = noopDescriptionParser{}
|
||||
|
||||
type noopDescriptionParser struct{}
|
||||
|
||||
func (n noopDescriptionParser) ParseChange(change *Change) ([]string, error) {
|
||||
return []string{"DOC"}, nil
|
||||
}
|
||||
|
||||
var ACLDescriptionParser = aclDescriptionParser{}
|
||||
|
||||
type aclDescriptionParser struct{}
|
||||
|
|
|
@ -6,17 +6,25 @@ import (
|
|||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage/treepb"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TreeUpdateListener interface {
|
||||
Update(tree DocTree)
|
||||
Rebuild(tree DocTree)
|
||||
}
|
||||
|
||||
type DocTree interface {
|
||||
RWLocker
|
||||
ID() string
|
||||
Header() *treepb.TreeHeader
|
||||
AddContent(ctx context.Context, content proto.Marshaler) (*aclpb.RawChange, error)
|
||||
AddRawChanges(ctx context.Context, validator ChangeValidator, changes ...*aclpb.RawChange) (AddResult, error)
|
||||
AddContent(ctx context.Context, aclTree ACLTree, content proto.Marshaler, isSnapshot bool) (*aclpb.RawChange, error)
|
||||
AddRawChanges(ctx context.Context, aclTree ACLTree, changes ...*aclpb.RawChange) (AddResult, error)
|
||||
Heads() []string
|
||||
Root() *Change
|
||||
Iterate(func(change *Change) bool)
|
||||
|
@ -41,29 +49,25 @@ type docTree struct {
|
|||
aclState *ACLState
|
||||
|
||||
treeBuilder *treeBuilder
|
||||
validator DocTreeValidator
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func BuildDocTreeWithIdentity(
|
||||
t treestorage.TreeStorage,
|
||||
acc *account.AccountData,
|
||||
listener TreeUpdateListener) (DocTree, error) {
|
||||
func BuildDocTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountData, listener TreeUpdateListener, aclTree ACLTree) (DocTree, error) {
|
||||
treeBuilder := newTreeBuilder(t, acc.Decoder)
|
||||
aclStateBuilder := newACLStateBuilderWithIdentity(acc.Decoder, acc)
|
||||
changeBuilder := newChangeBuilder()
|
||||
validator := newTreeValidator()
|
||||
|
||||
docTree := &docTree{
|
||||
treeStorage: t,
|
||||
accountData: acc,
|
||||
tree: nil,
|
||||
aclState: nil,
|
||||
treeBuilder: treeBuilder,
|
||||
aclStateBuilder: aclStateBuilder,
|
||||
changeBuilder: changeBuilder,
|
||||
updateListener: listener,
|
||||
treeStorage: t,
|
||||
accountData: acc,
|
||||
tree: nil,
|
||||
aclState: nil,
|
||||
treeBuilder: treeBuilder,
|
||||
validator: validator,
|
||||
updateListener: listener,
|
||||
}
|
||||
err := docTree.rebuildFromStorage()
|
||||
err := docTree.rebuildFromStorage(aclTree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -89,106 +93,155 @@ func BuildDocTreeWithIdentity(
|
|||
return docTree, nil
|
||||
}
|
||||
|
||||
func BuildACLTree(t treestorage.TreeStorage) {
|
||||
// TODO: Add logic for building without identity
|
||||
func BuildDocTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener TreeUpdateListener, aclTree ACLTree) (DocTree, error) {
|
||||
treeBuilder := newTreeBuilder(t, decoder)
|
||||
validator := newTreeValidator()
|
||||
|
||||
docTree := &docTree{
|
||||
treeStorage: t,
|
||||
tree: nil,
|
||||
aclState: nil,
|
||||
treeBuilder: treeBuilder,
|
||||
validator: validator,
|
||||
updateListener: listener,
|
||||
}
|
||||
err := docTree.rebuildFromStorage(aclTree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = docTree.removeOrphans()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = t.SetHeads(docTree.Heads())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
docTree.id, err = t.TreeID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
docTree.header, err = t.Header()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listener.Rebuild(docTree)
|
||||
|
||||
return docTree, nil
|
||||
}
|
||||
|
||||
func (a *docTree) removeOrphans() error {
|
||||
func (d *docTree) removeOrphans() error {
|
||||
// removing attached or invalid orphans
|
||||
var toRemove []string
|
||||
|
||||
orphans, err := a.treeStorage.Orphans()
|
||||
orphans, err := d.treeStorage.Orphans()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, orphan := range orphans {
|
||||
if _, exists := a.tree.attached[orphan]; exists {
|
||||
if _, exists := d.tree.attached[orphan]; exists {
|
||||
toRemove = append(toRemove, orphan)
|
||||
}
|
||||
if _, exists := a.tree.invalidChanges[orphan]; exists {
|
||||
if _, exists := d.tree.invalidChanges[orphan]; exists {
|
||||
toRemove = append(toRemove, orphan)
|
||||
}
|
||||
}
|
||||
return a.treeStorage.RemoveOrphans(toRemove...)
|
||||
return d.treeStorage.RemoveOrphans(toRemove...)
|
||||
}
|
||||
|
||||
func (a *docTree) rebuildFromStorage() (err error) {
|
||||
a.treeBuilder.Init()
|
||||
func (d *docTree) rebuildFromStorage(aclTree ACLTree) (err error) {
|
||||
d.treeBuilder.Init()
|
||||
|
||||
a.tree, err = a.treeBuilder.Build(false)
|
||||
d.tree, err = d.treeBuilder.Build(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = a.aclStateBuilder.Init(a.tree)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.aclState, err = a.aclStateBuilder.Build()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return d.validator.ValidateTree(d.tree, aclTree)
|
||||
}
|
||||
|
||||
func (a *docTree) ID() string {
|
||||
return a.id
|
||||
func (d *docTree) ID() string {
|
||||
return d.id
|
||||
}
|
||||
|
||||
func (a *docTree) Header() *treepb.TreeHeader {
|
||||
return a.header
|
||||
func (d *docTree) Header() *treepb.TreeHeader {
|
||||
return d.header
|
||||
}
|
||||
|
||||
func (a *docTree) ACLState() *ACLState {
|
||||
return a.aclState
|
||||
func (d *docTree) Storage() treestorage.TreeStorage {
|
||||
return d.treeStorage
|
||||
}
|
||||
|
||||
func (a *docTree) Storage() treestorage.TreeStorage {
|
||||
return a.treeStorage
|
||||
}
|
||||
|
||||
func (a *docTree) AddContent(ctx context.Context, build func(builder ChangeBuilder) error) (*aclpb.RawChange, error) {
|
||||
if a.accountData == nil {
|
||||
func (d *docTree) AddContent(ctx context.Context, aclTree ACLTree, content proto.Marshaler, isSnapshot bool) (*aclpb.RawChange, error) {
|
||||
if d.accountData == nil {
|
||||
return nil, ErrTreeWithoutIdentity
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// TODO: should this be called in a separate goroutine to prevent accidental cycles (tree->updater->tree)
|
||||
a.updateListener.Update(a)
|
||||
d.updateListener.Update(d)
|
||||
}()
|
||||
state := aclTree.ACLState()
|
||||
change := &aclpb.Change{
|
||||
TreeHeadIds: d.tree.Heads(),
|
||||
AclHeadIds: aclTree.Heads(),
|
||||
SnapshotBaseId: d.tree.RootId(),
|
||||
CurrentReadKeyHash: state.currentReadKeyHash,
|
||||
Timestamp: int64(time.Now().Nanosecond()),
|
||||
Identity: d.accountData.Identity,
|
||||
}
|
||||
|
||||
a.changeBuilder.Init(a.aclState, a.tree, a.accountData)
|
||||
err := build(a.changeBuilder)
|
||||
marshalledData, err := content.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch, marshalled, err := a.changeBuilder.BuildAndApply()
|
||||
encrypted, err := state.userReadKeys[state.currentReadKeyHash].Encrypt(marshalledData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.tree.AddFast(ch)
|
||||
change.ChangesData = encrypted
|
||||
|
||||
fullMarshalledChange, err := proto.Marshal(change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature, err := d.accountData.SignKey.Sign(fullMarshalledChange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := cid.NewCIDFromBytes(fullMarshalledChange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ch := NewChange(id, change)
|
||||
ch.ParsedModel = content
|
||||
ch.Sign = signature
|
||||
|
||||
if isSnapshot {
|
||||
// clearing tree, because we already fixed everything in the last snapshot
|
||||
d.tree = &Tree{}
|
||||
}
|
||||
d.tree.AddFast(ch)
|
||||
rawCh := &aclpb.RawChange{
|
||||
Payload: marshalled,
|
||||
Payload: fullMarshalledChange,
|
||||
Signature: ch.Signature(),
|
||||
Id: ch.Id,
|
||||
}
|
||||
|
||||
err = a.treeStorage.AddRawChange(rawCh)
|
||||
err = d.treeStorage.AddRawChange(rawCh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = a.treeStorage.SetHeads([]string{ch.Id})
|
||||
err = d.treeStorage.SetHeads([]string{ch.Id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rawCh, nil
|
||||
}
|
||||
|
||||
func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawChange) (AddResult, error) {
|
||||
func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges ...*aclpb.RawChange) (AddResult, error) {
|
||||
// TODO: make proper error handling, because there are a lot of corner cases where this will break
|
||||
var err error
|
||||
var mode Mode
|
||||
|
@ -208,21 +261,21 @@ func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawCha
|
|||
return
|
||||
}
|
||||
|
||||
err = a.removeOrphans()
|
||||
err = d.removeOrphans()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = a.treeStorage.SetHeads(a.tree.Heads())
|
||||
err = d.treeStorage.SetHeads(d.tree.Heads())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case Append:
|
||||
a.updateListener.Update(a)
|
||||
d.updateListener.Update(d)
|
||||
case Rebuild:
|
||||
a.updateListener.Rebuild(a)
|
||||
d.updateListener.Rebuild(d)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -231,28 +284,49 @@ func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawCha
|
|||
getAddedChanges := func() []*aclpb.RawChange {
|
||||
var added []*aclpb.RawChange
|
||||
for _, ch := range rawChanges {
|
||||
if _, exists := a.tree.attached[ch.Id]; exists {
|
||||
if _, exists := d.tree.attached[ch.Id]; exists {
|
||||
added = append(added, ch)
|
||||
}
|
||||
}
|
||||
return added
|
||||
}
|
||||
|
||||
for _, ch := range changes {
|
||||
err = a.treeStorage.AddChange(ch)
|
||||
prevHeads := d.tree.Heads()
|
||||
rebuild := func() (AddResult, error) {
|
||||
err = d.rebuildFromStorage(aclTree)
|
||||
if err != nil {
|
||||
return AddResult{}, err
|
||||
}
|
||||
err = a.treeStorage.AddOrphans(ch.Id)
|
||||
|
||||
return AddResult{
|
||||
OldHeads: prevHeads,
|
||||
Heads: d.tree.Heads(),
|
||||
Added: getAddedChanges(),
|
||||
Summary: AddResultSummaryRebuild,
|
||||
}, nil
|
||||
}
|
||||
|
||||
for _, ch := range changes {
|
||||
err = d.treeStorage.AddChange(ch)
|
||||
if err != nil {
|
||||
return AddResult{}, err
|
||||
}
|
||||
err = d.treeStorage.AddOrphans(ch.Id)
|
||||
if err != nil {
|
||||
return AddResult{}, err
|
||||
}
|
||||
}
|
||||
|
||||
prevHeads := a.tree.Heads()
|
||||
mode = a.tree.Add(changes...)
|
||||
mode = d.tree.Add(changes...)
|
||||
switch mode {
|
||||
case Nothing:
|
||||
for _, ch := range changes {
|
||||
// rebuilding if the snapshot is different from the root
|
||||
if ch.SnapshotId != d.tree.RootId() {
|
||||
return rebuild()
|
||||
}
|
||||
}
|
||||
|
||||
return AddResult{
|
||||
OldHeads: prevHeads,
|
||||
Heads: prevHeads,
|
||||
|
@ -260,69 +334,59 @@ func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawCha
|
|||
}, nil
|
||||
|
||||
case Rebuild:
|
||||
err = a.rebuildFromStorage()
|
||||
if err != nil {
|
||||
return AddResult{}, err
|
||||
}
|
||||
|
||||
return AddResult{
|
||||
OldHeads: prevHeads,
|
||||
Heads: a.tree.Heads(),
|
||||
Added: getAddedChanges(),
|
||||
Summary: AddResultSummaryRebuild,
|
||||
}, nil
|
||||
return rebuild()
|
||||
default:
|
||||
// just rebuilding the state from start without reloading everything from tree storage
|
||||
// as an optimization we could've started from current heads, but I didn't implement that
|
||||
a.aclState, err = a.aclStateBuilder.Build()
|
||||
err = d.validator.ValidateTree(d.tree, aclTree)
|
||||
if err != nil {
|
||||
return AddResult{}, err
|
||||
}
|
||||
|
||||
return AddResult{
|
||||
OldHeads: prevHeads,
|
||||
Heads: a.tree.Heads(),
|
||||
Heads: d.tree.Heads(),
|
||||
Added: getAddedChanges(),
|
||||
Summary: AddResultSummaryAppend,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *docTree) Iterate(f func(change *Change) bool) {
|
||||
a.tree.Iterate(a.tree.RootId(), f)
|
||||
func (d *docTree) Iterate(f func(change *Change) bool) {
|
||||
d.tree.Iterate(d.tree.RootId(), f)
|
||||
}
|
||||
|
||||
func (a *docTree) IterateFrom(s string, f func(change *Change) bool) {
|
||||
a.tree.Iterate(s, f)
|
||||
func (d *docTree) IterateFrom(s string, f func(change *Change) bool) {
|
||||
d.tree.Iterate(s, f)
|
||||
}
|
||||
|
||||
func (a *docTree) HasChange(s string) bool {
|
||||
_, attachedExists := a.tree.attached[s]
|
||||
_, unattachedExists := a.tree.unAttached[s]
|
||||
_, invalidExists := a.tree.invalidChanges[s]
|
||||
func (d *docTree) HasChange(s string) bool {
|
||||
_, attachedExists := d.tree.attached[s]
|
||||
_, unattachedExists := d.tree.unAttached[s]
|
||||
_, invalidExists := d.tree.invalidChanges[s]
|
||||
return attachedExists || unattachedExists || invalidExists
|
||||
}
|
||||
|
||||
func (a *docTree) Heads() []string {
|
||||
return a.tree.Heads()
|
||||
func (d *docTree) Heads() []string {
|
||||
return d.tree.Heads()
|
||||
}
|
||||
|
||||
func (a *docTree) Root() *Change {
|
||||
return a.tree.Root()
|
||||
func (d *docTree) Root() *Change {
|
||||
return d.tree.Root()
|
||||
}
|
||||
|
||||
func (a *docTree) Close() error {
|
||||
func (d *docTree) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *docTree) SnapshotPath() []string {
|
||||
func (d *docTree) SnapshotPath() []string {
|
||||
// TODO: think about caching this
|
||||
|
||||
var path []string
|
||||
// TODO: think that the user may have not all of the snapshots locally
|
||||
currentSnapshotId := a.tree.RootId()
|
||||
currentSnapshotId := d.tree.RootId()
|
||||
for currentSnapshotId != "" {
|
||||
sn, err := a.treeBuilder.loadChange(currentSnapshotId)
|
||||
sn, err := d.treeBuilder.loadChange(currentSnapshotId)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
@ -332,13 +396,13 @@ func (a *docTree) SnapshotPath() []string {
|
|||
return path
|
||||
}
|
||||
|
||||
func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawChange, error) {
|
||||
func (d *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawChange, error) {
|
||||
// TODO: think about when the clients will have their full acl tree and thus full snapshots
|
||||
// but no changes after some of the snapshots
|
||||
|
||||
var (
|
||||
isNewDocument = len(theirPath) == 0
|
||||
ourPath = a.SnapshotPath()
|
||||
ourPath = d.SnapshotPath()
|
||||
// by default returning everything we have
|
||||
commonSnapshot = ourPath[len(ourPath)-1] // TODO: root snapshot, probably it is better to have a specific method in treestorage
|
||||
err error
|
||||
|
@ -354,12 +418,12 @@ func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh
|
|||
var rawChanges []*aclpb.RawChange
|
||||
// using custom load function to skip verification step and save raw changes
|
||||
load := func(id string) (*Change, error) {
|
||||
raw, err := a.treeStorage.GetChange(context.Background(), id)
|
||||
raw, err := d.treeStorage.GetChange(context.Background(), id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aclChange, err := a.treeBuilder.makeUnverifiedACLChange(raw)
|
||||
aclChange, err := d.treeBuilder.makeUnverifiedACLChange(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -370,11 +434,11 @@ func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh
|
|||
}
|
||||
// we presume that we have everything after the common snapshot, though this may not be the case in case of clients and only ACL tree changes
|
||||
log.With(
|
||||
zap.Strings("heads", a.tree.Heads()),
|
||||
zap.Strings("heads", d.tree.Heads()),
|
||||
zap.String("breakpoint", commonSnapshot),
|
||||
zap.String("id", a.id)).
|
||||
zap.String("id", d.id)).
|
||||
Debug("getting all changes from common snapshot")
|
||||
_, err = a.treeBuilder.dfs(a.tree.Heads(), commonSnapshot, load)
|
||||
_, err = d.treeBuilder.dfs(d.tree.Heads(), commonSnapshot, load)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -387,12 +451,12 @@ func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh
|
|||
}
|
||||
log.With(
|
||||
zap.Int("len(changes)", len(rawChanges)),
|
||||
zap.String("id", a.id)).
|
||||
zap.String("id", d.id)).
|
||||
Debug("returning all changes after common snapshot")
|
||||
|
||||
return rawChanges, nil
|
||||
}
|
||||
|
||||
func (a *docTree) DebugDump() (string, error) {
|
||||
return a.tree.Graph(ACLDescriptionParser)
|
||||
func (d *docTree) DebugDump() (string, error) {
|
||||
return d.tree.Graph(NoOpDescriptionParser)
|
||||
}
|
||||
|
|
|
@ -5,5 +5,11 @@ option go_package = "treepb";
|
|||
message TreeHeader {
|
||||
string firstChangeId = 1;
|
||||
bool isWorkspace = 2;
|
||||
TreeType type = 3;
|
||||
// TODO: add user identity, signature and nano timestamp
|
||||
|
||||
enum TreeType {
|
||||
ACLTree = 0;
|
||||
DocTree = 1;
|
||||
}
|
||||
}
|
|
@ -22,9 +22,35 @@ var _ = math.Inf
|
|||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type TreeHeaderTreeType int32
|
||||
|
||||
const (
|
||||
TreeHeader_ACLTree TreeHeaderTreeType = 0
|
||||
TreeHeader_DocTree TreeHeaderTreeType = 1
|
||||
)
|
||||
|
||||
var TreeHeaderTreeType_name = map[int32]string{
|
||||
0: "ACLTree",
|
||||
1: "DocTree",
|
||||
}
|
||||
|
||||
var TreeHeaderTreeType_value = map[string]int32{
|
||||
"ACLTree": 0,
|
||||
"DocTree": 1,
|
||||
}
|
||||
|
||||
func (x TreeHeaderTreeType) String() string {
|
||||
return proto.EnumName(TreeHeaderTreeType_name, int32(x))
|
||||
}
|
||||
|
||||
func (TreeHeaderTreeType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e7d760b855878644, []int{0, 0}
|
||||
}
|
||||
|
||||
type TreeHeader struct {
|
||||
FirstChangeId string `protobuf:"bytes,1,opt,name=firstChangeId,proto3" json:"firstChangeId,omitempty"`
|
||||
IsWorkspace bool `protobuf:"varint,2,opt,name=isWorkspace,proto3" json:"isWorkspace,omitempty"`
|
||||
FirstChangeId string `protobuf:"bytes,1,opt,name=firstChangeId,proto3" json:"firstChangeId,omitempty"`
|
||||
IsWorkspace bool `protobuf:"varint,2,opt,name=isWorkspace,proto3" json:"isWorkspace,omitempty"`
|
||||
Type TreeHeaderTreeType `protobuf:"varint,3,opt,name=type,proto3,enum=tree.TreeHeaderTreeType" json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (m *TreeHeader) Reset() { *m = TreeHeader{} }
|
||||
|
@ -74,7 +100,15 @@ func (m *TreeHeader) GetIsWorkspace() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (m *TreeHeader) GetType() TreeHeaderTreeType {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return TreeHeader_ACLTree
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("tree.TreeHeaderTreeType", TreeHeaderTreeType_name, TreeHeaderTreeType_value)
|
||||
proto.RegisterType((*TreeHeader)(nil), "tree.TreeHeader")
|
||||
}
|
||||
|
||||
|
@ -83,18 +117,21 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptor_e7d760b855878644 = []byte{
|
||||
// 165 bytes of a gzipped FileDescriptorProto
|
||||
// 220 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x29, 0xc8, 0x4e, 0xd7,
|
||||
0x4f, 0x4c, 0xce, 0xd1, 0x2f, 0x29, 0x4a, 0x4d, 0x2d, 0x2e, 0xc9, 0x2f, 0x4a, 0x4c, 0x4f, 0x05,
|
||||
0xb3, 0x0b, 0x92, 0xf4, 0x0b, 0x8a, 0xf2, 0x4b, 0xf2, 0x8b, 0xc1, 0x3c, 0x3d, 0x30, 0x5b, 0x88,
|
||||
0x05, 0xc4, 0x56, 0x0a, 0xe1, 0xe2, 0x0a, 0x29, 0x4a, 0x4d, 0xf5, 0x48, 0x4d, 0x4c, 0x49, 0x2d,
|
||||
0x12, 0x52, 0xe1, 0xe2, 0x4d, 0xcb, 0x2c, 0x2a, 0x2e, 0x71, 0xce, 0x48, 0xcc, 0x4b, 0x4f, 0xf5,
|
||||
0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x42, 0x15, 0x14, 0x52, 0xe0, 0xe2, 0xce, 0x2c,
|
||||
0x0e, 0xcf, 0x2f, 0xca, 0x2e, 0x2e, 0x48, 0x4c, 0x4e, 0x95, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x08,
|
||||
0x42, 0x16, 0x72, 0x52, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
|
||||
0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x36,
|
||||
0x88, 0x7b, 0x92, 0xd8, 0xc0, 0x8e, 0x30, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x09, 0x4f, 0xc6,
|
||||
0xec, 0xb4, 0x00, 0x00, 0x00,
|
||||
0x05, 0xc4, 0x56, 0x5a, 0xc9, 0xc8, 0xc5, 0x15, 0x52, 0x94, 0x9a, 0xea, 0x91, 0x9a, 0x98, 0x92,
|
||||
0x5a, 0x24, 0xa4, 0xc2, 0xc5, 0x9b, 0x96, 0x59, 0x54, 0x5c, 0xe2, 0x9c, 0x91, 0x98, 0x97, 0x9e,
|
||||
0xea, 0x99, 0x22, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0x84, 0x2a, 0x28, 0xa4, 0xc0, 0xc5, 0x9d,
|
||||
0x59, 0x1c, 0x9e, 0x5f, 0x94, 0x5d, 0x5c, 0x90, 0x98, 0x9c, 0x2a, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1,
|
||||
0x11, 0x84, 0x2c, 0x24, 0xa4, 0xcb, 0xc5, 0x52, 0x52, 0x59, 0x90, 0x2a, 0xc1, 0xac, 0xc0, 0xa8,
|
||||
0xc1, 0x67, 0x24, 0xa9, 0x07, 0xb6, 0x17, 0x61, 0x0f, 0x98, 0x19, 0x52, 0x59, 0x90, 0x1a, 0x04,
|
||||
0x56, 0xa6, 0xa4, 0xc2, 0xc5, 0x01, 0x13, 0x11, 0xe2, 0xe6, 0x62, 0x77, 0x74, 0xf6, 0x01, 0x71,
|
||||
0x05, 0x18, 0x40, 0x1c, 0x97, 0xfc, 0x64, 0x30, 0x87, 0xd1, 0x49, 0xe1, 0xc4, 0x23, 0x39, 0xc6,
|
||||
0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39,
|
||||
0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0xd8, 0x20, 0xbe, 0x4c, 0x62, 0x03, 0x7b, 0xcd, 0x18, 0x10,
|
||||
0x00, 0x00, 0xff, 0xff, 0x72, 0x29, 0xbc, 0x0e, 0x0a, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *TreeHeader) Marshal() (dAtA []byte, err error) {
|
||||
|
@ -117,6 +154,11 @@ func (m *TreeHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.Type != 0 {
|
||||
i = encodeVarintTree(dAtA, i, uint64(m.Type))
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if m.IsWorkspace {
|
||||
i--
|
||||
if m.IsWorkspace {
|
||||
|
@ -161,6 +203,9 @@ func (m *TreeHeader) Size() (n int) {
|
|||
if m.IsWorkspace {
|
||||
n += 2
|
||||
}
|
||||
if m.Type != 0 {
|
||||
n += 1 + sovTree(uint64(m.Type))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -251,6 +296,25 @@ func (m *TreeHeader) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
}
|
||||
m.IsWorkspace = bool(v != 0)
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
|
||||
}
|
||||
m.Type = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTree
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Type |= TreeHeaderTreeType(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTree(dAtA[iNdEx:])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue