add miner fliter

This commit is contained in:
LexLuthr 2024-04-01 22:19:00 +04:00 committed by Łukasz Magiera
parent a99d8c8791
commit 2951d038a8
23 changed files with 834 additions and 123 deletions

View File

@ -200,11 +200,11 @@ type StorageMiner interface {
// StorageBestAlloc returns list of paths where sector files of the specified type can be allocated, ordered by preference. // StorageBestAlloc returns list of paths where sector files of the specified type can be allocated, ordered by preference.
// Paths with more weight and more % of free space are preferred. // Paths with more weight and more % of free space are preferred.
// Note: This method doesn't filter paths based on AllowTypes/DenyTypes. // Note: This method doesn't filter paths based on AllowTypes/DenyTypes.
StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) //perm:admin StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) //perm:admin
StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error //perm:admin StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error //perm:admin
StorageTryLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) (bool, error) //perm:admin StorageTryLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) (bool, error) //perm:admin
StorageList(ctx context.Context) (map[storiface.ID][]storiface.Decl, error) //perm:admin StorageList(ctx context.Context) (map[storiface.ID][]storiface.Decl, error) //perm:admin
StorageGetLocks(ctx context.Context) (storiface.SectorLocks, error) //perm:admin StorageGetLocks(ctx context.Context) (storiface.SectorLocks, error) //perm:admin
StorageLocal(ctx context.Context) (map[storiface.ID]string, error) //perm:admin StorageLocal(ctx context.Context) (map[storiface.ID]string, error) //perm:admin
StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) //perm:admin StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) //perm:admin

View File

