complete task 17: add tidy mode
This commit is contained in:
parent
b70a38e4b1
commit
dfa34016e5
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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 ""
|
||||
}
|
Loading…
Reference in New Issue