259 lines
8.7 KiB
Go
259 lines
8.7 KiB
Go
package jcstypes
|
||
|
||
import (
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/samber/lo"
|
||
"gitlink.org.cn/cloudream/common/utils/sort2"
|
||
)
|
||
|
||
const (
|
||
ObjectPathSeparator = "/"
|
||
)
|
||
|
||
type PackageID int64
|
||
|
||
type ObjectID int64
|
||
|
||
type BucketID int64
|
||
|
||
type UserSpaceID int64
|
||
|
||
type Bucket struct {
|
||
BucketID BucketID `gorm:"column:BucketID; primaryKey; type:bigint; autoIncrement" json:"bucketID"`
|
||
Name string `gorm:"column:Name; type:varchar(255); not null" json:"name"`
|
||
CreateTime time.Time `gorm:"column:CreateTime; type:datetime; not null" json:"createTime"`
|
||
}
|
||
|
||
func (Bucket) TableName() string {
|
||
return "Bucket"
|
||
}
|
||
|
||
type Package struct {
|
||
PackageID PackageID `gorm:"column:PackageID; primaryKey; type:bigint; autoIncrement" json:"packageID"`
|
||
Name string `gorm:"column:Name; type:varchar(255); not null" json:"name"`
|
||
BucketID BucketID `gorm:"column:BucketID; type:bigint; not null" json:"bucketID"`
|
||
CreateTime time.Time `gorm:"column:CreateTime; type:datetime; not null" json:"createTime"`
|
||
}
|
||
|
||
func (Package) TableName() string {
|
||
return "Package"
|
||
}
|
||
|
||
type Object struct {
|
||
ObjectID ObjectID `json:"objectID" gorm:"column:ObjectID; primaryKey; type:bigint; autoIncrement" `
|
||
PackageID PackageID `json:"packageID" gorm:"column:PackageID; type:bigint; not null"`
|
||
Path string `json:"path" gorm:"column:Path; type:varchar(1024); not null"`
|
||
Size int64 `json:"size,string" gorm:"column:Size; type:bigint; not null"`
|
||
FileHash FileHash `json:"fileHash" gorm:"column:FileHash; type:char(68); not null"`
|
||
Redundancy Redundancy `json:"redundancy" gorm:"column:Redundancy; type: json; serializer:union"`
|
||
CreateTime time.Time `json:"createTime" gorm:"column:CreateTime; type:datetime; not null"`
|
||
UpdateTime time.Time `json:"updateTime" gorm:"column:UpdateTime; type:datetime; not null"`
|
||
}
|
||
|
||
func (Object) TableName() string {
|
||
return "Object"
|
||
}
|
||
|
||
type ObjectBlock struct {
|
||
ObjectID ObjectID `gorm:"column:ObjectID; primaryKey; type:bigint" json:"objectID"`
|
||
Index int `gorm:"column:Index; primaryKey; type:int" json:"index"`
|
||
// 这个块应该在哪个空间中
|
||
UserSpaceID UserSpaceID `gorm:"column:UserSpaceID; primaryKey; type:bigint" json:"userSpaceID"`
|
||
FileHash FileHash `gorm:"column:FileHash; type:char(68); not null" json:"fileHash"`
|
||
Size int64 `gorm:"column:Size; type:bigint" json:"size"`
|
||
}
|
||
|
||
func (ObjectBlock) TableName() string {
|
||
return "ObjectBlock"
|
||
}
|
||
|
||
type UserSpace struct {
|
||
UserSpaceID UserSpaceID `gorm:"column:UserSpaceID; primaryKey; type:bigint" json:"userSpaceID"`
|
||
// 用户空间名称
|
||
Name string `gorm:"column:Name; type:varchar(255); not null" json:"name"`
|
||
// 用户空间所在的存储服务配置
|
||
Storage StorageType `gorm:"column:Storage; type:json; not null; serializer:union" json:"storage"`
|
||
// 用户在指定存储节点的凭证信息,比如用户账户,AK/SK等
|
||
Credential StorageCredential `gorm:"column:Credential; type:json; not null; serializer:union" json:"credential"`
|
||
// 用户空间的分片存储配置,如果为空,则表示不使用分片存储
|
||
ShardStore *ShardStoreUserConfig `gorm:"column:ShardStore; type:json; serializer:json" json:"shardStore"`
|
||
// 存储服务特性功能的配置
|
||
Features []StorageFeature `json:"features" gorm:"column:Features; type:json; serializer:union"`
|
||
// 各种组件保存数据的根目录。组件工作过程中都会以这个目录为根(除了BaseStore)。
|
||
WorkingDir JPath `gorm:"column:WorkingDir; type:varchar(1024); not null; serializer:string" json:"workingDir"`
|
||
// 工作目录在存储系统中的真实路径。当工作路径在挂载点内时,这个字段记录的是挂载背后的真实路径。部分直接与存储系统交互的组件需要知道真实路径。
|
||
// RealWorkingDir string `gorm:"column:RealWorkingDir; type:varchar(1024); not null" json:"realWorkingDir"`
|
||
// 用户空间信息的版本号,每一次更改都需要更新版本号
|
||
Revision int64 `gorm:"column:Revision; type:bigint; not null" json:"revision"`
|
||
}
|
||
|
||
func (UserSpace) TableName() string {
|
||
return "UserSpace"
|
||
}
|
||
|
||
func (s UserSpace) String() string {
|
||
return fmt.Sprintf("%v[id=%v,storage=%v,rev=%v]", s.Name, s.UserSpaceID, s.Storage, s.Revision)
|
||
}
|
||
|
||
type PackageAccessStat struct {
|
||
PackageID PackageID `gorm:"column:PackageID; primaryKey; type:bigint" json:"packageID"`
|
||
// 发起读取(调度)的用户空间ID
|
||
UserSpaceID UserSpaceID `gorm:"column:UserSpaceID; primaryKey; type:bigint" json:"storageID"`
|
||
// 前一日的读取量的滑动平均值
|
||
Amount float64 `gorm:"column:Amount; type:double" json:"amount"`
|
||
// 当日的读取量
|
||
Counter float64 `gorm:"column:Counter; type:double" json:"counter"`
|
||
}
|
||
|
||
func (PackageAccessStat) TableName() string {
|
||
return "PackageAccessStat"
|
||
}
|
||
|
||
type ObjectAccessStat struct {
|
||
ObjectID ObjectID `gorm:"column:ObjectID; primaryKey; type:bigint" json:"objectID"`
|
||
// 发起读取(调度)的用户空间ID
|
||
UserSpaceID UserSpaceID `gorm:"column:UserSpaceID; primaryKey; type:bigint" json:"userStorageID"`
|
||
// 前一日的读取量的滑动平均值
|
||
Amount float64 `gorm:"column:Amount; type:float; not null" json:"amount"`
|
||
// 当日的读取量
|
||
Counter float64 `gorm:"column:Counter; type:float; not null" json:"counter"`
|
||
}
|
||
|
||
func (ObjectAccessStat) TableName() string {
|
||
return "ObjectAccessStat"
|
||
}
|
||
|
||
type PinnedObject struct {
|
||
ObjectID ObjectID `gorm:"column:ObjectID; primaryKey; type:bigint" json:"objectID"`
|
||
UserSpaceID UserSpaceID `gorm:"column:UserSpaceID; primaryKey; type:bigint" json:"userSpaceID"`
|
||
CreateTime time.Time `gorm:"column:CreateTime; type:datetime; not null" json:"createTime"`
|
||
}
|
||
|
||
func (PinnedObject) TableName() string {
|
||
return "PinnedObject"
|
||
}
|
||
|
||
type ObjectDetail struct {
|
||
Object Object `json:"object"`
|
||
PinnedAt []UserSpaceID `json:"pinnedAt"`
|
||
Blocks []ObjectBlock `json:"blocks"`
|
||
}
|
||
|
||
func NewObjectDetail(object Object, pinnedAt []UserSpaceID, blocks []ObjectBlock) ObjectDetail {
|
||
return ObjectDetail{
|
||
Object: object,
|
||
PinnedAt: pinnedAt,
|
||
Blocks: blocks,
|
||
}
|
||
}
|
||
|
||
func DetailsFromObjects(objects []Object) []ObjectDetail {
|
||
details := make([]ObjectDetail, len(objects))
|
||
for i, object := range objects {
|
||
details[i] = ObjectDetail{
|
||
Object: object,
|
||
}
|
||
}
|
||
return details
|
||
}
|
||
|
||
// 将blocks放到对应的object中。要求objs和blocks都按ObjectID升序
|
||
func DetailsFillObjectBlocks(objs []ObjectDetail, blocks []ObjectBlock) {
|
||
blksCur := 0
|
||
for i := range objs {
|
||
obj := &objs[i]
|
||
// 1. 查询Object和ObjectBlock时均按照ObjectID升序排序
|
||
// 2. ObjectBlock结果集中的不同ObjectID数只会比Object结果集的少
|
||
// 因此在两个结果集上同时从头开始遍历时,如果两边的ObjectID字段不同,那么一定是ObjectBlock这边的ObjectID > Object的ObjectID,
|
||
// 此时让Object的遍历游标前进,直到两边的ObjectID再次相等
|
||
for ; blksCur < len(blocks); blksCur++ {
|
||
if blocks[blksCur].ObjectID != obj.Object.ObjectID {
|
||
break
|
||
}
|
||
obj.Blocks = append(obj.Blocks, blocks[blksCur])
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将pinnedAt放到对应的object中。要求objs和pinnedAt都按ObjectID升序
|
||
func DetailsFillPinnedAt(objs []ObjectDetail, pinnedAt []PinnedObject) {
|
||
pinnedCur := 0
|
||
for i := range objs {
|
||
obj := &objs[i]
|
||
for ; pinnedCur < len(pinnedAt); pinnedCur++ {
|
||
if pinnedAt[pinnedCur].ObjectID != obj.Object.ObjectID {
|
||
break
|
||
}
|
||
obj.PinnedAt = append(obj.PinnedAt, pinnedAt[pinnedCur].UserSpaceID)
|
||
}
|
||
}
|
||
}
|
||
|
||
type GrouppedObjectBlock struct {
|
||
ObjectID ObjectID
|
||
Index int
|
||
FileHash FileHash
|
||
Size int64
|
||
UserSpaceIDs []UserSpaceID
|
||
}
|
||
|
||
func (o *ObjectDetail) GroupBlocks() []GrouppedObjectBlock {
|
||
grps := make(map[int]GrouppedObjectBlock)
|
||
for _, block := range o.Blocks {
|
||
grp, ok := grps[block.Index]
|
||
if !ok {
|
||
grp = GrouppedObjectBlock{
|
||
ObjectID: block.ObjectID,
|
||
Index: block.Index,
|
||
FileHash: block.FileHash,
|
||
Size: block.Size,
|
||
}
|
||
}
|
||
grp.UserSpaceIDs = append(grp.UserSpaceIDs, block.UserSpaceID)
|
||
grps[block.Index] = grp
|
||
}
|
||
|
||
return sort2.Sort(lo.Values(grps), func(l, r GrouppedObjectBlock) int { return l.Index - r.Index })
|
||
}
|
||
|
||
func (o *ObjectDetail) ContainsBlock(idx int, userSpaceID UserSpaceID) bool {
|
||
for _, block := range o.Blocks {
|
||
if block.Index == idx && block.UserSpaceID == userSpaceID {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (o *ObjectDetail) ContainsPinned(userSpaceID UserSpaceID) bool {
|
||
for _, spaceID := range o.PinnedAt {
|
||
if spaceID == userSpaceID {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
type UserSpaceDetail struct {
|
||
UserID UserID
|
||
UserSpace UserSpace
|
||
RecommendHub *Hub
|
||
}
|
||
|
||
func (d UserSpaceDetail) String() string {
|
||
return d.UserSpace.String()
|
||
}
|
||
|
||
type PackageDetail struct {
|
||
Package Package
|
||
ObjectCount int64
|
||
TotalSize int64
|
||
}
|
||
|
||
type SpaceToSpaceResult struct {
|
||
Success []string `json:"success"`
|
||
Failed []string `json:"failed"`
|
||
}
|