fix(fileinfo_store): refactor file info store

This commit is contained in:
hexxa 2022-03-24 16:44:34 +08:00 committed by Hexxa
parent d65f1c4356
commit 41827f20c0
7 changed files with 194 additions and 175 deletions

View file

@ -116,7 +116,7 @@ func (bs *BoltStore) setUploadInfo(tx *bolt.Tx, userID uint64, uploadPath string
func (bs *BoltStore) getFileInfo(tx *bolt.Tx, userID uint64, itemPath string) (*db.FileInfo, error) {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
fileInfoBucket := tx.Bucket([]byte(db.FileInfoNs))
if fileInfoBucket == nil {
return nil, db.ErrBucketNotFound
}
@ -137,7 +137,7 @@ func (bs *BoltStore) getFileInfo(tx *bolt.Tx, userID uint64, itemPath string) (*
func (bs *BoltStore) setFileInfo(tx *bolt.Tx, userID uint64, itemPath string, fileInfo *db.FileInfo) error {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
fileInfoBucket := tx.Bucket([]byte(db.FileInfoNs))
if fileInfoBucket == nil {
return db.ErrBucketNotFound
}
@ -290,7 +290,7 @@ func (bs *BoltStore) DelInfos(userID uint64, itemPath string, isDir bool) error
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
fileInfoBucket := tx.Bucket([]byte(db.FileInfoNs))
if fileInfoBucket == nil {
return db.ErrBucketNotFound
}
@ -339,7 +339,7 @@ func (bs *BoltStore) MoveInfos(userID uint64, oldPath, newPath string, isDir boo
return bs.boltdb.Update(func(tx *bolt.Tx) error {
var err error
fileInfoBucket := tx.Bucket([]byte(db.InfoNs))
fileInfoBucket := tx.Bucket([]byte(db.FileInfoNs))
if fileInfoBucket == nil {
return db.ErrBucketNotFound
}

View file

@ -10,10 +10,11 @@ const (
SchemaV2 = "v2" // add size to file info
UserSchemaNs = "UserSchemaNs"
FileSchemaNs = "FileSchemaNs"
UserIDsNs = "UserIDsNs"
UsersNs = "UsersNs"
RolesNs = "RolesNs"
InfoNs = "InfoNs"
FileInfoNs = "FileInfoNs"
ShareIDNs = "ShareIDNs"
uploadsPrefix = "uploads"
@ -290,17 +291,17 @@ func CheckBgConfig(cfg *BgConfig, fillDefault bool) error {
func CheckUser(user *User, fillDefault bool) error {
if user.ID == 0 && user.Role != AdminRole {
return ErrInvalidUser
return fmt.Errorf("invalid ID: (%w)", ErrInvalidUser)
}
// TODO: add length check
if user.Name == "" || user.Pwd == "" || user.Role == "" {
return ErrInvalidUser
if user.Name == "" || user.Role == "" {
return fmt.Errorf("invalid Name/pwd/role: (%w)", ErrInvalidUser)
}
if user.UsedSpace < 0 {
return ErrInvalidUser
return fmt.Errorf("invalid UsedSpace: (%w)", ErrInvalidUser)
}
if user.Quota == nil || user.Preferences == nil {
return ErrInvalidUser
return fmt.Errorf("invalid Quota: (%w)", ErrInvalidUser)
}
var err error

View file

@ -11,7 +11,6 @@ import (
"github.com/ihexxa/quickshare/src/db"
"github.com/ihexxa/quickshare/src/kvstore"
"github.com/ihexxa/quickshare/src/kvstore/boltdbpvd"
)
const (
@ -50,16 +49,15 @@ type IFileInfoStore interface {
}
type FileInfoStore struct {
mtx *sync.RWMutex
store kvstore.IKVStore
boltdb boltdbpvd.BoltProvider
mtx *sync.RWMutex
store kvstore.IKVStore
}
func NewFileInfoStore(store kvstore.IKVStore) (*FileInfoStore, error) {
var err error
for _, nsName := range []string{
InitNs,
db.InfoNs,
db.FileSchemaNs,
db.FileInfoNs,
db.ShareIDNs,
} {
if !store.HasNamespace(nsName) {
@ -69,115 +67,15 @@ func NewFileInfoStore(store kvstore.IKVStore) (*FileInfoStore, error) {
}
}
boltdb := store.(boltdbpvd.BoltProvider)
fi := &FileInfoStore{
store: store,
boltdb: boltdb,
mtx: &sync.RWMutex{},
store: store,
mtx: &sync.RWMutex{},
}
return fi, nil
}
func (fi *FileInfoStore) AddSharing(dirPath string) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
info, err := fi.GetInfo(dirPath)
if err != nil {
if !errors.Is(err, ErrNotFound) {
return err
}
info = &db.FileInfo{
IsDir: true,
}
}
// TODO: ensure Atomicity
shareID, err := fi.getShareID(dirPath)
if err != nil {
return err
}
err = fi.store.SetStringIn(db.ShareIDNs, shareID, dirPath)
if err != nil {
return err
}
info.Shared = true
info.ShareID = shareID
return fi.SetInfo(dirPath, info)
}
func (fi *FileInfoStore) DelSharing(dirPath string) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
info, err := fi.GetInfo(dirPath)
if err != nil {
return err
}
// TODO: ensure Atomicity
// In the bolt, if the key does not exist
// then nothing is done and a nil error is returned
// because before this version, shareIDs are not removed correctly
// so it iterates all shareIDs and cleans remaining entries
shareIDtoDir, err := fi.store.ListStringsIn(db.ShareIDNs)
if err != nil {
return err
}
for shareID, shareDir := range shareIDtoDir {
if shareDir == dirPath {
err = fi.store.DelStringIn(db.ShareIDNs, shareID)
if err != nil {
return err
}
}
}
info.ShareID = ""
info.Shared = false
return fi.SetInfo(dirPath, info)
}
func (fi *FileInfoStore) GetSharing(dirPath string) (bool, bool) {
fi.mtx.Lock()
defer fi.mtx.Unlock()
// TODO: differentiate error and not exist
info, err := fi.GetInfo(dirPath)
if err != nil {
return false, false
}
return info.IsDir && info.Shared, true
}
func (fi *FileInfoStore) ListSharings(prefix string) (map[string]string, error) {
infoStrs, err := fi.store.ListStringsByPrefixIn(prefix, db.InfoNs)
if err != nil {
return nil, err
}
info := &db.FileInfo{}
sharings := map[string]string{}
for itemPath, infoStr := range infoStrs {
err = json.Unmarshal([]byte(infoStr), info)
if err != nil {
return nil, fmt.Errorf("list sharing error: %w", err)
}
if info.IsDir && info.Shared {
sharings[itemPath] = info.ShareID
}
}
return sharings, nil
}
func (fi *FileInfoStore) GetInfo(itemPath string) (*db.FileInfo, error) {
infoStr, ok := fi.store.GetStringIn(db.InfoNs, itemPath)
func (fi *FileInfoStore) getInfo(itemPath string) (*db.FileInfo, error) {
infoStr, ok := fi.store.GetStringIn(db.FileInfoNs, itemPath)
if !ok {
return nil, ErrNotFound
}
@ -190,10 +88,14 @@ func (fi *FileInfoStore) GetInfo(itemPath string) (*db.FileInfo, error) {
return info, nil
}
func (fi *FileInfoStore) GetInfo(itemPath string) (*db.FileInfo, error) {
return fi.getInfo(itemPath)
}
func (fi *FileInfoStore) GetInfos(itemPaths []string) (map[string]*db.FileInfo, error) {
infos := map[string]*db.FileInfo{}
for _, itemPath := range itemPaths {
info, err := fi.GetInfo(itemPath)
info, err := fi.getInfo(itemPath)
if err != nil {
if !errors.Is(err, ErrNotFound) {
return nil, err
@ -206,28 +108,34 @@ func (fi *FileInfoStore) GetInfos(itemPaths []string) (map[string]*db.FileInfo,
return infos, nil
}
func (fi *FileInfoStore) SetInfo(itemPath string, info *db.FileInfo) error {
func (fi *FileInfoStore) setInfo(itemPath string, info *db.FileInfo) error {
infoStr, err := json.Marshal(info)
if err != nil {
return fmt.Errorf("set file info: %w", err)
}
err = fi.store.SetStringIn(db.InfoNs, itemPath, string(infoStr))
err = fi.store.SetStringIn(db.FileInfoNs, itemPath, string(infoStr))
if err != nil {
return fmt.Errorf("set file info: %w", err)
}
return nil
}
func (fi *FileInfoStore) DelInfo(itemPath string) error {
return fi.store.DelStringIn(db.InfoNs, itemPath)
func (fi *FileInfoStore) SetInfo(itemPath string, info *db.FileInfo) error {
return fi.setInfo(itemPath, info)
}
func (fi *FileInfoStore) DelInfo(itemPath string) error {
return fi.store.DelStringIn(db.FileInfoNs, itemPath)
}
// sharings
func (fi *FileInfoStore) SetSha1(itemPath, sign string) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
info, err := fi.GetInfo(itemPath)
info, err := fi.getInfo(itemPath)
if err != nil {
if !errors.Is(err, ErrNotFound) {
return err
@ -238,7 +146,7 @@ func (fi *FileInfoStore) SetSha1(itemPath, sign string) error {
}
}
info.Sha1 = sign
return fi.SetInfo(itemPath, info)
return fi.setInfo(itemPath, info)
}
func (fi *FileInfoStore) getShareID(payload string) (string, error) {
@ -273,3 +181,100 @@ func (fi *FileInfoStore) GetSharingDir(hashID string) (string, error) {
}
return dirPath, nil
}
func (fi *FileInfoStore) AddSharing(dirPath string) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
info, err := fi.getInfo(dirPath)
if err != nil {
if !errors.Is(err, ErrNotFound) {
return err
}
info = &db.FileInfo{
IsDir: true,
}
}
// TODO: ensure Atomicity
shareID, err := fi.getShareID(dirPath)
if err != nil {
return err
}
err = fi.store.SetStringIn(db.ShareIDNs, shareID, dirPath)
if err != nil {
return err
}
info.Shared = true
info.ShareID = shareID
return fi.setInfo(dirPath, info)
}
func (fi *FileInfoStore) DelSharing(dirPath string) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
info, err := fi.getInfo(dirPath)
if err != nil {
return err
}
// TODO: ensure Atomicity
// In the bolt, if the key does not exist
// then nothing is done and a nil error is returned
// because before this version, shareIDs are not removed correctly
// so it iterates all shareIDs and cleans remaining entries
shareIDtoDir, err := fi.store.ListStringsIn(db.ShareIDNs)
if err != nil {
return err
}
for shareID, shareDir := range shareIDtoDir {
if shareDir == dirPath {
err = fi.store.DelStringIn(db.ShareIDNs, shareID)
if err != nil {
return err
}
}
}
info.ShareID = ""
info.Shared = false
return fi.setInfo(dirPath, info)
}
func (fi *FileInfoStore) GetSharing(dirPath string) (bool, bool) {
fi.mtx.Lock()
defer fi.mtx.Unlock()
// TODO: differentiate error and not exist
info, err := fi.getInfo(dirPath)
if err != nil {
return false, false
}
return info.IsDir && info.Shared, true
}
func (fi *FileInfoStore) ListSharings(prefix string) (map[string]string, error) {
infoStrs, err := fi.store.ListStringsByPrefixIn(prefix, db.FileInfoNs)
if err != nil {
return nil, err
}
info := &db.FileInfo{}
sharings := map[string]string{}
for itemPath, infoStr := range infoStrs {
err = json.Unmarshal([]byte(infoStr), info)
if err != nil {
return nil, fmt.Errorf("list sharing error: %w", err)
}
if info.IsDir && info.Shared {
sharings[itemPath] = info.ShareID
}
}
return sharings, nil
}

View file

@ -1,6 +1,7 @@
package fileinfostore
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
@ -140,7 +141,7 @@ func TestUserStores(t *testing.T) {
// get infos
for itemPath := range pathInfos {
_, err := store.GetInfo(itemPath)
if !IsNotFound(err) {
if !errors.Is(err, ErrNotFound) {
t.Fatal(err)
}
}

View file

@ -12,52 +12,7 @@ var (
ErrUploadNotFound = errors.New("upload info not found")
)
func (fi *FileInfoStore) AddUploadInfo(user, filePath, tmpPath string, fileSize int64) error {
ns := db.UploadNS(user)
err := fi.store.AddNamespace(ns)
if err != nil {
return err
}
_, ok := fi.store.GetStringIn(ns, tmpPath)
if ok {
return db.ErrCreateExisting
}
info := &db.UploadInfo{
RealFilePath: filePath,
Size: fileSize,
Uploaded: 0,
}
infoBytes, err := json.Marshal(info)
if err != nil {
return err
}
return fi.store.SetStringIn(ns, tmpPath, string(infoBytes))
}
func (fi *FileInfoStore) SetUploadInfo(user, filePath string, newUploaded int64) error {
realFilePath, fileSize, _, err := fi.GetUploadInfo(user, filePath)
if err != nil {
return err
} else if newUploaded > fileSize {
return ErrGreaterThanSize
}
newInfo := &db.UploadInfo{
RealFilePath: realFilePath,
Size: fileSize,
Uploaded: newUploaded,
}
newInfoBytes, err := json.Marshal(newInfo)
if err != nil {
return err
}
return fi.store.SetStringIn(db.UploadNS(user), filePath, string(newInfoBytes))
}
func (fi *FileInfoStore) GetUploadInfo(user, filePath string) (string, int64, int64, error) {
func (fi *FileInfoStore) getUploadInfo(user, filePath string) (string, int64, int64, error) {
ns := db.UploadNS(user)
infoBytes, ok := fi.store.GetStringIn(ns, filePath)
if !ok {
@ -73,6 +28,61 @@ func (fi *FileInfoStore) GetUploadInfo(user, filePath string) (string, int64, in
return info.RealFilePath, info.Size, info.Uploaded, nil
}
func (fi *FileInfoStore) setUploadInfo(user, filePath string, info *db.UploadInfo) error {
newInfoBytes, err := json.Marshal(info)
if err != nil {
return err
}
return fi.store.SetStringIn(db.UploadNS(user), filePath, string(newInfoBytes))
}
func (fi *FileInfoStore) AddUploadInfo(user, filePath, tmpPath string, fileSize int64) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
ns := db.UploadNS(user)
err := fi.store.AddNamespace(ns)
if err != nil {
return err
}
_, _, _, err = fi.getUploadInfo(user, tmpPath)
if err == nil {
return db.ErrCreateExisting
}
return fi.setUploadInfo(user, filePath, &db.UploadInfo{
RealFilePath: filePath,
Size: fileSize,
Uploaded: 0,
})
}
func (fi *FileInfoStore) SetUploadInfo(user, filePath string, newUploaded int64) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
realFilePath, fileSize, _, err := fi.getUploadInfo(user, filePath)
if err != nil {
return err
} else if newUploaded > fileSize {
return ErrGreaterThanSize
}
return fi.setUploadInfo(user, filePath, &db.UploadInfo{
RealFilePath: realFilePath,
Size: fileSize,
Uploaded: newUploaded,
})
}
func (fi *FileInfoStore) GetUploadInfo(user, filePath string) (string, int64, int64, error) {
fi.mtx.Lock()
defer fi.mtx.Unlock()
return fi.getUploadInfo(user, filePath)
}
func (fi *FileInfoStore) DelUploadInfo(user, filePath string) error {
return fi.store.DelInt64In(db.UploadNS(user), filePath)
}

View file

@ -32,7 +32,6 @@ type IUserStore interface {
GetUser(id uint64) (*db.User, error)
GetUserByName(name string) (*db.User, error)
SetInfo(id uint64, user *db.User) error
// CanIncrUsed(id uint64, capacity int64) (bool, error)
SetUsed(id uint64, incr bool, capacity int64) error
ResetUsed(id uint64, used int64) error
SetPwd(id uint64, pwd string) error
@ -322,6 +321,9 @@ func (us *KVUserStore) ListUsers() ([]*db.User, error) {
}
user.Pwd = ""
if err = db.CheckUser(user, true); err != nil {
return nil, err
}
users = append(users, user)
}

Binary file not shown.