[MM-21378] Add mutex to model.Post to guard against race conditions on Post.Props (#13884)

* Add mutex to model.Post to guard against race conditions on Post.Props

* Rename mutex

* Add GetProp() method to Post

* Fix more tests

* Fix flaky test

Benchmarks:

BenchmarkPostPropsGet_indirect
BenchmarkPostPropsGet_indirect-2     	85026746	        13.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_indirect-4     	90273747	        13.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_indirect-8     	88324293	        13.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_indirect-16    	91427720	        13.1 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_direct
BenchmarkPostPropsGet_direct-2       	1000000000	         0.242 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_direct-4       	1000000000	         0.241 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_direct-8       	1000000000	         0.240 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsGet_direct-16      	1000000000	         0.241 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsAdd_indirect
BenchmarkPostPropsAdd_indirect-2     	 5602224	       203 ns/op	     336 B/op	       2 allocs/op
BenchmarkPostPropsAdd_indirect-4     	 5959496	       206 ns/op	     336 B/op	       2 allocs/op
BenchmarkPostPropsAdd_indirect-8     	 5833999	       205 ns/op	     336 B/op	       2 allocs/op
BenchmarkPostPropsAdd_indirect-16    	 5802493	       225 ns/op	     336 B/op	       2 allocs/op
BenchmarkPostPropsAdd_direct
BenchmarkPostPropsAdd_direct-2       	100000000	        11.3 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsAdd_direct-4       	100000000	        11.3 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsAdd_direct-8       	100000000	        11.6 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsAdd_direct-16      	99840794	        11.4 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsDel_indirect
BenchmarkPostPropsDel_indirect-2     	18824002	        61.9 ns/op	      48 B/op	       1 allocs/op
BenchmarkPostPropsDel_indirect-4     	19470736	        63.8 ns/op	      48 B/op	       1 allocs/op
BenchmarkPostPropsDel_indirect-8     	17640460	        65.3 ns/op	      48 B/op	       1 allocs/op
BenchmarkPostPropsDel_indirect-16    	18692962	        65.4 ns/op	      48 B/op	       1 allocs/op
BenchmarkPostPropsDel_direct
BenchmarkPostPropsDel_direct-2       	516257440	         2.34 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsDel_direct-4       	514865216	         2.43 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsDel_direct-8       	511330477	         2.37 ns/op	       0 B/op	       0 allocs/op
BenchmarkPostPropsDel_direct-16      	499504010	         2.38 ns/op	       0 B/op	       0 allocs/op
Этот коммит содержится в:
Claudio Costa
2020-03-13 21:12:20 +01:00
коммит произвёл GitHub
родитель 9e580361c2
Коммит 1e53fe85ad
28 изменённых файлов: 430 добавлений и 195 удалений

Просмотреть файл

@@ -433,9 +433,9 @@ func (s *SqlPostStore) Delete(postId string, time int64, deleteByID string) *mod
return appErr(err.Error())
}
post.Props[model.POST_PROPS_DELETE_BY] = deleteByID
post.AddProp(model.POST_PROPS_DELETE_BY, deleteByID)
_, err = s.GetMaster().Exec("UPDATE Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt, Props = :Props WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "RootId": postId, "Props": model.StringInterfaceToJson(post.Props)})
_, err = s.GetMaster().Exec("UPDATE Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt, Props = :Props WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "RootId": postId, "Props": model.StringInterfaceToJson(post.GetProps())})
if err != nil {
return appErr(err.Error())
}

Просмотреть файл

@@ -733,7 +733,7 @@ func testEditExportMessage(t *testing.T, ss store.Store) {
//user 1 edits the previous post
post1e := &model.Post{}
*post1e = *post1
post1e = post1.Clone()
post1e.Message = "edit " + post1.Message
post1e, err = ss.Post().Update(post1e, post1)
@@ -845,7 +845,7 @@ func testEditAfterExportMessage(t *testing.T, ss store.Store) {
postEditTime := post1.UpdateAt + 1
//user 1 edits the previous post
post1e := &model.Post{}
*post1e = *post1
post1e = post1.Clone()
post1e.EditAt = postEditTime
post1e.Message = "edit " + post1.Message
post1e, err = ss.Post().Update(post1e, post1)

Просмотреть файл

@@ -259,16 +259,16 @@ func testFileInfoGetForUser(t *testing.T, ss store.Store) {
}
func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
makePost := func(chId string, user string) model.Post {
makePost := func(chId string, user string) *model.Post {
post := model.Post{}
post.ChannelId = chId
post.UserId = user
_, err := ss.Post().Save(&post)
require.Nil(t, err)
return post
return &post
}
makeFile := func(post model.Post, user string, createAt int64, idPrefix string) model.FileInfo {
makeFile := func(post *model.Post, user string, createAt int64, idPrefix string) model.FileInfo {
id := model.NewId()
id = idPrefix + id[1:] // hacky way to get sortable Ids to confirm secondary Id sort works
fileInfo := model.FileInfo{
@@ -298,10 +298,10 @@ func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
post2_2 := makePost(channelId3, userId2)
epoch := time.Date(2020, 1, 1, 1, 1, 1, 1, time.UTC)
file1_1 := makeFile(post1_1, userId1, epoch.AddDate(0, 0, 1).Unix(), "a") // file 1 by user 1
file1_2 := makeFile(post1_2, userId1, epoch.AddDate(0, 0, 2).Unix(), "b") // file 2 by user 1
file1_3 := makeFile(model.Post{}, userId1, epoch.AddDate(0, 0, 3).Unix(), "c") // file that is not attached to a post
file2_1 := makeFile(post2_1, userId2, epoch.AddDate(0, 0, 4).Unix(), "d") // file 2 by user 1
file1_1 := makeFile(post1_1, userId1, epoch.AddDate(0, 0, 1).Unix(), "a") // file 1 by user 1
file1_2 := makeFile(post1_2, userId1, epoch.AddDate(0, 0, 2).Unix(), "b") // file 2 by user 1
file1_3 := makeFile(&model.Post{}, userId1, epoch.AddDate(0, 0, 3).Unix(), "c") // file that is not attached to a post
file2_1 := makeFile(post2_1, userId2, epoch.AddDate(0, 0, 4).Unix(), "d") // file 2 by user 1
file2_2 := makeFile(post2_2, userId2, epoch.AddDate(0, 0, 5).Unix(), "e")
// delete a file

Просмотреть файл

@@ -88,6 +88,8 @@ func testPostStoreSave(t *testing.T, ss store.Store) {
_, err := ss.Post().Save(&rootPost)
require.Nil(t, err)
time.Sleep(2 * time.Millisecond)
replyPost := model.Post{}
replyPost.ChannelId = rootPost.ChannelId
replyPost.UserId = model.NewId()
@@ -410,8 +412,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
require.Equal(t, ro1.Message, o1.Message, "Failed to save/get")
o1a := &model.Post{}
*o1a = *ro1
o1a := ro1.Clone()
o1a.Message = ro1.Message + "BBBBBBBBBB"
_, err = ss.Post().Update(o1a, ro1)
require.Nil(t, err)
@@ -422,8 +423,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
ro1a := r1.Posts[o1.Id]
require.Equal(t, ro1a.Message, o1a.Message, "Failed to update/get")
o2a := &model.Post{}
*o2a = *ro2
o2a := ro2.Clone()
o2a.Message = ro2.Message + "DDDDDDD"
_, err = ss.Post().Update(o2a, ro2)
require.Nil(t, err)
@@ -434,8 +434,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
require.Equal(t, ro2a.Message, o2a.Message, "Failed to update/get")
o3a := &model.Post{}
*o3a = *ro3
o3a := ro3.Clone()
o3a.Message = ro3.Message + "WWWWWWW"
_, err = ss.Post().Update(o3a, ro3)
require.Nil(t, err)
@@ -460,8 +459,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
require.Nil(t, err)
ro4 := r4.Posts[o4.Id]
o4a := &model.Post{}
*o4a = *ro4
o4a := ro4.Clone()
o4a.Filenames = []string{}
o4a.FileIds = []string{model.NewId()}
_, err = ss.Post().Update(o4a, ro4)
@@ -497,7 +495,7 @@ func testPostStoreDelete(t *testing.T, ss store.Store) {
posts, _ := ss.Post().GetPostsCreatedAt(o1.ChannelId, o1.CreateAt)
post := posts[0]
actual := post.Props[model.POST_PROPS_DELETE_BY]
actual := post.GetProp(model.POST_PROPS_DELETE_BY)
assert.Equal(t, deleteByID, actual, "Expected (*Post).Props[model.POST_PROPS_DELETE_BY] to be %v but got %v.", deleteByID, actual)
@@ -2291,16 +2289,13 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
require.Equal(t, ro5.Filenames, o5.Filenames, "Failed to save/get")
t.Run("overwrite changing message", func(t *testing.T) {
o1a := &model.Post{}
*o1a = *ro1
o1a := ro1.Clone()
o1a.Message = ro1.Message + "BBBBBBBBBB"
o2a := &model.Post{}
*o2a = *ro2
o2a := ro2.Clone()
o2a.Message = ro2.Message + "DDDDDDD"
o3a := &model.Post{}
*o3a = *ro3
o3a := ro3.Clone()
o3a.Message = ro3.Message + "WWWWWWW"
_, err = ss.Post().OverwriteMultiple([]*model.Post{o1a, o2a, o3a})
@@ -2324,13 +2319,11 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
})
t.Run("overwrite clearing filenames", func(t *testing.T) {
o4a := &model.Post{}
*o4a = *ro4
o4a := ro4.Clone()
o4a.Filenames = []string{}
o4a.FileIds = []string{model.NewId()}
o5a := &model.Post{}
*o5a = *ro5
o5a := ro5.Clone()
o5a.Filenames = []string{}
o5a.FileIds = []string{}
@@ -2406,20 +2399,17 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
require.Equal(t, ro4.Message, o4.Message, "Failed to save/get")
t.Run("overwrite changing message", func(t *testing.T) {
o1a := &model.Post{}
*o1a = *ro1
o1a := ro1.Clone()
o1a.Message = ro1.Message + "BBBBBBBBBB"
_, err = ss.Post().Overwrite(o1a)
require.Nil(t, err)
o2a := &model.Post{}
*o2a = *ro2
o2a := ro2.Clone()
o2a.Message = ro2.Message + "DDDDDDD"
_, err = ss.Post().Overwrite(o2a)
require.Nil(t, err)
o3a := &model.Post{}
*o3a = *ro3
o3a := ro3.Clone()
o3a.Message = ro3.Message + "WWWWWWW"
_, err = ss.Post().Overwrite(o3a)
require.Nil(t, err)
@@ -2442,8 +2432,7 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
})
t.Run("overwrite clearing filenames", func(t *testing.T) {
o4a := &model.Post{}
*o4a = *ro4
o4a := ro4.Clone()
o4a.Filenames = []string{}
o4a.FileIds = []string{model.NewId()}
_, err = ss.Post().Overwrite(o4a)
@@ -2863,8 +2852,7 @@ func testPostStoreGetDirectPostParentsForExportAfterDeleted(t *testing.T, ss sto
p1, err = ss.Post().Save(p1)
require.Nil(t, err)
o1a := &model.Post{}
*o1a = *p1
o1a := p1.Clone()
o1a.DeleteAt = 1
o1a.Message = p1.Message + "BBBBBBBBBB"
_, err = ss.Post().Update(o1a, p1)