Skip to content

Commit de29cdc

Browse files
Refactor Presence data structure to repeated string (#1335)
Co-authored-by: Youngteac Hong <[email protected]>
1 parent eef220b commit de29cdc

File tree

8 files changed

+237
-274
lines changed

8 files changed

+237
-274
lines changed

api/docs/yorkie/v1/admin.openapi.yaml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,26 +2043,12 @@ components:
20432043
data:
20442044
additionalProperties: false
20452045
description: ""
2046+
items:
2047+
type: string
20462048
title: data
2047-
type: object
2049+
type: array
20482050
title: Presence
20492051
type: object
2050-
yorkie.v1.Presence.DataEntry:
2051-
additionalProperties: false
2052-
description: ""
2053-
properties:
2054-
key:
2055-
additionalProperties: false
2056-
description: ""
2057-
title: key
2058-
type: string
2059-
value:
2060-
additionalProperties: false
2061-
description: ""
2062-
title: value
2063-
type: string
2064-
title: DataEntry
2065-
type: object
20662052
yorkie.v1.PresenceChange:
20672053
additionalProperties: false
20682054
description: ""

api/docs/yorkie/v1/resources.openapi.yaml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,26 +1335,12 @@ components:
13351335
data:
13361336
additionalProperties: false
13371337
description: ""
1338+
items:
1339+
type: string
13381340
title: data
1339-
type: object
1341+
type: array
13401342
title: Presence
13411343
type: object
1342-
yorkie.v1.Presence.DataEntry:
1343-
additionalProperties: false
1344-
description: ""
1345-
properties:
1346-
key:
1347-
additionalProperties: false
1348-
description: ""
1349-
title: key
1350-
type: string
1351-
value:
1352-
additionalProperties: false
1353-
description: ""
1354-
title: value
1355-
type: string
1356-
title: DataEntry
1357-
type: object
13581344
yorkie.v1.PresenceChange:
13591345
additionalProperties: false
13601346
description: ""

api/docs/yorkie/v1/yorkie.openapi.yaml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,26 +1268,12 @@ components:
12681268
data:
12691269
additionalProperties: false
12701270
description: ""
1271+
items:
1272+
type: string
12711273
title: data
1272-
type: object
1274+
type: array
12731275
title: Presence
12741276
type: object
1275-
yorkie.v1.Presence.DataEntry:
1276-
additionalProperties: false
1277-
description: ""
1278-
properties:
1279-
key:
1280-
additionalProperties: false
1281-
description: ""
1282-
title: key
1283-
type: string
1284-
value:
1285-
additionalProperties: false
1286-
description: ""
1287-
title: value
1288-
type: string
1289-
title: DataEntry
1290-
type: object
12911277
yorkie.v1.PresenceChange:
12921278
additionalProperties: false
12931279
description: ""

api/yorkie/v1/resources.pb.go

Lines changed: 190 additions & 198 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/yorkie/v1/resources.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ message PresenceChange {
362362
}
363363

364364
message Presence {
365-
map<string, string> data = 1;
365+
repeated string data = 1;
366366
}
367367

368368
message Checkpoint {

pkg/document/innerpresence/presence.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,38 @@ func (m *Map) DeepCopy() *Map {
114114
}
115115

116116
// Presence represents custom presence that can be defined by the client.
117-
type Presence map[string]string
117+
type Presence []string
118118

119119
// New creates a new instance of Presence.
120120
func New() Presence {
121-
return make(map[string]string)
121+
return make([]string, 0)
122+
}
123+
124+
// index returns the index of the given key in the presence.
125+
func (p *Presence) index(key string) int {
126+
for i := 0; i < len(*p); i += 2 {
127+
if (*p)[i] == key {
128+
return i
129+
}
130+
}
131+
132+
return -1
122133
}
123134

124135
// Set sets the value of the given key.
125-
func (p Presence) Set(key string, value string) {
126-
p[key] = value
136+
func (p *Presence) Set(key string, value string) {
137+
if idx := p.index(key); idx != -1 {
138+
(*p)[idx] = key
139+
(*p)[idx+1] = value
140+
return
141+
}
142+
*p = append(*p, key)
143+
*p = append(*p, value)
127144
}
128145

129146
// Clear clears the presence.
130147
func (p *Presence) Clear() {
131-
*p = make(map[string]string)
148+
clear(*p)
132149
}
133150

134151
// DeepCopy copies itself deeply.
@@ -137,9 +154,7 @@ func (p Presence) DeepCopy() Presence {
137154
return nil
138155
}
139156

140-
clone := make(map[string]string, len(p))
141-
for k, v := range p {
142-
clone[k] = v
143-
}
157+
clone := make(Presence, len(p))
158+
copy(clone, p)
144159
return clone
145160
}

test/integration/presence_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ func TestPresence(t *testing.T) {
6060
}))
6161
encoded, err := gojson.Marshal(d1.AllPresences())
6262
assert.NoError(t, err)
63-
assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"true"}}`, c1.ID()), string(encoded))
63+
assert.Equal(t, fmt.Sprintf(`{"%s":["updated","true"]}`, c1.ID()), string(encoded))
6464

6565
// 03 Sync documents and check that the presence is updated on the other client
6666
assert.NoError(t, c1.Sync(ctx))
6767
assert.NoError(t, c2.Sync(ctx))
6868
encoded, err = gojson.Marshal(d2.AllPresences())
6969
assert.NoError(t, err)
70-
assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"true"},"%s":{}}`, c1.ID(), c2.ID()), string(encoded))
70+
assert.Equal(t, fmt.Sprintf(`{"%s":["updated","true"],"%s":[]}`, c1.ID(), c2.ID()), string(encoded))
7171
})
7272

