dragonfly/cdnsystem/daemon/cdn/storage/disk/disk.go

236 lines
7.8 KiB
Go

/*
* Copyright 2020 The Dragonfly Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package disk
import (
"encoding/json"
"fmt"
"io"
"strings"
"time"
"d7y.io/dragonfly/v2/cdnsystem/daemon"
"d7y.io/dragonfly/v2/cdnsystem/daemon/cdn/storage"
"d7y.io/dragonfly/v2/cdnsystem/daemon/gc"
cdnerrors "d7y.io/dragonfly/v2/cdnsystem/errors"
"d7y.io/dragonfly/v2/cdnsystem/storedriver"
"d7y.io/dragonfly/v2/cdnsystem/storedriver/local"
"d7y.io/dragonfly/v2/cdnsystem/types"
logger "d7y.io/dragonfly/v2/internal/dflog"
"d7y.io/dragonfly/v2/pkg/synclock"
"d7y.io/dragonfly/v2/pkg/unit"
"d7y.io/dragonfly/v2/pkg/util/fileutils"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const StorageMode = storage.DiskStorageMode
var (
_ gc.Executor = (*diskStorageMgr)(nil)
_ storage.Manager = (*diskStorageMgr)(nil)
)
func init() {
storage.Register(StorageMode, newStorageManager)
}
func newStorageManager(cfg *storage.Config) (storage.Manager, error) {
if len(cfg.DriverConfigs) != 1 {
return nil, fmt.Errorf("disk storage manager should have only one disk driver, cfg's driver number is wrong config: %v", cfg)
}
diskDriver, ok := storedriver.Get(local.DiskDriverName)
if !ok {
return nil, fmt.Errorf("can not find disk driver for disk storage manager, config is %#v", cfg)
}
storageMgr := &diskStorageMgr{
cfg: cfg,
diskDriver: diskDriver,
}
gc.Register("diskStorage", cfg.GCInitialDelay, cfg.GCInterval, storageMgr)
return storageMgr, nil
}
type diskStorageMgr struct {
cfg *storage.Config
diskDriver storedriver.Driver
cleaner *storage.Cleaner
taskMgr daemon.SeedTaskMgr
}
func (s *diskStorageMgr) getDefaultGcConfig() *storage.GCConfig {
totalSpace, err := s.diskDriver.GetTotalSpace()
if err != nil {
logger.GcLogger.With("type", "disk").Errorf("get total space of disk: %v", err)
}
yongGcThreshold := 200 * unit.GB
if totalSpace > 0 && totalSpace/4 < yongGcThreshold {
yongGcThreshold = totalSpace / 4
}
return &storage.GCConfig{
YoungGCThreshold: yongGcThreshold,
FullGCThreshold: 25 * unit.GB,
IntervalThreshold: 2 * time.Hour,
CleanRatio: 1,
}
}
func (s *diskStorageMgr) Initialize(taskMgr daemon.SeedTaskMgr) {
s.taskMgr = taskMgr
diskGcConfig := s.cfg.DriverConfigs[local.DiskDriverName].GCConfig
if diskGcConfig == nil {
diskGcConfig = s.getDefaultGcConfig()
logger.GcLogger.With("type", "disk").Warnf("disk gc config is nil, use default gcConfig: %v", diskGcConfig)
}
s.cleaner, _ = storage.NewStorageCleaner(diskGcConfig, s.diskDriver, s, taskMgr)
}
func (s *diskStorageMgr) AppendPieceMetaData(taskID string, pieceRecord *storage.PieceMetaRecord) error {
return s.diskDriver.PutBytes(storage.GetAppendPieceMetaDataRaw(taskID), []byte(pieceRecord.String()+"\n"))
}
func (s *diskStorageMgr) ReadPieceMetaRecords(taskID string) ([]*storage.PieceMetaRecord, error) {
readBytes, err := s.diskDriver.GetBytes(storage.GetPieceMetaDataRaw(taskID))
if err != nil {
return nil, err
}
pieceMetaRecords := strings.Split(strings.TrimSpace(string(readBytes)), "\n")
var result = make([]*storage.PieceMetaRecord, 0, len(pieceMetaRecords))
for _, pieceStr := range pieceMetaRecords {
record, err := storage.ParsePieceMetaRecord(pieceStr)
if err != nil {
return nil, errors.Wrapf(err, "get piece meta record: %v", pieceStr)
}
result = append(result, record)
}
return result, nil
}
func (s *diskStorageMgr) GC() error {
logger.GcLogger.With("type", "disk").Info("start the disk storage gc job")
gcTaskIDs, err := s.cleaner.GC("disk", false)
if err != nil {
logger.GcLogger.With("type", "disk").Error("failed to get gcTaskIDs")
}
var realGCCount int
for _, taskID := range gcTaskIDs {
synclock.Lock(taskID, false)
// try to ensure the taskID is not using again
if _, err := s.taskMgr.Get(taskID); err == nil || !cdnerrors.IsDataNotFound(err) {
if err != nil {
logger.GcLogger.With("type", "disk").Errorf("failed to get taskID(%s): %v", taskID, err)
}
synclock.UnLock(taskID, false)
continue
}
realGCCount++
if err := s.DeleteTask(taskID); err != nil {
logger.GcLogger.With("type", "disk").Errorf("failed to delete disk files with taskID(%s): %v", taskID, err)
synclock.UnLock(taskID, false)
continue
}
synclock.UnLock(taskID, false)
}
logger.GcLogger.With("type", "disk").Infof("at most %d tasks can be cleaned up, actual gc %d tasks", len(gcTaskIDs), realGCCount)
return nil
}
func (s *diskStorageMgr) WriteDownloadFile(taskID string, offset int64, len int64, data io.Reader) error {
raw := storage.GetDownloadRaw(taskID)
raw.Offset = offset
raw.Length = len
return s.diskDriver.Put(raw, data)
}
func (s *diskStorageMgr) ReadFileMetaData(taskID string) (*storage.FileMetaData, error) {
bytes, err := s.diskDriver.GetBytes(storage.GetTaskMetaDataRaw(taskID))
if err != nil {
return nil, errors.Wrapf(err, "get metadata bytes")
}
metaData := &storage.FileMetaData{}
if err := json.Unmarshal(bytes, metaData); err != nil {
return nil, errors.Wrapf(err, "unmarshal metadata bytes")
}
return metaData, nil
}
func (s *diskStorageMgr) WriteFileMetaData(taskID string, metaData *storage.FileMetaData) error {
data, err := json.Marshal(metaData)
if err != nil {
return errors.Wrapf(err, "marshal metadata")
}
return s.diskDriver.PutBytes(storage.GetTaskMetaDataRaw(taskID), data)
}
func (s *diskStorageMgr) WritePieceMetaRecords(taskID string, records []*storage.PieceMetaRecord) error {
recordStrs := make([]string, 0, len(records))
for i := range records {
recordStrs = append(recordStrs, records[i].String())
}
pieceRaw := storage.GetPieceMetaDataRaw(taskID)
pieceRaw.Trunc = true
pieceRaw.TruncSize = 0
return s.diskDriver.PutBytes(pieceRaw, []byte(strings.Join(recordStrs, "\n")))
}
func (s *diskStorageMgr) ReadPieceMetaBytes(taskID string) ([]byte, error) {
return s.diskDriver.GetBytes(storage.GetPieceMetaDataRaw(taskID))
}
func (s *diskStorageMgr) ReadDownloadFile(taskID string) (io.ReadCloser, error) {
return s.diskDriver.Get(storage.GetDownloadRaw(taskID))
}
func (s *diskStorageMgr) StatDownloadFile(taskID string) (*storedriver.StorageInfo, error) {
return s.diskDriver.Stat(storage.GetDownloadRaw(taskID))
}
func (s *diskStorageMgr) CreateUploadLink(taskID string) error {
// create a soft link from the upload file to the download file
if err := fileutils.SymbolicLink(s.diskDriver.GetPath(storage.GetDownloadRaw(taskID)),
s.diskDriver.GetPath(storage.GetUploadRaw(taskID))); err != nil {
return err
}
return nil
}
func (s *diskStorageMgr) DeleteTask(taskID string) error {
if err := s.diskDriver.Remove(storage.GetTaskMetaDataRaw(taskID)); err != nil && !cdnerrors.IsFileNotExist(err) {
return err
}
if err := s.diskDriver.Remove(storage.GetPieceMetaDataRaw(taskID)); err != nil && !cdnerrors.IsFileNotExist(err) {
return err
}
if err := s.diskDriver.Remove(storage.GetDownloadRaw(taskID)); err != nil && !cdnerrors.IsFileNotExist(err) {
return err
}
if err := s.diskDriver.Remove(storage.GetUploadRaw(taskID)); err != nil && !cdnerrors.IsFileNotExist(err) {
return err
}
// try to clean the parent bucket
if err := s.diskDriver.Remove(storage.GetParentRaw(taskID)); err != nil && !cdnerrors.IsFileNotExist(err) {
logrus.Warnf("taskID: %s failed remove parent bucket: %v", taskID, err)
}
return nil
}
func (s *diskStorageMgr) ResetRepo(task *types.SeedTask) error {
return s.DeleteTask(task.TaskID)
}