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.

check_package_redundancy.go 37 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  1. package event
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "time"
  7. "github.com/samber/lo"
  8. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  9. "gitlink.org.cn/cloudream/common/pkgs/logger"
  10. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  11. "gitlink.org.cn/cloudream/common/utils/sort2"
  12. stgglb "gitlink.org.cn/cloudream/storage/common/globals"
  13. stgmod "gitlink.org.cn/cloudream/storage/common/models"
  14. "gitlink.org.cn/cloudream/storage/common/pkgs/distlock/reqbuilder"
  15. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch2"
  16. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch2/ops2"
  17. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch2/parser"
  18. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitchlrc"
  19. lrcparser "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitchlrc/parser"
  20. coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
  21. scevt "gitlink.org.cn/cloudream/storage/common/pkgs/mq/scanner/event"
  22. "gitlink.org.cn/cloudream/storage/scanner/internal/config"
  23. )
  24. type CheckPackageRedundancy struct {
  25. *scevt.CheckPackageRedundancy
  26. }
  27. func NewCheckPackageRedundancy(evt *scevt.CheckPackageRedundancy) *CheckPackageRedundancy {
  28. return &CheckPackageRedundancy{
  29. CheckPackageRedundancy: evt,
  30. }
  31. }
  32. type StorageLoadInfo struct {
  33. Storage stgmod.StorageDetail
  34. AccessAmount float64
  35. }
  36. func (t *CheckPackageRedundancy) TryMerge(other Event) bool {
  37. event, ok := other.(*CheckPackageRedundancy)
  38. if !ok {
  39. return false
  40. }
  41. return event.PackageID == t.PackageID
  42. }
  43. func (t *CheckPackageRedundancy) Execute(execCtx ExecuteContext) {
  44. log := logger.WithType[CheckPackageRedundancy]("Event")
  45. startTime := time.Now()
  46. log.Debugf("begin with %v", logger.FormatStruct(t.CheckPackageRedundancy))
  47. defer func() {
  48. log.Debugf("end, time: %v", time.Since(startTime))
  49. }()
  50. // TODO 应该像其他event一样直接读取数据库
  51. coorCli, err := stgglb.CoordinatorMQPool.Acquire()
  52. if err != nil {
  53. log.Warnf("new coordinator client: %s", err.Error())
  54. return
  55. }
  56. defer stgglb.CoordinatorMQPool.Release(coorCli)
  57. getObjs, err := coorCli.GetPackageObjectDetails(coormq.ReqGetPackageObjectDetails(t.PackageID))
  58. if err != nil {
  59. log.Warnf("getting package objects: %s", err.Error())
  60. return
  61. }
  62. stats, err := execCtx.Args.DB.PackageAccessStat().GetByPackageID(execCtx.Args.DB.DefCtx(), t.PackageID)
  63. if err != nil {
  64. log.Warnf("getting package access stats: %s", err.Error())
  65. return
  66. }
  67. // TODO UserID
  68. getStgs, err := coorCli.GetUserStorageDetails(coormq.ReqGetUserStorageDetails(1))
  69. if err != nil {
  70. log.Warnf("getting all storages: %s", err.Error())
  71. return
  72. }
  73. if len(getStgs.Storages) == 0 {
  74. log.Warnf("no available storages")
  75. return
  76. }
  77. userAllStorages := make(map[cdssdk.StorageID]*StorageLoadInfo)
  78. for _, stg := range getStgs.Storages {
  79. userAllStorages[stg.Storage.StorageID] = &StorageLoadInfo{
  80. Storage: stg,
  81. }
  82. }
  83. for _, stat := range stats {
  84. info, ok := userAllStorages[stat.StorageID]
  85. if !ok {
  86. continue
  87. }
  88. info.AccessAmount = stat.Amount
  89. }
  90. var changedObjects []coormq.UpdatingObjectRedundancy
  91. defRep := cdssdk.DefaultRepRedundancy
  92. defEC := cdssdk.DefaultECRedundancy
  93. // TODO 目前rep的备份数量固定为2,所以这里直接选出两个节点
  94. // TODO 放到chooseRedundancy函数中
  95. mostBlockStgIDs := t.summaryRepObjectBlockStorages(getObjs.Objects, 2)
  96. newRepStgs := t.chooseNewStoragesForRep(&defRep, userAllStorages)
  97. rechoosedRepStgs := t.rechooseStoragesForRep(mostBlockStgIDs, &defRep, userAllStorages)
  98. newECStgs := t.chooseNewStoragesForEC(&defEC, userAllStorages)
  99. // 加锁
  100. builder := reqbuilder.NewBuilder()
  101. for _, storage := range newRepStgs {
  102. builder.Shard().Buzy(storage.Storage.Storage.StorageID)
  103. }
  104. for _, storage := range newECStgs {
  105. builder.Shard().Buzy(storage.Storage.Storage.StorageID)
  106. }
  107. mutex, err := builder.MutexLock(execCtx.Args.DistLock)
  108. if err != nil {
  109. log.Warnf("acquiring dist lock: %s", err.Error())
  110. return
  111. }
  112. defer mutex.Unlock()
  113. for _, obj := range getObjs.Objects {
  114. var updating *coormq.UpdatingObjectRedundancy
  115. var err error
  116. newRed, selectedStorages := t.chooseRedundancy(obj, userAllStorages)
  117. switch srcRed := obj.Object.Redundancy.(type) {
  118. case *cdssdk.NoneRedundancy:
  119. switch newRed := newRed.(type) {
  120. case *cdssdk.RepRedundancy:
  121. log.WithField("ObjectID", obj.Object.ObjectID).Debugf("redundancy: none -> rep")
  122. updating, err = t.noneToRep(execCtx, obj, newRed, newRepStgs, userAllStorages)
  123. case *cdssdk.ECRedundancy:
  124. log.WithField("ObjectID", obj.Object.ObjectID).Debugf("redundancy: none -> ec")
  125. updating, err = t.noneToEC(execCtx, obj, newRed, newECStgs, userAllStorages)
  126. case *cdssdk.LRCRedundancy:
  127. log.WithField("ObjectID", obj.Object.ObjectID).Debugf("redundancy: none -> lrc")
  128. updating, err = t.noneToLRC(execCtx, obj, newRed, selectedStorages, userAllStorages)
  129. case *cdssdk.SegmentRedundancy:
  130. log.WithField("ObjectID", obj.Object.ObjectID).Debugf("redundancy: none -> segment")
  131. updating, err = t.noneToSeg(execCtx, obj, newRed, selectedStorages, userAllStorages)
  132. }
  133. case *cdssdk.RepRedundancy:
  134. switch newRed := newRed.(type) {
  135. case *cdssdk.RepRedundancy:
  136. updating, err = t.repToRep(execCtx, obj, srcRed, rechoosedRepStgs, userAllStorages)
  137. case *cdssdk.ECRedundancy:
  138. log.WithField("ObjectID", obj.Object.ObjectID).Debugf("redundancy: rep -> ec")
  139. updating, err = t.repToEC(execCtx, obj, newRed, newECStgs, userAllStorages)
  140. }
  141. case *cdssdk.ECRedundancy:
  142. switch newRed := newRed.(type) {
  143. case *cdssdk.RepRedundancy:
  144. log.WithField("ObjectID", obj.Object.ObjectID).Debugf("redundancy: ec -> rep")
  145. updating, err = t.ecToRep(execCtx, obj, srcRed, newRed, newRepStgs, userAllStorages)
  146. case *cdssdk.ECRedundancy:
  147. uploadStorages := t.rechooseStoragesForEC(obj, srcRed, userAllStorages)
  148. updating, err = t.ecToEC(execCtx, obj, srcRed, newRed, uploadStorages, userAllStorages)
  149. }
  150. case *cdssdk.LRCRedundancy:
  151. switch newRed := newRed.(type) {
  152. case *cdssdk.LRCRedundancy:
  153. uploadStorages := t.rechooseStoragesForLRC(obj, srcRed, userAllStorages)
  154. updating, err = t.lrcToLRC(execCtx, obj, srcRed, newRed, uploadStorages, userAllStorages)
  155. }
  156. }
  157. if updating != nil {
  158. changedObjects = append(changedObjects, *updating)
  159. }
  160. if err != nil {
  161. log.WithField("ObjectID", obj.Object.ObjectID).Warnf("%s, its redundancy wont be changed", err.Error())
  162. }
  163. }
  164. if len(changedObjects) == 0 {
  165. return
  166. }
  167. _, err = coorCli.UpdateObjectRedundancy(coormq.ReqUpdateObjectRedundancy(changedObjects))
  168. if err != nil {
  169. log.Warnf("requesting to change object redundancy: %s", err.Error())
  170. return
  171. }
  172. }
  173. func (t *CheckPackageRedundancy) chooseRedundancy(obj stgmod.ObjectDetail, userAllStgs map[cdssdk.StorageID]*StorageLoadInfo) (cdssdk.Redundancy, []*StorageLoadInfo) {
  174. switch obj.Object.Redundancy.(type) {
  175. case *cdssdk.NoneRedundancy:
  176. if obj.Object.Size > config.Cfg().ECFileSizeThreshold {
  177. newStgs := t.chooseNewStoragesForEC(&cdssdk.DefaultECRedundancy, userAllStgs)
  178. return &cdssdk.DefaultECRedundancy, newStgs
  179. }
  180. return &cdssdk.DefaultRepRedundancy, t.chooseNewStoragesForRep(&cdssdk.DefaultRepRedundancy, userAllStgs)
  181. case *cdssdk.RepRedundancy:
  182. if obj.Object.Size > config.Cfg().ECFileSizeThreshold {
  183. newStgs := t.chooseNewStoragesForEC(&cdssdk.DefaultECRedundancy, userAllStgs)
  184. return &cdssdk.DefaultECRedundancy, newStgs
  185. }
  186. case *cdssdk.ECRedundancy:
  187. if obj.Object.Size <= config.Cfg().ECFileSizeThreshold {
  188. return &cdssdk.DefaultRepRedundancy, t.chooseNewStoragesForRep(&cdssdk.DefaultRepRedundancy, userAllStgs)
  189. }
  190. case *cdssdk.LRCRedundancy:
  191. newLRCStgs := t.rechooseStoragesForLRC(obj, &cdssdk.DefaultLRCRedundancy, userAllStgs)
  192. return &cdssdk.DefaultLRCRedundancy, newLRCStgs
  193. }
  194. return nil, nil
  195. }
  196. // 统计每个对象块所在的节点,选出块最多的不超过storageCnt个节点
  197. func (t *CheckPackageRedundancy) summaryRepObjectBlockStorages(objs []stgmod.ObjectDetail, storageCnt int) []cdssdk.StorageID {
  198. type stgBlocks struct {
  199. StorageID cdssdk.StorageID
  200. Count int
  201. }
  202. stgBlocksMap := make(map[cdssdk.StorageID]*stgBlocks)
  203. for _, obj := range objs {
  204. shouldUseEC := obj.Object.Size > config.Cfg().ECFileSizeThreshold
  205. if _, ok := obj.Object.Redundancy.(*cdssdk.RepRedundancy); ok && !shouldUseEC {
  206. for _, block := range obj.Blocks {
  207. if _, ok := stgBlocksMap[block.StorageID]; !ok {
  208. stgBlocksMap[block.StorageID] = &stgBlocks{
  209. StorageID: block.StorageID,
  210. Count: 0,
  211. }
  212. }
  213. stgBlocksMap[block.StorageID].Count++
  214. }
  215. }
  216. }
  217. storages := lo.Values(stgBlocksMap)
  218. sort2.Sort(storages, func(left *stgBlocks, right *stgBlocks) int {
  219. return right.Count - left.Count
  220. })
  221. ids := lo.Map(storages, func(item *stgBlocks, idx int) cdssdk.StorageID { return item.StorageID })
  222. if len(ids) > storageCnt {
  223. ids = ids[:storageCnt]
  224. }
  225. return ids
  226. }
  227. func (t *CheckPackageRedundancy) chooseNewStoragesForRep(red *cdssdk.RepRedundancy, allStgs map[cdssdk.StorageID]*StorageLoadInfo) []*StorageLoadInfo {
  228. sortedStorages := sort2.Sort(lo.Values(allStgs), func(left *StorageLoadInfo, right *StorageLoadInfo) int {
  229. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  230. })
  231. return t.chooseSoManyStorages(red.RepCount, sortedStorages)
  232. }
  233. func (t *CheckPackageRedundancy) chooseNewStoragesForEC(red *cdssdk.ECRedundancy, allStgs map[cdssdk.StorageID]*StorageLoadInfo) []*StorageLoadInfo {
  234. sortedStorages := sort2.Sort(lo.Values(allStgs), func(left *StorageLoadInfo, right *StorageLoadInfo) int {
  235. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  236. })
  237. return t.chooseSoManyStorages(red.N, sortedStorages)
  238. }
  239. func (t *CheckPackageRedundancy) chooseNewStoragesForLRC(red *cdssdk.LRCRedundancy, allStorages map[cdssdk.HubID]*StorageLoadInfo) []*StorageLoadInfo {
  240. sortedStorages := sort2.Sort(lo.Values(allStorages), func(left *StorageLoadInfo, right *StorageLoadInfo) int {
  241. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  242. })
  243. return t.chooseSoManyStorages(red.N, sortedStorages)
  244. }
  245. func (t *CheckPackageRedundancy) chooseNewStoragesForSeg(segCount int, allStgs map[cdssdk.StorageID]*StorageLoadInfo) []*StorageLoadInfo {
  246. sortedStorages := sort2.Sort(lo.Values(allStgs), func(left *StorageLoadInfo, right *StorageLoadInfo) int {
  247. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  248. })
  249. return t.chooseSoManyStorages(segCount, sortedStorages)
  250. }
  251. func (t *CheckPackageRedundancy) rechooseStoragesForRep(mostBlockStgIDs []cdssdk.StorageID, red *cdssdk.RepRedundancy, allStgs map[cdssdk.StorageID]*StorageLoadInfo) []*StorageLoadInfo {
  252. type rechooseStorage struct {
  253. *StorageLoadInfo
  254. HasBlock bool
  255. }
  256. var rechooseStgs []*rechooseStorage
  257. for _, stg := range allStgs {
  258. hasBlock := false
  259. for _, id := range mostBlockStgIDs {
  260. if id == stg.Storage.Storage.StorageID {
  261. hasBlock = true
  262. break
  263. }
  264. }
  265. rechooseStgs = append(rechooseStgs, &rechooseStorage{
  266. StorageLoadInfo: stg,
  267. HasBlock: hasBlock,
  268. })
  269. }
  270. sortedStgs := sort2.Sort(rechooseStgs, func(left *rechooseStorage, right *rechooseStorage) int {
  271. // 已经缓存了文件块的节点优先选择
  272. v := sort2.CmpBool(right.HasBlock, left.HasBlock)
  273. if v != 0 {
  274. return v
  275. }
  276. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  277. })
  278. return t.chooseSoManyStorages(red.RepCount, lo.Map(sortedStgs, func(storage *rechooseStorage, idx int) *StorageLoadInfo { return storage.StorageLoadInfo }))
  279. }
  280. func (t *CheckPackageRedundancy) rechooseStoragesForEC(obj stgmod.ObjectDetail, red *cdssdk.ECRedundancy, allStgs map[cdssdk.StorageID]*StorageLoadInfo) []*StorageLoadInfo {
  281. type rechooseStg struct {
  282. *StorageLoadInfo
  283. CachedBlockIndex int
  284. }
  285. var rechooseStgs []*rechooseStg
  286. for _, stg := range allStgs {
  287. cachedBlockIndex := -1
  288. for _, block := range obj.Blocks {
  289. if block.StorageID == stg.Storage.Storage.StorageID {
  290. cachedBlockIndex = block.Index
  291. break
  292. }
  293. }
  294. rechooseStgs = append(rechooseStgs, &rechooseStg{
  295. StorageLoadInfo: stg,
  296. CachedBlockIndex: cachedBlockIndex,
  297. })
  298. }
  299. sortedStgs := sort2.Sort(rechooseStgs, func(left *rechooseStg, right *rechooseStg) int {
  300. // 已经缓存了文件块的节点优先选择
  301. v := sort2.CmpBool(right.CachedBlockIndex > -1, left.CachedBlockIndex > -1)
  302. if v != 0 {
  303. return v
  304. }
  305. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  306. })
  307. // TODO 可以考虑选择已有块的节点时,能依然按照Index顺序选择
  308. return t.chooseSoManyStorages(red.N, lo.Map(sortedStgs, func(storage *rechooseStg, idx int) *StorageLoadInfo { return storage.StorageLoadInfo }))
  309. }
  310. func (t *CheckPackageRedundancy) rechooseStoragesForLRC(obj stgmod.ObjectDetail, red *cdssdk.LRCRedundancy, allStgs map[cdssdk.StorageID]*StorageLoadInfo) []*StorageLoadInfo {
  311. type rechooseStg struct {
  312. *StorageLoadInfo
  313. CachedBlockIndex int
  314. }
  315. var rechooseStgs []*rechooseStg
  316. for _, stg := range allStgs {
  317. cachedBlockIndex := -1
  318. for _, block := range obj.Blocks {
  319. if block.StorageID == stg.Storage.Storage.StorageID {
  320. cachedBlockIndex = block.Index
  321. break
  322. }
  323. }
  324. rechooseStgs = append(rechooseStgs, &rechooseStg{
  325. StorageLoadInfo: stg,
  326. CachedBlockIndex: cachedBlockIndex,
  327. })
  328. }
  329. sortedStgs := sort2.Sort(rechooseStgs, func(left *rechooseStg, right *rechooseStg) int {
  330. // 已经缓存了文件块的节点优先选择
  331. v := sort2.CmpBool(right.CachedBlockIndex > -1, left.CachedBlockIndex > -1)
  332. if v != 0 {
  333. return v
  334. }
  335. return sort2.Cmp(right.AccessAmount, left.AccessAmount)
  336. })
  337. // TODO 可以考虑选择已有块的节点时,能依然按照Index顺序选择
  338. return t.chooseSoManyStorages(red.N, lo.Map(sortedStgs, func(storage *rechooseStg, idx int) *StorageLoadInfo { return storage.StorageLoadInfo }))
  339. }
  340. func (t *CheckPackageRedundancy) chooseSoManyStorages(count int, stgs []*StorageLoadInfo) []*StorageLoadInfo {
  341. repeateCount := (count + len(stgs) - 1) / len(stgs)
  342. extendStgs := make([]*StorageLoadInfo, repeateCount*len(stgs))
  343. // 使用复制的方式将节点数扩充到要求的数量
  344. // 复制之后的结构:ABCD -> AAABBBCCCDDD
  345. for p := 0; p < repeateCount; p++ {
  346. for i, storage := range stgs {
  347. putIdx := i*repeateCount + p
  348. extendStgs[putIdx] = storage
  349. }
  350. }
  351. extendStgs = extendStgs[:count]
  352. var chosen []*StorageLoadInfo
  353. for len(chosen) < count {
  354. // 在每一轮内都选不同地区的节点,如果节点数不够,那么就再来一轮
  355. chosenLocations := make(map[cdssdk.LocationID]bool)
  356. for i, stg := range extendStgs {
  357. if stg == nil {
  358. continue
  359. }
  360. if chosenLocations[stg.Storage.MasterHub.LocationID] {
  361. continue
  362. }
  363. chosen = append(chosen, stg)
  364. chosenLocations[stg.Storage.MasterHub.LocationID] = true
  365. extendStgs[i] = nil
  366. }
  367. }
  368. return chosen
  369. }
  370. func (t *CheckPackageRedundancy) noneToRep(ctx ExecuteContext, obj stgmod.ObjectDetail, red *cdssdk.RepRedundancy, uploadStgs []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  371. if len(obj.Blocks) == 0 {
  372. return nil, fmt.Errorf("object is not cached on any storages, cannot change its redundancy to rep")
  373. }
  374. srcStg, ok := allStgs[obj.Blocks[0].StorageID]
  375. if !ok {
  376. return nil, fmt.Errorf("storage %v not found", obj.Blocks[0].StorageID)
  377. }
  378. if srcStg.Storage.MasterHub == nil {
  379. return nil, fmt.Errorf("storage %v has no master hub", obj.Blocks[0].StorageID)
  380. }
  381. // 如果选择的备份节点都是同一个,那么就只要上传一次
  382. uploadStgs = lo.UniqBy(uploadStgs, func(item *StorageLoadInfo) cdssdk.StorageID { return item.Storage.Storage.StorageID })
  383. ft := ioswitch2.NewFromTo()
  384. ft.AddFrom(ioswitch2.NewFromShardstore(obj.Object.FileHash, *srcStg.Storage.MasterHub, srcStg.Storage.Storage, ioswitch2.RawStream()))
  385. for i, stg := range uploadStgs {
  386. ft.AddTo(ioswitch2.NewToShardStore(*stg.Storage.MasterHub, stg.Storage.Storage, ioswitch2.RawStream(), fmt.Sprintf("%d", i)))
  387. }
  388. plans := exec.NewPlanBuilder()
  389. err := parser.Parse(ft, plans)
  390. if err != nil {
  391. return nil, fmt.Errorf("parsing plan: %w", err)
  392. }
  393. // TODO 添加依赖
  394. execCtx := exec.NewExecContext()
  395. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  396. ret, err := plans.Execute(execCtx).Wait(context.Background())
  397. if err != nil {
  398. return nil, fmt.Errorf("executing io plan: %w", err)
  399. }
  400. var blocks []stgmod.ObjectBlock
  401. for i, stg := range uploadStgs {
  402. blocks = append(blocks, stgmod.ObjectBlock{
  403. ObjectID: obj.Object.ObjectID,
  404. Index: 0,
  405. StorageID: stg.Storage.Storage.StorageID,
  406. FileHash: ret[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  407. })
  408. }
  409. return &coormq.UpdatingObjectRedundancy{
  410. ObjectID: obj.Object.ObjectID,
  411. Redundancy: red,
  412. Blocks: blocks,
  413. }, nil
  414. }
  415. func (t *CheckPackageRedundancy) noneToEC(ctx ExecuteContext, obj stgmod.ObjectDetail, red *cdssdk.ECRedundancy, uploadStgs []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  416. if len(obj.Blocks) == 0 {
  417. return nil, fmt.Errorf("object is not cached on any storages, cannot change its redundancy to ec")
  418. }
  419. srcStg, ok := allStgs[obj.Blocks[0].StorageID]
  420. if !ok {
  421. return nil, fmt.Errorf("storage %v not found", obj.Blocks[0].StorageID)
  422. }
  423. if srcStg.Storage.MasterHub == nil {
  424. return nil, fmt.Errorf("storage %v has no master hub", obj.Blocks[0].StorageID)
  425. }
  426. ft := ioswitch2.NewFromTo()
  427. ft.ECParam = red
  428. ft.AddFrom(ioswitch2.NewFromShardstore(obj.Object.FileHash, *srcStg.Storage.MasterHub, srcStg.Storage.Storage, ioswitch2.RawStream()))
  429. for i := 0; i < red.N; i++ {
  430. ft.AddTo(ioswitch2.NewToShardStore(*uploadStgs[i].Storage.MasterHub, uploadStgs[i].Storage.Storage, ioswitch2.ECSrteam(i), fmt.Sprintf("%d", i)))
  431. }
  432. plans := exec.NewPlanBuilder()
  433. err := parser.Parse(ft, plans)
  434. if err != nil {
  435. return nil, fmt.Errorf("parsing plan: %w", err)
  436. }
  437. execCtx := exec.NewExecContext()
  438. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  439. ioRet, err := plans.Execute(execCtx).Wait(context.Background())
  440. if err != nil {
  441. return nil, fmt.Errorf("executing io plan: %w", err)
  442. }
  443. var blocks []stgmod.ObjectBlock
  444. for i := 0; i < red.N; i++ {
  445. blocks = append(blocks, stgmod.ObjectBlock{
  446. ObjectID: obj.Object.ObjectID,
  447. Index: i,
  448. StorageID: uploadStgs[i].Storage.Storage.StorageID,
  449. FileHash: ioRet[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  450. })
  451. }
  452. return &coormq.UpdatingObjectRedundancy{
  453. ObjectID: obj.Object.ObjectID,
  454. Redundancy: red,
  455. Blocks: blocks,
  456. }, nil
  457. }
  458. func (t *CheckPackageRedundancy) noneToLRC(ctx ExecuteContext, obj stgmod.ObjectDetail, red *cdssdk.LRCRedundancy, uploadStorages []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  459. if len(obj.Blocks) == 0 {
  460. return nil, fmt.Errorf("object is not cached on any storages, cannot change its redundancy to ec")
  461. }
  462. srcStg, ok := allStgs[obj.Blocks[0].StorageID]
  463. if !ok {
  464. return nil, fmt.Errorf("storage %v not found", obj.Blocks[0].StorageID)
  465. }
  466. if srcStg.Storage.MasterHub == nil {
  467. return nil, fmt.Errorf("storage %v has no master hub", obj.Blocks[0].StorageID)
  468. }
  469. var toes []ioswitchlrc.To
  470. for i := 0; i < red.N; i++ {
  471. toes = append(toes, ioswitchlrc.NewToStorage(*uploadStorages[i].Storage.MasterHub, uploadStorages[i].Storage.Storage, i, fmt.Sprintf("%d", i)))
  472. }
  473. plans := exec.NewPlanBuilder()
  474. err := lrcparser.Encode(ioswitchlrc.NewFromStorage(obj.Object.FileHash, *srcStg.Storage.MasterHub, srcStg.Storage.Storage, -1), toes, plans)
  475. if err != nil {
  476. return nil, fmt.Errorf("parsing plan: %w", err)
  477. }
  478. execCtx := exec.NewExecContext()
  479. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  480. ioRet, err := plans.Execute(execCtx).Wait(context.Background())
  481. if err != nil {
  482. return nil, fmt.Errorf("executing io plan: %w", err)
  483. }
  484. var blocks []stgmod.ObjectBlock
  485. for i := 0; i < red.N; i++ {
  486. blocks = append(blocks, stgmod.ObjectBlock{
  487. ObjectID: obj.Object.ObjectID,
  488. Index: i,
  489. StorageID: uploadStorages[i].Storage.Storage.StorageID,
  490. FileHash: ioRet[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  491. })
  492. }
  493. return &coormq.UpdatingObjectRedundancy{
  494. ObjectID: obj.Object.ObjectID,
  495. Redundancy: red,
  496. Blocks: blocks,
  497. }, nil
  498. }
  499. func (t *CheckPackageRedundancy) noneToSeg(ctx ExecuteContext, obj stgmod.ObjectDetail, red *cdssdk.SegmentRedundancy, uploadStgs []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  500. if len(obj.Blocks) == 0 {
  501. return nil, fmt.Errorf("object is not cached on any storages, cannot change its redundancy to rep")
  502. }
  503. srcStg, ok := allStgs[obj.Blocks[0].StorageID]
  504. if !ok {
  505. return nil, fmt.Errorf("storage %v not found", obj.Blocks[0].StorageID)
  506. }
  507. if srcStg.Storage.MasterHub == nil {
  508. return nil, fmt.Errorf("storage %v has no master hub", obj.Blocks[0].StorageID)
  509. }
  510. // 如果选择的备份节点都是同一个,那么就只要上传一次
  511. uploadStgs = lo.UniqBy(uploadStgs, func(item *StorageLoadInfo) cdssdk.StorageID { return item.Storage.Storage.StorageID })
  512. ft := ioswitch2.NewFromTo()
  513. ft.SegmentParam = red
  514. ft.AddFrom(ioswitch2.NewFromShardstore(obj.Object.FileHash, *srcStg.Storage.MasterHub, srcStg.Storage.Storage, ioswitch2.RawStream()))
  515. for i, stg := range uploadStgs {
  516. ft.AddTo(ioswitch2.NewToShardStore(*stg.Storage.MasterHub, stg.Storage.Storage, ioswitch2.SegmentStream(i), fmt.Sprintf("%d", i)))
  517. }
  518. plans := exec.NewPlanBuilder()
  519. err := parser.Parse(ft, plans)
  520. if err != nil {
  521. return nil, fmt.Errorf("parsing plan: %w", err)
  522. }
  523. // TODO 添加依赖
  524. execCtx := exec.NewExecContext()
  525. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  526. ret, err := plans.Execute(execCtx).Wait(context.Background())
  527. if err != nil {
  528. return nil, fmt.Errorf("executing io plan: %w", err)
  529. }
  530. var blocks []stgmod.ObjectBlock
  531. for i, stg := range uploadStgs {
  532. blocks = append(blocks, stgmod.ObjectBlock{
  533. ObjectID: obj.Object.ObjectID,
  534. Index: i,
  535. StorageID: stg.Storage.Storage.StorageID,
  536. FileHash: ret[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  537. })
  538. }
  539. return &coormq.UpdatingObjectRedundancy{
  540. ObjectID: obj.Object.ObjectID,
  541. Redundancy: red,
  542. Blocks: blocks,
  543. }, nil
  544. }
  545. func (t *CheckPackageRedundancy) repToRep(ctx ExecuteContext, obj stgmod.ObjectDetail, red *cdssdk.RepRedundancy, uploadStgs []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  546. if len(obj.Blocks) == 0 {
  547. return nil, fmt.Errorf("object is not cached on any storages, cannot change its redundancy to rep")
  548. }
  549. srcStg, ok := allStgs[obj.Blocks[0].StorageID]
  550. if !ok {
  551. return nil, fmt.Errorf("storage %v not found", obj.Blocks[0].StorageID)
  552. }
  553. if srcStg.Storage.MasterHub == nil {
  554. return nil, fmt.Errorf("storage %v has no master hub", obj.Blocks[0].StorageID)
  555. }
  556. // 如果选择的备份节点都是同一个,那么就只要上传一次
  557. uploadStgs = lo.UniqBy(uploadStgs, func(item *StorageLoadInfo) cdssdk.StorageID { return item.Storage.Storage.StorageID })
  558. ft := ioswitch2.NewFromTo()
  559. ft.AddFrom(ioswitch2.NewFromShardstore(obj.Object.FileHash, *srcStg.Storage.MasterHub, srcStg.Storage.Storage, ioswitch2.RawStream()))
  560. for i, stg := range uploadStgs {
  561. ft.AddTo(ioswitch2.NewToShardStore(*stg.Storage.MasterHub, stg.Storage.Storage, ioswitch2.RawStream(), fmt.Sprintf("%d", i)))
  562. }
  563. plans := exec.NewPlanBuilder()
  564. err := parser.Parse(ft, plans)
  565. if err != nil {
  566. return nil, fmt.Errorf("parsing plan: %w", err)
  567. }
  568. // TODO 添加依赖
  569. execCtx := exec.NewExecContext()
  570. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  571. ret, err := plans.Execute(execCtx).Wait(context.Background())
  572. if err != nil {
  573. return nil, fmt.Errorf("executing io plan: %w", err)
  574. }
  575. var blocks []stgmod.ObjectBlock
  576. for i, stg := range uploadStgs {
  577. blocks = append(blocks, stgmod.ObjectBlock{
  578. ObjectID: obj.Object.ObjectID,
  579. Index: 0,
  580. StorageID: stg.Storage.Storage.StorageID,
  581. FileHash: ret[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  582. })
  583. }
  584. return &coormq.UpdatingObjectRedundancy{
  585. ObjectID: obj.Object.ObjectID,
  586. Redundancy: red,
  587. Blocks: blocks,
  588. }, nil
  589. }
  590. func (t *CheckPackageRedundancy) repToEC(ctx ExecuteContext, obj stgmod.ObjectDetail, red *cdssdk.ECRedundancy, uploadStorages []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  591. return t.noneToEC(ctx, obj, red, uploadStorages, allStgs)
  592. }
  593. func (t *CheckPackageRedundancy) ecToRep(ctx ExecuteContext, obj stgmod.ObjectDetail, srcRed *cdssdk.ECRedundancy, tarRed *cdssdk.RepRedundancy, uploadStgs []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  594. var chosenBlocks []stgmod.GrouppedObjectBlock
  595. var chosenBlockIndexes []int
  596. var chosenBlockStg []stgmod.StorageDetail
  597. for _, block := range obj.GroupBlocks() {
  598. if len(block.StorageIDs) > 0 {
  599. // TODO 考虑选择最优的节点
  600. stg, ok := allStgs[block.StorageIDs[0]]
  601. if !ok {
  602. continue
  603. }
  604. if stg.Storage.MasterHub == nil {
  605. continue
  606. }
  607. chosenBlocks = append(chosenBlocks, block)
  608. chosenBlockIndexes = append(chosenBlockIndexes, block.Index)
  609. chosenBlockStg = append(chosenBlockStg, stg.Storage)
  610. }
  611. if len(chosenBlocks) == srcRed.K {
  612. break
  613. }
  614. }
  615. if len(chosenBlocks) < srcRed.K {
  616. return nil, fmt.Errorf("no enough blocks to reconstruct the original file data")
  617. }
  618. // 如果选择的备份节点都是同一个,那么就只要上传一次
  619. uploadStgs = lo.UniqBy(uploadStgs, func(item *StorageLoadInfo) cdssdk.StorageID { return item.Storage.Storage.StorageID })
  620. // 每个被选节点都在自己节点上重建原始数据
  621. planBlder := exec.NewPlanBuilder()
  622. for i := range uploadStgs {
  623. ft := ioswitch2.NewFromTo()
  624. ft.ECParam = srcRed
  625. for i2, block := range chosenBlocks {
  626. ft.AddFrom(ioswitch2.NewFromShardstore(block.FileHash, *chosenBlockStg[i2].MasterHub, chosenBlockStg[i2].Storage, ioswitch2.ECSrteam(block.Index)))
  627. }
  628. len := obj.Object.Size
  629. ft.AddTo(ioswitch2.NewToShardStoreWithRange(*uploadStgs[i].Storage.MasterHub, uploadStgs[i].Storage.Storage, ioswitch2.RawStream(), fmt.Sprintf("%d", i), exec.Range{
  630. Offset: 0,
  631. Length: &len,
  632. }))
  633. err := parser.Parse(ft, planBlder)
  634. if err != nil {
  635. return nil, fmt.Errorf("parsing plan: %w", err)
  636. }
  637. }
  638. // TODO 添加依赖
  639. execCtx := exec.NewExecContext()
  640. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  641. ioRet, err := planBlder.Execute(execCtx).Wait(context.Background())
  642. if err != nil {
  643. return nil, fmt.Errorf("executing io plan: %w", err)
  644. }
  645. var blocks []stgmod.ObjectBlock
  646. for i := range uploadStgs {
  647. blocks = append(blocks, stgmod.ObjectBlock{
  648. ObjectID: obj.Object.ObjectID,
  649. Index: 0,
  650. StorageID: uploadStgs[i].Storage.Storage.StorageID,
  651. FileHash: ioRet[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  652. })
  653. }
  654. return &coormq.UpdatingObjectRedundancy{
  655. ObjectID: obj.Object.ObjectID,
  656. Redundancy: tarRed,
  657. Blocks: blocks,
  658. }, nil
  659. }
  660. func (t *CheckPackageRedundancy) ecToEC(ctx ExecuteContext, obj stgmod.ObjectDetail, srcRed *cdssdk.ECRedundancy, tarRed *cdssdk.ECRedundancy, uploadStorages []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  661. grpBlocks := obj.GroupBlocks()
  662. var chosenBlocks []stgmod.GrouppedObjectBlock
  663. var chosenBlockStg []stgmod.StorageDetail
  664. for _, block := range grpBlocks {
  665. if len(block.StorageIDs) > 0 {
  666. stg, ok := allStgs[block.StorageIDs[0]]
  667. if !ok {
  668. continue
  669. }
  670. if stg.Storage.MasterHub == nil {
  671. continue
  672. }
  673. chosenBlocks = append(chosenBlocks, block)
  674. chosenBlockStg = append(chosenBlockStg, stg.Storage)
  675. }
  676. if len(chosenBlocks) == srcRed.K {
  677. break
  678. }
  679. }
  680. if len(chosenBlocks) < srcRed.K {
  681. return nil, fmt.Errorf("no enough blocks to reconstruct the original file data")
  682. }
  683. // 目前EC的参数都相同,所以可以不用重建出完整数据然后再分块,可以直接构建出目的节点需要的块
  684. planBlder := exec.NewPlanBuilder()
  685. var newBlocks []stgmod.ObjectBlock
  686. shouldUpdateBlocks := false
  687. for i, stg := range uploadStorages {
  688. newBlock := stgmod.ObjectBlock{
  689. ObjectID: obj.Object.ObjectID,
  690. Index: i,
  691. StorageID: stg.Storage.Storage.StorageID,
  692. }
  693. grp, ok := lo.Find(grpBlocks, func(grp stgmod.GrouppedObjectBlock) bool { return grp.Index == i })
  694. // 如果新选中的节点已经记录在Block表中,那么就不需要任何变更
  695. if ok && lo.Contains(grp.StorageIDs, stg.Storage.Storage.StorageID) {
  696. newBlock.FileHash = grp.FileHash
  697. newBlocks = append(newBlocks, newBlock)
  698. continue
  699. }
  700. shouldUpdateBlocks = true
  701. // 否则就要重建出这个节点需要的块
  702. ft := ioswitch2.NewFromTo()
  703. ft.ECParam = srcRed
  704. for i2, block := range chosenBlocks {
  705. ft.AddFrom(ioswitch2.NewFromShardstore(block.FileHash, *chosenBlockStg[i2].MasterHub, chosenBlockStg[i2].Storage, ioswitch2.ECSrteam(block.Index)))
  706. }
  707. // 输出只需要自己要保存的那一块
  708. ft.AddTo(ioswitch2.NewToShardStore(*stg.Storage.MasterHub, stg.Storage.Storage, ioswitch2.ECSrteam(i), fmt.Sprintf("%d", i)))
  709. err := parser.Parse(ft, planBlder)
  710. if err != nil {
  711. return nil, fmt.Errorf("parsing plan: %w", err)
  712. }
  713. newBlocks = append(newBlocks, newBlock)
  714. }
  715. // 如果没有任何Plan,Wait会直接返回成功
  716. execCtx := exec.NewExecContext()
  717. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  718. ret, err := planBlder.Execute(execCtx).Wait(context.Background())
  719. if err != nil {
  720. return nil, fmt.Errorf("executing io plan: %w", err)
  721. }
  722. if !shouldUpdateBlocks {
  723. return nil, nil
  724. }
  725. for k, v := range ret {
  726. idx, err := strconv.ParseInt(k, 10, 64)
  727. if err != nil {
  728. return nil, fmt.Errorf("parsing result key %s as index: %w", k, err)
  729. }
  730. newBlocks[idx].FileHash = v.(*ops2.FileHashValue).Hash
  731. }
  732. return &coormq.UpdatingObjectRedundancy{
  733. ObjectID: obj.Object.ObjectID,
  734. Redundancy: tarRed,
  735. Blocks: newBlocks,
  736. }, nil
  737. }
  738. func (t *CheckPackageRedundancy) lrcToLRC(ctx ExecuteContext, obj stgmod.ObjectDetail, srcRed *cdssdk.LRCRedundancy, tarRed *cdssdk.LRCRedundancy, uploadStorages []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  739. blocksGrpByIndex := obj.GroupBlocks()
  740. var lostBlocks []int
  741. var lostBlockGrps []int
  742. canGroupReconstruct := true
  743. allBlockFlags := make([]bool, srcRed.N)
  744. for _, block := range blocksGrpByIndex {
  745. allBlockFlags[block.Index] = true
  746. }
  747. for i, ok := range allBlockFlags {
  748. grpID := srcRed.FindGroup(i)
  749. if !ok {
  750. if grpID == -1 {
  751. canGroupReconstruct = false
  752. break
  753. }
  754. if len(lostBlocks) > 0 && lostBlockGrps[len(lostBlockGrps)-1] == grpID {
  755. canGroupReconstruct = false
  756. break
  757. }
  758. lostBlocks = append(lostBlocks, i)
  759. lostBlockGrps = append(lostBlockGrps, grpID)
  760. }
  761. }
  762. if canGroupReconstruct {
  763. // return t.groupReconstructLRC(obj, lostBlocks, lostBlockGrps, blocksGrpByIndex, srcRed, uploadStorages)
  764. }
  765. return t.reconstructLRC(ctx, obj, blocksGrpByIndex, srcRed, uploadStorages, allStgs)
  766. }
  767. /*
  768. TODO2 修复这一块的代码
  769. func (t *CheckPackageRedundancy) groupReconstructLRC(obj stgmod.ObjectDetail, lostBlocks []int, lostBlockGrps []int, grpedBlocks []stgmod.GrouppedObjectBlock, red *cdssdk.LRCRedundancy, uploadStorages []*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  770. grped := make(map[int]stgmod.GrouppedObjectBlock)
  771. for _, b := range grpedBlocks {
  772. grped[b.Index] = b
  773. }
  774. plans := exec.NewPlanBuilder()
  775. for i := 0; i < len(lostBlocks); i++ {
  776. var froms []ioswitchlrc.From
  777. grpEles := red.GetGroupElements(lostBlockGrps[i])
  778. for _, ele := range grpEles {
  779. if ele == lostBlocks[i] {
  780. continue
  781. }
  782. froms = append(froms, ioswitchlrc.NewFromStorage(grped[ele].FileHash, nil, ele))
  783. }
  784. err := lrcparser.ReconstructGroup(froms, []ioswitchlrc.To{
  785. ioswitchlrc.NewToStorage(uploadStorages[i].Storage, lostBlocks[i], fmt.Sprintf("%d", lostBlocks[i])),
  786. }, plans)
  787. if err != nil {
  788. return nil, fmt.Errorf("parsing plan: %w", err)
  789. }
  790. }
  791. fmt.Printf("plans: %v\n", plans)
  792. // 如果没有任何Plan,Wait会直接返回成功
  793. // TODO 添加依赖
  794. ret, err := plans.Execute(exec.NewExecContext()).Wait(context.TODO())
  795. if err != nil {
  796. return nil, fmt.Errorf("executing io plan: %w", err)
  797. }
  798. var newBlocks []stgmod.ObjectBlock
  799. for _, i := range lostBlocks {
  800. newBlocks = append(newBlocks, stgmod.ObjectBlock{
  801. ObjectID: obj.Object.ObjectID,
  802. Index: i,
  803. StorageID: uploadStorages[i].Storage.Storage.StorageID,
  804. FileHash: ret[fmt.Sprintf("%d", i)].(*ops2.FileHashValue).Hash,
  805. })
  806. }
  807. for _, b := range grpedBlocks {
  808. for _, hubID := range b.StorageIDs {
  809. newBlocks = append(newBlocks, stgmod.ObjectBlock{
  810. ObjectID: obj.Object.ObjectID,
  811. Index: b.Index,
  812. StorageID: hubID,
  813. FileHash: b.FileHash,
  814. })
  815. }
  816. }
  817. return &coormq.UpdatingObjectRedundancy{
  818. ObjectID: obj.Object.ObjectID,
  819. Redundancy: red,
  820. Blocks: newBlocks,
  821. }, nil
  822. }
  823. */
  824. func (t *CheckPackageRedundancy) reconstructLRC(ctx ExecuteContext, obj stgmod.ObjectDetail, grpBlocks []stgmod.GrouppedObjectBlock, red *cdssdk.LRCRedundancy, uploadStorages []*StorageLoadInfo, allStgs map[cdssdk.StorageID]*StorageLoadInfo) (*coormq.UpdatingObjectRedundancy, error) {
  825. var chosenBlocks []stgmod.GrouppedObjectBlock
  826. var chosenBlockStg []stgmod.StorageDetail
  827. for _, block := range grpBlocks {
  828. if len(block.StorageIDs) > 0 && block.Index < red.M() {
  829. stg, ok := allStgs[block.StorageIDs[0]]
  830. if !ok {
  831. continue
  832. }
  833. if stg.Storage.MasterHub == nil {
  834. continue
  835. }
  836. chosenBlocks = append(chosenBlocks, block)
  837. chosenBlockStg = append(chosenBlockStg, stg.Storage)
  838. }
  839. if len(chosenBlocks) == red.K {
  840. break
  841. }
  842. }
  843. if len(chosenBlocks) < red.K {
  844. return nil, fmt.Errorf("no enough blocks to reconstruct the original file data")
  845. }
  846. // 目前LRC的参数都相同,所以可以不用重建出完整数据然后再分块,可以直接构建出目的节点需要的块
  847. planBlder := exec.NewPlanBuilder()
  848. var froms []ioswitchlrc.From
  849. var toes []ioswitchlrc.To
  850. var newBlocks []stgmod.ObjectBlock
  851. shouldUpdateBlocks := false
  852. for i, storage := range uploadStorages {
  853. newBlock := stgmod.ObjectBlock{
  854. ObjectID: obj.Object.ObjectID,
  855. Index: i,
  856. StorageID: storage.Storage.Storage.StorageID,
  857. }
  858. grp, ok := lo.Find(grpBlocks, func(grp stgmod.GrouppedObjectBlock) bool { return grp.Index == i })
  859. // 如果新选中的节点已经记录在Block表中,那么就不需要任何变更
  860. if ok && lo.Contains(grp.StorageIDs, storage.Storage.Storage.StorageID) {
  861. newBlock.FileHash = grp.FileHash
  862. newBlocks = append(newBlocks, newBlock)
  863. continue
  864. }
  865. shouldUpdateBlocks = true
  866. // 否则就要重建出这个节点需要的块
  867. for i2, block := range chosenBlocks {
  868. froms = append(froms, ioswitchlrc.NewFromStorage(block.FileHash, *chosenBlockStg[i2].MasterHub, chosenBlockStg[i2].Storage, block.Index))
  869. }
  870. // 输出只需要自己要保存的那一块
  871. toes = append(toes, ioswitchlrc.NewToStorage(*storage.Storage.MasterHub, storage.Storage.Storage, i, fmt.Sprintf("%d", i)))
  872. newBlocks = append(newBlocks, newBlock)
  873. }
  874. err := lrcparser.ReconstructAny(froms, toes, planBlder)
  875. if err != nil {
  876. return nil, fmt.Errorf("parsing plan: %w", err)
  877. }
  878. fmt.Printf("plans: %v\n", planBlder)
  879. // 如果没有任何Plan,Wait会直接返回成功
  880. execCtx := exec.NewExecContext()
  881. exec.SetValueByType(execCtx, ctx.Args.StgMgr)
  882. ret, err := planBlder.Execute(execCtx).Wait(context.Background())
  883. if err != nil {
  884. return nil, fmt.Errorf("executing io plan: %w", err)
  885. }
  886. if !shouldUpdateBlocks {
  887. return nil, nil
  888. }
  889. for k, v := range ret {
  890. idx, err := strconv.ParseInt(k, 10, 64)
  891. if err != nil {
  892. return nil, fmt.Errorf("parsing result key %s as index: %w", k, err)
  893. }
  894. newBlocks[idx].FileHash = v.(*ops2.FileHashValue).Hash
  895. }
  896. return &coormq.UpdatingObjectRedundancy{
  897. ObjectID: obj.Object.ObjectID,
  898. Redundancy: red,
  899. Blocks: newBlocks,
  900. }, nil
  901. }
  902. // func (t *CheckPackageRedundancy) pinObject(hubID cdssdk.HubID, fileHash string) error {
  903. // agtCli, err := stgglb.AgentMQPool.Acquire(hubID)
  904. // if err != nil {
  905. // return fmt.Errorf("new agent client: %w", err)
  906. // }
  907. // defer stgglb.AgentMQPool.Release(agtCli)
  908. // _, err = agtCli.PinObject(agtmq.ReqPinObject([]string{fileHash}, false))
  909. // if err != nil {
  910. // return fmt.Errorf("start pinning object: %w", err)
  911. // }
  912. // return nil
  913. // }
  914. func init() {
  915. RegisterMessageConvertor(NewCheckPackageRedundancy)
  916. }

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