You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

object.go 6.7 kB

2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package mq
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "github.com/jmoiron/sqlx"
  6. "github.com/samber/lo"
  7. "gitlink.org.cn/cloudream/common/consts/errorcode"
  8. "gitlink.org.cn/cloudream/common/pkgs/logger"
  9. "gitlink.org.cn/cloudream/common/pkgs/mq"
  10. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  11. "gitlink.org.cn/cloudream/common/utils/sort2"
  12. stgmod "gitlink.org.cn/cloudream/storage/common/models"
  13. coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
  14. )
  15. func (svc *Service) GetPackageObjects(msg *coormq.GetPackageObjects) (*coormq.GetPackageObjectsResp, *mq.CodeMessage) {
  16. // TODO 检查用户是否有权限
  17. objs, err := svc.db.Object().GetPackageObjects(svc.db.SQLCtx(), msg.PackageID)
  18. if err != nil {
  19. logger.WithField("PackageID", msg.PackageID).
  20. Warnf("get package objects: %s", err.Error())
  21. return nil, mq.Failed(errorcode.OperationFailed, "get package objects failed")
  22. }
  23. return mq.ReplyOK(coormq.NewGetPackageObjectsResp(objs))
  24. }
  25. func (svc *Service) GetPackageObjectDetails(msg *coormq.GetPackageObjectDetails) (*coormq.GetPackageObjectDetailsResp, *mq.CodeMessage) {
  26. var details []stgmod.ObjectDetail
  27. // 必须放在事务里进行,因为GetPackageBlockDetails是由多次数据库操作组成,必须保证数据的一致性
  28. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  29. var err error
  30. _, err = svc.db.Package().GetByID(tx, msg.PackageID)
  31. if err != nil {
  32. return fmt.Errorf("getting package by id: %w", err)
  33. }
  34. details, err = svc.db.Object().GetPackageObjectDetails(tx, msg.PackageID)
  35. if err != nil {
  36. return fmt.Errorf("getting package block details: %w", err)
  37. }
  38. return nil
  39. })
  40. if err != nil {
  41. logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
  42. return nil, mq.Failed(errorcode.OperationFailed, "get package object block details failed")
  43. }
  44. return mq.ReplyOK(coormq.NewGetPackageObjectDetailsResp(details))
  45. }
  46. func (svc *Service) UpdateObjectRedundancy(msg *coormq.UpdateObjectRedundancy) (*coormq.UpdateObjectRedundancyResp, *mq.CodeMessage) {
  47. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  48. return svc.db.Object().BatchUpdateRedundancy(tx, msg.Updatings)
  49. })
  50. if err != nil {
  51. logger.Warnf("batch updating redundancy: %s", err.Error())
  52. return nil, mq.Failed(errorcode.OperationFailed, "batch update redundancy failed")
  53. }
  54. return mq.ReplyOK(coormq.RespUpdateObjectRedundancy())
  55. }
  56. func (svc *Service) UpdateObjectInfos(msg *coormq.UpdateObjectInfos) (*coormq.UpdateObjectInfosResp, *mq.CodeMessage) {
  57. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  58. msg.Updatings = sort2.Sort(msg.Updatings, func(o1, o2 cdssdk.UpdatingObject) int {
  59. return sort2.Cmp(o1.ObjectID, o2.ObjectID)
  60. })
  61. objIDs := make([]cdssdk.ObjectID, len(msg.Updatings))
  62. for i, obj := range msg.Updatings {
  63. objIDs[i] = obj.ObjectID
  64. }
  65. oldObjs, err := svc.db.Object().BatchGet(tx, objIDs)
  66. if err != nil {
  67. return fmt.Errorf("batch getting objects: %w", err)
  68. }
  69. oldObjIDs := make([]cdssdk.ObjectID, len(oldObjs))
  70. for i, obj := range oldObjs {
  71. oldObjIDs[i] = obj.ObjectID
  72. }
  73. avaiUpdatings, notExistsObjs := pickByObjectIDs(msg.Updatings, oldObjIDs)
  74. if len(notExistsObjs) > 0 {
  75. // TODO 部分对象已经不存在
  76. }
  77. // 筛选出PackageID变化、Path变化的对象,这两种对象要检测改变后是否有冲突
  78. // 否则,直接更新即可
  79. //var pkgIDChangedObjs []cdssdk.Object
  80. //var pathChangedObjs []cdssdk.Object
  81. //var infoChangedObjs []cdssdk.Object
  82. //for i := range willUpdateObjs {
  83. // if willUpdateObjs[i].PackageID != oldObjs[i].PackageID {
  84. // newObj := oldObjs[i]
  85. // willUpdateObjs[i].ApplyTo(&newObj)
  86. // pkgIDChangedObjs = append(pkgIDChangedObjs, newObj)
  87. // } else if willUpdateObjs[i].Path != oldObjs[i].Path {
  88. // newObj := oldObjs[i]
  89. // willUpdateObjs[i].ApplyTo(&newObj)
  90. // pathChangedObjs = append(pathChangedObjs, newObj)
  91. // } else {
  92. // newObj := oldObjs[i]
  93. // willUpdateObjs[i].ApplyTo(&newObj)
  94. // infoChangedObjs = append(infoChangedObjs, newObj)
  95. // }
  96. //}
  97. newObjs := make([]cdssdk.Object, len(avaiUpdatings))
  98. for i := range newObjs {
  99. newObj := oldObjs[i]
  100. avaiUpdatings[i].ApplyTo(&newObj)
  101. }
  102. err = svc.db.Object().BatchCreateOrUpdate(tx, newObjs)
  103. if err != nil {
  104. return fmt.Errorf("batch create or update: %w", err)
  105. }
  106. return nil
  107. })
  108. if err != nil {
  109. logger.Warnf("batch updating objects: %s", err.Error())
  110. return nil, mq.Failed(errorcode.OperationFailed, "batch update objects failed")
  111. }
  112. return mq.ReplyOK(coormq.RespUpdateObjectInfos())
  113. }
  114. func pickByObjectIDs(objs []cdssdk.UpdatingObject, objIDs []cdssdk.ObjectID) (pickedObjs []cdssdk.UpdatingObject, notFoundObjs []cdssdk.ObjectID) {
  115. objIdx := 0
  116. IDIdx := 0
  117. for IDIdx < len(objIDs) {
  118. if objs[objIdx].ObjectID == objIDs[IDIdx] {
  119. pickedObjs = append(pickedObjs, objs[objIdx])
  120. IDIdx++
  121. objIdx++
  122. } else if objs[objIdx].ObjectID < objIDs[IDIdx] {
  123. objIdx++
  124. } else {
  125. notFoundObjs = append(notFoundObjs, objIDs[IDIdx])
  126. IDIdx++
  127. }
  128. }
  129. return
  130. }
  131. func (svc *Service) ensurePackageChangedObjects(tx *sqlx.Tx, objs []cdssdk.Object) ([]cdssdk.Object, error) {
  132. type PackageObjects struct {
  133. PackageID cdssdk.PackageID
  134. ObjectByPath map[string]*cdssdk.Object
  135. }
  136. packages := make(map[cdssdk.PackageID]*PackageObjects)
  137. for _, obj := range objs {
  138. pkg, ok := packages[obj.PackageID]
  139. if !ok {
  140. pkg = &PackageObjects{
  141. PackageID: obj.PackageID,
  142. ObjectByPath: make(map[string]*cdssdk.Object),
  143. }
  144. packages[obj.PackageID] = pkg
  145. }
  146. if pkg.ObjectByPath[obj.Path] == nil {
  147. o := obj
  148. pkg.ObjectByPath[obj.Path] = &o
  149. } else {
  150. // TODO 有冲突
  151. }
  152. }
  153. var willUpdateObjs []cdssdk.Object
  154. for _, pkg := range packages {
  155. existsObjs, err := svc.db.Object().BatchByPackagePath(tx, pkg.PackageID, lo.Keys(pkg.ObjectByPath))
  156. if err != nil {
  157. return nil, fmt.Errorf("batch getting objects by package path: %w", err)
  158. }
  159. for _, obj := range existsObjs {
  160. pkg.ObjectByPath[obj.Path] = nil
  161. }
  162. for _, obj := range pkg.ObjectByPath {
  163. if obj == nil {
  164. continue
  165. }
  166. willUpdateObjs = append(willUpdateObjs, *obj)
  167. }
  168. }
  169. return willUpdateObjs, nil
  170. }
  171. func (svc *Service) DeleteObjects(msg *coormq.DeleteObjects) (*coormq.DeleteObjectsResp, *mq.CodeMessage) {
  172. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  173. return svc.db.Object().BatchDelete(tx, msg.ObjectIDs)
  174. })
  175. if err != nil {
  176. logger.Warnf("batch deleting objects: %s", err.Error())
  177. return nil, mq.Failed(errorcode.OperationFailed, "batch delete objects failed")
  178. }
  179. return mq.ReplyOK(coormq.RespDeleteObjects())
  180. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。