package redis_lua import ( "context" "fmt" "github.com/redis/go-redis/v9" "robotfs/pb" "robotfs/store" "robotfs/store/redis_lua/stored_procedure" "robotfs/utils" ) const ( DIR_LIST_MARKER = "\x00" ) type UniversalRedisLuaStore struct { Client redis.UniversalClient superLargeDirectoryHash map[string]bool } func (store *UniversalRedisLuaStore) isSuperLargeDirectory(dir string) (isSuperLargeDirectory bool) { _, isSuperLargeDirectory = store.superLargeDirectoryHash[dir] return } func (store *UniversalRedisLuaStore) loadSuperLargeDirectories(superLargeDirectories []string) { store.superLargeDirectoryHash = make(map[string]bool) for _, dir := range superLargeDirectories { store.superLargeDirectoryHash[dir] = true } } func (store *UniversalRedisLuaStore) BeginTransaction(ctx context.Context) (context.Context, error) { return ctx, nil } func (store *UniversalRedisLuaStore) CommitTransaction(ctx context.Context) error { return nil } func (store *UniversalRedisLuaStore) RollbackTransaction(ctx context.Context) error { return nil } func (store *UniversalRedisLuaStore) InsertEntry(ctx context.Context, entry *pb.FileEntry) (err error) { // value, err := entry.EncodeAttributesAndChunks() // if err != nil { // return fmt.Errorf("encoding %s %+v: %v", entry.FullPath, entry.Attr, err) // } // if len(entry.GetChunks()) > CountEntryChunksForGzip { // value = util.MaybeGzipData(value) // } // dir, name := entry.FullPath.DirAndName() // err = stored_procedure.InsertEntryScript.Run(ctx, store.Client, // []string{string(entry.FullPath), genDirectoryListKey(dir)}, // value, entry.TtlSec, // store.isSuperLargeDirectory(dir), 0, name).Err() // if err != nil { // return fmt.Errorf("persisting %s : %v", entry.FullPath, err) // } return nil } func (store *UniversalRedisLuaStore) UpdateEntry(ctx context.Context, entry *pb.FileEntry) (err error) { return store.InsertEntry(ctx, entry) } func (store *UniversalRedisLuaStore) FindEntry(ctx context.Context, fullpath utils.FullPath) (entry *pb.FileEntry, err error) { // data, err := store.Client.Get(ctx, string(fullpath)).Result() // if err == redis.Nil { // return nil, pb.ErrNotFound // } // if err != nil { // return nil, fmt.Errorf("get %s : %v", fullpath, err) // } // entry = &pb.FileEntry{ // FullPath: fullpath.Name(), // } // err = entry.DecodeAttributesAndChunks(util.MaybeDecompressData([]byte(data))) // if err != nil { // return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err) // } return entry, nil } func (store *UniversalRedisLuaStore) DeleteEntry(ctx context.Context, fullpath utils.FullPath) (err error) { dir, name := fullpath.DirAndName() err = stored_procedure.DeleteEntryScript.Run(ctx, store.Client, []string{string(fullpath), genDirectoryListKey(string(fullpath)), genDirectoryListKey(dir)}, store.isSuperLargeDirectory(dir), name).Err() if err != nil { return fmt.Errorf("DeleteEntry %s : %v", fullpath, err) } return nil } func (store *UniversalRedisLuaStore) DeleteFolderChildren(ctx context.Context, fullpath utils.FullPath) (err error) { if store.isSuperLargeDirectory(string(fullpath)) { return nil } err = stored_procedure.DeleteFolderChildrenScript.Run(ctx, store.Client, []string{string(fullpath)}).Err() if err != nil { return fmt.Errorf("DeleteFolderChildren %s : %v", fullpath, err) } return nil } func (store *UniversalRedisLuaStore) ListDirectoryPrefixedEntries(ctx context.Context, dirPath utils.FullPath, startFileName string, includeStartFile bool, limit int64, prefix string, eachEntryFunc store.ListEachEntryFunc) (lastFileName string, err error) { // return lastFileName, engine.ErrUnsupportedListDirectoryPrefixed return lastFileName, err } func (store *UniversalRedisLuaStore) ListDirectoryEntries(ctx context.Context, dirPath utils.FullPath, startFileName string, includeStartFile bool, limit int64, eachEntryFunc store.ListEachEntryFunc) (lastFileName string, err error) { // dirListKey := genDirectoryListKey(string(dirPath)) // min := "-" // if startFileName != "" { // if includeStartFile { // min = "[" + startFileName // } else { // min = "(" + startFileName // } // } // members, err := store.Client.ZRangeByLex(ctx, dirListKey, &redis.ZRangeBy{ // Min: min, // Max: "+", // Offset: 0, // Count: limit, // }).Result() // if err != nil { // return lastFileName, fmt.Errorf("list %s : %v", dirPath, err) // } // // fetch entry meta // for _, fileName := range members { // path := utils.NewFullPath(string(dirPath), fileName) // entry, err := store.FindEntry(ctx, path) // lastFileName = fileName // if err != nil { // if err == pb.ErrNotFound { // continue // } // } else { // if entry.TtlSec > 0 { // if entry.Attr.Crtime.Add(time.Duration(entry.TtlSec) * time.Second).Before(time.Now()) { // store.DeleteEntry(ctx, path) // continue // } // } // if !eachEntryFunc(entry) { // break // } // } // } return lastFileName, err } func genDirectoryListKey(dir string) (dirList string) { return dir + DIR_LIST_MARKER } func (store *UniversalRedisLuaStore) Shutdown() { store.Client.Close() }