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.

client_command_ec.go 10 kB

2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. package services
  2. // TODO 将这里的逻辑拆分到services中实现
  3. import (
  4. "fmt"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "sync"
  9. "gitlink.org.cn/cloudream/client/internal/config"
  10. "gitlink.org.cn/cloudream/common/utils"
  11. "gitlink.org.cn/cloudream/ec"
  12. )
  13. func EcWrite(localFilePath string, bucketID int, objectName string, ecName string) error {
  14. panic("not implement yet!")
  15. /*
  16. fmt.Println("write " + localFilePath + " as " + bucketName + "/" + objectName)
  17. // TODO 需要参考RepWrite函数的代码逻辑,做好错误处理
  18. //获取文件大小
  19. fileInfo, err := os.Stat(localFilePath)
  20. if err != nil {
  21. return fmt.Errorf("get file %s state failed, err: %w", localFilePath, err)
  22. }
  23. fileSize := fileInfo.Size()
  24. //调用纠删码库,获取编码参数及生成矩阵
  25. ecPolicies := *utils.GetEcPolicy()
  26. ecPolicy := ecPolicies[ecName]
  27. ipss := utils.GetAgentIps()
  28. fmt.Println(ipss)
  29. print("@!@!@!@!@!@!")
  30. //var policy utils.EcConfig
  31. //policy = ecPolicy[0]
  32. ecK := ecPolicy.GetK()
  33. ecN := ecPolicy.GetN()
  34. //const ecK int = ecPolicy.GetK()
  35. //const ecN int = ecPolicy.GetN()
  36. var coefs = [][]int64{{1, 1, 1}, {1, 2, 3}} //2应替换为ecK,3应替换为ecN
  37. //计算每个块的packet数
  38. numPacket := (fileSize + int64(ecK)*config.Cfg().GRCPPacketSize - 1) / (int64(ecK) * config.Cfg().GRCPPacketSize)
  39. fmt.Println(numPacket)
  40. userId := 0
  41. coorClient, err := racli.NewCoordinatorClient()
  42. if err != nil {
  43. return fmt.Errorf("create coordinator client failed, err: %w", err)
  44. }
  45. defer coorClient.Close()
  46. //发送写请求,请求Coor分配写入节点Ip
  47. ecWriteResp, err := coorClient.ECWrite(bucketName, objectName, fileSize, ecName, userId)
  48. if err != nil {
  49. return fmt.Errorf("request to coordinator failed, err: %w", err)
  50. }
  51. if ecWriteResp.IsFailed() {
  52. return fmt.Errorf("coordinator ECWrite failed, err: %w", err)
  53. }
  54. //创建channel
  55. loadBufs := make([]chan []byte, ecN)
  56. encodeBufs := make([]chan []byte, ecN)
  57. for i := 0; i < ecN; i++ {
  58. loadBufs[i] = make(chan []byte)
  59. }
  60. for i := 0; i < ecN; i++ {
  61. encodeBufs[i] = make(chan []byte)
  62. }
  63. hashs := make([]string, ecN)
  64. //正式开始写入
  65. go load(localFilePath, loadBufs[:ecN], ecK, numPacket*int64(ecK), fileSize) //从本地文件系统加载数据
  66. go encode(loadBufs[:ecN], encodeBufs[:ecN], ecK, coefs, numPacket)
  67. var wg sync.WaitGroup
  68. wg.Add(ecN)
  69. for i := 0; i < ecN; i++ {
  70. go send(ecWriteResp.NodeIPs[i], encodeBufs[i], numPacket, &wg, hashs, i)
  71. }
  72. wg.Wait()
  73. //第二轮通讯:插入元数据hashs
  74. writeECHashResp, err := coorClient.WriteECHash(bucketName, objectName, hashs, ecWriteResp.NodeIPs, userId)
  75. if err != nil {
  76. return fmt.Errorf("request to coordinator failed, err: %w", err)
  77. }
  78. if writeECHashResp.IsFailed() {
  79. return fmt.Errorf("coordinator WriteECHash failed, err: %w", err)
  80. }
  81. return nil
  82. */
  83. }
  84. func load(localFilePath string, loadBufs []chan []byte, ecK int, totalNumPacket int64, fileSize int64) {
  85. fmt.Println("load " + localFilePath)
  86. file, _ := os.Open(localFilePath)
  87. for i := 0; int64(i) < totalNumPacket; i++ {
  88. print(totalNumPacket)
  89. buf := make([]byte, config.Cfg().GRCPPacketSize)
  90. idx := i % ecK
  91. print(len(loadBufs))
  92. _, err := file.Read(buf)
  93. loadBufs[idx] <- buf
  94. if idx == ecK-1 {
  95. print("***")
  96. for j := ecK; j < len(loadBufs); j++ {
  97. print(j)
  98. zeroPkt := make([]byte, config.Cfg().GRCPPacketSize)
  99. fmt.Printf("%v", zeroPkt)
  100. loadBufs[j] <- zeroPkt
  101. }
  102. }
  103. if err != nil && err != io.EOF {
  104. break
  105. }
  106. }
  107. fmt.Println("load over")
  108. for i := 0; i < len(loadBufs); i++ {
  109. print(i)
  110. close(loadBufs[i])
  111. }
  112. file.Close()
  113. }
  114. func encode(inBufs []chan []byte, outBufs []chan []byte, ecK int, coefs [][]int64, numPacket int64) {
  115. fmt.Println("encode ")
  116. var tmpIn [][]byte
  117. tmpIn = make([][]byte, len(outBufs))
  118. enc := ec.NewRsEnc(ecK, len(outBufs))
  119. for i := 0; int64(i) < numPacket; i++ {
  120. for j := 0; j < len(outBufs); j++ { //3
  121. tmpIn[j] = <-inBufs[j]
  122. //print(i)
  123. //fmt.Printf("%v",tmpIn[j])
  124. //print("@#$")
  125. }
  126. enc.Encode(tmpIn)
  127. fmt.Printf("%v", tmpIn)
  128. print("$$$$$$$$$$$$$$$$$$")
  129. for j := 0; j < len(outBufs); j++ { //1,2,3//示意,需要调用纠删码编解码引擎: tmp[k] = tmp[k]+(tmpIn[w][k]*coefs[w][j])
  130. outBufs[j] <- tmpIn[j]
  131. }
  132. }
  133. fmt.Println("encode over")
  134. for i := 0; i < len(outBufs); i++ {
  135. close(outBufs[i])
  136. }
  137. }
  138. func decode(inBufs []chan []byte, outBufs []chan []byte, blockSeq []int, ecK int, coefs [][]int64, numPacket int64) {
  139. fmt.Println("decode ")
  140. var tmpIn [][]byte
  141. var zeroPkt []byte
  142. tmpIn = make([][]byte, len(inBufs))
  143. hasBlock := map[int]bool{}
  144. for j := 0; j < len(blockSeq); j++ {
  145. hasBlock[blockSeq[j]] = true
  146. }
  147. needRepair := false //检测是否传入了所有数据块
  148. for j := 0; j < len(outBufs); j++ {
  149. if blockSeq[j] != j {
  150. needRepair = true
  151. }
  152. }
  153. enc := ec.NewRsEnc(ecK, len(inBufs))
  154. for i := 0; int64(i) < numPacket; i++ {
  155. for j := 0; j < len(inBufs); j++ { //3
  156. if hasBlock[j] {
  157. tmpIn[j] = <-inBufs[j]
  158. } else {
  159. tmpIn[j] = zeroPkt
  160. }
  161. }
  162. fmt.Printf("%v", tmpIn)
  163. if needRepair {
  164. err := enc.Repair(tmpIn)
  165. print("&&&&&")
  166. if err != nil {
  167. fmt.Fprintf(os.Stderr, "Decode Repair Error: %s", err.Error())
  168. }
  169. }
  170. //fmt.Printf("%v",tmpIn)
  171. for j := 0; j < len(outBufs); j++ { //1,2,3//示意,需要调用纠删码编解码引擎: tmp[k] = tmp[k]+(tmpIn[w][k]*coefs[w][j])
  172. outBufs[j] <- tmpIn[j]
  173. }
  174. }
  175. fmt.Println("decode over")
  176. for i := 0; i < len(outBufs); i++ {
  177. close(outBufs[i])
  178. }
  179. }
  180. func send(ip string, inBuf chan []byte, numPacket int64, wg *sync.WaitGroup, hashs []string, idx int) error {
  181. panic("not implement yet!")
  182. /*
  183. // TO DO ss: 判断本地有没有ipfs daemon、能否与目标agent的ipfs daemon连通、本地ipfs目录空间是否充足
  184. // 如果本地有ipfs daemon、能与目标agent的ipfs daemon连通、本地ipfs目录空间充足,将所有内容写入本地ipfs目录,得到对象的cid,发送cid给目标agent让其pin相应的对象
  185. // 否则,像目前一样,使用grpc向指定节点获取
  186. // TODO 如果发生错误,需要考虑将错误传递出去
  187. defer wg.Done()
  188. grpcAddr := fmt.Sprintf("%s:%d", ip, config.Cfg().GRPCPort)
  189. conn, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
  190. if err != nil {
  191. return fmt.Errorf("connect to grpc server at %s failed, err: %w", grpcAddr, err)
  192. }
  193. defer conn.Close()
  194. client := agentcaller.NewFileTransportClient(conn)
  195. stream, err := client.SendFile(context.Background())
  196. if err != nil {
  197. return fmt.Errorf("request to send file failed, err: %w", err)
  198. }
  199. for i := 0; int64(i) < numPacket; i++ {
  200. buf := <-inBuf
  201. err := stream.Send(&agentcaller.FileDataPacket{
  202. Code: agentcaller.FileDataPacket_OK,
  203. Data: buf,
  204. })
  205. if err != nil {
  206. stream.CloseSend()
  207. return fmt.Errorf("send file data failed, err: %w", err)
  208. }
  209. }
  210. err = stream.Send(&agentcaller.FileDataPacket{
  211. Code: agentcaller.FileDataPacket_EOF,
  212. })
  213. if err != nil {
  214. stream.CloseSend()
  215. return fmt.Errorf("send file data failed, err: %w", err)
  216. }
  217. resp, err := stream.CloseAndRecv()
  218. if err != nil {
  219. return fmt.Errorf("receive response failed, err: %w", err)
  220. }
  221. hashs[idx] = resp.FileHash
  222. return nil
  223. */
  224. }
  225. func get(blockHash string, nodeIP string, getBuf chan []byte, numPacket int64) error {
  226. panic("not implement yet!")
  227. /*
  228. grpcAddr := fmt.Sprintf("%s:%d", nodeIP, config.Cfg().GRPCPort)
  229. conn, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
  230. if err != nil {
  231. return fmt.Errorf("connect to grpc server at %s failed, err: %w", grpcAddr, err)
  232. }
  233. defer conn.Close()
  234. // TO DO: 判断本地有没有ipfs daemon、能否获取相应对象的cid
  235. // 如果本地有ipfs daemon且能获取相应编码块的cid,则获取编码块cid对应的ipfsblock的cid,通过ipfs网络获取这些ipfsblock
  236. // 否则,像目前一样,使用grpc向指定节点获取
  237. client := agentcaller.NewFileTransportClient(conn)
  238. //rpc get
  239. // TODO 要考虑读取失败后,如何中断后续解码过程
  240. stream, err := client.GetFile(context.Background(), &agentcaller.GetReq{
  241. FileHash: blockHash,
  242. })
  243. for i := 0; int64(i) < numPacket; i++ {
  244. fmt.Println(i)
  245. // TODO 同上
  246. res, _ := stream.Recv()
  247. fmt.Println(res.BlockOrReplicaData)
  248. getBuf <- res.BlockOrReplicaData
  249. }
  250. close(getBuf)
  251. return nil
  252. */
  253. }
  254. func persist(inBuf []chan []byte, numPacket int64, localFilePath string, wg *sync.WaitGroup) {
  255. fDir, err := os.Executable()
  256. if err != nil {
  257. panic(err)
  258. }
  259. fURL := filepath.Join(filepath.Dir(fDir), "assets")
  260. _, err = os.Stat(fURL)
  261. if os.IsNotExist(err) {
  262. os.MkdirAll(fURL, os.ModePerm)
  263. }
  264. file, err := os.Create(filepath.Join(fURL, localFilePath))
  265. if err != nil {
  266. return
  267. }
  268. for i := 0; int64(i) < numPacket; i++ {
  269. for j := 0; j < len(inBuf); j++ {
  270. tmp := <-inBuf[j]
  271. fmt.Println(tmp)
  272. file.Write(tmp)
  273. }
  274. }
  275. file.Close()
  276. wg.Done()
  277. }
  278. func ecRead(fileSize int64, nodeIPs []string, blockHashs []string, blockIds []int, ecName string, localFilePath string) {
  279. //根据ecName获得以下参数
  280. wg := sync.WaitGroup{}
  281. ecPolicies := *utils.GetEcPolicy()
  282. ecPolicy := ecPolicies[ecName]
  283. fmt.Println(ecPolicy)
  284. ecK := ecPolicy.GetK()
  285. ecN := ecPolicy.GetN()
  286. var coefs = [][]int64{{1, 1, 1}, {1, 2, 3}} //2应替换为ecK,3应替换为ecN
  287. numPacket := (fileSize + int64(ecK)*config.Cfg().GRCPPacketSize - 1) / (int64(ecK) * config.Cfg().GRCPPacketSize)
  288. fmt.Println(numPacket)
  289. //创建channel
  290. getBufs := make([]chan []byte, ecN)
  291. decodeBufs := make([]chan []byte, ecK)
  292. for i := 0; i < ecN; i++ {
  293. getBufs[i] = make(chan []byte)
  294. }
  295. for i := 0; i < ecK; i++ {
  296. decodeBufs[i] = make(chan []byte)
  297. }
  298. //从协调端获取有哪些编码块
  299. //var blockSeq = []int{0,1}
  300. blockSeq := blockIds
  301. wg.Add(1)
  302. for i := 0; i < len(blockSeq); i++ {
  303. go get(blockHashs[i], nodeIPs[i], getBufs[blockSeq[i]], numPacket)
  304. }
  305. go decode(getBufs[:], decodeBufs[:], blockSeq, ecK, coefs, numPacket)
  306. go persist(decodeBufs[:], numPacket, localFilePath, &wg)
  307. wg.Wait()
  308. }

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