seaweedfs/weed/filer/filer_remote_storage.go

230 lines
7.1 KiB
Go
Raw Normal View History

2021-07-27 05:53:44 +00:00
package filer
import (
"context"
"fmt"
2021-08-04 23:25:46 +00:00
"github.com/chrislusf/seaweedfs/weed/pb"
2021-07-27 08:16:28 +00:00
"github.com/chrislusf/seaweedfs/weed/remote_storage"
"github.com/chrislusf/seaweedfs/weed/util"
2021-07-27 05:53:44 +00:00
"github.com/golang/protobuf/proto"
2021-08-04 23:25:46 +00:00
"google.golang.org/grpc"
2021-07-27 05:53:44 +00:00
"math"
2021-07-27 08:16:28 +00:00
"strings"
2021-07-27 05:53:44 +00:00
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/viant/ptrie"
)
2021-07-27 08:16:28 +00:00
const REMOTE_STORAGE_CONF_SUFFIX = ".conf"
const REMOTE_STORAGE_MOUNT_FILE = "mount.mapping"
2021-07-27 05:53:44 +00:00
type FilerRemoteStorage struct {
2021-07-27 08:16:28 +00:00
rules ptrie.Trie
storageNameToConf map[string]*filer_pb.RemoteConf
2021-07-27 05:53:44 +00:00
}
2021-07-27 08:16:28 +00:00
func NewFilerRemoteStorage() (rs *FilerRemoteStorage) {
rs = &FilerRemoteStorage{
rules: ptrie.New(),
storageNameToConf: make(map[string]*filer_pb.RemoteConf),
2021-07-27 05:53:44 +00:00
}
2021-07-27 08:16:28 +00:00
return rs
2021-07-27 05:53:44 +00:00
}
func (rs *FilerRemoteStorage) LoadRemoteStorageConfigurationsAndMapping(filer *Filer) (err error) {
2021-07-27 08:16:28 +00:00
// execute this on filer
limit := int64(math.MaxInt32)
entries, _, err := filer.ListDirectoryEntries(context.Background(), DirectoryEtcRemote, "", false, limit, "", "", "")
2021-07-27 05:53:44 +00:00
if err != nil {
if err == filer_pb.ErrNotFound {
return nil
}
glog.Errorf("read remote storage %s: %v", DirectoryEtcRemote, err)
return
}
for _, entry := range entries {
2021-07-27 08:16:28 +00:00
if entry.Name() == REMOTE_STORAGE_MOUNT_FILE {
2021-08-01 05:39:38 +00:00
if err := rs.loadRemoteStorageMountMapping(entry.Content); err != nil {
return err
}
continue
2021-07-27 08:16:28 +00:00
}
if !strings.HasSuffix(entry.Name(), REMOTE_STORAGE_CONF_SUFFIX) {
return nil
}
2021-07-27 05:53:44 +00:00
conf := &filer_pb.RemoteConf{}
if err := proto.Unmarshal(entry.Content, conf); err != nil {
2021-07-27 08:16:28 +00:00
return fmt.Errorf("unmarshal %s/%s: %v", DirectoryEtcRemote, entry.Name(), err)
2021-07-27 05:53:44 +00:00
}
2021-07-27 08:16:28 +00:00
rs.storageNameToConf[conf.Name] = conf
2021-07-27 05:53:44 +00:00
}
return nil
}
2021-07-27 08:16:28 +00:00
func (rs *FilerRemoteStorage) loadRemoteStorageMountMapping(data []byte) (err error) {
2021-07-27 10:26:35 +00:00
mappings := &filer_pb.RemoteStorageMapping{}
2021-07-27 08:16:28 +00:00
if err := proto.Unmarshal(data, mappings); err != nil {
return fmt.Errorf("unmarshal %s/%s: %v", DirectoryEtcRemote, REMOTE_STORAGE_MOUNT_FILE, err)
}
2021-07-27 10:26:35 +00:00
for dir, storageLocation := range mappings.Mappings {
rs.mapDirectoryToRemoteStorage(util.FullPath(dir), storageLocation)
2021-07-27 08:16:28 +00:00
}
return nil
}
func (rs *FilerRemoteStorage) mapDirectoryToRemoteStorage(dir util.FullPath, loc *filer_pb.RemoteStorageLocation) {
rs.rules.Put([]byte(dir+"/"), loc)
2021-07-27 08:16:28 +00:00
}
func (rs *FilerRemoteStorage) FindMountDirectory(p util.FullPath) (mountDir util.FullPath, remoteLocation *filer_pb.RemoteStorageLocation) {
rs.rules.MatchPrefix([]byte(p), func(key []byte, value interface{}) bool {
2021-08-01 05:39:38 +00:00
mountDir = util.FullPath(string(key[:len(key)-1]))
remoteLocation = value.(*filer_pb.RemoteStorageLocation)
return true
})
return
}
func (rs *FilerRemoteStorage) FindRemoteStorageClient(p util.FullPath) (client remote_storage.RemoteStorageClient, remoteConf *filer_pb.RemoteConf, found bool) {
2021-08-04 07:31:06 +00:00
var storageLocation *filer_pb.RemoteStorageLocation
2021-07-27 08:16:28 +00:00
rs.rules.MatchPrefix([]byte(p), func(key []byte, value interface{}) bool {
2021-08-04 07:31:06 +00:00
storageLocation = value.(*filer_pb.RemoteStorageLocation)
2021-07-27 08:16:28 +00:00
return true
})
2021-08-04 07:31:06 +00:00
if storageLocation == nil {
found = false
2021-07-27 08:16:28 +00:00
return
}
2021-08-04 07:31:06 +00:00
return rs.GetRemoteStorageClient(storageLocation.Name)
}
func (rs *FilerRemoteStorage) GetRemoteStorageClient(storageName string) (client remote_storage.RemoteStorageClient, remoteConf *filer_pb.RemoteConf, found bool) {
remoteConf, found = rs.storageNameToConf[storageName]
if !found {
2021-07-27 08:16:28 +00:00
return
}
var err error
if client, err = remote_storage.GetRemoteStorage(remoteConf); err == nil {
found = true
return
}
return
}
2021-07-27 10:26:35 +00:00
2021-08-01 05:39:38 +00:00
func UnmarshalRemoteStorageMappings(oldContent []byte) (mappings *filer_pb.RemoteStorageMapping, err error) {
mappings = &filer_pb.RemoteStorageMapping{
Mappings: make(map[string]*filer_pb.RemoteStorageLocation),
2021-07-27 10:26:35 +00:00
}
if len(oldContent) > 0 {
if err = proto.Unmarshal(oldContent, mappings); err != nil {
glog.Warningf("unmarshal existing mappings: %v", err)
2021-07-27 10:26:35 +00:00
}
}
2021-08-01 05:39:38 +00:00
return
}
func AddRemoteStorageMapping(oldContent []byte, dir string, storageLocation *filer_pb.RemoteStorageLocation) (newContent []byte, err error) {
mappings, unmarshalErr := UnmarshalRemoteStorageMappings(oldContent)
if unmarshalErr != nil {
// skip
}
2021-07-27 10:26:35 +00:00
// set the new mapping
mappings.Mappings[dir] = storageLocation
2021-07-27 10:26:35 +00:00
if newContent, err = proto.Marshal(mappings); err != nil {
return oldContent, fmt.Errorf("marshal mappings: %v", err)
2021-07-27 10:26:35 +00:00
}
return
2021-08-04 23:25:46 +00:00
}
2021-08-09 05:26:37 +00:00
func RemoveRemoteStorageMapping(oldContent []byte, dir string) (newContent []byte, err error) {
mappings, unmarshalErr := UnmarshalRemoteStorageMappings(oldContent)
if unmarshalErr != nil {
return nil, unmarshalErr
}
// set the new mapping
delete(mappings.Mappings, dir)
if newContent, err = proto.Marshal(mappings); err != nil {
return oldContent, fmt.Errorf("marshal mappings: %v", err)
}
return
}
2021-08-04 23:25:46 +00:00
func ReadMountMappings(grpcDialOption grpc.DialOption, filerAddress string) (mappings *filer_pb.RemoteStorageMapping, readErr error) {
var oldContent []byte
if readErr = pb.WithFilerClient(filerAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
oldContent, readErr = ReadInsideFiler(client, DirectoryEtcRemote, REMOTE_STORAGE_MOUNT_FILE)
return readErr
}); readErr != nil {
return nil, readErr
}
mappings, readErr = UnmarshalRemoteStorageMappings(oldContent)
if readErr != nil {
return nil, fmt.Errorf("unmarshal mappings: %v", readErr)
}
return
}
func ReadRemoteStorageConf(grpcDialOption grpc.DialOption, filerAddress string, storageName string) (conf *filer_pb.RemoteConf, readErr error) {
var oldContent []byte
if readErr = pb.WithFilerClient(filerAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
oldContent, readErr = ReadInsideFiler(client, DirectoryEtcRemote, storageName+REMOTE_STORAGE_CONF_SUFFIX)
return readErr
}); readErr != nil {
return nil, readErr
}
// unmarshal storage configuration
conf = &filer_pb.RemoteConf{}
if unMarshalErr := proto.Unmarshal(oldContent, conf); unMarshalErr != nil {
readErr = fmt.Errorf("unmarshal %s/%s: %v", DirectoryEtcRemote, storageName+REMOTE_STORAGE_CONF_SUFFIX, unMarshalErr)
return
}
return
}
func DetectMountInfo(grpcDialOption grpc.DialOption, filerAddress string, dir string) (*filer_pb.RemoteStorageMapping, string, *filer_pb.RemoteStorageLocation, *filer_pb.RemoteConf, error) {
mappings, listErr := ReadMountMappings(grpcDialOption, filerAddress)
if listErr != nil {
return nil, "", nil, nil, listErr
}
if dir == "" {
return mappings, "", nil, nil, fmt.Errorf("need to specify '-dir' option")
}
var localMountedDir string
var remoteStorageMountedLocation *filer_pb.RemoteStorageLocation
for k, loc := range mappings.Mappings {
if strings.HasPrefix(dir, k) {
localMountedDir, remoteStorageMountedLocation = k, loc
}
}
if localMountedDir == "" {
return mappings, localMountedDir, remoteStorageMountedLocation, nil, fmt.Errorf("%s is not mounted", dir)
}
// find remote storage configuration
remoteStorageConf, err := ReadRemoteStorageConf(grpcDialOption, filerAddress, remoteStorageMountedLocation.Name)
if err != nil {
return mappings, localMountedDir, remoteStorageMountedLocation, remoteStorageConf, err
}
return mappings, localMountedDir, remoteStorageMountedLocation, remoteStorageConf, nil
}