add flush 操作
This commit is contained in:
parent
bcf7eac85f
commit
8e464964d9
|
@ -0,0 +1,64 @@
|
|||
### README 文档
|
||||
|
||||
#### 项目名称:gocache
|
||||
|
||||
#### 简介
|
||||
`gocache` 是一个简单的内存键值存储系统,支持持久化、事务处理和内存限制功能。它提供了基本的 `Put`、`Get` 和 `Delete` 操作,并且可以通过日志文件进行恢复。此外,还支持事务处理,确保数据的一致性和可靠性。
|
||||
|
||||
#### 目录结构
|
||||
```
|
||||
gocache/
|
||||
├── kvstore.go # 主要实现代码
|
||||
└── kvstore_test.go # 测试代码
|
||||
```
|
||||
|
||||
#### 安装与使用
|
||||
1. **安装依赖**
|
||||
本项目仅依赖 Go 标准库,无需额外安装第三方库。
|
||||
`go get git.pyer.club/kingecg/gocache`
|
||||
|
||||
#### 功能说明
|
||||
|
||||
- **KVStore 结构体**
|
||||
- `NewKVStore(file string, memoryLimit int64, bucketCount int) *KVStore`: 创建一个新的 KVStore 实例。
|
||||
- `Put(key, value string)`: 添加或更新键值对。
|
||||
- `Get(key string) (string, bool)`: 获取指定键的值。
|
||||
- `Delete(key string)`: 删除指定键的键值对。
|
||||
- `SaveToFile() error`: 将当前存储的数据保存到文件中。
|
||||
- `LoadFromFile(keys ...string) error`: 从文件加载数据,支持部分加载。
|
||||
- `BeginTransaction()`: 开始一个新的事务。
|
||||
- `Commit() error`: 提交当前事务。
|
||||
- `Rollback()`: 回滚当前事务。
|
||||
- `PutInTransaction(key, value string)`: 在当前事务中添加或更新键值对。
|
||||
- `LogOperation(op string, key, value string) error`: 记录操作日志。
|
||||
- `RecoverFromLog() error`: 从日志文件恢复数据。
|
||||
- `periodicSave()`: 定时保存脏数据并清空日志文件。
|
||||
|
||||
#### 测试用例说明
|
||||
|
||||
- **TestNewKVStore**: 测试创建新的 KVStore 实例是否成功。
|
||||
- **TestPutAndGet**: 测试 `Put` 和 `Get` 操作是否正确。
|
||||
- **TestDelete**: 测试 `Delete` 操作是否能正确删除键值对。
|
||||
- **TestSaveAndLoadFromFile**: 测试将数据保存到文件并从文件加载的功能。
|
||||
- **TestLogOperation**: 测试日志记录功能。
|
||||
- **TestTransaction**: 测试事务处理功能,包括提交和回滚。
|
||||
|
||||
#### 注意事项
|
||||
- **内存限制**:`memoryLimit` 参数用于限制内存使用量,当超过限制时会触发 panic。可以根据实际需求调整该参数。
|
||||
- **持久化**:数据会定期保存到文件中,并且可以通过日志文件进行恢复。请确保有足够的磁盘空间来存储这些文件。
|
||||
- **事务处理**:事务可以保证一组操作的原子性,但在高并发场景下需要注意锁机制的影响。
|
||||
|
||||
#### 贡献指南
|
||||
欢迎任何开发者为本项目贡献代码或提出改进建议。请遵循以下步骤:
|
||||
1. Fork 本仓库。
|
||||
2. 创建新分支 (`git checkout -b feature/your-feature`)。
|
||||
3. 提交更改 (`git commit -am 'Add some feature'`)。
|
||||
4. 推送到远程分支 (`git push origin feature/your-feature`)。
|
||||
5. 提交 Pull Request。
|
||||
|
||||
#### 许可证
|
||||
本项目采用 MIT 许可证,详情请参见 [LICENSE](LICENSE) 文件。
|
||||
|
||||
---
|
||||
|
||||
希望这份 README 文档能够帮助您更好地理解和使用 `gocache`。如果有任何问题或建议,请随时联系开发者。
|
60
kvstore.go
60
kvstore.go
|
@ -112,15 +112,54 @@ func hashKey(key string) int {
|
|||
return hash
|
||||
}
|
||||
|
||||
// Flush saves dirty keys to file and clears the memory
|
||||
func (k *KVStore) Flush() error {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
|
||||
if len(k.dirtyKeys) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 保存变化到文件
|
||||
for key := range k.dirtyKeys {
|
||||
if err := k.saveKeyToBucket(key); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 清空dirtyKeys
|
||||
k.dirtyKeys = make(map[string]bool)
|
||||
// 清空日志文件
|
||||
if err := os.Truncate(k.logFile, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 清空内存
|
||||
k.store = make(map[string]string)
|
||||
k.memoryUsage = 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Put adds a key/value pair to the store.
|
||||
func (k *KVStore) Put(key, value string) {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
|
||||
// 如果处于事务中,不检查内存限制
|
||||
if k.transaction != nil {
|
||||
k.transaction.store[key] = value
|
||||
return
|
||||
}
|
||||
|
||||
// 检查内存使用量
|
||||
newMemoryUsage := k.memoryUsage + int64(len(key)+len(value))
|
||||
if newMemoryUsage > k.memoryLimit {
|
||||
panic("Memory limit exceeded")
|
||||
if err := k.Flush(); err != nil {
|
||||
panic("Failed to flush store")
|
||||
}
|
||||
newMemoryUsage = int64(len(key) + len(value))
|
||||
}
|
||||
|
||||
k.store[key] = value
|
||||
|
@ -181,10 +220,29 @@ func (k *KVStore) Commit() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// 计算事务中键值对的内存使用量
|
||||
var transactionMemoryUsage int64
|
||||
for key, value := range k.transaction.store {
|
||||
transactionMemoryUsage += int64(len(key) + len(value))
|
||||
}
|
||||
|
||||
// 检查内存使用量
|
||||
newMemoryUsage := k.memoryUsage + transactionMemoryUsage
|
||||
if newMemoryUsage > k.memoryLimit {
|
||||
if err := k.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
newMemoryUsage = transactionMemoryUsage
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
for key, value := range k.transaction.store {
|
||||
k.store[key] = value
|
||||
k.dirtyKeys[key] = true
|
||||
}
|
||||
k.memoryUsage = newMemoryUsage
|
||||
k.transaction = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue