Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce object creation interface with initial values #756

Merged
merged 36 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9263c17
Add testcode for garbage collection
highcloud100 Jan 4, 2024
3987dba
Draft the SetNewObject function for given json literal
highcloud100 Jan 7, 2024
feb4633
Add support for additional primitive types in buildCRDTElement function
highcloud100 Jan 8, 2024
0f6949a
Add support for Array type in buildCRDTElement function and update re…
highcloud100 Jan 8, 2024
cdeb834
Refactor element registration and deregistration in Root
highcloud100 Jan 8, 2024
2f8d50a
Add support for Counter type in buildCRDTElement function and relevan…
highcloud100 Jan 8, 2024
6a338b8
Merge branch 'main' of https://github.com/yorkie-team/yorkie into set…
highcloud100 Jan 8, 2024
6e830a3
Naive implementation for text, tree type in buildCRDTElement function
highcloud100 Jan 8, 2024
ca7579b
Add test code for set nested object
highcloud100 Jan 9, 2024
a8c58f9
Lint
highcloud100 Jan 9, 2024
2dd5891
Add comment for counter due to lint
highcloud100 Jan 9, 2024
085c495
Handle the primitive null type and unsupported type in buildCRDTElement
highcloud100 Jan 10, 2024
a7e7c90
Apply the comment
highcloud100 Jan 10, 2024
32a2188
Add tests for duplicated deregister check and nested object primitive…
highcloud100 Jan 10, 2024
c34c09e
Merge branch 'main' of https://github.com/yorkie-team/yorkie into set…
highcloud100 Jan 10, 2024
035a5f0
Fix duplicate register
highcloud100 Jan 10, 2024
68599a2
Update object_test.go with new JSON object literal tests
highcloud100 Jan 10, 2024
a30fb8a
Merge branch 'main' of https://github.com/yorkie-team/yorkie into set…
highcloud100 Jan 10, 2024
0cc5001
Remove register code in NewRoot function that trigger duplicate
highcloud100 Jan 10, 2024
51de8a1
Refactor object test code
highcloud100 Jan 12, 2024
883c836
Add support for initializing Array and Object with values
highcloud100 Jan 16, 2024
9970280
Add error handler in NewArray function
highcloud100 Jan 16, 2024
aac72ef
Replace CreateCounter with NewCounter
highcloud100 Jan 16, 2024
b03df91
Replace CreateText with NewText
highcloud100 Jan 16, 2024
0563131
Replace CreateTree with NewTree
highcloud100 Jan 16, 2024
44c1809
Lint
highcloud100 Jan 16, 2024
4ffdbf3
Refactor SetNewArray method to accept initial values and add tests
highcloud100 Jan 16, 2024
e6fc05d
Revise test codes
hackerwins Jan 17, 2024
896eaf1
Refactor object test, Array and Object types
highcloud100 Jan 17, 2024
652540c
Refactor array test, newObject
highcloud100 Jan 17, 2024
0e71bdf
Refactor array and object, tree
highcloud100 Jan 17, 2024
657f595
Refactor json text, tree
highcloud100 Jan 17, 2024
68b4e32
Add some comment for test
highcloud100 Jan 17, 2024
df46de3
Revise codes
hackerwins Jan 17, 2024
bbe3f8c
Revise comments
hackerwins Jan 17, 2024
cee9b6d
Remove unnecessary newline
hackerwins Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion pkg/document/crdt/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ type Array struct {
}

// NewArray creates a new instance of Array.
func NewArray(elements *RGATreeList, createdAt *time.Ticket) *Array {
func NewArray(elements *RGATreeList, createdAt *time.Ticket, value ...[]Element) *Array {
if len(value) == 1 {
for _, v := range value[0] {
_ = elements.InsertAfter(elements.LastCreatedAt(), v)
}
}
return &Array{
elements: elements,
createdAt: createdAt,
Expand Down
6 changes: 6 additions & 0 deletions pkg/document/crdt/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ func (p *Counter) ValueType() CounterType {
return p.valueType
}

// Value returns the value of this counter.
// TODO(hackerwins): We need to use generics to avoid using interface{}.
func (p *Counter) Value() interface{} {
return p.value
}

// Increase increases integer, long or double.
// If the result of the operation is greater than MaxInt32 or less
// than MinInt32, Counter's value type can be changed Integer to Long.
Expand Down
7 changes: 6 additions & 1 deletion pkg/document/crdt/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ type Object struct {
}

// NewObject creates a new instance of Object.
func NewObject(memberNodes *ElementRHT, createdAt *time.Ticket) *Object {
func NewObject(memberNodes *ElementRHT, createdAt *time.Ticket, value ...map[string]Element) *Object {
if len(value) == 1 {
for k, v := range value[0] {
memberNodes.Set(k, v)
}
}
return &Object{
memberNodes: memberNodes,
createdAt: createdAt,
Expand Down
66 changes: 37 additions & 29 deletions pkg/document/crdt/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ func NewRoot(root *Object) *Root {
r.RegisterElement(root)

root.Descendants(func(elem Element, parent Container) bool {
r.RegisterElement(elem)
if elem.RemovedAt() != nil {
r.RegisterRemovedElementPair(parent, elem)
}
Expand All @@ -76,15 +75,44 @@ func (r *Root) FindByCreatedAt(createdAt *time.Ticket) Element {
}

// RegisterElement registers the given element to hash table.
func (r *Root) RegisterElement(elem Element) {
r.elementMapByCreatedAt[elem.CreatedAt().Key()] = elem
func (r *Root) RegisterElement(element Element) {
chacha912 marked this conversation as resolved.
Show resolved Hide resolved
r.elementMapByCreatedAt[element.CreatedAt().Key()] = element

switch element := element.(type) {
case Container:
{
element.Descendants(func(elem Element, parent Container) bool {
r.elementMapByCreatedAt[elem.CreatedAt().Key()] = elem
return false
})
}
}
}

// DeregisterElement deregister the given element from hash tables.
func (r *Root) DeregisterElement(elem Element) {
createdAt := elem.CreatedAt().Key()
delete(r.elementMapByCreatedAt, createdAt)
delete(r.removedElementPairMapByCreatedAt, createdAt)
// deregisterElement deregister the given element from hash tables.
func (r *Root) deregisterElement(element Element) int {
count := 0

deregisterElementInternal := func(elem Element) {
createdAt := elem.CreatedAt().Key()
delete(r.elementMapByCreatedAt, createdAt)
delete(r.removedElementPairMapByCreatedAt, createdAt)
count++
}

deregisterElementInternal(element)

switch element := element.(type) {
case Container:
{
element.Descendants(func(elem Element, parent Container) bool {
deregisterElementInternal(elem)
return false
})
}
}

return count
}

// RegisterRemovedElementPair register the given element pair to hash table.
Expand Down Expand Up @@ -119,7 +147,7 @@ func (r *Root) GarbageCollect(ticket *time.Ticket) (int, error) {
return 0, err
}

count += r.garbageCollect(pair.elem)
count += r.deregisterElement(pair.elem)
}
}

Expand Down Expand Up @@ -173,23 +201,3 @@ func (r *Root) GarbageLen() int {

return count
}

func (r *Root) garbageCollect(elem Element) int {
count := 0

callback := func(elem Element, parent Container) bool {
r.DeregisterElement(elem)
count++
return false
}

callback(elem, nil)
switch elem := elem.(type) {
case *Object:
elem.Descendants(callback)
case *Array:
elem.Descendants(callback)
}

return count
}
15 changes: 15 additions & 0 deletions pkg/document/json/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,18 @@ func (p *Array) moveBeforeInternal(nextCreatedAt, createdAt *time.Ticket) {
panic(err)
}
}

// buildArrayElements return the element slice of the given array.
func buildArrayElements(
context *change.Context,
elements []interface{},
) []crdt.Element {
elems := make([]crdt.Element, len(elements))

for idx, value := range elements {
ticket := context.IssueTimeTicket()
elems[idx] = buildCRDTElement(context, value, ticket)
}

return elems
}
24 changes: 17 additions & 7 deletions pkg/document/json/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,28 @@ import (
// it is used when the user manipulates the counter from the outside.
type Counter struct {
*crdt.Counter
context *change.Context
context *change.Context
valueType crdt.CounterType
value interface{}
}

// NewCounter create Counter instance.
func NewCounter(ctx *change.Context, counter *crdt.Counter) *Counter {
// NewCounter creates a new instance of Counter.
func NewCounter(n interface{}, t crdt.CounterType) *Counter {
return &Counter{
valueType: t,
value: n,
}
}

// Initialize initializes the Counter by the given context and counter.
func (p *Counter) Initialize(ctx *change.Context, counter *crdt.Counter) *Counter {
if !counter.IsNumericType() {
panic("unsupported type")
}
return &Counter{
Counter: counter,
context: ctx,
}
p.Counter = counter
p.context = ctx

return p
}

// Increase adds an increase operations.
Expand Down
65 changes: 64 additions & 1 deletion pkg/document/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@
// Package json provides the JSON document implementation.
package json

import "github.com/yorkie-team/yorkie/pkg/document/crdt"
import (
gotime "time"

"github.com/yorkie-team/yorkie/pkg/document/change"
"github.com/yorkie-team/yorkie/pkg/document/crdt"
"github.com/yorkie-team/yorkie/pkg/document/time"
)

func toOriginal(elem crdt.Element) crdt.Element {
switch elem := elem.(type) {
Expand All @@ -37,3 +43,60 @@ func toOriginal(elem crdt.Element) crdt.Element {

panic("unsupported type")
}

func toElement(ctx *change.Context, elem crdt.Element) crdt.Element {
switch elem := elem.(type) {
case *crdt.Object:
return NewObject(ctx, elem)
case *crdt.Array:
return NewArray(ctx, elem)
case *crdt.Text:
text := NewText()
return text.Initialize(ctx, elem)
case *crdt.Counter:
counter := NewCounter(elem.Value(), elem.ValueType())
return counter.Initialize(ctx, elem)
case *crdt.Tree:
tree := NewTree()
return tree.Initialize(ctx, elem)
case *crdt.Primitive:
return elem
}

panic("unsupported type")
}

func buildCRDTElement(
context *change.Context,
value interface{},
ticket *time.Ticket,
) crdt.Element {
highcloud100 marked this conversation as resolved.
Show resolved Hide resolved
switch elem := value.(type) {
case nil, string, int, int32, int64, float32, float64, []byte, bool, gotime.Time:
primitive, err := crdt.NewPrimitive(elem, ticket)
if err != nil {
panic(err)
}
return primitive
case *Tree:
crdtTree := crdt.NewTree(buildRoot(context, elem.initialRoot, ticket), ticket)
return crdtTree
case *Text:
return crdt.NewText(crdt.NewRGATreeSplit(crdt.InitialTextNode()), ticket)
case *Counter:
counter, err := crdt.NewCounter(elem.valueType, elem.value, ticket)
if err != nil {
panic(err)
}
return counter
case []interface{}:
array := crdt.NewArray(crdt.NewRGATreeList(), ticket, buildArrayElements(context, elem))
return array
case map[string]interface{}:
obj := crdt.NewObject(crdt.NewElementRHT(), ticket, buildObjectMembers(context, elem))
return obj
default:
panic("unsupported type")
}

}
Loading
Loading