Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

save device type instead of caching it #2023

Merged
merged 9 commits into from
Aug 21, 2023
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First time for me to know about the seektime tool, maybe we can enhance it to include that it's an approximation too https://github.com/maxux/seektime not 100% correct

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")
rawdaGastan marked this conversation as resolved.
Show resolved Hide resolved
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