XL: Introduce new API StorageInfo. (#1770)

This is necessary for calculating the total storage
capacity from object layer. This value is also needed for
browser UI.

Buckets used to carry this information, this patch
deprecates this feature.
This commit is contained in:
Harshavardhana 2016-05-26 14:13:10 -07:00 committed by Harshavardhana
parent b2293c2bf4
commit 34e9ad24aa
7 changed files with 80 additions and 43 deletions

View file

@ -25,29 +25,31 @@ import (
"strings"
"sync"
"github.com/minio/minio/pkg/disk"
"github.com/minio/minio/pkg/mimedb"
)
// fsObjects - Implements fs object layer.
type fsObjects struct {
storage StorageAPI
physicalDisk string
listObjectMap map[listParams][]*treeWalkerFS
listObjectMapMutex *sync.Mutex
}
// newFSObjects - initialize new fs object layer.
func newFSObjects(exportPath string) (ObjectLayer, error) {
func newFSObjects(disk string) (ObjectLayer, error) {
var storage StorageAPI
var err error
if !strings.ContainsRune(exportPath, ':') || filepath.VolumeName(exportPath) != "" {
if !strings.ContainsRune(disk, ':') || filepath.VolumeName(disk) != "" {
// Initialize filesystem storage API.
storage, err = newPosix(exportPath)
storage, err = newPosix(disk)
if err != nil {
return nil, err
}
} else {
// Initialize rpc client storage API.
storage, err = newRPCClient(exportPath)
storage, err = newRPCClient(disk)
if err != nil {
return nil, err
}
@ -60,11 +62,22 @@ func newFSObjects(exportPath string) (ObjectLayer, error) {
// Return successfully initialized object layer.
return fsObjects{
storage: storage,
physicalDisk: disk,
listObjectMap: make(map[listParams][]*treeWalkerFS),
listObjectMapMutex: &sync.Mutex{},
}, nil
}
// StorageInfo - returns underlying storage statistics.
func (fs fsObjects) StorageInfo() StorageInfo {
info, err := disk.GetInfo(fs.physicalDisk)
fatalIf(err, "Unable to get disk info "+fs.physicalDisk)
return StorageInfo{
Total: info.Total,
Free: info.Free,
}
}
/// Bucket operations
// MakeBucket - make a bucket.
@ -92,8 +105,6 @@ func (fs fsObjects) GetBucketInfo(bucket string) (BucketInfo, error) {
return BucketInfo{
Name: bucket,
Created: vi.Created,
Total: vi.Total,
Free: vi.Free,
}, nil
}
@ -113,8 +124,6 @@ func (fs fsObjects) ListBuckets() ([]BucketInfo, error) {
bucketInfos = append(bucketInfos, BucketInfo{
Name: vol.Name,
Created: vol.Created,
Total: vol.Total,
Free: vol.Free,
})
}
sort.Sort(byBucketName(bucketInfos))

View file

@ -18,12 +18,16 @@ package main
import "time"
// StorageInfo - represents total capacity of underlying storage.
type StorageInfo struct {
Total int64 // Total disk space.
Free int64 // Free total available disk space.
}
// BucketInfo - bucket name and create date
type BucketInfo struct {
Name string
Created time.Time
Total int64
Free int64
}
// ObjectInfo - object info.

View file

@ -20,6 +20,9 @@ import "io"
// ObjectLayer implements primitives for object API layer.
type ObjectLayer interface {
// Storage operations.
StorageInfo() StorageInfo
// Bucket operations.
MakeBucket(bucket string) error
GetBucketInfo(bucket string) (bucketInfo BucketInfo, err error)

View file

@ -202,15 +202,6 @@ func (s fsStorage) MakeVol(volume string) (err error) {
// ListVols - list volumes.
func (s fsStorage) ListVols() (volsInfo []VolInfo, err error) {
// Get disk info to be populated for VolInfo.
var diskInfo disk.Info
diskInfo, err = disk.GetInfo(s.diskPath)
if err != nil {
if os.IsNotExist(err) {
return nil, errDiskNotFound
}
return nil, err
}
volsInfo, err = listVols(s.diskPath)
if err != nil {
return nil, err
@ -219,9 +210,6 @@ func (s fsStorage) ListVols() (volsInfo []VolInfo, err error) {
volInfo := VolInfo{
Name: vol.Name,
Created: vol.Created,
Total: diskInfo.Total,
Free: diskInfo.Free,
FSType: diskInfo.FSType,
}
volsInfo[i] = volInfo
}
@ -244,24 +232,12 @@ func (s fsStorage) StatVol(volume string) (volInfo VolInfo, err error) {
}
return VolInfo{}, err
}
// Get disk info, to be returned back along with volume info.
var diskInfo disk.Info
diskInfo, err = disk.GetInfo(s.diskPath)
if err != nil {
if os.IsNotExist(err) {
return VolInfo{}, errDiskNotFound
}
return VolInfo{}, err
}
// As os.Stat() doesn't carry other than ModTime(), use ModTime()
// as CreatedTime.
createdTime := st.ModTime()
return VolInfo{
Name: volume,
Created: createdTime,
Free: diskInfo.Free,
Total: diskInfo.Total,
FSType: diskInfo.FSType,
}, nil
}

View file

@ -25,9 +25,6 @@ import (
type VolInfo struct {
Name string
Created time.Time
Total int64
Free int64
FSType string
}
// FileInfo - file stat information.

View file

@ -98,6 +98,22 @@ func (web *webAPIHandlers) ServerInfo(r *http.Request, args *WebGenericArgs, rep
return nil
}
// StorageInfoRep - contains storage usage statistics.
type StorageInfoRep struct {
StorageInfo StorageInfo `json:"storageInfo"`
UIVersion string `json:"uiVersion"`
}
// StorageInfo - web call to gather storage usage statistics.
func (web *webAPIHandlers) StorageInfo(r *http.Request, args *GenericArgs, reply *StorageInfoRep) error {
if !isJWTReqAuthenticated(r) {
return &json2.Error{Message: "Unauthorized request"}
}
reply.UIVersion = miniobrowser.UIVersion
reply.StorageInfo = web.ObjectAPI.StorageInfo()
return nil
}
// MakeBucketArgs - make bucket args.
type MakeBucketArgs struct {
BucketName string `json:"bucketName"`
@ -127,10 +143,6 @@ type WebBucketInfo struct {
Name string `json:"name"`
// Date the bucket was created.
CreationDate time.Time `json:"creationDate"`
// Total storage space where the bucket resides.
Total int64 `json:"total"`
// Free storage space where the bucket resides.
Free int64 `json:"free"`
}
// ListBuckets - list buckets api.
@ -148,8 +160,6 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re
reply.Buckets = append(reply.Buckets, WebBucketInfo{
Name: bucket.Name,
CreationDate: bucket.Created,
Total: bucket.Total,
Free: bucket.Free,
})
}
}

View file

@ -20,8 +20,11 @@ import (
"errors"
"fmt"
"path/filepath"
"sort"
"strings"
"sync"
"github.com/minio/minio/pkg/disk"
)
const (
@ -33,6 +36,7 @@ const (
// xlObjects - Implements fs object layer.
type xlObjects struct {
storageDisks []StorageAPI
physicalDisks []string
dataBlocks int
parityBlocks int
readQuorum int
@ -147,6 +151,7 @@ func newXLObjects(disks []string) (ObjectLayer, error) {
xl := xlObjects{
storageDisks: newPosixDisks,
physicalDisks: disks,
dataBlocks: dataBlocks,
parityBlocks: parityBlocks,
listObjectMap: make(map[listParams][]*treeWalker),
@ -168,3 +173,36 @@ func newXLObjects(disks []string) (ObjectLayer, error) {
// Return successfully initialized object layer.
return xl, nil
}
// byDiskTotal is a collection satisfying sort.Interface.
type byDiskTotal []disk.Info
func (d byDiskTotal) Len() int { return len(d) }
func (d byDiskTotal) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d byDiskTotal) Less(i, j int) bool {
return d[i].Total < d[j].Total
}
// StorageInfo - returns underlying storage statistics.
func (xl xlObjects) StorageInfo() StorageInfo {
var disksInfo []disk.Info
for _, diskPath := range xl.physicalDisks {
info, err := disk.GetInfo(diskPath)
if err != nil {
errorIf(err, "Unable to fetch disk info for "+diskPath)
continue
}
disksInfo = append(disksInfo, info)
}
// Sort so that the first element is the smallest.
sort.Sort(byDiskTotal(disksInfo))
// Return calculated storage info, choose the lowest Total and
// Free as the total aggregated values. Total capacity is always
// the multiple of smallest disk among the disk list.
return StorageInfo{
Total: disksInfo[0].Total * int64(len(xl.storageDisks)),
Free: disksInfo[0].Free * int64(len(xl.storageDisks)),
}
}