@ -1185,7 +1185,7 @@ type StorageMinerMethods struct {
StorageAuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"` StorageAuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"`
StorageBestAlloc func(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) `perm:"admin"` StorageBestAlloc func(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) `perm:"admin"`
StorageDeclareSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType, p4 bool) error `perm:"admin"` StorageDeclareSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType, p4 bool) error `perm:"admin"`
@ -6988,14 +6988,14 @@ func (s *StorageMinerStub) StorageAuthVerify(p0 context.Context, p1 string) ([]a
return *new([]auth.Permission), ErrNotSupported return *new([]auth.Permission), ErrNotSupported
} }
func (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) { func (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) {
if s.Internal.StorageBestAlloc == nil { if s.Internal.StorageBestAlloc == nil {
return *new([]storiface.StorageInfo), ErrNotSupported return *new([]storiface.StorageInfo), ErrNotSupported
} }
return s.Internal.StorageBestAlloc(p0, p1, p2, p3) return s.Internal.StorageBestAlloc(p0, p1, p2, p3, p4)
} }
func (s *StorageMinerStub) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) { func (s *StorageMinerStub) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) {
return *new([]storiface.StorageInfo), ErrNotSupported return *new([]storiface.StorageInfo), ErrNotSupported
} }

View File

@ -8897,11 +8897,23 @@
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
], ],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"AllowMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"AllowTo": { "AllowTo": {
"items": { "items": {
"type": "string" "type": "string"
@ -8920,6 +8932,12 @@
"CanStore": { "CanStore": {
"type": "boolean" "type": "boolean"
}, },
"DenyMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"DenyTypes": { "DenyTypes": {
"items": { "items": {
"type": "string" "type": "string"
@ -9078,7 +9096,7 @@
}, },
{ {
"name": "Filecoin.StorageBestAlloc", "name": "Filecoin.StorageBestAlloc",
"description": "```go\nfunc (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) {\n\tif s.Internal.StorageBestAlloc == nil {\n\t\treturn *new([]storiface.StorageInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StorageBestAlloc(p0, p1, p2, p3)\n}\n```", "description": "```go\nfunc (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) {\n\tif s.Internal.StorageBestAlloc == nil {\n\t\treturn *new([]storiface.StorageInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StorageBestAlloc(p0, p1, p2, p3, p4)\n}\n```",
"summary": "StorageBestAlloc returns list of paths where sector files of the specified type can be allocated, ordered by preference.\nPaths with more weight and more % of free space are preferred.\nNote: This method doesn't filter paths based on AllowTypes/DenyTypes.\n", "summary": "StorageBestAlloc returns list of paths where sector files of the specified type can be allocated, ordered by preference.\nPaths with more weight and more % of free space are preferred.\nNote: This method doesn't filter paths based on AllowTypes/DenyTypes.\n",
"paramStructure": "by-position", "paramStructure": "by-position",
"params": [ "params": [
@ -9130,6 +9148,23 @@
}, },
"required": true, "required": true,
"deprecated": false "deprecated": false
},
{
"name": "p4",
"description": "abi.ActorID",
"summary": "",
"schema": {
"title": "number",
"description": "Number is a number",
"examples": [
1000
],
"type": [
"number"
]
},
"required": true,
"deprecated": false
} }
], ],
"result": { "result": {
@ -9159,6 +9194,12 @@
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
] ]
@ -9167,6 +9208,12 @@
{ {
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"AllowMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"AllowTo": { "AllowTo": {
"items": { "items": {
"type": "string" "type": "string"
@ -9185,6 +9232,12 @@
"CanStore": { "CanStore": {
"type": "boolean" "type": "boolean"
}, },
"DenyMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"DenyTypes": { "DenyTypes": {
"items": { "items": {
"type": "string" "type": "string"
@ -9620,6 +9673,12 @@
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
] ]
@ -9628,6 +9687,12 @@
{ {
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"AllowMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"AllowTypes": { "AllowTypes": {
"items": { "items": {
"type": "string" "type": "string"
@ -9646,6 +9711,12 @@
"CanStore": { "CanStore": {
"type": "boolean" "type": "boolean"
}, },
"DenyMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"DenyTypes": { "DenyTypes": {
"items": { "items": {
"type": "string" "type": "string"
@ -9833,11 +9904,23 @@
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
], ],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"AllowMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"AllowTo": { "AllowTo": {
"items": { "items": {
"type": "string" "type": "string"
@ -9856,6 +9939,12 @@
"CanStore": { "CanStore": {
"type": "boolean" "type": "boolean"
}, },
"DenyMiners": {
"items": {
"type": "string"
},
"type": "array"
},
"DenyTypes": { "DenyTypes": {
"items": { "items": {
"type": "string" "type": "string"

View File

@ -8,6 +8,8 @@ import (
"github.com/samber/lo" "github.com/samber/lo"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/cmd/curio/deps" "github.com/filecoin-project/lotus/cmd/curio/deps"
curio "github.com/filecoin-project/lotus/curiosrc" curio "github.com/filecoin-project/lotus/curiosrc"
"github.com/filecoin-project/lotus/curiosrc/chainsched" "github.com/filecoin-project/lotus/curiosrc/chainsched"
@ -37,6 +39,20 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
si := dependencies.Si si := dependencies.Si
var activeTasks []harmonytask.TaskInterface var activeTasks []harmonytask.TaskInterface
// Get all miner address from config
var miners []address.Address
for _, ad := range cfg.Addresses {
ad := ad
for _, m := range ad.MinerAddresses {
m := m
maddr, err := address.NewFromString(m)
if err != nil {
return nil, xerrors.Errorf("failed to parse the miner address: %w", err)
}
miners = append(miners, maddr)
}
}
sender, sendTask := message.NewSender(full, full, db) sender, sendTask := message.NewSender(full, full, db)
activeTasks = append(activeTasks, sendTask) activeTasks = append(activeTasks, sendTask)
@ -76,7 +92,7 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
{ {
// Piece handling // Piece handling
if cfg.Subsystems.EnableParkPiece { if cfg.Subsystems.EnableParkPiece {
parkPieceTask := piece.NewParkPieceTask(db, must.One(slrLazy.Val()), cfg.Subsystems.ParkPieceMaxTasks) parkPieceTask := piece.NewParkPieceTask(db, must.One(slrLazy.Val()), cfg.Subsystems.ParkPieceMaxTasks, miners)
cleanupPieceTask := piece.NewCleanupPieceTask(db, must.One(slrLazy.Val()), 0) cleanupPieceTask := piece.NewCleanupPieceTask(db, must.One(slrLazy.Val()), 0)
activeTasks = append(activeTasks, parkPieceTask, cleanupPieceTask) activeTasks = append(activeTasks, parkPieceTask, cleanupPieceTask)
} }

View File

@ -68,7 +68,7 @@ func (sb *SealCalls) Storage(taskToSectorRef func(taskID harmonytask.TaskID) (Se
func (t *TaskStorage) HasCapacity() bool { func (t *TaskStorage) HasCapacity() bool {
ctx := context.Background() ctx := context.Background()
paths, err := t.sc.sectors.sindex.StorageBestAlloc(ctx, t.alloc, t.ssize, t.pathType) paths, err := t.sc.sectors.sindex.StorageBestAlloc(ctx, t.alloc, t.ssize, t.pathType, abi.ActorID(0))
if err != nil { if err != nil {
log.Errorf("finding best alloc in HasCapacity: %+v", err) log.Errorf("finding best alloc in HasCapacity: %+v", err)
return false return false

View File

@ -9,6 +9,8 @@ import (
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/curiosrc/ffi" "github.com/filecoin-project/lotus/curiosrc/ffi"
"github.com/filecoin-project/lotus/curiosrc/seal" "github.com/filecoin-project/lotus/curiosrc/seal"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb" "github.com/filecoin-project/lotus/lib/harmony/harmonydb"
@ -32,13 +34,14 @@ type ParkPieceTask struct {
max int max int
} }
func NewParkPieceTask(db *harmonydb.DB, sc *ffi.SealCalls, max int) *ParkPieceTask { func NewParkPieceTask(db *harmonydb.DB, sc *ffi.SealCalls, max int, miners []address.Address) *ParkPieceTask {
pt := &ParkPieceTask{ pt := &ParkPieceTask{
db: db, db: db,
sc: sc, sc: sc,
max: max, max: max,
} }
go pt.pollPieceTasks(context.Background()) go pt.pollPieceTasks(context.Background())
return pt return pt
} }

View File

@ -393,6 +393,8 @@ type machineInfo struct {
FSAvailable int64 FSAvailable int64
Reserved int64 Reserved int64
Used int64 Used int64
AllowMiners string
DenyMiners string
LastHeartbeat time.Time LastHeartbeat time.Time
HeartbeatErr *string HeartbeatErr *string
@ -458,7 +460,7 @@ func (a *app) clusterNodeInfo(ctx context.Context, id int64) (*machineInfo, erro
} }
// query storage info // query storage info
rows2, err := a.db.Query(ctx, "SELECT storage_id, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types, capacity, available, fs_available, reserved, used, last_heartbeat, heartbeat_err FROM storage_path WHERE urls LIKE '%' || $1 || '%'", summaries[0].Info.Host) rows2, err := a.db.Query(ctx, "SELECT storage_id, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types, capacity, available, fs_available, reserved, used, allow_miners, deny_miners, last_heartbeat, heartbeat_err FROM storage_path WHERE urls LIKE '%' || $1 || '%'", summaries[0].Info.Host)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -481,13 +483,15 @@ func (a *app) clusterNodeInfo(ctx context.Context, id int64) (*machineInfo, erro
FSAvailable int64 FSAvailable int64
Reserved int64 Reserved int64
Used int64 Used int64
AllowMiners string
DenyMiners string
LastHeartbeat time.Time LastHeartbeat time.Time
HeartbeatErr *string HeartbeatErr *string
UsedPercent float64 UsedPercent float64
ReservedPercent float64 ReservedPercent float64
} }
if err := rows2.Scan(&s.ID, &s.Weight, &s.MaxStorage, &s.CanSeal, &s.CanStore, &s.Groups, &s.AllowTo, &s.AllowTypes, &s.DenyTypes, &s.Capacity, &s.Available, &s.FSAvailable, &s.Reserved, &s.Used, &s.LastHeartbeat, &s.HeartbeatErr); err != nil { if err := rows2.Scan(&s.ID, &s.Weight, &s.MaxStorage, &s.CanSeal, &s.CanStore, &s.Groups, &s.AllowTo, &s.AllowTypes, &s.DenyTypes, &s.Capacity, &s.Available, &s.FSAvailable, &s.Reserved, &s.Used, &s.AllowMiners, &s.DenyMiners, &s.LastHeartbeat, &s.HeartbeatErr); err != nil {
return nil, err return nil, err
} }

View File

@ -179,6 +179,12 @@ Response:
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
] ]
@ -218,6 +224,12 @@ Response:
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
``` ```

View File

@ -3735,6 +3735,12 @@ Inputs:
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
}, },
{ {
@ -3782,7 +3788,8 @@ Inputs:
[ [
1, 1,
34359738368, 34359738368,
"sealing" "sealing",
1000
] ]
``` ```
@ -3809,6 +3816,12 @@ Response:
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
] ]
@ -3928,6 +3941,12 @@ Response:
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
] ]
@ -4004,6 +4023,12 @@ Response:
], ],
"DenyTypes": [ "DenyTypes": [
"string value" "string value"
],
"AllowMiners": [
"string value"
],
"DenyMiners": [
"string value"
] ]
} }
``` ```

View File

@ -0,0 +1 @@
ALTER TABLE storage_path ADD COLUMN IF NOT EXISTS allow_miners varchar, ADD COLUMN IF NOT EXISTS deny_miners varchar; -- comma separated list of miner addresses

View File

@ -15,6 +15,7 @@ import (
"go.opencensus.io/tag" "go.opencensus.io/tag"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/journal/alerting" "github.com/filecoin-project/lotus/journal/alerting"
@ -200,7 +201,7 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo,
currUrls = union(currUrls, si.URLs) currUrls = union(currUrls, si.URLs)
_, err = tx.Exec( _, err = tx.Exec(
"UPDATE storage_path set urls=$1, weight=$2, max_storage=$3, can_seal=$4, can_store=$5, groups=$6, allow_to=$7, allow_types=$8, deny_types=$9, last_heartbeat=NOW() WHERE storage_id=$10", "UPDATE storage_path set urls=$1, weight=$2, max_storage=$3, can_seal=$4, can_store=$5, groups=$6, allow_to=$7, allow_types=$8, deny_types=$9, allow_miners=$10, deny_miners=$11, last_heartbeat=NOW() WHERE storage_id=$12",
strings.Join(currUrls, ","), strings.Join(currUrls, ","),
si.Weight, si.Weight,
si.MaxStorage, si.MaxStorage,
@ -210,6 +211,8 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo,
strings.Join(si.AllowTo, ","), strings.Join(si.AllowTo, ","),
strings.Join(si.AllowTypes, ","), strings.Join(si.AllowTypes, ","),
strings.Join(si.DenyTypes, ","), strings.Join(si.DenyTypes, ","),
strings.Join(si.AllowMiners, ","),
strings.Join(si.DenyMiners, ","),
si.ID) si.ID)
if err != nil { if err != nil {
return false, xerrors.Errorf("storage attach UPDATE fails: %v", err) return false, xerrors.Errorf("storage attach UPDATE fails: %v", err)
@ -221,7 +224,7 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo,
// Insert storage id // Insert storage id
_, err = tx.Exec( _, err = tx.Exec(
"INSERT INTO storage_path "+ "INSERT INTO storage_path "+
"Values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW())", "Values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW(), $16, $17)",
si.ID, si.ID,
strings.Join(si.URLs, ","), strings.Join(si.URLs, ","),
si.Weight, si.Weight,
@ -236,7 +239,9 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo,
st.Available, st.Available,
st.FSAvailable, st.FSAvailable,
st.Reserved, st.Reserved,
st.Used) st.Used,
strings.Join(si.AllowMiners, ","),
strings.Join(si.DenyMiners, ","))
if err != nil { if err != nil {
return false, xerrors.Errorf("StorageAttach insert fails: %v", err) return false, xerrors.Errorf("StorageAttach insert fails: %v", err)
} }
@ -532,14 +537,16 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st
// 7. Storage path is part of the groups which are allowed from the storage paths which already hold the sector // 7. Storage path is part of the groups which are allowed from the storage paths which already hold the sector
var rows []struct { var rows []struct {
StorageId string StorageId string
Urls string Urls string
Weight uint64 Weight uint64
CanSeal bool CanSeal bool
CanStore bool CanStore bool
Groups string Groups string
AllowTypes string AllowTypes string
DenyTypes string DenyTypes string
AllowMiners string
DenyMiners string
} }
err = dbi.harmonyDB.Select(ctx, &rows, err = dbi.harmonyDB.Select(ctx, &rows,
`SELECT storage_id, `SELECT storage_id,
@ -549,7 +556,9 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st
can_store, can_store,
groups, groups,
allow_types, allow_types,
deny_types deny_types,
allow_miners,
deny_miners
FROM storage_path FROM storage_path
WHERE can_seal=true WHERE can_seal=true
and available >= $1 and available >= $1
@ -570,6 +579,53 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st
continue continue
} }
if len(row.AllowMiners) > 0 {
found := false
allowMiners := splitString(row.AllowMiners)
for _, m := range allowMiners {
m := m
maddr, err := address.NewFromString(m)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("parsing miner ID: %w", err)
}
if abi.ActorID(mid) == s.Miner {
found = true
break
}
}
if !found {
log.Debugf("not selecting on %s, not allowed by allow miners filters", row.StorageId)
continue
}
}
if len(row.DenyMiners) > 0 {
found := false
denyMiners := splitString(row.DenyMiners)
for _, m := range denyMiners {
m := m
maddr, err := address.NewFromString(m)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("parsing miner ID: %w", err)
}
if abi.ActorID(mid) == s.Miner {
found = true
break
}
}
if found {
log.Debugf("not selecting on %s, not allowed by deny miners filters", row.StorageId)
continue
}
}
if allowList != nil { if allowList != nil {
groups := splitString(row.Groups) groups := splitString(row.Groups)
allow := false allow := false
@ -618,19 +674,21 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st
func (dbi *DBIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.StorageInfo, error) { func (dbi *DBIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.StorageInfo, error) {
var qResults []struct { var qResults []struct {
Urls string Urls string
Weight uint64 Weight uint64
MaxStorage uint64 MaxStorage uint64
CanSeal bool CanSeal bool
CanStore bool CanStore bool
Groups string Groups string
AllowTo string AllowTo string
AllowTypes string AllowTypes string
DenyTypes string DenyTypes string
AllowMiners string
DenyMiners string
} }
err := dbi.harmonyDB.Select(ctx, &qResults, err := dbi.harmonyDB.Select(ctx, &qResults,
"SELECT urls, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types "+ "SELECT urls, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types, allow_miners, deny_miners "+
"FROM storage_path WHERE storage_id=$1", string(id)) "FROM storage_path WHERE storage_id=$1", string(id))
if err != nil { if err != nil {
return storiface.StorageInfo{}, xerrors.Errorf("StorageInfo query fails: %v", err) return storiface.StorageInfo{}, xerrors.Errorf("StorageInfo query fails: %v", err)
@ -647,11 +705,13 @@ func (dbi *DBIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface
sinfo.AllowTo = splitString(qResults[0].AllowTo) sinfo.AllowTo = splitString(qResults[0].AllowTo)
sinfo.AllowTypes = splitString(qResults[0].AllowTypes) sinfo.AllowTypes = splitString(qResults[0].AllowTypes)
sinfo.DenyTypes = splitString(qResults[0].DenyTypes) sinfo.DenyTypes = splitString(qResults[0].DenyTypes)
sinfo.AllowMiners = splitString(qResults[0].AllowMiners)
sinfo.DenyMiners = splitString(qResults[0].DenyMiners)
return sinfo, nil return sinfo, nil
} }
func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) { func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) {
var err error var err error
var spaceReq uint64 var spaceReq uint64
switch pathType { switch pathType {
@ -667,16 +727,18 @@ func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sec
} }
var rows []struct { var rows []struct {
StorageId string StorageId string
Urls string Urls string
Weight uint64 Weight uint64
MaxStorage uint64 MaxStorage uint64
CanSeal bool CanSeal bool
CanStore bool CanStore bool
Groups string Groups string
AllowTo string AllowTo string
AllowTypes string AllowTypes string
DenyTypes string DenyTypes string
AllowMiners string
DenyMiners string
} }
err = dbi.harmonyDB.Select(ctx, &rows, err = dbi.harmonyDB.Select(ctx, &rows,
@ -689,7 +751,9 @@ func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sec
groups, groups,
allow_to, allow_to,
allow_types, allow_types,
deny_types deny_types,
allow_miners,
deny_miners
FROM storage_path FROM storage_path
WHERE available >= $1 WHERE available >= $1
and NOW()-($2 * INTERVAL '1 second') < last_heartbeat and NOW()-($2 * INTERVAL '1 second') < last_heartbeat
@ -700,24 +764,77 @@ func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sec
SkippedHeartbeatThresh.Seconds(), SkippedHeartbeatThresh.Seconds(),
pathType == storiface.PathSealing, pathType == storiface.PathSealing,
pathType == storiface.PathStorage, pathType == storiface.PathStorage,
miner.String(),
) )
if err != nil { if err != nil {
return nil, xerrors.Errorf("Querying for best storage sectors fails with err %w: ", err) return nil, xerrors.Errorf("Querying for best storage sectors fails with err %w: ", err)
} }
var result []storiface.StorageInfo var result []storiface.StorageInfo
for _, row := range rows { for _, row := range rows {
// Matching with 0 as a workaround to avoid having minerID
// present when calling TaskStorage.HasCapacity()
if !(miner == abi.ActorID(0)) {
if len(row.AllowMiners) > 0 {
found := false
allowMiners := splitString(row.AllowMiners)
for _, m := range allowMiners {
m := m
maddr, err := address.NewFromString(m)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("parsing miner ID: %w", err)
}
if abi.ActorID(mid) == miner {
found = true
break
}
}
if !found {
continue
}
}
if len(row.DenyMiners) > 0 {
found := false
denyMiners := splitString(row.DenyMiners)
for _, m := range denyMiners {
m := m
maddr, err := address.NewFromString(m)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("parsing miner ID: %w", err)
}
if abi.ActorID(mid) == miner {
found = true
break
}
}
if found {
continue
}
}
}
result = append(result, storiface.StorageInfo{ result = append(result, storiface.StorageInfo{
ID: storiface.ID(row.StorageId), ID: storiface.ID(row.StorageId),
URLs: splitString(row.Urls), URLs: splitString(row.Urls),
Weight: row.Weight, Weight: row.Weight,
MaxStorage: row.MaxStorage, MaxStorage: row.MaxStorage,
CanSeal: row.CanSeal, CanSeal: row.CanSeal,
CanStore: row.CanStore, CanStore: row.CanStore,
Groups: splitString(row.Groups), Groups: splitString(row.Groups),
AllowTo: splitString(row.AllowTo), AllowTo: splitString(row.AllowTo),
AllowTypes: splitString(row.AllowTypes), AllowTypes: splitString(row.AllowTypes),
DenyTypes: splitString(row.DenyTypes), DenyTypes: splitString(row.DenyTypes),
AllowMiners: splitString(row.AllowMiners),
DenyMiners: splitString(row.DenyMiners),
}) })
} }

View File

@ -14,6 +14,7 @@ import (
"go.opencensus.io/tag" "go.opencensus.io/tag"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
@ -38,7 +39,7 @@ type SectorIndex interface { // part of storage-miner api
StorageDropSector(ctx context.Context, storageID storiface.ID, s abi.SectorID, ft storiface.SectorFileType) error StorageDropSector(ctx context.Context, storageID storiface.ID, s abi.SectorID, ft storiface.SectorFileType) error
StorageFindSector(ctx context.Context, sector abi.SectorID, ft storiface.SectorFileType, ssize abi.SectorSize, allowFetch bool) ([]storiface.SectorStorageInfo, error) StorageFindSector(ctx context.Context, sector abi.SectorID, ft storiface.SectorFileType, ssize abi.SectorSize, allowFetch bool) ([]storiface.SectorStorageInfo, error)
StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error)
// atomically acquire locks on all sector file types. close ctx to unlock // atomically acquire locks on all sector file types. close ctx to unlock
StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error
@ -61,6 +62,7 @@ type storageEntry struct {
heartbeatErr error heartbeatErr error
} }
// MemIndex represents an in-memory index of storage sectors and storage entries.
type MemIndex struct { type MemIndex struct {
*indexLocks *indexLocks
lk sync.RWMutex lk sync.RWMutex
@ -206,6 +208,8 @@ func (i *MemIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo,
i.stores[si.ID].info.AllowTo = si.AllowTo i.stores[si.ID].info.AllowTo = si.AllowTo
i.stores[si.ID].info.AllowTypes = allow i.stores[si.ID].info.AllowTypes = allow
i.stores[si.ID].info.DenyTypes = deny i.stores[si.ID].info.DenyTypes = deny
i.stores[si.ID].info.AllowMiners = si.AllowMiners
i.stores[si.ID].info.DenyMiners = si.DenyMiners
return nil return nil
} }
@ -476,8 +480,10 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto
Primary: isprimary[id], Primary: isprimary[id],
AllowTypes: st.info.AllowTypes, AllowTypes: st.info.AllowTypes,
DenyTypes: st.info.DenyTypes, DenyTypes: st.info.DenyTypes,
AllowMiners: st.info.AllowMiners,
DenyMiners: st.info.DenyMiners,
}) })
} }
@ -492,6 +498,52 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto
continue continue
} }
if len(st.info.AllowMiners) > 0 {
found := false
for _, m := range st.info.AllowMiners {
minerIDStr := m
maddr, err := address.NewFromString(minerIDStr)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("converting miner address to ID: %w", err)
}
if abi.ActorID(mid) == s.Miner {
found = true
break
}
}
if !found {
log.Debugf("not allocating on %s, miner %s not allowed", st.info.ID, s.Miner.String())
continue
}
}
if len(st.info.DenyMiners) > 0 {
found := false
for _, m := range st.info.DenyMiners {
minerIDStr := m
maddr, err := address.NewFromString(minerIDStr)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("converting miner address to ID: %w", err)
}
if abi.ActorID(mid) == s.Miner {
found = true
break
}
}
if found {
log.Debugf("not allocating on %s, miner %s denied", st.info.ID, s.Miner.String())
continue
}
}
if spaceReq > uint64(st.fsi.Available) { if spaceReq > uint64(st.fsi.Available) {
log.Debugf("not selecting on %s, out of space (available: %d, need: %d)", st.info.ID, st.fsi.Available, spaceReq) log.Debugf("not selecting on %s, out of space (available: %d, need: %d)", st.info.ID, st.fsi.Available, spaceReq)
continue continue
@ -555,8 +607,10 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto
Primary: false, Primary: false,
AllowTypes: st.info.AllowTypes, AllowTypes: st.info.AllowTypes,
DenyTypes: st.info.DenyTypes, DenyTypes: st.info.DenyTypes,
AllowMiners: st.info.AllowMiners,
DenyMiners: st.info.DenyMiners,
}) })
} }
} }
@ -564,6 +618,21 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto
return out, nil return out, nil
} }
// StorageInfo retrieves the storage information for a given storage ID.
//
// The method first acquires a read lock on the MemIndex to ensure thread-safety.
// It then checks if the storage ID exists in the stores map. If not, it returns
// an error indicating that the sector store was not found.
//
// Finally, it returns the storage information of the selected storage.
//
// Parameters:
// - ctx: the context.Context object for cancellation and timeouts
// - id: the ID of the storage to retrieve information for
//
// Returns:
// - storiface.StorageInfo: the storage information of the selected storage ID
// - error: an error indicating any issues encountered during the process
func (i *MemIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.StorageInfo, error) { func (i *MemIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.StorageInfo, error) {
i.lk.RLock() i.lk.RLock()
defer i.lk.RUnlock() defer i.lk.RUnlock()
@ -576,7 +645,33 @@ func (i *MemIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.
return *si.info, nil return *si.info, nil
} }
func (i *MemIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) { // StorageBestAlloc selects the best available storage options for allocating
// a sector file. It takes into account the allocation type (sealing or storage),
// sector size, and path type (sealing or storage).
//
// The method first estimates the required space for the allocation based on the
// sector size and path type. It then iterates through all available storage options
// and filters out those that cannot be used for the given path type. It also filters
// out storage options that do not have enough available space or have not received
// heartbeats within a certain threshold.
//
// The remaining storage options are sorted based on their available space and weight,
// with higher availability and weight being prioritized. The method then returns
// the information of the selected storage options.
//
// If no suitable storage options are found, it returns an error indicating that
// no good path is available.
//
// Parameters:
// - ctx: the context.Context object for cancellation and timeouts
// - allocate: the type of allocation (sealing or storage)
// - ssize: the size of the sector file
// - pathType: the path type (sealing or storage)
//
// Returns:
// - []storiface.StorageInfo: the information of the selected storage options
// - error: an error indicating any issues encountered during the process
func (i *MemIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) {
i.lk.RLock() i.lk.RLock()
defer i.lk.RUnlock() defer i.lk.RUnlock()
@ -604,6 +699,52 @@ func (i *MemIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sect
continue continue
} }
if len(p.info.AllowMiners) > 0 {
found := false
for _, m := range p.info.AllowMiners {
minerIDStr := m
maddr, err := address.NewFromString(minerIDStr)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("converting miner address to ID: %w", err)
}
if abi.ActorID(mid) == miner {
found = true
break
}
}
if !found {
log.Debugf("not allocating on %s, miner %s not allowed", p.info.ID, miner.String())
continue
}
}
if len(p.info.DenyMiners) > 0 {
found := false
for _, m := range p.info.DenyMiners {
minerIDStr := m
maddr, err := address.NewFromString(minerIDStr)
if err != nil {
return nil, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("converting miner address to ID: %w", err)
}
if abi.ActorID(mid) == miner {
found = true
break
}
}
if found {
log.Debugf("not allocating on %s, miner %s denied", p.info.ID, miner.String())
continue
}
}
if spaceReq > uint64(p.fsi.Available) { if spaceReq > uint64(p.fsi.Available) {
log.Debugf("not allocating on %s, out of space (available: %d, need: %d)", p.info.ID, p.fsi.Available, spaceReq) log.Debugf("not allocating on %s, out of space (available: %d, need: %d)", p.info.ID, p.fsi.Available, spaceReq)
continue continue

View File

@ -152,3 +152,61 @@ func TestFindAllow(t *testing.T) {
} }
} }
} }
func TestStorageBestAlloc(t *testing.T) {
idx := NewMemIndex(nil)
dummyStorageInfo := storiface.StorageInfo{
ID: storiface.ID("dummy"),
CanSeal: true,
CanStore: true,
URLs: []string{"http://localhost:9999/"},
Weight: 10,
AllowMiners: []string{
"t001",
},
}
dummyFsStat := fsutil.FsStat{
Capacity: 10000000000,
Available: 7000000000,
Reserved: 100000000,
Used: 3000000000,
}
err := idx.StorageAttach(context.Background(), dummyStorageInfo, dummyFsStat)
require.NoError(t, err)
t.Run("PathSealing", func(t *testing.T) {
result, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathSealing, 1)
require.Equal(t, err, nil)
require.NotNil(t, result)
require.Equal(t, len(result), 1)
require.Equal(t, result[0].ID, dummyStorageInfo.ID)
})
t.Run("PathStorage", func(t *testing.T) {
result, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathStorage, 1)
require.Equal(t, err, nil)
require.NotNil(t, result)
require.Equal(t, len(result), 1)
require.Equal(t, result[0].ID, dummyStorageInfo.ID)
})
t.Run("NotAllowedMiner", func(t *testing.T) {
_, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathSealing, 2)
require.Error(t, err)
})
t.Run("NoAvailableSpace", func(t *testing.T) {
bigSectorSize := abi.SectorSize(10000000000)
_, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, bigSectorSize, storiface.PathSealing, 1)
require.Error(t, err)
})
t.Run("AllowedMiner", func(t *testing.T) {
_, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathSealing, 1)
require.NoError(t, err)
})
}

View File

@ -14,6 +14,7 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
ffi "github.com/filecoin-project/filecoin-ffi" ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/proof" "github.com/filecoin-project/go-state-types/proof"
@ -204,16 +205,18 @@ func (st *Local) OpenPath(ctx context.Context, p string) error {
} }
err = st.index.StorageAttach(ctx, storiface.StorageInfo{ err = st.index.StorageAttach(ctx, storiface.StorageInfo{
ID: meta.ID, ID: meta.ID,
URLs: st.urls, URLs: st.urls,
Weight: meta.Weight, Weight: meta.Weight,
MaxStorage: meta.MaxStorage, MaxStorage: meta.MaxStorage,
CanSeal: meta.CanSeal, CanSeal: meta.CanSeal,
CanStore: meta.CanStore, CanStore: meta.CanStore,
Groups: meta.Groups, Groups: meta.Groups,
AllowTo: meta.AllowTo, AllowTo: meta.AllowTo,
AllowTypes: meta.AllowTypes, AllowTypes: meta.AllowTypes,
DenyTypes: meta.DenyTypes, DenyTypes: meta.DenyTypes,
AllowMiners: meta.AllowMiners,
DenyMiners: meta.DenyMiners,
}, fst) }, fst)
if err != nil { if err != nil {
return xerrors.Errorf("declaring storage in index: %w", err) return xerrors.Errorf("declaring storage in index: %w", err)
@ -294,16 +297,18 @@ func (st *Local) Redeclare(ctx context.Context, filterId *storiface.ID, dropMiss
} }
err = st.index.StorageAttach(ctx, storiface.StorageInfo{ err = st.index.StorageAttach(ctx, storiface.StorageInfo{
ID: id, ID: id,
URLs: st.urls, URLs: st.urls,
Weight: meta.Weight, Weight: meta.Weight,
MaxStorage: meta.MaxStorage, MaxStorage: meta.MaxStorage,
CanSeal: meta.CanSeal, CanSeal: meta.CanSeal,
CanStore: meta.CanStore, CanStore: meta.CanStore,
Groups: meta.Groups, Groups: meta.Groups,
AllowTo: meta.AllowTo, AllowTo: meta.AllowTo,
AllowTypes: meta.AllowTypes, AllowTypes: meta.AllowTypes,
DenyTypes: meta.DenyTypes, DenyTypes: meta.DenyTypes,
AllowMiners: meta.AllowMiners,
DenyMiners: meta.DenyMiners,
}, fst) }, fst)
if err != nil { if err != nil {
return xerrors.Errorf("redeclaring storage in index: %w", err) return xerrors.Errorf("redeclaring storage in index: %w", err)
@ -495,20 +500,64 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi
var out storiface.SectorPaths var out storiface.SectorPaths
var storageIDs storiface.SectorPaths var storageIDs storiface.SectorPaths
allocPathOk := func(canSeal, canStore bool, allowTypes, denyTypes []string, fileType storiface.SectorFileType) bool { allocPathOk := func(canSeal, canStore bool, allowTypes, denyTypes, allowMiners, denyMiners []string, fileType storiface.SectorFileType, miner abi.ActorID) (bool, error) {
if (pathType == storiface.PathSealing) && !canSeal { if (pathType == storiface.PathSealing) && !canSeal {
return false return false, nil
} }
if (pathType == storiface.PathStorage) && !canStore { if (pathType == storiface.PathStorage) && !canStore {
return false return false, nil
} }
if !fileType.Allowed(allowTypes, denyTypes) { if !fileType.Allowed(allowTypes, denyTypes) {
return false return false, nil
} }
return true if len(allowMiners) > 0 {
found := false
for _, m := range allowMiners {
minerIDStr := m
maddr, err := address.NewFromString(minerIDStr)
if err != nil {
return false, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return false, xerrors.Errorf("converting miner address to ID: %w", err)
}
if abi.ActorID(mid) == miner {
found = true
break
}
}
if !found {
return false, nil
}
}
if len(denyMiners) > 0 {
found := false
for _, m := range denyMiners {
minerIDStr := m
maddr, err := address.NewFromString(minerIDStr)
if err != nil {
return false, xerrors.Errorf("parsing miner address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return false, xerrors.Errorf("converting miner address to ID: %w", err)
}
if abi.ActorID(mid) == miner {
found = true
break
}
}
if found {
return false, nil
}
}
return true, nil
} }
// First find existing files // First find existing files
@ -536,8 +585,15 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi
continue continue
} }
if allocate.Has(fileType) && !allocPathOk(info.CanSeal, info.CanStore, info.AllowTypes, info.DenyTypes, fileType) { if allocate.Has(fileType) {
continue // allocate request for a path of different type ok, err := allocPathOk(info.CanSeal, info.CanStore, info.AllowTypes, info.DenyTypes, info.AllowMiners, info.DenyMiners, fileType, sid.ID.Miner)
if err != nil {
log.Debug(err)
continue
}
if !ok {
continue // allocate request for a path of different type
}
} }
spath := p.sectorPath(sid.ID, fileType) spath := p.sectorPath(sid.ID, fileType)
@ -556,7 +612,7 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi
continue continue
} }
sis, err := st.index.StorageBestAlloc(ctx, fileType, ssize, pathType) sis, err := st.index.StorageBestAlloc(ctx, fileType, ssize, pathType, sid.ID.Miner)
if err != nil { if err != nil {
return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("finding best storage for allocating : %w", err) return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("finding best storage for allocating : %w", err)
} }
@ -574,7 +630,14 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi
continue continue
} }
if !allocPathOk(si.CanSeal, si.CanStore, si.AllowTypes, si.DenyTypes, fileType) { alloc, err := allocPathOk(si.CanSeal, si.CanStore, si.AllowTypes, si.DenyTypes, si.AllowMiners, si.DenyMiners, fileType, sid.ID.Miner)
if err != nil {
log.Debug(err)
continue
}
if !alloc {
continue continue
} }

View File

@ -54,18 +54,18 @@ func (mr *MockSectorIndexMockRecorder) StorageAttach(arg0, arg1, arg2 interface{
} }
// StorageBestAlloc mocks base method. // StorageBestAlloc mocks base method.
func (m *MockSectorIndex) StorageBestAlloc(arg0 context.Context, arg1 storiface.SectorFileType, arg2 abi.SectorSize, arg3 storiface.PathType) ([]storiface.StorageInfo, error) { func (m *MockSectorIndex) StorageBestAlloc(arg0 context.Context, arg1 storiface.SectorFileType, arg2 abi.SectorSize, arg3 storiface.PathType, arg4 abi.ActorID) ([]storiface.StorageInfo, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StorageBestAlloc", arg0, arg1, arg2, arg3) ret := m.ctrl.Call(m, "StorageBestAlloc", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].([]storiface.StorageInfo) ret0, _ := ret[0].([]storiface.StorageInfo)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// StorageBestAlloc indicates an expected call of StorageBestAlloc. // StorageBestAlloc indicates an expected call of StorageBestAlloc.
func (mr *MockSectorIndexMockRecorder) StorageBestAlloc(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { func (mr *MockSectorIndexMockRecorder) StorageBestAlloc(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageBestAlloc", reflect.TypeOf((*MockSectorIndex)(nil).StorageBestAlloc), arg0, arg1, arg2, arg3) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageBestAlloc", reflect.TypeOf((*MockSectorIndex)(nil).StorageBestAlloc), arg0, arg1, arg2, arg3, arg4)
} }
// StorageDeclareSector mocks base method. // StorageDeclareSector mocks base method.

View File

@ -356,7 +356,7 @@ func (m *Manager) SectorsUnsealPiece(ctx context.Context, sector storiface.Secto
// selector will schedule the Unseal task on a worker that either already has the sealed sector files or has space in // selector will schedule the Unseal task on a worker that either already has the sealed sector files or has space in
// one of it's sealing scratch spaces to store them after fetching them from another worker. // one of it's sealing scratch spaces to store them after fetching them from another worker.
selector := newExistingSelector(m.index, sector.ID, storiface.FTSealed|storiface.FTCache, true) selector := newExistingSelector(m.index, sector.ID, storiface.FTSealed|storiface.FTCache, sector.ID.Miner, true)
log.Debugf("will schedule unseal for sector %d", sector.ID) log.Debugf("will schedule unseal for sector %d", sector.ID)
err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error {
@ -377,7 +377,7 @@ func (m *Manager) SectorsUnsealPiece(ctx context.Context, sector storiface.Secto
} }
// get a selector for moving unsealed sector into long-term storage // get a selector for moving unsealed sector into long-term storage
fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTUnsealed, storiface.PathStorage, !m.disallowRemoteFinalize) fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTUnsealed, storiface.PathStorage, sector.ID.Miner, !m.disallowRemoteFinalize)
// move unsealed sector to long-term storage // move unsealed sector to long-term storage
// Possible TODO: Add an option to not keep the unsealed sector in long term storage? // Possible TODO: Add an option to not keep the unsealed sector in long term storage?
@ -431,9 +431,9 @@ func (m *Manager) AddPiece(ctx context.Context, sector storiface.SectorRef, exis
var selector WorkerSelector var selector WorkerSelector
var err error var err error
if len(existingPieces) == 0 { // new if len(existingPieces) == 0 { // new
selector = newAllocSelector(m.index, storiface.FTUnsealed, storiface.PathSealing) selector = newAllocSelector(m.index, storiface.FTUnsealed, storiface.PathSealing, sector.ID.Miner)
} else { // use existing } else { // use existing
selector = newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, false) selector = newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, sector.ID.Miner, false)
} }
var out abi.PieceInfo var out abi.PieceInfo
@ -484,7 +484,7 @@ func (m *Manager) SealPreCommit1(ctx context.Context, sector storiface.SectorRef
// TODO: also consider where the unsealed data sits // TODO: also consider where the unsealed data sits
selector := newAllocSelector(m.index, storiface.FTCache|storiface.FTSealed, storiface.PathSealing) selector := newAllocSelector(m.index, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, sector.ID.Miner)
err = m.sched.Schedule(ctx, sector, sealtasks.TTPreCommit1, selector, m.schedFetch(sector, storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTPreCommit1, selector, m.schedFetch(sector, storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error {
err := m.startWork(ctx, w, wk)(w.SealPreCommit1(ctx, sector, ticket, pieces)) err := m.startWork(ctx, w, wk)(w.SealPreCommit1(ctx, sector, ticket, pieces))
@ -533,7 +533,7 @@ func (m *Manager) SealPreCommit2(ctx context.Context, sector storiface.SectorRef
return storiface.SectorCids{}, xerrors.Errorf("acquiring sector lock: %w", err) return storiface.SectorCids{}, xerrors.Errorf("acquiring sector lock: %w", err)
} }
selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, true) selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, sector.ID.Miner, true)
err = m.sched.Schedule(ctx, sector, sealtasks.TTPreCommit2, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTPreCommit2, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error {
err := m.startWork(ctx, w, wk)(w.SealPreCommit2(ctx, sector, phase1Out)) err := m.startWork(ctx, w, wk)(w.SealPreCommit2(ctx, sector, phase1Out))
@ -585,7 +585,7 @@ func (m *Manager) SealCommit1(ctx context.Context, sector storiface.SectorRef, t
// NOTE: We set allowFetch to false in so that we always execute on a worker // NOTE: We set allowFetch to false in so that we always execute on a worker
// with direct access to the data. We want to do that because this step is // with direct access to the data. We want to do that because this step is
// generally very cheap / fast, and transferring data is not worth the effort // generally very cheap / fast, and transferring data is not worth the effort
selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, false) selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, sector.ID.Miner, false)
err = m.sched.Schedule(ctx, sector, sealtasks.TTCommit1, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTCommit1, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error {
err := m.startWork(ctx, w, wk)(w.SealCommit1(ctx, sector, ticket, seed, pieces, cids)) err := m.startWork(ctx, w, wk)(w.SealCommit1(ctx, sector, ticket, seed, pieces, cids))
@ -700,7 +700,7 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef
// do the cache trimming wherever the likely still very large cache lives. // do the cache trimming wherever the likely still very large cache lives.
// we really don't want to move it. // we really don't want to move it.
selector := newExistingSelector(m.index, sector.ID, storiface.FTCache, false) selector := newExistingSelector(m.index, sector.ID, storiface.FTCache, sector.ID.Miner, false)
err = m.sched.Schedule(ctx, sector, sealtasks.TTFinalize, selector, err = m.sched.Schedule(ctx, sector, sealtasks.TTFinalize, selector,
m.schedFetch(sector, storiface.FTCache, cachePathType, storiface.AcquireMove), m.schedFetch(sector, storiface.FTCache, cachePathType, storiface.AcquireMove),
@ -713,7 +713,7 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef
} }
// get a selector for moving stuff into long-term storage // get a selector for moving stuff into long-term storage
fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, storiface.PathStorage, !m.disallowRemoteFinalize) fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, storiface.PathStorage, sector.ID.Miner, !m.disallowRemoteFinalize)
// only move the unsealed file if it still exists and needs moving // only move the unsealed file if it still exists and needs moving
moveUnsealed := storiface.FTUnsealed moveUnsealed := storiface.FTUnsealed
@ -769,7 +769,7 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se
// do the cache trimming wherever the likely still large cache lives. // do the cache trimming wherever the likely still large cache lives.
// we really don't want to move it. // we really don't want to move it.
selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdateCache, false) selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdateCache, sector.ID.Miner, false)
err := m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeReplicaUpdate, selector, err := m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeReplicaUpdate, selector,
m.schedFetch(sector, storiface.FTCache|storiface.FTUpdateCache, pathType, storiface.AcquireMove), m.schedFetch(sector, storiface.FTCache|storiface.FTUpdateCache, pathType, storiface.AcquireMove),
@ -783,7 +783,7 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se
move := func(types storiface.SectorFileType) error { move := func(types storiface.SectorFileType) error {
// get a selector for moving stuff into long-term storage // get a selector for moving stuff into long-term storage
fetchSel := newMoveSelector(m.index, sector.ID, types, storiface.PathStorage, !m.disallowRemoteFinalize) fetchSel := newMoveSelector(m.index, sector.ID, types, storiface.PathStorage, sector.ID.Miner, !m.disallowRemoteFinalize)
err = m.sched.Schedule(ctx, sector, sealtasks.TTFetch, fetchSel, err = m.sched.Schedule(ctx, sector, sealtasks.TTFetch, fetchSel,
m.schedFetch(sector, types, storiface.PathStorage, storiface.AcquireMove), m.schedFetch(sector, types, storiface.PathStorage, storiface.AcquireMove),
@ -834,7 +834,7 @@ func (m *Manager) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRe
return nil return nil
} }
selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, false) selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, sector.ID.Miner, false)
return m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeUnsealed, selector, m.schedFetch(sector, storiface.FTUnsealed, pathType, storiface.AcquireMove), func(ctx context.Context, w Worker) error { return m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeUnsealed, selector, m.schedFetch(sector, storiface.FTUnsealed, pathType, storiface.AcquireMove), func(ctx context.Context, w Worker) error {
_, err := m.waitSimpleCall(ctx)(w.ReleaseUnsealed(ctx, sector, keepUnsealed)) _, err := m.waitSimpleCall(ctx)(w.ReleaseUnsealed(ctx, sector, keepUnsealed))
@ -906,7 +906,7 @@ func (m *Manager) GenerateSectorKeyFromData(ctx context.Context, sector storifac
// NOTE: We set allowFetch to false in so that we always execute on a worker // NOTE: We set allowFetch to false in so that we always execute on a worker
// with direct access to the data. We want to do that because this step is // with direct access to the data. We want to do that because this step is
// generally very cheap / fast, and transferring data is not worth the effort // generally very cheap / fast, and transferring data is not worth the effort
selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache|storiface.FTCache, true) selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache|storiface.FTCache, sector.ID.Miner, true)
err = m.sched.Schedule(ctx, sector, sealtasks.TTRegenSectorKey, selector, m.schedFetch(sector, storiface.FTUpdate|storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTRegenSectorKey, selector, m.schedFetch(sector, storiface.FTUpdate|storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error {
err := m.startWork(ctx, w, wk)(w.GenerateSectorKeyFromData(ctx, sector, commD)) err := m.startWork(ctx, w, wk)(w.GenerateSectorKeyFromData(ctx, sector, commD))
@ -984,7 +984,7 @@ func (m *Manager) ReplicaUpdate(ctx context.Context, sector storiface.SectorRef,
return storiface.ReplicaUpdateOut{}, xerrors.Errorf("acquiring sector lock: %w", err) return storiface.ReplicaUpdateOut{}, xerrors.Errorf("acquiring sector lock: %w", err)
} }
selector := newAllocSelector(m.index, storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing) selector := newAllocSelector(m.index, storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing, sector.ID.Miner)
err = m.sched.Schedule(ctx, sector, sealtasks.TTReplicaUpdate, selector, m.schedFetch(sector, storiface.FTUnsealed|storiface.FTSealed|storiface.FTCache, storiface.PathSealing, storiface.AcquireCopy), func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTReplicaUpdate, selector, m.schedFetch(sector, storiface.FTUnsealed|storiface.FTSealed|storiface.FTCache, storiface.PathSealing, storiface.AcquireCopy), func(ctx context.Context, w Worker) error {
err := m.startWork(ctx, w, wk)(w.ReplicaUpdate(ctx, sector, pieces)) err := m.startWork(ctx, w, wk)(w.ReplicaUpdate(ctx, sector, pieces))
@ -1035,7 +1035,7 @@ func (m *Manager) ProveReplicaUpdate1(ctx context.Context, sector storiface.Sect
// NOTE: We set allowFetch to false in so that we always execute on a worker // NOTE: We set allowFetch to false in so that we always execute on a worker
// with direct access to the data. We want to do that because this step is // with direct access to the data. We want to do that because this step is
// generally very cheap / fast, and transferring data is not worth the effort // generally very cheap / fast, and transferring data is not worth the effort
selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdate|storiface.FTUpdateCache, false) selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdate|storiface.FTUpdateCache, sector.ID.Miner, false)
err = m.sched.Schedule(ctx, sector, sealtasks.TTProveReplicaUpdate1, selector, m.schedFetch(sector, storiface.FTSealed|storiface.FTCache|storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing, storiface.AcquireCopy), func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTProveReplicaUpdate1, selector, m.schedFetch(sector, storiface.FTSealed|storiface.FTCache|storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing, storiface.AcquireCopy), func(ctx context.Context, w Worker) error {
@ -1153,7 +1153,7 @@ func (m *Manager) DownloadSectorData(ctx context.Context, sector storiface.Secto
ptype = storiface.PathStorage ptype = storiface.PathStorage
} }
selector := newAllocSelector(m.index, toFetch, ptype) selector := newAllocSelector(m.index, toFetch, ptype, sector.ID.Miner)
err = m.sched.Schedule(ctx, sector, sealtasks.TTDownloadSector, selector, schedNop, func(ctx context.Context, w Worker) error { err = m.sched.Schedule(ctx, sector, sealtasks.TTDownloadSector, selector, schedNop, func(ctx context.Context, w Worker) error {
err := m.startWork(ctx, w, wk)(w.DownloadSectorData(ctx, sector, finalized, src)) err := m.startWork(ctx, w, wk)(w.DownloadSectorData(ctx, sector, finalized, src))

View File

@ -274,7 +274,7 @@ func TestSched(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
rm.done[taskName] = done rm.done[taskName] = done
sel := newAllocSelector(index, storiface.FTCache, storiface.PathSealing) sel := newAllocSelector(index, storiface.FTCache, storiface.PathSealing, abi.ActorID(1000))
rm.wg.Add(1) rm.wg.Add(1)
go func() { go func() {

View File

@ -16,13 +16,15 @@ type allocSelector struct {
index paths.SectorIndex index paths.SectorIndex
alloc storiface.SectorFileType alloc storiface.SectorFileType
ptype storiface.PathType ptype storiface.PathType
miner abi.ActorID
} }
func newAllocSelector(index paths.SectorIndex, alloc storiface.SectorFileType, ptype storiface.PathType) *allocSelector { func newAllocSelector(index paths.SectorIndex, alloc storiface.SectorFileType, ptype storiface.PathType, miner abi.ActorID) *allocSelector {
return &allocSelector{ return &allocSelector{
index: index, index: index,
alloc: alloc, alloc: alloc,
ptype: ptype, ptype: ptype,
miner: miner,
} }
} }
@ -50,7 +52,7 @@ func (s *allocSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi
return false, false, xerrors.Errorf("getting sector size: %w", err) return false, false, xerrors.Errorf("getting sector size: %w", err)
} }
best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.ptype) best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.ptype, s.miner)
if err != nil { if err != nil {
return false, false, xerrors.Errorf("finding best alloc storage: %w", err) return false, false, xerrors.Errorf("finding best alloc storage: %w", err)
} }

View File

@ -16,14 +16,16 @@ type existingSelector struct {
index paths.SectorIndex index paths.SectorIndex
sector abi.SectorID sector abi.SectorID
fileType storiface.SectorFileType fileType storiface.SectorFileType
miner abi.ActorID
allowFetch bool allowFetch bool
} }
func newExistingSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, allowFetch bool) *existingSelector { func newExistingSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, miner abi.ActorID, allowFetch bool) *existingSelector {
return &existingSelector{ return &existingSelector{
index: index, index: index,
sector: sector, sector: sector,
fileType: alloc, fileType: alloc,
miner: miner,
allowFetch: allowFetch, allowFetch: allowFetch,
} }
} }

View File

@ -17,10 +17,11 @@ type moveSelector struct {
sector abi.SectorID sector abi.SectorID
alloc storiface.SectorFileType alloc storiface.SectorFileType
destPtype storiface.PathType destPtype storiface.PathType
miner abi.ActorID
allowRemote bool allowRemote bool
} }
func newMoveSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, destPtype storiface.PathType, allowRemote bool) *moveSelector { func newMoveSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, destPtype storiface.PathType, miner abi.ActorID, allowRemote bool) *moveSelector {
return &moveSelector{ return &moveSelector{
index: index, index: index,
sector: sector, sector: sector,
@ -67,7 +68,7 @@ func (s *moveSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi.
} }
} }
best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.destPtype) best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.destPtype, s.miner)
if err != nil { if err != nil {
return false, false, xerrors.Errorf("finding best dest storage: %w", err) return false, false, xerrors.Errorf("finding best dest storage: %w", err)
} }

View File

@ -8,6 +8,28 @@ import (
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
) )
// FTUnsealed represents an unsealed sector file type.
// FTSealed represents a sealed sector file type.
// FTCache represents a cache sector file type.
// FTUpdate represents an update sector file type.
// FTUpdateCache represents an update cache sector file type.
// FTPiece represents a Piece Park sector file type.
// FileTypes represents the total number of file types.
//
// The SectorFileType type is an integer type that represents different sector file types.
// It has several methods to manipulate and query the file type.
// The String method returns a string representation of the file type.
// The Strings method returns a slice of string representations of all the file types that are set in the receiver object.
// The AllSet method returns a slice of all the file types that are set in the receiver object.
// The Has method checks whether a specific file type is set in the receiver object.
// The SealSpaceUse method calculates the space used by the receiver object in sealing a sector of a given size.
// The SubAllowed method removes selected file types from the receiver object based on a list of allowed and denied file types.
// The Unset method removes selected file types from the receiver object.
// The AnyAllowed method checks whether any file types in the receiver object are allowed based on a list of allowed and denied file types.
// The Allowed method checks whether all file types in the receiver object are allowed based on a list of allowed and denied file types.
// The StoreSpaceUse method calculates the space used by the receiver object in storing a sector of a given size.
// The All method returns an array that represents which file types are set in the receiver object.
// The IsNone method checks whether the receiver object represents no file types.
const ( const (
// "regular" sectors // "regular" sectors
FTUnsealed SectorFileType = 1 << iota FTUnsealed SectorFileType = 1 << iota
@ -24,12 +46,28 @@ const (
FileTypes = iota FileTypes = iota
) )
// PathTypes is a slice of SectorFileType that represents different types of sector file paths.
// It contains the following types of sector file paths:
// - FTUnsealed: represents regular unsealed sectors
// - FTSealed: represents sealed sectors
// - FTCache: represents cache sectors
// - FTUpdate: represents snap sectors
// - FTUpdateCache: represents snap cache sectors
// - FTPiece: represents Piece Park sectors
var PathTypes = []SectorFileType{FTUnsealed, FTSealed, FTCache, FTUpdate, FTUpdateCache, FTPiece} var PathTypes = []SectorFileType{FTUnsealed, FTSealed, FTCache, FTUpdate, FTUpdateCache, FTPiece}
// FTNone represents a sector file type of none. This constant is used in the StorageLock method to specify that a sector should not have any file types locked.
// Example usage:
// err := m.index.StorageLock(ctx, sector.ID, storiface.FTNone, storiface.FTSealed|storiface.FTUnsealed|storiface.FTCache)
const ( const (
FTNone SectorFileType = 0 FTNone SectorFileType = 0
) )
// FTAll represents the combination of all available sector file types.
// It is a variable of type SectorFileType.
// The value of FTAll is calculated by iterating over the PathTypes slice and using the |= operator to perform a bitwise OR operation on each path type.
// The result is assigned to the variable out and returned.
// FTAll is immediately invoked as a function using the anonymous function syntax, so the result is returned as soon as it is calculated.
var FTAll = func() (out SectorFileType) { var FTAll = func() (out SectorFileType) {
for _, pathType := range PathTypes { for _, pathType := range PathTypes {
out |= pathType out |= pathType
@ -37,8 +75,10 @@ var FTAll = func() (out SectorFileType) {
return out return out
}() }()
// FSOverheadDen represents the constant value 10, which is used to calculate the overhead in various storage space utilization calculations.
const FSOverheadDen = 10 const FSOverheadDen = 10
// FSOverheadSeal is a map that represents the overheads for different SectorFileType in sealed sectors.
var FSOverheadSeal = map[SectorFileType]int{ // 10x overheads var FSOverheadSeal = map[SectorFileType]int{ // 10x overheads
FTUnsealed: FSOverheadDen, FTUnsealed: FSOverheadDen,
FTSealed: FSOverheadDen, FTSealed: FSOverheadDen,
@ -50,6 +90,30 @@ var FSOverheadSeal = map[SectorFileType]int{ // 10x overheads
// sector size * disk / fs overhead. FSOverheadDen is like the unit of sector size // sector size * disk / fs overhead. FSOverheadDen is like the unit of sector size
// FsOverheadFinalized is a map that represents the finalized overhead for different types of SectorFileType.
// The keys in the map are the SectorFileType values, and the values are integers representing the overhead.
// It is used to calculate the storage space usage for different types of sectors, as shown in the example below:
//
// func (t SectorFileType) StoreSpaceUse(ssize abi.SectorSize) (uint64, error) {
// var need uint64
// for _, pathType := range PathTypes {
// if !t.Has(pathType) {
// continue
// }
//
// oh, ok := FsOverheadFinalized[pathType]
// if !ok {
// return 0, xerrors.Errorf("no finalized overhead info for %s", pathType)
// }
//
// need += uint64(oh) * uint64(ssize) / FSOverheadDen
// }
//
// return need, nil
// }
//
// The overhead value is retrieved from FsOverheadFinalized by using the SectorFileType value as the key.
// If the overhead value is not found in the map, an error is returned indicating that there is no finalized overhead information for the given sector type.
var FsOverheadFinalized = map[SectorFileType]int{ var FsOverheadFinalized = map[SectorFileType]int{
FTUnsealed: FSOverheadDen, FTUnsealed: FSOverheadDen,
FTSealed: FSOverheadDen, FTSealed: FSOverheadDen,
@ -59,8 +123,13 @@ var FsOverheadFinalized = map[SectorFileType]int{
FTPiece: FSOverheadDen, FTPiece: FSOverheadDen,
} }
// SectorFileType represents the type of a sector file
// TypeFromString converts a string to a SectorFileType
type SectorFileType int type SectorFileType int
// TypeFromString converts a string representation of a SectorFileType to its corresponding value.
// It returns the SectorFileType and nil error if the string matches one of the existing types.
// If the string does not match any type, it returns 0 and an error.
func TypeFromString(s string) (SectorFileType, error) { func TypeFromString(s string) (SectorFileType, error) {
switch s { switch s {
case "unsealed": case "unsealed":
@ -80,6 +149,7 @@ func TypeFromString(s string) (SectorFileType, error) {
} }
} }
// String returns a string representation of the SectorFileType.
func (t SectorFileType) String() string { func (t SectorFileType) String() string {
switch t { switch t {
case FTUnsealed: case FTUnsealed:
@ -99,6 +169,12 @@ func (t SectorFileType) String() string {
} }
} }
// Strings returns a slice of strings representing the names of the SectorFileType values that are set in the receiver value.
// Example usage:
//
// fileType := SectorFileType(FTSealed | FTCache)
// names := fileType.Strings() // names = ["sealed", "cache"]
// fmt.Println(names)
func (t SectorFileType) Strings() []string { func (t SectorFileType) Strings() []string {
var out []string var out []string
for _, fileType := range PathTypes { for _, fileType := range PathTypes {
@ -111,6 +187,7 @@ func (t SectorFileType) Strings() []string {
return out return out
} }
// AllSet returns a slice of SectorFileType values that are set in the SectorFileType receiver value
func (t SectorFileType) AllSet() []SectorFileType { func (t SectorFileType) AllSet() []SectorFileType {
var out []SectorFileType var out []SectorFileType
for _, fileType := range PathTypes { for _, fileType := range PathTypes {
@ -123,10 +200,33 @@ func (t SectorFileType) AllSet() []SectorFileType {
return out return out
} }
// Has checks if the SectorFileType has a specific singleType.
func (t SectorFileType) Has(singleType SectorFileType) bool { func (t SectorFileType) Has(singleType SectorFileType) bool {
return t&singleType == singleType return t&singleType == singleType
} }
// SealSpaceUse calculates the amount of space needed for sealing the sector
// based on the given sector size. It iterates over the different path types
// and calculates the space needed for each path type using the FSOverheadSeal
// map. The overhead value is multiplied by the sector size and divided by the
// FSOverheadDen constant. The total space needed is accumulated and returned.
// If there is no seal overhead information for a particular path type, an error
// is returned.
//
// Example usage:
//
// fileType := FTSealed | FTCache
// sectorSize := abi.SectorSize(32 << 20) // 32 MiB
// spaceNeeded, err := fileType.SealSpaceUse(sectorSize)
//
// Parameters:
//
// ssize: The size of the sector
//
// Returns:
//
// uint64: The amount of space needed for sealing the sector
// error: If there is no seal overhead information for a path type
func (t SectorFileType) SealSpaceUse(ssize abi.SectorSize) (uint64, error) { func (t SectorFileType) SealSpaceUse(ssize abi.SectorSize) (uint64, error) {
var need uint64 var need uint64
for _, pathType := range PathTypes { for _, pathType := range PathTypes {
@ -145,6 +245,15 @@ func (t SectorFileType) SealSpaceUse(ssize abi.SectorSize) (uint64, error) {
return need, nil return need, nil
} }
// The method takes in two parameters: allowTypes and denyTypes, both of which are slices of strings.
// If allowTypes is not empty, the method sets a denyMask with all bits set to 1, and then iterates over each allowType,
// converting it to a SectorFileType using the TypeFromString function and unsetting the corresponding bit in the denyMask.
// If a string in allowTypes cannot be converted to a valid SectorFileType, it is ignored.
// After processing allowTypes, the method iterates over each denyType, converting it to a SectorFileType using the TypeFromString function
// and setting the corresponding bit in the denyMask.
// If a string in denyTypes cannot be converted to a valid SectorFileType, it is ignored.
// Finally, the method returns the bitwise AND of the original SectorFileType and the denyMask.
// The returned SectorFileType will only allow the types specified in allowTypes and exclude the types specified in denyTypes.`
func (t SectorFileType) SubAllowed(allowTypes []string, denyTypes []string) SectorFileType { func (t SectorFileType) SubAllowed(allowTypes []string, denyTypes []string) SectorFileType {
var denyMask SectorFileType // 1s deny var denyMask SectorFileType // 1s deny
@ -174,18 +283,30 @@ func (t SectorFileType) SubAllowed(allowTypes []string, denyTypes []string) Sect
return t & denyMask return t & denyMask
} }
// Unset removes the specified sector file type(s) from the current SectorFileType value.
// It performs a bitwise AND operation between the current value and the bitwise complement of the toUnset value.
// The result is returned as a new SectorFileType value.
// Any bits that are set in toUnset will be cleared in the result.
// Usage: result = value.Unset(typesToUnset)
func (t SectorFileType) Unset(toUnset SectorFileType) SectorFileType { func (t SectorFileType) Unset(toUnset SectorFileType) SectorFileType {
return t &^ toUnset return t &^ toUnset
} }
// AnyAllowed checks if the SectorFileType has any allowed types and no denied types.
func (t SectorFileType) AnyAllowed(allowTypes []string, denyTypes []string) bool { func (t SectorFileType) AnyAllowed(allowTypes []string, denyTypes []string) bool {
return t.SubAllowed(allowTypes, denyTypes) != t return t.SubAllowed(allowTypes, denyTypes) != t
} }
// Allowed checks if the SectorFileType is allowed based on the given allowTypes and denyTypes.
// Returns true if the SectorFileType is allowed, otherwise false.
func (t SectorFileType) Allowed(allowTypes []string, denyTypes []string) bool { func (t SectorFileType) Allowed(allowTypes []string, denyTypes []string) bool {
return t.SubAllowed(allowTypes, denyTypes) == 0 return t.SubAllowed(allowTypes, denyTypes) == 0
} }
// StoreSpaceUse calculates the space used for storing sectors of a specific file type.
// It takes the sector size as input and returns the total space needed in bytes and an error, if any.
// The calculation is based on the finalized overhead information for the file type.
// If the overhead information is not available for a particular file type, an error will be returned.
func (t SectorFileType) StoreSpaceUse(ssize abi.SectorSize) (uint64, error) { func (t SectorFileType) StoreSpaceUse(ssize abi.SectorSize) (uint64, error) {
var need uint64 var need uint64
for _, pathType := range PathTypes { for _, pathType := range PathTypes {
@ -204,6 +325,7 @@ func (t SectorFileType) StoreSpaceUse(ssize abi.SectorSize) (uint64, error) {
return need, nil return need, nil
} }
// All returns an array indicating whether each FileTypes flag is set in the SectorFileType.
func (t SectorFileType) All() [FileTypes]bool { func (t SectorFileType) All() [FileTypes]bool {
var out [FileTypes]bool var out [FileTypes]bool
@ -214,10 +336,13 @@ func (t SectorFileType) All() [FileTypes]bool {
return out return out
} }
// IsNone checks if the SectorFileType value is equal to zero.
// It returns true if the value is zero, indicating that the type is none.
func (t SectorFileType) IsNone() bool { func (t SectorFileType) IsNone() bool {
return t == 0 return t == 0
} }
// SectorPaths represents the paths for different sector files.
type SectorPaths struct { type SectorPaths struct {
ID abi.SectorID ID abi.SectorID
@ -229,6 +354,7 @@ type SectorPaths struct {
Piece string Piece string
} }
// HasAllSet checks if all paths of a SectorPaths struct are set for a given SectorFileType.
func (sp SectorPaths) HasAllSet(ft SectorFileType) bool { func (sp SectorPaths) HasAllSet(ft SectorFileType) bool {
for _, fileType := range ft.AllSet() { for _, fileType := range ft.AllSet() {
if PathByType(sp, fileType) == "" { if PathByType(sp, fileType) == "" {
@ -239,6 +365,9 @@ func (sp SectorPaths) HasAllSet(ft SectorFileType) bool {
return true return true
} }
// Subset returns a new instance of SectorPaths that contains only the paths specified by the filter SectorFileType.
// It iterates over each fileType in the filter, retrieves the corresponding path from the original SectorPaths instance, and sets it in the new instance.
// Finally, it sets the ID field of the new instance to be the same as the original instance.
func (sp SectorPaths) Subset(filter SectorFileType) SectorPaths { func (sp SectorPaths) Subset(filter SectorFileType) SectorPaths {
var out SectorPaths var out SectorPaths
@ -251,6 +380,24 @@ func (sp SectorPaths) Subset(filter SectorFileType) SectorPaths {
return out return out
} }
// ParseSectorID parses a sector ID from a given base name.
// It expects the format "s-t0%d-%d", where the first %d represents the miner ID
// and the second %d represents the sector number.
//
// Parameters:
// - baseName: The base name from which to parse the sector ID.
//
// Returns:
// - abi.SectorID: The parsed sector ID.
// - error: An error if parsing fails.
//
// Example usage:
//
// id, err := ParseSectorID(baseName)
// if err != nil {
// // handle error
// }
// // use id
func ParseSectorID(baseName string) (abi.SectorID, error) { func ParseSectorID(baseName string) (abi.SectorID, error) {
var n abi.SectorNumber var n abi.SectorNumber
var mid abi.ActorID var mid abi.ActorID
@ -269,10 +416,19 @@ func ParseSectorID(baseName string) (abi.SectorID, error) {
}, nil }, nil
} }
// SectorName returns the name of a sector in the format "s-t0<Miner>-<Number>"
//
// Parameters:
// - sid: The sector ID
//
// Returns:
// - The name of the sector as a string
func SectorName(sid abi.SectorID) string { func SectorName(sid abi.SectorID) string {
return fmt.Sprintf("s-t0%d-%d", sid.Miner, sid.Number) return fmt.Sprintf("s-t0%d-%d", sid.Miner, sid.Number)
} }
// PathByType returns the path associated with the specified fileType in the given SectorPaths.
// It panics if the requested path type is unknown.
func PathByType(sps SectorPaths, fileType SectorFileType) string { func PathByType(sps SectorPaths, fileType SectorFileType) string {
switch fileType { switch fileType {
case FTUnsealed: case FTUnsealed:
@ -309,11 +465,14 @@ func SetPathByType(sps *SectorPaths, fileType SectorFileType, p string) {
} }
} }
// PathsWithIDs represents paths and IDs for sector files.
type PathsWithIDs struct { type PathsWithIDs struct {
Paths SectorPaths Paths SectorPaths
IDs SectorPaths IDs SectorPaths
} }
// HasAllSet checks if all paths and IDs in PathsWithIDs have a corresponding path set for the specified SectorFileType.
// It returns true if all paths and IDs are set, and false otherwise.
func (p PathsWithIDs) HasAllSet(ft SectorFileType) bool { func (p PathsWithIDs) HasAllSet(ft SectorFileType) bool {
return p.Paths.HasAllSet(ft) && p.IDs.HasAllSet(ft) return p.Paths.HasAllSet(ft) && p.IDs.HasAllSet(ft)
} }

View File

@ -86,6 +86,14 @@ type StorageInfo struct {
// - "update-cache" // - "update-cache"
// Any other value will generate a warning and be ignored. // Any other value will generate a warning and be ignored.
DenyTypes []string DenyTypes []string
// AllowMiners lists miner IDs which are allowed to store their sector data into
// this path. If empty, all miner IDs are allowed
AllowMiners []string
// DenyMiners lists miner IDs which are denied to store their sector data into
// this path
DenyMiners []string
} }
type HealthReport struct { type HealthReport struct {
@ -104,8 +112,10 @@ type SectorStorageInfo struct {
Primary bool Primary bool
AllowTypes []string AllowTypes []string
DenyTypes []string DenyTypes []string
AllowMiners []string
DenyMiners []string
} }
type Decl struct { type Decl struct {

View File

@ -225,4 +225,12 @@ type LocalStorageMeta struct {
// - "update-cache" // - "update-cache"
// Any other value will generate a warning and be ignored. // Any other value will generate a warning and be ignored.
DenyTypes []string DenyTypes []string
// AllowMiners lists miner IDs which are allowed to store their sector data into
// this path. If empty, all miner IDs are allowed
AllowMiners []string
// DenyMiners lists miner IDs which are denied to store their sector data into
// this path
DenyMiners []string
} }