302 lines
10 KiB
Go
302 lines
10 KiB
Go
package mq
|
||
|
||
import (
|
||
"database/sql"
|
||
"fmt"
|
||
"sort"
|
||
|
||
"github.com/jmoiron/sqlx"
|
||
"gitlink.org.cn/cloudream/common/consts/errorcode"
|
||
"gitlink.org.cn/cloudream/common/pkgs/logger"
|
||
"gitlink.org.cn/cloudream/common/pkgs/mq"
|
||
cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
|
||
"gitlink.org.cn/cloudream/storage/common/pkgs/db/model"
|
||
coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
|
||
)
|
||
|
||
// GetPackage 通过PackageID获取包信息
|
||
// 参数:
|
||
// - msg: 包含需要获取的PackageID的请求消息
|
||
// 返回值:
|
||
// - *coormq.GetPackageResp: 获取包信息成功的响应
|
||
// - *mq.CodeMessage: 错误时返回的错误信息
|
||
func (svc *Service) GetPackage(msg *coormq.GetPackage) (*coormq.GetPackageResp, *mq.CodeMessage) {
|
||
// 通过ID从数据库获取包信息
|
||
pkg, err := svc.db.Package().GetByID(svc.db.SQLCtx(), msg.PackageID)
|
||
if err != nil {
|
||
// 记录日志并返回错误信息
|
||
logger.WithField("PackageID", msg.PackageID).
|
||
Warnf("get package: %s", err.Error())
|
||
|
||
return nil, mq.Failed(errorcode.OperationFailed, "get package failed")
|
||
}
|
||
|
||
// 返回成功响应
|
||
return mq.ReplyOK(coormq.NewGetPackageResp(pkg))
|
||
}
|
||
|
||
// CreatePackage 创建一个新的包
|
||
// 参数:
|
||
// - msg: 包含创建包所需信息的请求消息
|
||
// 返回值:
|
||
// - *coormq.CreatePackageResp: 创建包成功的响应
|
||
// - *mq.CodeMessage: 错误时返回的错误信息
|
||
func (svc *Service) CreatePackage(msg *coormq.CreatePackage) (*coormq.CreatePackageResp, *mq.CodeMessage) {
|
||
var pkgID cdssdk.PackageID
|
||
// 在事务中执行创建包的操作
|
||
err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
|
||
var err error
|
||
|
||
// 检查桶是否可用
|
||
isAvai, _ := svc.db.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
|
||
if !isAvai {
|
||
return fmt.Errorf("bucket is not avaiable to the user")
|
||
}
|
||
|
||
// 创建包
|
||
pkgID, err = svc.db.Package().Create(tx, msg.BucketID, msg.Name)
|
||
if err != nil {
|
||
return fmt.Errorf("creating package: %w", err)
|
||
}
|
||
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
// 记录日志并返回错误信息
|
||
logger.WithField("BucketID", msg.BucketID).
|
||
WithField("Name", msg.Name).
|
||
Warn(err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "creating package failed")
|
||
}
|
||
|
||
// 返回成功响应
|
||
return mq.ReplyOK(coormq.NewCreatePackageResp(pkgID))
|
||
}
|
||
|
||
// UpdatePackage 更新包的信息
|
||
// 参数:
|
||
// - msg: 包含更新包所需信息的请求消息
|
||
// 返回值:
|
||
// - *coormq.UpdatePackageResp: 更新包成功的响应
|
||
// - *mq.CodeMessage: 错误时返回的错误信息
|
||
func (svc *Service) UpdatePackage(msg *coormq.UpdatePackage) (*coormq.UpdatePackageResp, *mq.CodeMessage) {
|
||
// 在事务中执行更新包的操作
|
||
err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
|
||
// 验证包是否存在
|
||
_, err := svc.db.Package().GetByID(tx, msg.PackageID)
|
||
if err != nil {
|
||
return fmt.Errorf("getting package by id: %w", err)
|
||
}
|
||
|
||
// 删除对象
|
||
if len(msg.Deletes) > 0 {
|
||
if err := svc.db.Object().BatchDelete(tx, msg.Deletes); err != nil {
|
||
return fmt.Errorf("deleting objects: %w", err)
|
||
}
|
||
}
|
||
|
||
// 添加对象
|
||
if len(msg.Adds) > 0 {
|
||
if _, err := svc.db.Object().BatchAdd(tx, msg.PackageID, msg.Adds); err != nil {
|
||
return fmt.Errorf("adding objects: %w", err)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
// 记录日志并返回错误信息
|
||
logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "update package failed")
|
||
}
|
||
|
||
// 返回成功响应
|
||
return mq.ReplyOK(coormq.NewUpdatePackageResp())
|
||
}
|
||
|
||
// DeletePackage 删除一个包
|
||
// 参数:
|
||
// - msg: 包含删除包所需信息的请求消息
|
||
// 返回值:
|
||
// - *coormq.DeletePackageResp: 删除包成功的响应
|
||
// - *mq.CodeMessage: 错误时返回的错误信息
|
||
func (svc *Service) DeletePackage(msg *coormq.DeletePackage) (*coormq.DeletePackageResp, *mq.CodeMessage) {
|
||
// 在事务中执行删除包的操作
|
||
err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
|
||
// 验证包是否可用
|
||
isAvai, _ := svc.db.Package().IsAvailable(tx, msg.UserID, msg.PackageID)
|
||
if !isAvai {
|
||
return fmt.Errorf("package is not available to the user")
|
||
}
|
||
|
||
// 软删除包
|
||
err := svc.db.Package().SoftDelete(tx, msg.PackageID)
|
||
if err != nil {
|
||
return fmt.Errorf("soft delete package: %w", err)
|
||
}
|
||
|
||
// 删除未使用的包
|
||
err = svc.db.Package().DeleteUnused(tx, msg.PackageID)
|
||
if err != nil {
|
||
logger.WithField("UserID", msg.UserID).
|
||
WithField("PackageID", msg.PackageID).
|
||
Warnf("deleting unused package: %w", err.Error())
|
||
}
|
||
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
// 记录日志并返回错误信息
|
||
logger.WithField("UserID", msg.UserID).
|
||
WithField("PackageID", msg.PackageID).
|
||
Warnf(err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "delete package failed")
|
||
}
|
||
|
||
// 返回成功响应
|
||
return mq.ReplyOK(coormq.NewDeletePackageResp())
|
||
}
|
||
|
||
// GetPackageCachedNodes 获取缓存了指定package的节点信息
|
||
// 参数:
|
||
// - msg: 包含packageID和用户ID的信息请求
|
||
// 返回值:
|
||
// - *coormq.GetPackageCachedNodesResp: 包含缓存了package数据的节点信息列表
|
||
// - *mq.CodeMessage: 错误信息,如果操作失败
|
||
func (svc *Service) GetPackageCachedNodes(msg *coormq.GetPackageCachedNodes) (*coormq.GetPackageCachedNodesResp, *mq.CodeMessage) {
|
||
// 检查package是否可用
|
||
isAva, err := svc.db.Package().IsAvailable(svc.db.SQLCtx(), msg.UserID, msg.PackageID)
|
||
if err != nil {
|
||
// 记录检查package可用性失败的日志
|
||
logger.WithField("UserID", msg.UserID).
|
||
WithField("PackageID", msg.PackageID).
|
||
Warnf("check package available failed, err: %s", err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "check package available failed")
|
||
}
|
||
if !isAva {
|
||
// 记录package不可用的日志
|
||
logger.WithField("UserID", msg.UserID).
|
||
WithField("PackageID", msg.PackageID).
|
||
Warnf("package is not available to the user")
|
||
return nil, mq.Failed(errorcode.OperationFailed, "package is not available to the user")
|
||
}
|
||
|
||
// 获取package中的对象详情,用于后续统计节点缓存信息
|
||
objDetails, err := svc.db.Object().GetPackageObjectDetails(svc.db.SQLCtx(), msg.PackageID)
|
||
if err != nil {
|
||
// 记录获取package对象详情失败的日志
|
||
logger.WithField("PackageID", msg.PackageID).
|
||
Warnf("get package block details: %s", err.Error())
|
||
|
||
return nil, mq.Failed(errorcode.OperationFailed, "get package block details failed")
|
||
}
|
||
|
||
// 统计各节点缓存的文件信息
|
||
var packageSize int64
|
||
nodeInfoMap := make(map[cdssdk.NodeID]*cdssdk.NodePackageCachingInfo)
|
||
for _, obj := range objDetails {
|
||
for _, block := range obj.Blocks {
|
||
// 更新或创建节点缓存信息
|
||
info, ok := nodeInfoMap[block.NodeID]
|
||
if !ok {
|
||
info = &cdssdk.NodePackageCachingInfo{
|
||
NodeID: block.NodeID,
|
||
}
|
||
nodeInfoMap[block.NodeID] = info
|
||
}
|
||
|
||
// 更新节点的文件大小和对象计数
|
||
info.FileSize += obj.Object.Size
|
||
info.ObjectCount++
|
||
}
|
||
}
|
||
|
||
// 整理节点缓存信息,并按节点ID排序
|
||
var nodeInfos []cdssdk.NodePackageCachingInfo
|
||
for _, nodeInfo := range nodeInfoMap {
|
||
nodeInfos = append(nodeInfos, *nodeInfo)
|
||
}
|
||
|
||
sort.Slice(nodeInfos, func(i, j int) bool {
|
||
return nodeInfos[i].NodeID < nodeInfos[j].NodeID
|
||
})
|
||
// 返回成功响应,包含节点缓存信息
|
||
return mq.ReplyOK(coormq.NewGetPackageCachedNodesResp(nodeInfos, packageSize))
|
||
}
|
||
|
||
// GetPackageLoadedNodes 获取加载了指定package的节点ID列表
|
||
// 参数:
|
||
// - msg: 包含packageID的信息请求
|
||
// 返回值:
|
||
// - *coormq.GetPackageLoadedNodesResp: 包含加载了package的节点ID列表
|
||
// - *mq.CodeMessage: 错误信息,如果操作失败
|
||
func (svc *Service) GetPackageLoadedNodes(msg *coormq.GetPackageLoadedNodes) (*coormq.GetPackageLoadedNodesResp, *mq.CodeMessage) {
|
||
// 根据packageID查找相关的存储信息
|
||
storages, err := svc.db.StoragePackage().FindPackageStorages(svc.db.SQLCtx(), msg.PackageID)
|
||
if err != nil {
|
||
// 记录查找存储信息失败的日志
|
||
logger.WithField("PackageID", msg.PackageID).
|
||
Warnf("get storages by packageID failed, err: %s", err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "get storages by packageID failed")
|
||
}
|
||
|
||
// 去重,获取唯一节点ID列表
|
||
uniqueNodeIDs := make(map[cdssdk.NodeID]bool)
|
||
var nodeIDs []cdssdk.NodeID
|
||
for _, stg := range storages {
|
||
if !uniqueNodeIDs[stg.NodeID] {
|
||
uniqueNodeIDs[stg.NodeID] = true
|
||
nodeIDs = append(nodeIDs, stg.NodeID)
|
||
}
|
||
}
|
||
|
||
// 返回成功响应,包含节点ID列表
|
||
return mq.ReplyOK(coormq.NewGetPackageLoadedNodesResp(nodeIDs))
|
||
}
|
||
|
||
// GetPackageLoadLogDetails 获取指定package的加载日志详情
|
||
// 参数:
|
||
// - msg: 包含packageID的信息请求
|
||
// 返回值:
|
||
// - *coormq.GetPackageLoadLogDetailsResp: 包含package加载日志的详细信息列表
|
||
// - *mq.CodeMessage: 错误信息,如果操作失败
|
||
func (svc *Service) GetPackageLoadLogDetails(msg *coormq.GetPackageLoadLogDetails) (*coormq.GetPackageLoadLogDetailsResp, *mq.CodeMessage) {
|
||
var logs []coormq.PackageLoadLogDetail
|
||
// 根据packageID获取加载日志
|
||
rawLogs, err := svc.db.StoragePackageLog().GetByPackageID(svc.db.SQLCtx(), msg.PackageID)
|
||
if err != nil {
|
||
// 记录获取加载日志失败的日志
|
||
logger.WithField("PackageID", msg.PackageID).
|
||
Warnf("getting storage package log: %s", err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "get storage package log failed")
|
||
}
|
||
|
||
// 通过存储ID获取存储信息,用于填充日志详情
|
||
stgs := make(map[cdssdk.StorageID]model.Storage)
|
||
|
||
for _, raw := range rawLogs {
|
||
stg, ok := stgs[raw.StorageID]
|
||
if !ok {
|
||
stg, err = svc.db.Storage().GetByID(svc.db.SQLCtx(), raw.StorageID)
|
||
if err != nil {
|
||
// 记录获取存储信息失败的日志
|
||
logger.WithField("PackageID", msg.PackageID).
|
||
Warnf("getting storage: %s", err.Error())
|
||
return nil, mq.Failed(errorcode.OperationFailed, "get storage failed")
|
||
}
|
||
|
||
stgs[raw.StorageID] = stg
|
||
}
|
||
|
||
// 填充日志详情
|
||
logs = append(logs, coormq.PackageLoadLogDetail{
|
||
Storage: stg,
|
||
UserID: raw.UserID,
|
||
CreateTime: raw.CreateTime,
|
||
})
|
||
}
|
||
|
||
// 返回成功响应,包含package加载日志详情
|
||
return mq.ReplyOK(coormq.RespGetPackageLoadLogDetails(logs))
|
||
}
|