lotus/storage/sector/store.go
Łukasz Magiera 399f91940b Sector store
2019-08-14 22:27:32 +02:00

146 lines
2.7 KiB
Go

package sector
import (
"context"
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
"io"
"io/ioutil"
"os"
"sync"
)
// TODO: eventually handle sector storage here instead of in rust-sectorbuilder
type Store struct {
lk sync.Mutex
sb *sectorbuilder.SectorBuilder
waiting map[uint64]chan struct{}
incoming []chan sectorbuilder.SectorSealingStatus
// TODO: outdated chan
close chan struct{}
}
func NewStore(sb *sectorbuilder.SectorBuilder) *Store {
return &Store{
sb: sb,
waiting: map[uint64]chan struct{}{},
close: make(chan struct{}),
}
}
func (s *Store) Service() {
go s.service()
}
func (s *Store) service() {
sealed := s.sb.SealedSectorChan()
for {
select {
case sector := <-sealed:
s.lk.Lock()
watch, ok := s.waiting[sector.SectorID]
if ok {
close(watch)
delete(s.waiting, sector.SectorID)
}
for _, c := range s.incoming {
c <- sector // TODO: ctx!
}
s.lk.Unlock()
case <-s.close:
s.lk.Lock()
for _, c := range s.incoming {
close(c)
}
s.lk.Unlock()
return
}
}
}
func (s *Store) AddPiece(ref string, size uint64, r io.Reader, keepAtLeast uint64) (sectorID uint64, err error) {
err = withTemp(r, func(f string) (err error) {
sectorID, err = s.sb.AddPiece(ref, size, f)
return err
})
if err != nil {
return 0, err
}
s.lk.Lock()
_, exists := s.waiting[sectorID]
if !exists {
s.waiting[sectorID] = make(chan struct{})
}
s.lk.Unlock()
return sectorID, nil
}
func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) {
s.lk.Lock()
var at = -1
for i, ch := range s.incoming {
if ch == c {
at = i
}
}
if at == -1 {
s.lk.Unlock()
return
}
if len(s.incoming) > 1 {
s.incoming[at] = s.incoming[len(s.incoming)-1]
}
s.incoming = s.incoming[:len(s.incoming)-1]
s.lk.Unlock()
}
func (s *Store) Incoming() <-chan sectorbuilder.SectorSealingStatus {
ch := make(chan sectorbuilder.SectorSealingStatus, 8)
s.lk.Lock()
s.incoming = append(s.incoming, ch)
s.lk.Unlock()
return ch
}
func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.SectorSealingStatus, error) {
s.lk.Lock()
watch, ok := s.waiting[sector]
s.lk.Unlock()
if ok {
select {
case <-watch:
case <-ctx.Done():
return sectorbuilder.SectorSealingStatus{}, ctx.Err()
}
}
return s.sb.SealStatus(sector)
}
func (s *Store) Stop() {
close(s.close)
}
func withTemp(r io.Reader, cb func(string) error) error {
f, err := ioutil.TempFile(os.TempDir(), "lotus-temp-")
if err != nil {
return err
}
if _, err := io.Copy(f, r); err != nil {
return err
}
if err := f.Close(); err != nil {
return err
}
err = cb(f.Name())
if err != nil {
os.Remove(f.Name())
return err
}
return os.Remove(f.Name())
}