7373
t.Run("presence with snapshot test", func(t *testing.T) {
@@ -90,36 +90,36 @@ func TestPresence(t *testing.T) {
9090
}
9191
encoded, err := gojson.Marshal(d1.AllPresences())
9292
assert.NoError(t, err)
93-
assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"9"}}`, c1.ID()), string(encoded))
93+
assert.Equal(t, fmt.Sprintf(`{"%s":["updated","9"]}`, c1.ID()), string(encoded))
9494

9595
// 03 Sync documents and check that the presence is updated on the other client
9696
assert.NoError(t, c1.Sync(ctx))
9797
assert.NoError(t, c2.Sync(ctx))
9898
encoded, err = gojson.Marshal(d2.AllPresences())
9999
assert.NoError(t, err)
100-
assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"9"},"%s":{}}`, c1.ID(), c2.ID()), string(encoded))
100+
assert.Equal(t, fmt.Sprintf(`{"%s":["updated","9"],"%s":[]}`, c1.ID(), c2.ID()), string(encoded))
101101
})
102102

103103
t.Run("presence with attach and detach test", func(t *testing.T) {
104104
// 01. Create a document and attach it to the clients
105105
ctx := context.Background()
106106
d1 := document.New(helper.TestDocKey(t))
107-
assert.NoError(t, c1.Attach(ctx, d1, client.WithPresence(innerpresence.Presence{"key": c1.Key()})))
107+
assert.NoError(t, c1.Attach(ctx, d1, client.WithPresence(innerpresence.Presence{"key", c1.Key()})))
108108
d2 := document.New(helper.TestDocKey(t))
109-
assert.NoError(t, c2.Attach(ctx, d2, client.WithPresence(innerpresence.Presence{"key": c2.Key()})))
109+
assert.NoError(t, c2.Attach(ctx, d2, client.WithPresence(innerpresence.Presence{"key", c2.Key()})))
110110
defer func() { assert.NoError(t, c2.Detach(ctx, d2)) }()
111111

112112
// 02. Check that the presence is updated on the other client.
113113
assert.NoError(t, c1.Sync(ctx))
114-
assert.Equal(t, innerpresence.Presence{"key": c1.Key()}, d1.MyPresence())
115-
assert.Equal(t, innerpresence.Presence{"key": c2.Key()}, d1.PresenceForTest(c2.ID().String()))
116-
assert.Equal(t, innerpresence.Presence{"key": c2.Key()}, d2.MyPresence())
117-
assert.Equal(t, innerpresence.Presence{"key": c1.Key()}, d2.PresenceForTest(c1.ID().String()))
114+
assert.Equal(t, innerpresence.Presence{"key", c1.Key()}, d1.MyPresence())
115+
assert.Equal(t, innerpresence.Presence{"key", c2.Key()}, d1.PresenceForTest(c2.ID().String()))
116+
assert.Equal(t, innerpresence.Presence{"key", c2.Key()}, d2.MyPresence())
117+
assert.Equal(t, innerpresence.Presence{"key", c1.Key()}, d2.PresenceForTest(c1.ID().String()))
118118

119119
// 03. The first client detaches the document and check that the presence is updated on the other client.
120120
assert.NoError(t, c1.Detach(ctx, d1))
121121
assert.NoError(t, c2.Sync(ctx))
122-
assert.Equal(t, innerpresence.Presence{"key": c2.Key()}, d2.MyPresence())
122+
assert.Equal(t, innerpresence.Presence{"key", c2.Key()}, d2.MyPresence())
123123
assert.Nil(t, d2.PresenceForTest(c1.ID().String()))
124124
})
125125

@@ -559,7 +559,7 @@ func TestPresence(t *testing.T) {
559559
expected = append(expected, watchResponsePair{
560560
Type: client.DocumentWatched,
561561
Presences: map[string]innerpresence.Presence{
562-
c2.ID().String(): {"updated": "true"},
562+
c2.ID().String(): {"updated", "true"},
563563
},
564564
})
565565
err = d2.Update(func(root *json.Object, p *presence.Presence) error {

test/k6/presence.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,7 @@ function attachDocument(clientID: string, actorID: string, docKey: string) {
263263
presenceChange: {
264264
type: "CHANGE_TYPE_PUT",
265265
presence: {
266-
data: {
267-
color: `"${randomColor}"`,
268-
},
266+
data: ["color", `"${randomColor}"`],
269267
},
270268
},
271269
},

0 commit comments

Comments
 (0)