complete task 17: add tidy mode

This commit is contained in:
kingecg 2025-06-08 10:31:34 +08:00
parent b70a38e4b1
commit dfa34016e5
5 changed files with 139 additions and 30 deletions

View File

@ -2,7 +2,6 @@ package document
import (
"fmt"
"os"
"strings"
"sync"
@ -20,19 +19,15 @@ type DocumentStore struct {
}
// NewDocumentStore 创建新的文档存储实例
func NewDocumentStore(path string) (*DocumentStore, error) {
// 确保目录存在
if err := os.MkdirAll(path, 0755); err != nil {
return nil, fmt.Errorf("failed to create storage directory: %v", err)
}
storage, err := storage.NewLevelDBStorage(path)
func NewDocumentStore(storeName string) (*DocumentStore, error) {
sm := storage.GetInstance()
storage, err := sm.GetStorage(storeName)
if err != nil {
return nil, fmt.Errorf("failed to create LevelDB storage: %v", err)
}
// 创建关联的索引存储
is, err := index.NewIndexStore(path)
is, err := index.NewIndexStore(storeName)
if err != nil {
storage.Close()
return nil, fmt.Errorf("failed to create index store: %v", err)

View File

@ -3,8 +3,12 @@ package document
import (
"fmt"
"os"
"path/filepath"
"sync"
"testing"
"git.pyer.club/kingecg/godocdb/storage"
"git.pyer.club/kingecg/godocdb/utils"
)
// 测试用结构体
@ -14,13 +18,20 @@ type TestDoc struct {
Age int `bson:"age"`
}
func TestMain(m *testing.M) {
projectRoot := utils.GetProjectRootDir()
dir := filepath.Join(projectRoot, "test_data")
defer os.RemoveAll(dir)
storage.NewStorageManager(dir, 0)
m.Run()
storage.GetInstance().Close()
}
func TestDocumentStore(t *testing.T) {
// 测试目录
dir := "./testdb"
defer os.RemoveAll(dir)
// 初始化文档存储
ds, err := NewDocumentStore(dir)
ds, err := NewDocumentStore("test")
if err != nil {
t.Fatalf("Failed to create document store: %v", err)
}
@ -57,11 +68,8 @@ func TestDocumentStore(t *testing.T) {
}
func TestErrorHandling(t *testing.T) {
// 测试无效文档(包含不支持的类型)
dir := "./testdb_error"
defer os.RemoveAll(dir)
ds, _ := NewDocumentStore(dir)
ds, _ := NewDocumentStore("test_error")
// 测试存储非map文档
invalidDoc := struct {
@ -80,8 +88,7 @@ func TestErrorHandling(t *testing.T) {
func TestConcurrentAccess(t *testing.T) {
// 测试并发写入同一ID
dir := "./testdb_concurrent"
defer os.RemoveAll(dir)
dir := "testdb_concurrent"
numGoroutines := 10
var wg sync.WaitGroup
@ -91,7 +98,7 @@ func TestConcurrentAccess(t *testing.T) {
if err != nil {
t.Fatalf("Failed to create document store: %v", err)
}
defer ds.storage.Close()
// defer ds.storage.Close()
wg.Add(numGoroutines)

View File

@ -3,7 +3,6 @@ package index
import (
"bytes"
"fmt"
"os"
"strings"
"sync"
@ -44,20 +43,14 @@ type IndexStore struct {
}
// NewIndexStore 创建新的索引存储实例
func NewIndexStore(path string) (*IndexStore, error) {
func NewIndexStore(storeName string) (*IndexStore, error) {
// 确保目录存在
if strings.HasPrefix(path, "/") {
path = strings.TrimSuffix(path, "/")
}
if !strings.HasSuffix(path, "_index") {
if !strings.HasSuffix(storeName, "_index") {
// add _index suffix to avoid name confilict with document store, do remove this
path += "_index"
}
if err := os.MkdirAll(path, 0755); err != nil {
return nil, fmt.Errorf("failed to create storage directory: %v", err)
storeName += "_index"
}
storage, err := storage.NewLevelDBStorage(path)
storage, err := storage.GetInstance().GetStorage(storeName)
if err != nil {
return nil, fmt.Errorf("failed to create LevelDB storage: %v", err)
}

79
storage/storage.go Normal file
View File

@ -0,0 +1,79 @@
package storage
import (
"fmt"
"sync"
)
type DbPolicy int
const (
DbPolicy_Tidy DbPolicy = iota // all store in one db
DbPolicy_Loosy // store in different db
)
const (
DefaultDbName = "default"
)
type StorageManager struct {
policy DbPolicy
dbrootDir string
db map[string]*LevelDBStorage
}
var (
instance *StorageManager
once sync.Once
)
// 修改工厂函数实现单例模式
func NewStorageManager(dbrootDir string, dbPolicy int) (*StorageManager, error) {
var initErr error
once.Do(func() {
instance = &StorageManager{
policy: DbPolicy(dbPolicy),
dbrootDir: dbrootDir,
db: make(map[string]*LevelDBStorage),
}
// 预初始化默认数据库
if _, err := instance.GetStorage(DefaultDbName); err != nil {
initErr = err
}
})
if initErr != nil {
return nil, initErr
}
return instance, nil
}
// 新增获取单例实例的方法
func GetInstance() *StorageManager {
return instance
}
func (sm *StorageManager) GetStorage(dbName string) (*LevelDBStorage, error) {
if dbName == "" {
return nil, fmt.Errorf("db name is empty")
}
if sm.policy == DbPolicy_Tidy {
dbName = DefaultDbName
}
_, exists := sm.db[dbName]
if !exists {
db, err := NewLevelDBStorage(sm.dbrootDir + "/" + dbName)
if err != nil {
return nil, err
}
sm.db[dbName] = db
}
return sm.db[dbName], nil
}
func (sm *StorageManager) Close() {
for _, db := range sm.db {
db.Close()
}
}

35
utils/utils.go Normal file
View File

@ -0,0 +1,35 @@
package utils
import (
"os"
"path/filepath"
)
func GetRootDir() string {
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
panic(err)
}
rootDir := filepath.VolumeName(dir)
if rootDir == "" {
return "/"
}
return rootDir
}
func GetProjectRootDir() string {
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
panic(err)
}
rootDir := GetRootDir()
for dir != rootDir {
//check go.mod file under dir
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir
}
dir = filepath.Dir(dir)
}
return ""
}