You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Open-IM-Server/internal/rpc/incrversion/option.go

157 lines
3.6 KiB

feat: support incremental synchronization (#2379) * fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task * fix: minio config url recognition error * new mongo * new mongo * new mongo * new mongo * new mongo * new mongo * new mongo * new mongo * friend incr sync * friend incr sync * friend incr sync * friend incr sync * friend incr sync * mage * optimization version log * optimization version log * sync * sync * sync * group sync * sync option * sync option * refactor: replace `friend` package with `realtion`. * refactor: update lastest commit to relation. * sync option * sync option * sync option * sync * sync * go.mod * update: go mod * refactor: change incremental to full * feat: get full friend user ids * feat: api and config * group version * merge * fix: sort by id avoid unstable sort friends. * group * group * group * fix: sort by id avoid unstable sort friends. * fix: sort by id avoid unstable sort friends. * fix: sort by id avoid unstable sort friends. * user version * fix: sort by id avoid unstable sort friends. * test: test log add. * test: debug log remove. * fix: transfer group owner incr version more than 1. * fix: add condition to kick owner. * feat: replace resp nil * feat: replace nil * fix: delete cache of max group joined version avoid sync joined group failed. * fix: nil * fix: delete cache of max group joined version avoid sync joined group failed. * fix: delete cache of max group joined version avoid sync joined group failed. * return group information for any changes * online cache --------- Co-authored-by: withchao <withchao@users.noreply.github.com> Co-authored-by: Monet Lee <monet_lee@163.com> Co-authored-by: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Co-authored-by: icey-yu <1186114839@qq.com>
5 months ago
package incrversion
import (
"context"
"fmt"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/tools/errs"
"go.mongodb.org/mongo-driver/bson/primitive"
)
//func Limit(maxSync int, version uint64) int {
// if version == 0 {
// return 0
// }
// return maxSync
//}
const syncLimit = 200
const (
tagQuery = iota + 1
tagFull
tageEqual
)
type Option[A, B any] struct {
Ctx context.Context
VersionKey string
VersionID string
VersionNumber uint64
//SyncLimit int
CacheMaxVersion func(ctx context.Context, dId string) (*model.VersionLog, error)
Version func(ctx context.Context, dId string, version uint, limit int) (*model.VersionLog, error)
//SortID func(ctx context.Context, dId string) ([]string, error)
Find func(ctx context.Context, ids []string) ([]A, error)
ID func(elem A) string
Resp func(version *model.VersionLog, deleteIds []string, insertList, updateList []A, full bool) *B
}
func (o *Option[A, B]) newError(msg string) error {
return errs.ErrInternalServer.WrapMsg(msg)
}
func (o *Option[A, B]) check() error {
if o.Ctx == nil {
return o.newError("opt ctx is nil")
}
if o.VersionKey == "" {
return o.newError("versionKey is empty")
}
//if o.SyncLimit <= 0 {
// return o.newError("invalid synchronization quantity")
//}
if o.Version == nil {
return o.newError("func version is nil")
}
//if o.SortID == nil {
// return o.newError("func allID is nil")
//}
if o.Find == nil {
return o.newError("func find is nil")
}
if o.ID == nil {
return o.newError("func id is nil")
}
if o.Resp == nil {
return o.newError("func resp is nil")
}
return nil
}
func (o *Option[A, B]) validVersion() bool {
objID, err := primitive.ObjectIDFromHex(o.VersionID)
return err == nil && (!objID.IsZero()) && o.VersionNumber > 0
}
func (o *Option[A, B]) equalID(objID primitive.ObjectID) bool {
return o.VersionID == objID.Hex()
}
func (o *Option[A, B]) getVersion(tag *int) (*model.VersionLog, error) {
if o.CacheMaxVersion == nil {
if o.validVersion() {
*tag = tagQuery
return o.Version(o.Ctx, o.VersionKey, uint(o.VersionNumber), syncLimit)
}
*tag = tagFull
return o.Version(o.Ctx, o.VersionKey, 0, 0)
} else {
cache, err := o.CacheMaxVersion(o.Ctx, o.VersionKey)
if err != nil {
return nil, err
}
if !o.validVersion() {
*tag = tagFull
return cache, nil
}
if !o.equalID(cache.ID) {
*tag = tagFull
return cache, nil
}
if o.VersionNumber == uint64(cache.Version) {
*tag = tageEqual
return cache, nil
}
*tag = tagQuery
return o.Version(o.Ctx, o.VersionKey, uint(o.VersionNumber), syncLimit)
}
}
func (o *Option[A, B]) Build() (*B, error) {
if err := o.check(); err != nil {
return nil, err
}
var tag int
version, err := o.getVersion(&tag)
if err != nil {
return nil, err
}
var full bool
switch tag {
case tagQuery:
full = version.ID.Hex() != o.VersionID || uint64(version.Version) < o.VersionNumber || len(version.Logs) != version.LogLen
case tagFull:
full = true
case tageEqual:
full = false
default:
panic(fmt.Errorf("undefined tag %d", tag))
}
var (
insertIds []string
deleteIds []string
updateIds []string
)
if !full {
insertIds, deleteIds, updateIds = version.DeleteAndChangeIDs()
}
var (
insertList []A
updateList []A
)
if len(insertIds) > 0 {
insertList, err = o.Find(o.Ctx, insertIds)
if err != nil {
return nil, err
}
}
if len(updateIds) > 0 {
updateList, err = o.Find(o.Ctx, updateIds)
if err != nil {
return nil, err
}
}
return o.Resp(version, deleteIds, insertList, updateList, full), nil
}