Skip to content

Commit

Permalink
save device type instead of caching it (#2023)
Browse files Browse the repository at this point in the history
* save device type instead of caching it

* add func comments

* split checking device type in a separate funtion

* storing device type after cache or detection, return types without storing if it's vm

* add to broken devices if type is not detected

* improve readability

* improve readability

* use the correct pool mounting path

* update doc string

---------

Co-authored-by: Muhamad Azamy <muhamad@incubaid.com>
  • Loading branch information
rawdaGastan and muhamadazmy authored Aug 21, 2023
1 parent 5aabc89 commit d96dff4
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 38 deletions.
2 changes: 1 addition & 1 deletion pkg/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const (

// VolatileDir creates a new cache directory that is stored on a tmpfs.
// This means data stored in this directory will NOT survive a reboot.
// Use this when you need to store data that needs to survice deamon reboot but not between reboots
// Use this when you need to store data that needs to survive deamon reboot but not between reboots
// It is the caller's responsibility to remove the directory when no longer needed.
// If the directory already exist error of type os.IsExist will be returned
func VolatileDir(name string, size uint64) (string, error) {
Expand Down
40 changes: 40 additions & 0 deletions pkg/storage/filesystem/btrfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/threefoldtech/zos/pkg/gridtypes/zos"
)

var (
Expand Down Expand Up @@ -308,6 +309,45 @@ func (p *btrfsPool) Shutdown() error {
return nil
}

// SetType sets the device type to the disk
func (p *btrfsPool) SetType(typ zos.DeviceType) error {
path, err := p.Mounted()
if err != nil {
return err
}
diskTypePath := filepath.Join(path, ".seektime")
if err := os.WriteFile(diskTypePath, []byte(typ), 0644); err != nil {
return errors.Wrapf(err, "failed to store device type for '%s' in '%s'", p.Name(), diskTypePath)
}

return nil
}

// Type gets the device type from the disk
// return the device type, if it's found and an error
// that's based on .seektime file existing in the /mnt/DeviceName/.seektime, that contains the device type being SSD or HDD
func (p *btrfsPool) Type() (zos.DeviceType, bool, error) {
path, err := p.Mounted()
if err != nil {
return "", false, err
}
diskTypePath := filepath.Join(path, ".seektime")
diskType, err := os.ReadFile(diskTypePath)
if os.IsNotExist(err) {
return "", false, nil
}

if err != nil {
return "", false, err
}

if len(diskType) == 0 {
return "", false, nil
}

return zos.DeviceType(diskType), true, nil
}

type btrfsVolume struct {
id int
path string
Expand Down
3 changes: 2 additions & 1 deletion pkg/storage/filesystem/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ func (i *DeviceInfo) Used() bool {
return len(i.Label) != 0 || len(i.Filesystem) != 0
}

func (d *DeviceInfo) Type() (zos.DeviceType, error) {
// DetectType returns the device type according to seektime
func (d *DeviceInfo) DetectType() (zos.DeviceType, error) {
return d.mgr.Seektime(context.Background(), d.Path)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/filesystem/device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestDeviceManagerScan(t *testing.T) {
// make sure all types are set.
expected := []zos.DeviceType{zos.SSDDevice, zos.HDDDevice}
for i, dev := range cached {
typ, err := dev.Type()
typ, err := dev.DetectType()
require.NoError(err)
require.Equal(expected[i], typ)
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/storage/filesystem/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"github.com/pkg/errors"
"github.com/threefoldtech/zos/pkg/gridtypes/zos"
)

// Usage struct (in bytes)
Expand Down Expand Up @@ -72,6 +73,13 @@ type Pool interface {
Shutdown() error
// Device return device associated with pool
Device() DeviceInfo
// SetType sets a device type on the pool. this will make
// sure that the detected device type is reported
// correctly by calling the Type() method.
SetType(typ zos.DeviceType) error
// Type returns the device type set by a previous call
// to SetType.
Type() (zos.DeviceType, bool, error)
}

// Filter closure for Filesystem list
Expand Down
84 changes: 51 additions & 33 deletions pkg/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,15 @@ type Module struct {
mu sync.RWMutex

// cache is a cache directory can be used with some files
// NOTED: this is deprecated, now type is stored on the device
// itself not in temp cache
cache TypeCache
}

type TypeCache struct {
base string
}

func (t *TypeCache) Set(name string, typ pkg.DeviceType) error {
if err := os.WriteFile(filepath.Join(t.base, name), []byte(typ), 0644); err != nil {
return errors.Wrapf(err, "failed to store device type for '%s'", name)
}

return nil
}

func (t *TypeCache) Get(name string) (pkg.DeviceType, bool) {
data, err := os.ReadFile(filepath.Join(t.base, name))
if err != nil {
Expand Down Expand Up @@ -157,6 +151,50 @@ func (s *Module) dump() {

}

// poolType gets the device type of a disk
func (s *Module) poolType(pool filesystem.Pool, vm bool) (zos.DeviceType, error) {
var typ zos.DeviceType
device := pool.Device()
// for development purposes only
if vm {
// force ssd device for vms
typ = zos.SSDDevice

if device.Path == "/dev/vdd" || device.Path == "/dev/vde" {
typ = zos.HDDDevice
}
return typ, nil
}

log.Debug().Str("device", device.Path).Msg("checking device type in disk")
typ, ok, err := pool.Type()
if err != nil {
return "", errors.Wrap(err, "failed to get device type")
}

if ok {
log.Debug().Str("device", device.Path).Str("type", typ.String()).Msg("device type loaded from disk")
return typ, nil
}

log.Debug().Str("device", device.Path).Msg("checking device type in cache")
typ, ok = s.cache.Get(device.Name())
if !ok {
log.Debug().Str("device", device.Path).Msg("detecting device type")
typ, err = device.DetectType()
if err != nil {
return "", errors.Wrap(err, "failed to detect device type")
}
}

log.Debug().Str("device", device.Path).Str("type", typ.String()).Msg("setting device type")
if err := pool.SetType(typ); err != nil {
return "", errors.Wrap(err, "failed to set device type")
}

return typ, nil
}

/*
*
initialize, must be called at least onetime each boot.
Expand Down Expand Up @@ -206,31 +244,11 @@ func (s *Module) initialize(ctx context.Context) error {
log.Error().Err(err).Str("pool", pool.Name()).Str("device", device.Path).Msg("failed to get usage of pool")
}

typ, ok := s.cache.Get(device.Name())
if !ok {
log.Debug().Str("device", device.Path).Msg("detecting device type")
typ, err = device.Type()
if err != nil {
log.Error().Str("device", device.Path).Err(err).Msg("failed to check device type")
continue
}

// for development purposes only
if vm {
// force ssd device for vms
typ = zos.SSDDevice

if device.Path == "/dev/vdd" || device.Path == "/dev/vde" {
typ = zos.HDDDevice
}
}

log.Debug().Str("device", device.Path).Str("type", typ.String()).Msg("caching device type")
if err := s.cache.Set(device.Name(), typ); err != nil {
log.Error().Str("device", device.Path).Err(err).Msg("failed to cache device type")
}
} else {
log.Debug().Str("device", device.Path).Str("type", typ.String()).Msg("device type loaded from cache")
typ, err := s.poolType(pool, vm)
if err != nil {
log.Error().Str("device", device.Path).Err(err).Msg("failed to get device type")
s.brokenDevices = append(s.brokenDevices, pkg.BrokenDevice{Path: device.Path, Err: err})
continue
}

switch typ {
Expand Down
8 changes: 6 additions & 2 deletions pkg/storage/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,12 @@ func (p *testPool) UnMount() error {
return fmt.Errorf("UnMount not implemented")
}

func (p *testPool) Type() zos.DeviceType {
return p.ptype
func (p *testPool) Type() (zos.DeviceType, bool, error) {
return p.ptype, false, nil
}

func (p *testPool) SetType(_ zos.DeviceType) error {
return nil
}

func (p *testPool) Volumes() ([]filesystem.Volume, error) {
Expand Down

0 comments on commit d96dff4

Please sign in to comment.