Initial commit: Pipeline Database
This commit is contained in:
182
examples/README.md
Normal file
182
examples/README.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Pipeline Database V4 示例
|
||||
|
||||
本目录包含了 Pipeline Database V4 的各种使用示例,展示了不同场景下的应用方法。
|
||||
|
||||
## 示例列表
|
||||
|
||||
### 1. 基础使用 (`basic-usage/`)
|
||||
演示 Pipeline Database 的基本功能:
|
||||
- 数据库初始化和配置
|
||||
- 数据插入和查询
|
||||
- 基本统计信息获取
|
||||
- **Handler**: `LoggingHandler` (简单日志处理)
|
||||
|
||||
### 2. 组管理 (`group-management/`)
|
||||
展示分组管理功能:
|
||||
- 多组数据管理
|
||||
- 按组查询和统计
|
||||
- 跨组数据分析
|
||||
- **Handler**: `ExampleHandler` (完整示例处理器)
|
||||
|
||||
### 3. 外部处理器 (`external-handler/`)
|
||||
演示自定义外部处理器:
|
||||
- 实现 Handler 接口
|
||||
- 热数据预热处理
|
||||
- 温数据冷却处理
|
||||
- 组完成回调
|
||||
- **Handler**: 自定义 `EmailHandler`
|
||||
|
||||
### 4. 数据分析 (`data-analytics/`)
|
||||
展示数据分析和报告功能:
|
||||
- 用户行为分析
|
||||
- 统计报告生成
|
||||
- 数据可视化
|
||||
- **Handler**: `ExampleHandler` (数据分析处理器)
|
||||
|
||||
### 5. 并发处理 (`concurrent-processing/`)
|
||||
演示并发数据处理:
|
||||
- 多生产者并发写入
|
||||
- 实时统计监控
|
||||
- 并发查询测试
|
||||
- **Handler**: `ExampleHandler` (并发处理器)
|
||||
|
||||
### 6. 高并发压力测试 (`high-concurrency/`)
|
||||
演示极限并发性能:
|
||||
- 50个写入goroutine + 20个读取goroutine
|
||||
- 目标1000写入QPS + 500读取QPS
|
||||
- 30秒压力测试
|
||||
- 性能评估和报告
|
||||
- **Handler**: `LoggingHandler` (轻量级处理)
|
||||
|
||||
## Handler 配置说明
|
||||
|
||||
所有示例现在都配置了适当的 Handler,避免了空指针异常:
|
||||
|
||||
### LoggingHandler
|
||||
- **用途**: 简单的日志输出,适合基础示例
|
||||
- **特点**: 轻量级,不做复杂处理
|
||||
- **使用场景**: 基础使用、高并发测试
|
||||
|
||||
### ExampleHandler
|
||||
- **用途**: 完整的示例处理器,包含详细日志
|
||||
- **特点**: 展示完整的处理流程
|
||||
- **使用场景**: 组管理、数据分析、并发处理
|
||||
|
||||
### 自定义Handler
|
||||
- **用途**: 特定业务逻辑处理
|
||||
- **特点**: 根据具体需求实现
|
||||
- **使用场景**: 外部处理器示例
|
||||
|
||||
## 运行示例
|
||||
|
||||
每个示例都是独立的,可以直接运行:
|
||||
|
||||
```bash
|
||||
# 基础使用示例
|
||||
```
|
||||
|
||||
2. **运行任意示例**:
|
||||
```bash
|
||||
cd basic-usage
|
||||
go run main.go
|
||||
```
|
||||
|
||||
3. **查看输出**: 每个示例都会产生详细的输出,展示各个步骤的执行过程
|
||||
|
||||
## 📚 示例特点
|
||||
|
||||
### 🎯 实用性
|
||||
- 每个示例都模拟真实的业务场景
|
||||
- 包含完整的错误处理
|
||||
- 提供详细的日志输出
|
||||
|
||||
### 🔧 可定制性
|
||||
- 易于修改和扩展
|
||||
- 清晰的代码结构
|
||||
- 丰富的注释说明
|
||||
|
||||
### 📊 教育性
|
||||
- 渐进式学习路径
|
||||
- 从基础到高级功能
|
||||
- 最佳实践演示
|
||||
|
||||
## 💡 使用建议
|
||||
|
||||
### 学习路径
|
||||
1. **新手**: 从 `basic-usage` 开始
|
||||
2. **进阶**: 学习 `external-handler` 和 `group-management`
|
||||
3. **高级**: 研究 `concurrent-processing` 和 `data-analytics`
|
||||
|
||||
### 生产环境适配
|
||||
- 修改数据库文件路径
|
||||
- 调整缓存大小配置
|
||||
- 实现自定义的外部处理器
|
||||
- 添加适当的监控和日志
|
||||
|
||||
### 性能优化
|
||||
- 根据数据量调整 `CacheSize`
|
||||
- 合理设计组结构
|
||||
- 优化查询分页大小
|
||||
- 监控系统资源使用
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
### 数据库配置
|
||||
```go
|
||||
config := &pipelinedb.Config{
|
||||
CacheSize: 100, // 缓存页面数量
|
||||
}
|
||||
```
|
||||
|
||||
### 打开选项
|
||||
```go
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: "database.db", // 数据库文件路径
|
||||
Config: config, // 配置选项
|
||||
Handler: yourHandler, // 外部处理器(可选)
|
||||
Logger: yourLogger, // 日志器(可选)
|
||||
})
|
||||
```
|
||||
|
||||
## 🐛 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **文件权限错误**
|
||||
- 确保对数据库文件目录有写权限
|
||||
- 检查临时文件创建权限
|
||||
|
||||
2. **内存不足**
|
||||
- 减少 `CacheSize` 配置
|
||||
- 优化数据处理逻辑
|
||||
|
||||
3. **并发冲突**
|
||||
- 检查并发访问模式
|
||||
- 确保正确的错误处理
|
||||
|
||||
### 调试技巧
|
||||
- 启用详细日志输出
|
||||
- 使用分步调试
|
||||
- 监控系统资源使用
|
||||
- 检查数据库统计信息
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
如果你在使用示例时遇到问题:
|
||||
|
||||
1. 查看示例代码中的注释
|
||||
2. 检查错误信息和日志输出
|
||||
3. 参考 Pipeline Database V4 的文档
|
||||
4. 在项目仓库提交 Issue
|
||||
|
||||
## 🎉 贡献
|
||||
|
||||
欢迎贡献新的示例!请确保:
|
||||
- 代码清晰易懂
|
||||
- 包含详细注释
|
||||
- 模拟真实场景
|
||||
- 添加到此 README
|
||||
|
||||
---
|
||||
|
||||
**Pipeline Database V4** - 高性能的管道式数据库系统
|
||||
9
examples/basic-usage/go.mod
Normal file
9
examples/basic-usage/go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module basic-usage
|
||||
|
||||
go 1.24.0
|
||||
|
||||
replace code.tczkiot.com/wlw/pipelinedb => ../../
|
||||
|
||||
require code.tczkiot.com/wlw/pipelinedb v0.0.0-00010101000000-000000000000
|
||||
|
||||
require github.com/google/btree v1.1.3 // indirect
|
||||
2
examples/basic-usage/go.sum
Normal file
2
examples/basic-usage/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
121
examples/basic-usage/main.go
Normal file
121
examples/basic-usage/main.go
Normal file
@@ -0,0 +1,121 @@
|
||||
// 演示 Pipeline Database 的基础使用
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"code.tczkiot.com/wlw/pipelinedb"
|
||||
"code.tczkiot.com/wlw/pipelinedb/examples/common"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 创建临时数据库文件
|
||||
dbFile := "basic_example.db"
|
||||
defer os.Remove(dbFile) // 清理临时文件
|
||||
|
||||
// 确保文件可以创建
|
||||
if _, err := os.Create(dbFile); err != nil {
|
||||
log.Fatalf("创建数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("🚀 Pipeline Database 基础使用示例")
|
||||
fmt.Println("================================")
|
||||
|
||||
// 1. 打开数据库
|
||||
fmt.Println("\n📂 步骤1: 打开数据库")
|
||||
config := &pipelinedb.Config{
|
||||
CacheSize: 100, // 缓存100个页面
|
||||
}
|
||||
|
||||
// 创建处理器
|
||||
handler := common.NewLoggingHandler()
|
||||
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: dbFile,
|
||||
Config: config,
|
||||
Handler: handler,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("打开数据库失败: %v", err)
|
||||
}
|
||||
defer pdb.Stop()
|
||||
|
||||
fmt.Printf("✅ 数据库已打开: %s\n", dbFile)
|
||||
|
||||
// 2. 接收数据
|
||||
fmt.Println("\n📥 步骤2: 接收数据")
|
||||
testData := []struct {
|
||||
group string
|
||||
data []byte
|
||||
metadata string
|
||||
}{
|
||||
{"用户行为", []byte("用户点击了首页按钮"), `{"timestamp": "2024-01-01T10:00:00Z", "user_id": "user123"}`},
|
||||
{"用户行为", []byte("用户浏览了产品页面"), `{"timestamp": "2024-01-01T10:01:00Z", "user_id": "user123"}`},
|
||||
{"系统日志", []byte("系统启动完成"), `{"timestamp": "2024-01-01T09:00:00Z", "level": "info"}`},
|
||||
{"系统日志", []byte("数据库连接建立"), `{"timestamp": "2024-01-01T09:01:00Z", "level": "info"}`},
|
||||
{"错误日志", []byte("网络连接超时"), `{"timestamp": "2024-01-01T10:30:00Z", "level": "error"}`},
|
||||
}
|
||||
|
||||
var recordIDs []int64
|
||||
for _, item := range testData {
|
||||
recordID, err := pdb.AcceptData(item.group, item.data, item.metadata)
|
||||
if err != nil {
|
||||
log.Fatalf("接收数据失败: %v", err)
|
||||
}
|
||||
recordIDs = append(recordIDs, recordID)
|
||||
fmt.Printf(" ✅ 记录 %d: [%s] %s\n", recordID, item.group, string(item.data))
|
||||
}
|
||||
|
||||
// 3. 查询数据
|
||||
fmt.Println("\n🔍 步骤3: 查询数据")
|
||||
|
||||
// 按组查询
|
||||
groups := []string{"用户行为", "系统日志", "错误日志"}
|
||||
for _, group := range groups {
|
||||
fmt.Printf("\n📋 查询组: %s\n", group)
|
||||
|
||||
pageReq := &pipelinedb.PageRequest{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
}
|
||||
|
||||
response, err := pdb.GetRecordsByGroup(group, pageReq)
|
||||
if err != nil {
|
||||
fmt.Printf(" ❌ 查询失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf(" 📊 总记录数: %d, 当前页: %d/%d\n",
|
||||
response.TotalCount, response.Page, response.TotalPages)
|
||||
|
||||
for _, record := range response.Records {
|
||||
fmt.Printf(" 📄 ID:%d [%s] %s (创建时间: %s)\n",
|
||||
record.ID, record.Status, string(record.Data),
|
||||
record.CreatedAt.Format("15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 获取统计信息
|
||||
fmt.Println("\n📊 步骤4: 获取统计信息")
|
||||
stats, err := pdb.GetStats()
|
||||
if err != nil {
|
||||
log.Fatalf("获取统计信息失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("📈 数据库统计信息:\n")
|
||||
fmt.Printf(" 总记录数: %d\n", stats.TotalRecords)
|
||||
fmt.Printf(" 总组数: %d\n", len(stats.GroupStats))
|
||||
|
||||
fmt.Println("\n📋 各组统计:")
|
||||
for group, groupStats := range stats.GroupStats {
|
||||
fmt.Printf(" %s:\n", group)
|
||||
fmt.Printf(" 热数据: %d\n", groupStats.HotRecords)
|
||||
fmt.Printf(" 温数据: %d\n", groupStats.WarmRecords)
|
||||
fmt.Printf(" 冷数据: %d\n", groupStats.ColdRecords)
|
||||
fmt.Printf(" 总计: %d\n", groupStats.TotalRecords)
|
||||
}
|
||||
|
||||
fmt.Println("\n🎉 基础使用示例完成!")
|
||||
}
|
||||
72
examples/common/handler.go
Normal file
72
examples/common/handler.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// 通用示例处理器
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// ExampleHandler 示例外部处理器
|
||||
type ExampleHandler struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// NewExampleHandler 创建示例处理器
|
||||
func NewExampleHandler(name string) *ExampleHandler {
|
||||
return &ExampleHandler{
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// WillWarm 热数据预热处理
|
||||
func (h *ExampleHandler) WillWarm(ctx context.Context, group string, data []byte) ([]byte, error) {
|
||||
log.Printf("🔥 [%s] 预热处理, 组=%s, 数据大小=%d bytes", h.name, group, len(data))
|
||||
|
||||
// 示例:可以在这里进行数据预处理、验证、转换等
|
||||
// 这里简单返回原数据
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// WillCold 温数据冷却处理
|
||||
func (h *ExampleHandler) WillCold(ctx context.Context, group string, data []byte) ([]byte, error) {
|
||||
log.Printf("❄️ [%s] 冷却处理, 组=%s, 数据大小=%d bytes", h.name, group, len(data))
|
||||
|
||||
// 示例:可以在这里进行数据压缩、归档、清理等
|
||||
// 这里简单返回原数据
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// OnComplete 组完成回调
|
||||
func (h *ExampleHandler) OnComplete(ctx context.Context, group string) error {
|
||||
log.Printf("🎉 [%s] 组完成回调, 组=%s - 所有数据已处理完成", h.name, group)
|
||||
|
||||
// 示例:可以在这里进行组级别的清理、通知、统计等
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoggingHandler 简单的日志处理器(用于不需要复杂处理的示例)
|
||||
type LoggingHandler struct{}
|
||||
|
||||
// NewLoggingHandler 创建日志处理器
|
||||
func NewLoggingHandler() *LoggingHandler {
|
||||
return &LoggingHandler{}
|
||||
}
|
||||
|
||||
// WillWarm 热数据预热处理
|
||||
func (h *LoggingHandler) WillWarm(ctx context.Context, group string, data []byte) ([]byte, error) {
|
||||
fmt.Printf("🔥 数据预热: 组[%s] %d bytes\n", group, len(data))
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// WillCold 温数据冷却处理
|
||||
func (h *LoggingHandler) WillCold(ctx context.Context, group string, data []byte) ([]byte, error) {
|
||||
fmt.Printf("❄️ 数据冷却: 组[%s] %d bytes\n", group, len(data))
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// OnComplete 组完成回调
|
||||
func (h *LoggingHandler) OnComplete(ctx context.Context, group string) error {
|
||||
fmt.Printf("✅ 组完成: [%s]\n", group)
|
||||
return nil
|
||||
}
|
||||
9
examples/concurrent-processing/go.mod
Normal file
9
examples/concurrent-processing/go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module concurrent-processing
|
||||
|
||||
go 1.24.0
|
||||
|
||||
replace code.tczkiot.com/wlw/pipelinedb => ../../
|
||||
|
||||
require code.tczkiot.com/wlw/pipelinedb v0.0.0-00010101000000-000000000000
|
||||
|
||||
require github.com/google/btree v1.1.3 // indirect
|
||||
2
examples/concurrent-processing/go.sum
Normal file
2
examples/concurrent-processing/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
229
examples/concurrent-processing/main.go
Normal file
229
examples/concurrent-processing/main.go
Normal file
@@ -0,0 +1,229 @@
|
||||
// 演示并发数据处理
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.tczkiot.com/wlw/pipelinedb"
|
||||
"code.tczkiot.com/wlw/pipelinedb/examples/common"
|
||||
)
|
||||
|
||||
// 模拟不同类型的数据源
|
||||
type DataSource struct {
|
||||
name string
|
||||
group string
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 创建临时数据库文件
|
||||
dbFile := "concurrent_example.db"
|
||||
defer os.Remove(dbFile)
|
||||
|
||||
// 确保文件可以创建
|
||||
if _, err := os.Create(dbFile); err != nil {
|
||||
log.Fatalf("创建数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("🚀 并发处理示例")
|
||||
fmt.Println("================")
|
||||
|
||||
// 配置数据库
|
||||
fmt.Println("\n📂 步骤1: 配置数据库")
|
||||
config := &pipelinedb.Config{
|
||||
CacheSize: 200, // 增大缓存以支持并发
|
||||
}
|
||||
|
||||
// 创建处理器
|
||||
handler := common.NewExampleHandler("并发处理")
|
||||
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: dbFile,
|
||||
Config: config,
|
||||
Handler: handler,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("打开数据库失败: %v", err)
|
||||
}
|
||||
defer pdb.Stop()
|
||||
|
||||
fmt.Println("✅ 数据库已配置")
|
||||
|
||||
// 定义数据源
|
||||
dataSources := []DataSource{
|
||||
{"Web服务器", "访问日志", 100 * time.Millisecond},
|
||||
{"API网关", "API调用", 150 * time.Millisecond},
|
||||
{"数据库", "慢查询", 300 * time.Millisecond},
|
||||
{"缓存系统", "缓存命中", 50 * time.Millisecond},
|
||||
{"消息队列", "消息处理", 200 * time.Millisecond},
|
||||
}
|
||||
|
||||
// 启动并发数据生产者
|
||||
fmt.Println("\n🏭 步骤2: 启动并发数据生产者")
|
||||
var wg sync.WaitGroup
|
||||
stopChan := make(chan bool)
|
||||
|
||||
// 统计计数器
|
||||
var totalRecords int64
|
||||
var mu sync.Mutex
|
||||
|
||||
for i, source := range dataSources {
|
||||
wg.Add(1)
|
||||
go func(id int, src DataSource) {
|
||||
defer wg.Done()
|
||||
|
||||
fmt.Printf("🔄 启动生产者 %d: %s (组: %s)\n", id+1, src.name, src.group)
|
||||
|
||||
count := 0
|
||||
for {
|
||||
select {
|
||||
case <-stopChan:
|
||||
fmt.Printf("🛑 生产者 %d (%s) 停止,共生产 %d 条记录\n",
|
||||
id+1, src.name, count)
|
||||
return
|
||||
default:
|
||||
// 生成模拟数据
|
||||
data := fmt.Sprintf("[%s] 时间戳: %d, 随机值: %d",
|
||||
src.name, time.Now().Unix(), rand.Intn(1000))
|
||||
|
||||
metadata := fmt.Sprintf(`{"source": "%s", "producer_id": %d, "sequence": %d}`,
|
||||
src.name, id+1, count+1)
|
||||
|
||||
// 发送数据
|
||||
recordID, err := pdb.AcceptData(src.group, []byte(data), metadata)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 生产者 %d 发送失败: %v\n", id+1, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 更新计数
|
||||
mu.Lock()
|
||||
totalRecords++
|
||||
count++
|
||||
mu.Unlock()
|
||||
|
||||
if count%10 == 0 {
|
||||
fmt.Printf("📊 生产者 %d (%s) 已生产 %d 条记录,最新ID: %d\n",
|
||||
id+1, src.name, count, recordID)
|
||||
}
|
||||
|
||||
// 按间隔休眠
|
||||
time.Sleep(src.interval)
|
||||
}
|
||||
}
|
||||
}(i, source)
|
||||
}
|
||||
|
||||
// 启动统计监控
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopChan:
|
||||
return
|
||||
case <-ticker.C:
|
||||
// 获取实时统计
|
||||
stats, err := pdb.GetStats()
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 获取统计失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("\n📈 实时统计 (时间: %s)\n", time.Now().Format("15:04:05"))
|
||||
fmt.Printf(" 数据库总记录: %d\n", stats.TotalRecords)
|
||||
fmt.Printf(" 生产者总计数: %d\n", totalRecords)
|
||||
|
||||
for group, groupStats := range stats.GroupStats {
|
||||
fmt.Printf(" [%s] 热:%d 温:%d 冷:%d 总:%d\n",
|
||||
group, groupStats.HotRecords, groupStats.WarmRecords,
|
||||
groupStats.ColdRecords, groupStats.TotalRecords)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 运行一段时间
|
||||
fmt.Println("\n⏳ 步骤3: 运行并发处理")
|
||||
fmt.Println("正在并发处理数据,运行10秒...")
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
// 停止所有生产者
|
||||
fmt.Println("\n🛑 步骤4: 停止生产者")
|
||||
close(stopChan)
|
||||
wg.Wait()
|
||||
|
||||
// 最终统计
|
||||
fmt.Println("\n📊 步骤5: 最终统计")
|
||||
finalStats, err := pdb.GetStats()
|
||||
if err != nil {
|
||||
log.Fatalf("获取最终统计失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("🎯 最终结果:\n")
|
||||
fmt.Printf(" 总记录数: %d\n", finalStats.TotalRecords)
|
||||
fmt.Printf(" 总组数: %d\n", len(finalStats.GroupStats))
|
||||
|
||||
fmt.Println("\n📋 各组详细统计:")
|
||||
for group, groupStats := range finalStats.GroupStats {
|
||||
fmt.Printf(" %s:\n", group)
|
||||
fmt.Printf(" 热数据: %d (%.1f%%)\n",
|
||||
groupStats.HotRecords, float64(groupStats.HotRecords)/float64(groupStats.TotalRecords)*100)
|
||||
fmt.Printf(" 温数据: %d (%.1f%%)\n",
|
||||
groupStats.WarmRecords, float64(groupStats.WarmRecords)/float64(groupStats.TotalRecords)*100)
|
||||
fmt.Printf(" 冷数据: %d (%.1f%%)\n",
|
||||
groupStats.ColdRecords, float64(groupStats.ColdRecords)/float64(groupStats.TotalRecords)*100)
|
||||
fmt.Printf(" 总计: %d\n", groupStats.TotalRecords)
|
||||
}
|
||||
|
||||
// 测试并发查询
|
||||
fmt.Println("\n🔍 步骤6: 测试并发查询")
|
||||
var queryWg sync.WaitGroup
|
||||
|
||||
for _, source := range dataSources {
|
||||
queryWg.Add(1)
|
||||
go func(group string) {
|
||||
defer queryWg.Done()
|
||||
|
||||
pageReq := &pipelinedb.PageRequest{
|
||||
Page: 1,
|
||||
PageSize: 5,
|
||||
}
|
||||
|
||||
response, err := pdb.GetRecordsByGroup(group, pageReq)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 查询组 %s 失败: %v\n", group, err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("🔍 组 [%s] 查询结果: %d/%d 条记录\n",
|
||||
group, len(response.Records), response.TotalCount)
|
||||
|
||||
for i, record := range response.Records {
|
||||
if i < 2 { // 只显示前2条
|
||||
dataStr := string(record.Data)
|
||||
if len(dataStr) > 50 {
|
||||
dataStr = dataStr[:50]
|
||||
}
|
||||
fmt.Printf(" 📄 ID:%d [%s] %s...\n",
|
||||
record.ID, record.Status, dataStr)
|
||||
}
|
||||
}
|
||||
}(source.group)
|
||||
}
|
||||
|
||||
queryWg.Wait()
|
||||
|
||||
fmt.Println("\n🎉 并发处理示例完成!")
|
||||
fmt.Println("💡 提示: 这个示例展示了Pipeline Database在高并发场景下的稳定性")
|
||||
}
|
||||
9
examples/data-analytics/go.mod
Normal file
9
examples/data-analytics/go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module data-analytics
|
||||
|
||||
go 1.24.0
|
||||
|
||||
replace code.tczkiot.com/wlw/pipelinedb => ../../
|
||||
|
||||
require code.tczkiot.com/wlw/pipelinedb v0.0.0-00010101000000-000000000000
|
||||
|
||||
require github.com/google/btree v1.1.3 // indirect
|
||||
2
examples/data-analytics/go.sum
Normal file
2
examples/data-analytics/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
304
examples/data-analytics/main.go
Normal file
304
examples/data-analytics/main.go
Normal file
@@ -0,0 +1,304 @@
|
||||
// 演示数据分析和报告功能
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"code.tczkiot.com/wlw/pipelinedb"
|
||||
"code.tczkiot.com/wlw/pipelinedb/examples/common"
|
||||
)
|
||||
|
||||
// UserEvent 用户事件结构
|
||||
type UserEvent struct {
|
||||
UserID string `json:"user_id"`
|
||||
Action string `json:"action"`
|
||||
Page string `json:"page"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Value float64 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// AnalyticsReport 分析报告
|
||||
type AnalyticsReport struct {
|
||||
TotalEvents int `json:"total_events"`
|
||||
UniqueUsers int `json:"unique_users"`
|
||||
TopActions []ActionCount `json:"top_actions"`
|
||||
TopPages []PageCount `json:"top_pages"`
|
||||
UserActivity map[string]int `json:"user_activity"`
|
||||
HourlyActivity map[int]int `json:"hourly_activity"`
|
||||
TotalValue float64 `json:"total_value"`
|
||||
}
|
||||
|
||||
type ActionCount struct {
|
||||
Action string `json:"action"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type PageCount struct {
|
||||
Page string `json:"page"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 创建临时数据库文件
|
||||
dbFile := "analytics_example.db"
|
||||
defer os.Remove(dbFile)
|
||||
|
||||
// 确保文件可以创建
|
||||
if _, err := os.Create(dbFile); err != nil {
|
||||
log.Fatalf("创建数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("🚀 数据分析示例")
|
||||
fmt.Println("================")
|
||||
|
||||
// 配置数据库
|
||||
fmt.Println("\n📂 步骤1: 配置数据库")
|
||||
config := &pipelinedb.Config{
|
||||
CacheSize: 100,
|
||||
}
|
||||
|
||||
// 创建处理器
|
||||
handler := common.NewExampleHandler("数据分析")
|
||||
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: dbFile,
|
||||
Config: config,
|
||||
Handler: handler,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("打开数据库失败: %v", err)
|
||||
}
|
||||
defer pdb.Stop()
|
||||
|
||||
fmt.Println("✅ 数据库已配置")
|
||||
|
||||
// 生成模拟用户行为数据
|
||||
fmt.Println("\n📊 步骤2: 生成模拟用户行为数据")
|
||||
|
||||
users := []string{"user001", "user002", "user003", "user004", "user005"}
|
||||
actions := []string{"页面访问", "按钮点击", "表单提交", "文件下载", "搜索"}
|
||||
pages := []string{"/home", "/products", "/about", "/contact", "/login", "/checkout"}
|
||||
|
||||
// 生成1000个随机事件
|
||||
events := make([]UserEvent, 1000)
|
||||
baseTime := time.Now().Add(-24 * time.Hour) // 从24小时前开始
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
event := UserEvent{
|
||||
UserID: users[rand.Intn(len(users))],
|
||||
Action: actions[rand.Intn(len(actions))],
|
||||
Page: pages[rand.Intn(len(pages))],
|
||||
Timestamp: baseTime.Add(time.Duration(i) * time.Minute),
|
||||
}
|
||||
|
||||
// 为某些动作添加价值
|
||||
if event.Action == "表单提交" || event.Action == "文件下载" {
|
||||
event.Value = rand.Float64() * 100
|
||||
}
|
||||
|
||||
events[i] = event
|
||||
}
|
||||
|
||||
fmt.Printf("✅ 生成了 %d 个用户事件\n", len(events))
|
||||
|
||||
// 将事件存储到数据库
|
||||
fmt.Println("\n💾 步骤3: 存储事件数据")
|
||||
|
||||
for i, event := range events {
|
||||
// 序列化事件数据
|
||||
eventData, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
log.Fatalf("序列化事件失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建元数据
|
||||
metadata := fmt.Sprintf(`{"user_id": "%s", "action": "%s", "page": "%s"}`,
|
||||
event.UserID, event.Action, event.Page)
|
||||
|
||||
// 根据动作类型分组
|
||||
group := "用户行为"
|
||||
if event.Action == "搜索" {
|
||||
group = "搜索行为"
|
||||
} else if event.Value > 0 {
|
||||
group = "有价值行为"
|
||||
}
|
||||
|
||||
recordID, err := pdb.AcceptData(group, eventData, metadata)
|
||||
if err != nil {
|
||||
log.Fatalf("存储事件失败: %v", err)
|
||||
}
|
||||
|
||||
if (i+1)%200 == 0 {
|
||||
fmt.Printf(" 📝 已存储 %d/%d 个事件,最新ID: %d\n", i+1, len(events), recordID)
|
||||
}
|
||||
}
|
||||
|
||||
// 数据分析
|
||||
fmt.Println("\n🔍 步骤4: 执行数据分析")
|
||||
|
||||
report := &AnalyticsReport{
|
||||
UserActivity: make(map[string]int),
|
||||
HourlyActivity: make(map[int]int),
|
||||
}
|
||||
|
||||
// 获取所有组的数据
|
||||
groups := []string{"用户行为", "搜索行为", "有价值行为"}
|
||||
allEvents := []UserEvent{}
|
||||
|
||||
for _, group := range groups {
|
||||
fmt.Printf("📋 分析组: %s\n", group)
|
||||
|
||||
pageReq := &pipelinedb.PageRequest{
|
||||
Page: 1,
|
||||
PageSize: 1000, // 获取所有数据
|
||||
}
|
||||
|
||||
response, err := pdb.GetRecordsByGroup(group, pageReq)
|
||||
if err != nil {
|
||||
fmt.Printf(" ❌ 查询组失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf(" 📊 找到 %d 条记录\n", len(response.Records))
|
||||
|
||||
// 解析事件数据
|
||||
for _, record := range response.Records {
|
||||
var event UserEvent
|
||||
if err := json.Unmarshal(record.Data, &event); err != nil {
|
||||
continue
|
||||
}
|
||||
allEvents = append(allEvents, event)
|
||||
}
|
||||
}
|
||||
|
||||
// 分析数据
|
||||
fmt.Println("\n📈 步骤5: 生成分析报告")
|
||||
|
||||
report.TotalEvents = len(allEvents)
|
||||
|
||||
// 统计唯一用户
|
||||
uniqueUsers := make(map[string]bool)
|
||||
actionCounts := make(map[string]int)
|
||||
pageCounts := make(map[string]int)
|
||||
|
||||
for _, event := range allEvents {
|
||||
// 唯一用户
|
||||
uniqueUsers[event.UserID] = true
|
||||
|
||||
// 用户活跃度
|
||||
report.UserActivity[event.UserID]++
|
||||
|
||||
// 动作统计
|
||||
actionCounts[event.Action]++
|
||||
|
||||
// 页面统计
|
||||
pageCounts[event.Page]++
|
||||
|
||||
// 小时活跃度
|
||||
hour := event.Timestamp.Hour()
|
||||
report.HourlyActivity[hour]++
|
||||
|
||||
// 总价值
|
||||
report.TotalValue += event.Value
|
||||
}
|
||||
|
||||
report.UniqueUsers = len(uniqueUsers)
|
||||
|
||||
// 排序Top动作
|
||||
for action, count := range actionCounts {
|
||||
report.TopActions = append(report.TopActions, ActionCount{
|
||||
Action: action,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
sort.Slice(report.TopActions, func(i, j int) bool {
|
||||
return report.TopActions[i].Count > report.TopActions[j].Count
|
||||
})
|
||||
|
||||
// 排序Top页面
|
||||
for page, count := range pageCounts {
|
||||
report.TopPages = append(report.TopPages, PageCount{
|
||||
Page: page,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
sort.Slice(report.TopPages, func(i, j int) bool {
|
||||
return report.TopPages[i].Count > report.TopPages[j].Count
|
||||
})
|
||||
|
||||
// 显示报告
|
||||
fmt.Println("\n📋 数据分析报告")
|
||||
fmt.Println("================")
|
||||
|
||||
fmt.Printf("📊 总体统计:\n")
|
||||
fmt.Printf(" 总事件数: %d\n", report.TotalEvents)
|
||||
fmt.Printf(" 唯一用户数: %d\n", report.UniqueUsers)
|
||||
fmt.Printf(" 总价值: %.2f\n", report.TotalValue)
|
||||
fmt.Printf(" 平均每用户事件: %.1f\n", float64(report.TotalEvents)/float64(report.UniqueUsers))
|
||||
|
||||
fmt.Printf("\n🔥 热门动作 (Top 5):\n")
|
||||
for i, action := range report.TopActions {
|
||||
if i >= 5 {
|
||||
break
|
||||
}
|
||||
percentage := float64(action.Count) / float64(report.TotalEvents) * 100
|
||||
fmt.Printf(" %d. %s: %d 次 (%.1f%%)\n",
|
||||
i+1, action.Action, action.Count, percentage)
|
||||
}
|
||||
|
||||
fmt.Printf("\n📄 热门页面 (Top 5):\n")
|
||||
for i, page := range report.TopPages {
|
||||
if i >= 5 {
|
||||
break
|
||||
}
|
||||
percentage := float64(page.Count) / float64(report.TotalEvents) * 100
|
||||
fmt.Printf(" %d. %s: %d 次 (%.1f%%)\n",
|
||||
i+1, page.Page, page.Count, percentage)
|
||||
}
|
||||
|
||||
fmt.Printf("\n👥 用户活跃度:\n")
|
||||
for userID, count := range report.UserActivity {
|
||||
fmt.Printf(" %s: %d 次事件\n", userID, count)
|
||||
}
|
||||
|
||||
// 数据库统计
|
||||
fmt.Println("\n💾 数据库统计")
|
||||
stats, err := pdb.GetStats()
|
||||
if err != nil {
|
||||
log.Fatalf("获取数据库统计失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("📈 存储统计:\n")
|
||||
fmt.Printf(" 数据库总记录: %d\n", stats.TotalRecords)
|
||||
fmt.Printf(" 总组数: %d\n", len(stats.GroupStats))
|
||||
|
||||
for group, groupStats := range stats.GroupStats {
|
||||
fmt.Printf(" [%s]: 热:%d 温:%d 冷:%d\n",
|
||||
group, groupStats.HotRecords, groupStats.WarmRecords, groupStats.ColdRecords)
|
||||
}
|
||||
|
||||
// 导出报告
|
||||
fmt.Println("\n📤 步骤6: 导出分析报告")
|
||||
reportJSON, err := json.MarshalIndent(report, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("序列化报告失败: %v", err)
|
||||
}
|
||||
|
||||
reportFile := "analytics_report.json"
|
||||
err = os.WriteFile(reportFile, reportJSON, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("写入报告文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✅ 分析报告已导出到: %s\n", reportFile)
|
||||
defer os.Remove(reportFile) // 清理示例文件
|
||||
|
||||
fmt.Println("\n🎉 数据分析示例完成!")
|
||||
fmt.Println("💡 提示: 这个示例展示了如何使用Pipeline Database进行复杂的数据分析")
|
||||
}
|
||||
9
examples/external-handler/go.mod
Normal file
9
examples/external-handler/go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module external-handler
|
||||
|
||||
go 1.24.0
|
||||
|
||||
replace code.tczkiot.com/wlw/pipelinedb => ../../
|
||||
|
||||
require code.tczkiot.com/wlw/pipelinedb v0.0.0-00010101000000-000000000000
|
||||
|
||||
require github.com/google/btree v1.1.3 // indirect
|
||||
2
examples/external-handler/go.sum
Normal file
2
examples/external-handler/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
179
examples/external-handler/main.go
Normal file
179
examples/external-handler/main.go
Normal file
@@ -0,0 +1,179 @@
|
||||
// 演示如何使用外部处理器进行数据处理
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.tczkiot.com/wlw/pipelinedb"
|
||||
)
|
||||
|
||||
// EmailProcessor 邮件处理器示例
|
||||
type EmailProcessor struct {
|
||||
name string
|
||||
processed int
|
||||
}
|
||||
|
||||
func NewEmailProcessor(name string) *EmailProcessor {
|
||||
return &EmailProcessor{
|
||||
name: name,
|
||||
processed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// WillWarm 预热阶段:验证邮件格式
|
||||
func (ep *EmailProcessor) WillWarm(ctx context.Context, group string, data []byte) ([]byte, error) {
|
||||
fmt.Printf("🔥 [%s] 预热处理 - 组: %s\n", ep.name, group)
|
||||
|
||||
email := string(data)
|
||||
|
||||
// 简单的邮件格式验证
|
||||
if !strings.Contains(email, "@") {
|
||||
return nil, fmt.Errorf("无效的邮件格式: %s", email)
|
||||
}
|
||||
|
||||
// 标准化邮件地址(转为小写)
|
||||
normalizedEmail := strings.ToLower(strings.TrimSpace(email))
|
||||
|
||||
fmt.Printf(" 📧 邮件验证通过: %s -> %s\n", email, normalizedEmail)
|
||||
|
||||
// 模拟处理时间
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
return []byte(normalizedEmail), nil
|
||||
}
|
||||
|
||||
// WillCold 冷却阶段:发送邮件通知
|
||||
func (ep *EmailProcessor) WillCold(ctx context.Context, group string, data []byte) ([]byte, error) {
|
||||
fmt.Printf("❄️ [%s] 冷却处理 - 组: %s\n", ep.name, group)
|
||||
|
||||
email := string(data)
|
||||
|
||||
// 模拟发送邮件
|
||||
fmt.Printf(" 📮 发送邮件到: %s\n", email)
|
||||
fmt.Printf(" 📝 邮件内容: 您的数据已成功处理完成\n")
|
||||
|
||||
// 模拟发送时间
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
ep.processed++
|
||||
fmt.Printf(" ✅ 邮件发送成功 (已处理 %d 封邮件)\n", ep.processed)
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// OnComplete 完成回调:统计处理结果
|
||||
func (ep *EmailProcessor) OnComplete(ctx context.Context, group string) error {
|
||||
fmt.Printf("🎉 [%s] 组处理完成 - 组: %s\n", ep.name, group)
|
||||
fmt.Printf(" 📊 本组共处理邮件: %d 封\n", ep.processed)
|
||||
|
||||
// 重置计数器
|
||||
ep.processed = 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 创建临时数据库文件
|
||||
dbFile := "handler_example.db"
|
||||
defer os.Remove(dbFile)
|
||||
|
||||
// 确保文件可以创建
|
||||
if _, err := os.Create(dbFile); err != nil {
|
||||
log.Fatalf("创建数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("🚀 外部处理器示例")
|
||||
fmt.Println("==================")
|
||||
|
||||
// 创建邮件处理器
|
||||
emailHandler := NewEmailProcessor("邮件处理器")
|
||||
|
||||
// 打开数据库并配置处理器
|
||||
fmt.Println("\n📂 步骤1: 配置数据库和处理器")
|
||||
config := &pipelinedb.Config{
|
||||
CacheSize: 50,
|
||||
}
|
||||
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: dbFile,
|
||||
Config: config,
|
||||
Handler: emailHandler,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("打开数据库失败: %v", err)
|
||||
}
|
||||
defer pdb.Stop()
|
||||
|
||||
fmt.Printf("✅ 数据库已配置外部处理器: %s\n", emailHandler.name)
|
||||
|
||||
// 接收邮件数据
|
||||
fmt.Println("\n📥 步骤2: 接收邮件数据")
|
||||
emails := []string{
|
||||
"user1@example.com",
|
||||
"USER2@EXAMPLE.COM", // 测试大小写转换
|
||||
"user3@test.org",
|
||||
"invalid-email", // 测试无效邮件
|
||||
"admin@company.net",
|
||||
}
|
||||
|
||||
for i, email := range emails {
|
||||
fmt.Printf("\n📧 处理邮件 %d: %s\n", i+1, email)
|
||||
|
||||
recordID, err := pdb.AcceptData("邮件处理", []byte(email),
|
||||
fmt.Sprintf(`{"batch": %d, "source": "web_form"}`, i+1))
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf(" ❌ 接收失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf(" ✅ 记录ID: %d\n", recordID)
|
||||
}
|
||||
|
||||
// 等待处理完成
|
||||
fmt.Println("\n⏳ 步骤3: 等待处理完成")
|
||||
fmt.Println("正在处理数据,请稍候...")
|
||||
|
||||
// 给处理器一些时间来处理数据
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// 查看处理结果
|
||||
fmt.Println("\n🔍 步骤4: 查看处理结果")
|
||||
pageReq := &pipelinedb.PageRequest{
|
||||
Page: 1,
|
||||
PageSize: 20,
|
||||
}
|
||||
|
||||
response, err := pdb.GetRecordsByGroup("邮件处理", pageReq)
|
||||
if err != nil {
|
||||
log.Fatalf("查询记录失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("📊 处理结果统计:\n")
|
||||
fmt.Printf(" 总记录数: %d\n", response.TotalCount)
|
||||
|
||||
statusCount := make(map[pipelinedb.DataStatus]int)
|
||||
for _, record := range response.Records {
|
||||
statusCount[record.Status]++
|
||||
}
|
||||
|
||||
fmt.Printf(" 状态分布:\n")
|
||||
fmt.Printf(" 热数据 (hot): %d\n", statusCount[pipelinedb.StatusHot])
|
||||
fmt.Printf(" 温数据 (warm): %d\n", statusCount[pipelinedb.StatusWarm])
|
||||
fmt.Printf(" 冷数据 (cold): %d\n", statusCount[pipelinedb.StatusCold])
|
||||
|
||||
// 显示详细记录
|
||||
fmt.Println("\n📋 详细记录:")
|
||||
for _, record := range response.Records {
|
||||
fmt.Printf(" ID:%d [%s] %s\n",
|
||||
record.ID, record.Status, string(record.Data))
|
||||
}
|
||||
|
||||
fmt.Println("\n🎉 外部处理器示例完成!")
|
||||
fmt.Println("💡 提示: 查看上面的日志,可以看到数据如何通过预热->冷却的完整流程")
|
||||
}
|
||||
9
examples/group-management/go.mod
Normal file
9
examples/group-management/go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module group-management
|
||||
|
||||
go 1.24.0
|
||||
|
||||
replace code.tczkiot.com/wlw/pipelinedb => ../../
|
||||
|
||||
require code.tczkiot.com/wlw/pipelinedb v0.0.0-00010101000000-000000000000
|
||||
|
||||
require github.com/google/btree v1.1.3 // indirect
|
||||
2
examples/group-management/go.sum
Normal file
2
examples/group-management/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
231
examples/group-management/main.go
Normal file
231
examples/group-management/main.go
Normal file
@@ -0,0 +1,231 @@
|
||||
// 演示组管理功能
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"code.tczkiot.com/wlw/pipelinedb"
|
||||
"code.tczkiot.com/wlw/pipelinedb/examples/common"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 创建临时数据库文件
|
||||
dbFile := "group_example.db"
|
||||
defer os.Remove(dbFile)
|
||||
|
||||
// 确保文件可以创建
|
||||
if _, err := os.Create(dbFile); err != nil {
|
||||
log.Fatalf("创建数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("🚀 组管理示例")
|
||||
fmt.Println("==============")
|
||||
|
||||
// 配置数据库
|
||||
fmt.Println("\n📂 步骤1: 配置数据库")
|
||||
config := &pipelinedb.Config{
|
||||
CacheSize: 50,
|
||||
}
|
||||
|
||||
// 创建处理器
|
||||
handler := common.NewExampleHandler("组管理示例")
|
||||
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: dbFile,
|
||||
Config: config,
|
||||
Handler: handler,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("打开数据库失败: %v", err)
|
||||
}
|
||||
defer pdb.Stop()
|
||||
|
||||
fmt.Println("✅ 数据库已配置")
|
||||
|
||||
// 创建多个组的数据
|
||||
fmt.Println("\n📊 步骤2: 创建多组数据")
|
||||
|
||||
groups := map[string][]string{
|
||||
"订单处理": {
|
||||
"新订单创建: 订单号 #12345",
|
||||
"支付确认: 订单号 #12345",
|
||||
"库存检查: 商品 SKU-001",
|
||||
"发货准备: 订单号 #12345",
|
||||
"物流跟踪: 快递单号 SF123456",
|
||||
},
|
||||
"用户管理": {
|
||||
"用户注册: user@example.com",
|
||||
"邮箱验证: user@example.com",
|
||||
"个人资料更新: 用户ID 1001",
|
||||
"密码修改: 用户ID 1001",
|
||||
"账户注销: 用户ID 1002",
|
||||
},
|
||||
"系统监控": {
|
||||
"CPU使用率: 85%",
|
||||
"内存使用率: 70%",
|
||||
"磁盘空间: 剩余 20GB",
|
||||
"网络延迟: 50ms",
|
||||
"数据库连接数: 150",
|
||||
},
|
||||
"安全审计": {
|
||||
"登录尝试: IP 192.168.1.100",
|
||||
"权限检查: 用户ID 1001",
|
||||
"异常访问: IP 10.0.0.1",
|
||||
"数据访问: 表 users",
|
||||
"API调用: /api/v1/users",
|
||||
},
|
||||
}
|
||||
|
||||
// 插入数据到各个组
|
||||
for group, messages := range groups {
|
||||
fmt.Printf("\n📝 插入数据到组: %s\n", group)
|
||||
|
||||
for i, message := range messages {
|
||||
metadata := fmt.Sprintf(`{"sequence": %d, "priority": "normal"}`, i+1)
|
||||
|
||||
recordID, err := pdb.AcceptData(group, []byte(message), metadata)
|
||||
if err != nil {
|
||||
log.Fatalf("插入数据失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf(" ✅ 记录 %d: %s\n", recordID, message)
|
||||
}
|
||||
}
|
||||
|
||||
// 查看初始统计
|
||||
fmt.Println("\n📊 步骤3: 查看初始统计")
|
||||
stats, err := pdb.GetStats()
|
||||
if err != nil {
|
||||
log.Fatalf("获取统计失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("📈 数据库统计:\n")
|
||||
fmt.Printf(" 总记录数: %d\n", stats.TotalRecords)
|
||||
fmt.Printf(" 总组数: %d\n", len(stats.GroupStats))
|
||||
|
||||
for group, groupStats := range stats.GroupStats {
|
||||
fmt.Printf(" [%s]: 总计:%d (热:%d 温:%d 冷:%d)\n",
|
||||
group, groupStats.TotalRecords, groupStats.HotRecords, groupStats.WarmRecords, groupStats.ColdRecords)
|
||||
}
|
||||
|
||||
// 演示组查询
|
||||
fmt.Println("\n🔍 步骤4: 演示组查询")
|
||||
|
||||
for group := range groups {
|
||||
fmt.Printf("\n📋 查询组: %s\n", group)
|
||||
|
||||
// 分页查询
|
||||
pageReq := &pipelinedb.PageRequest{
|
||||
Page: 1,
|
||||
PageSize: 3, // 每页3条记录
|
||||
}
|
||||
|
||||
response, err := pdb.GetRecordsByGroup(group, pageReq)
|
||||
if err != nil {
|
||||
fmt.Printf(" ❌ 查询失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf(" 📊 总记录: %d, 当前页: %d/%d\n",
|
||||
response.TotalCount, response.Page, response.TotalPages)
|
||||
|
||||
for _, record := range response.Records {
|
||||
fmt.Printf(" 📄 ID:%d [%s] %s\n",
|
||||
record.ID, record.Status, string(record.Data))
|
||||
}
|
||||
|
||||
// 如果有多页,查询第二页
|
||||
if response.TotalPages > 1 {
|
||||
fmt.Printf(" 📄 查询第2页:\n")
|
||||
pageReq.Page = 2
|
||||
|
||||
response2, err := pdb.GetRecordsByGroup(group, pageReq)
|
||||
if err != nil {
|
||||
fmt.Printf(" ❌ 查询第2页失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, record := range response2.Records {
|
||||
fmt.Printf(" 📄 ID:%d [%s] %s\n",
|
||||
record.ID, record.Status, string(record.Data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 演示数据状态流转
|
||||
fmt.Println("\n🔄 步骤5: 观察数据状态流转")
|
||||
|
||||
// 等待一段时间让数据处理
|
||||
fmt.Println("⏳ 等待数据处理...")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// 再次查看统计
|
||||
fmt.Println("\n📊 处理后的统计:")
|
||||
finalStats, err := pdb.GetStats()
|
||||
if err != nil {
|
||||
log.Fatalf("获取最终统计失败: %v", err)
|
||||
}
|
||||
|
||||
for group, groupStats := range finalStats.GroupStats {
|
||||
fmt.Printf(" [%s]: 总计:%d (热:%d 温:%d 冷:%d)\n",
|
||||
group, groupStats.TotalRecords, groupStats.HotRecords, groupStats.WarmRecords, groupStats.ColdRecords)
|
||||
}
|
||||
|
||||
// 演示跨组查询
|
||||
fmt.Println("\n🔍 步骤6: 跨组数据分析")
|
||||
|
||||
totalRecords := 0
|
||||
totalHot := 0
|
||||
totalWarm := 0
|
||||
totalCold := 0
|
||||
|
||||
for _, groupStats := range finalStats.GroupStats {
|
||||
totalRecords += groupStats.TotalRecords
|
||||
totalHot += groupStats.HotRecords
|
||||
totalWarm += groupStats.WarmRecords
|
||||
totalCold += groupStats.ColdRecords
|
||||
}
|
||||
|
||||
fmt.Printf("📊 跨组统计汇总:\n")
|
||||
fmt.Printf(" 总记录数: %d\n", totalRecords)
|
||||
fmt.Printf(" 状态分布:\n")
|
||||
fmt.Printf(" 热数据: %d (%.1f%%)\n", totalHot, float64(totalHot)/float64(totalRecords)*100)
|
||||
fmt.Printf(" 温数据: %d (%.1f%%)\n", totalWarm, float64(totalWarm)/float64(totalRecords)*100)
|
||||
fmt.Printf(" 冷数据: %d (%.1f%%)\n", totalCold, float64(totalCold)/float64(totalRecords)*100)
|
||||
|
||||
// 找出最活跃的组
|
||||
maxRecords := 0
|
||||
mostActiveGroup := ""
|
||||
for group, groupStats := range finalStats.GroupStats {
|
||||
if groupStats.TotalRecords > maxRecords {
|
||||
maxRecords = groupStats.TotalRecords
|
||||
mostActiveGroup = group
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\n🏆 最活跃的组: %s (%d 条记录)\n", mostActiveGroup, maxRecords)
|
||||
|
||||
// 演示组级别的操作
|
||||
fmt.Println("\n🛠️ 步骤7: 组级别操作演示")
|
||||
|
||||
fmt.Printf("📋 所有组列表:\n")
|
||||
for group := range finalStats.GroupStats {
|
||||
fmt.Printf(" 📁 %s\n", group)
|
||||
}
|
||||
|
||||
// 模拟组的生命周期管理
|
||||
fmt.Printf("\n🔄 组生命周期管理:\n")
|
||||
fmt.Printf(" 1. 创建组 -> 接收数据 -> 处理数据\n")
|
||||
fmt.Printf(" 2. 监控组状态 -> 统计分析\n")
|
||||
fmt.Printf(" 3. 暂停/恢复组 -> 组级别控制\n")
|
||||
fmt.Printf(" 4. 查询组数据 -> 分页浏览\n")
|
||||
fmt.Printf(" 5. 跨组分析 -> 全局统计\n")
|
||||
|
||||
fmt.Println("\n🎉 组管理示例完成!")
|
||||
fmt.Println("💡 提示: 组功能让你可以按业务逻辑组织和管理数据")
|
||||
fmt.Println("💡 每个组都有独立的统计信息和处理流程")
|
||||
fmt.Println("💡 支持组级别的暂停、恢复和查询操作")
|
||||
}
|
||||
9
examples/high-concurrency/go.mod
Normal file
9
examples/high-concurrency/go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module high-concurrency
|
||||
|
||||
go 1.24.0
|
||||
|
||||
replace code.tczkiot.com/wlw/pipelinedb => ../../
|
||||
|
||||
require code.tczkiot.com/wlw/pipelinedb v0.0.0-00010101000000-000000000000
|
||||
|
||||
require github.com/google/btree v1.1.3 // indirect
|
||||
2
examples/high-concurrency/go.sum
Normal file
2
examples/high-concurrency/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
315
examples/high-concurrency/main.go
Normal file
315
examples/high-concurrency/main.go
Normal file
@@ -0,0 +1,315 @@
|
||||
// 高并发压力测试示例
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"code.tczkiot.com/wlw/pipelinedb"
|
||||
"code.tczkiot.com/wlw/pipelinedb/examples/common"
|
||||
)
|
||||
|
||||
// 性能指标
|
||||
type PerformanceMetrics struct {
|
||||
TotalOperations int64
|
||||
SuccessfulWrites int64
|
||||
FailedWrites int64
|
||||
SuccessfulReads int64
|
||||
FailedReads int64
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
}
|
||||
|
||||
// 工作负载配置
|
||||
type WorkloadConfig struct {
|
||||
NumWriters int // 写入goroutine数量
|
||||
NumReaders int // 读取goroutine数量
|
||||
WritesPerSecond int // 每秒写入次数
|
||||
ReadsPerSecond int // 每秒读取次数
|
||||
TestDuration time.Duration // 测试持续时间
|
||||
DataSize int // 每条记录的数据大小
|
||||
NumGroups int // 数据组数量
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 设置随机种子
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
// 创建临时数据库文件
|
||||
dbFile := "high_concurrency_test.db"
|
||||
defer os.Remove(dbFile)
|
||||
|
||||
// 确保文件可以创建
|
||||
if _, err := os.Create(dbFile); err != nil {
|
||||
log.Fatalf("创建数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("🚀 高并发压力测试")
|
||||
fmt.Println("==================")
|
||||
fmt.Printf("🖥️ 系统信息: %d CPU核心, %s\n", runtime.NumCPU(), runtime.Version())
|
||||
|
||||
// 配置工作负载
|
||||
config := WorkloadConfig{
|
||||
NumWriters: 50, // 50个写入goroutine
|
||||
NumReaders: 20, // 20个读取goroutine
|
||||
WritesPerSecond: 1000, // 每秒1000次写入
|
||||
ReadsPerSecond: 500, // 每秒500次读取
|
||||
TestDuration: 30 * time.Second, // 运行30秒
|
||||
DataSize: 256, // 256字节数据
|
||||
NumGroups: 10, // 10个数据组
|
||||
}
|
||||
|
||||
fmt.Printf("📊 测试配置:\n")
|
||||
fmt.Printf(" 写入goroutine: %d\n", config.NumWriters)
|
||||
fmt.Printf(" 读取goroutine: %d\n", config.NumReaders)
|
||||
fmt.Printf(" 目标写入QPS: %d\n", config.WritesPerSecond)
|
||||
fmt.Printf(" 目标读取QPS: %d\n", config.ReadsPerSecond)
|
||||
fmt.Printf(" 测试时长: %v\n", config.TestDuration)
|
||||
fmt.Printf(" 数据大小: %d bytes\n", config.DataSize)
|
||||
fmt.Printf(" 数据组数: %d\n", config.NumGroups)
|
||||
|
||||
// 配置数据库
|
||||
fmt.Println("\n📂 步骤1: 初始化数据库")
|
||||
dbConfig := &pipelinedb.Config{
|
||||
CacheSize: 1000, // 大缓存支持高并发
|
||||
WarmInterval: 5 * time.Second, // 较长的预热间隔
|
||||
ProcessInterval: 10 * time.Second, // 较长的处理间隔
|
||||
BatchSize: 100, // 大批次处理
|
||||
}
|
||||
|
||||
// 创建处理器
|
||||
handler := common.NewLoggingHandler()
|
||||
|
||||
pdb, err := pipelinedb.Open(pipelinedb.Options{
|
||||
Filename: dbFile,
|
||||
Config: dbConfig,
|
||||
Handler: handler,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("打开数据库失败: %v", err)
|
||||
}
|
||||
defer pdb.Stop()
|
||||
|
||||
fmt.Println("✅ 数据库已初始化")
|
||||
|
||||
// 性能指标
|
||||
metrics := &PerformanceMetrics{
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
|
||||
// 控制通道
|
||||
stopChan := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 启动写入goroutine
|
||||
fmt.Println("\n🏭 步骤2: 启动写入压力测试")
|
||||
writeInterval := time.Duration(int64(time.Second) / int64(config.WritesPerSecond/config.NumWriters))
|
||||
|
||||
for i := 0; i < config.NumWriters; i++ {
|
||||
wg.Add(1)
|
||||
go func(writerID int) {
|
||||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(writeInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
localWrites := 0
|
||||
for {
|
||||
select {
|
||||
case <-stopChan:
|
||||
fmt.Printf("📝 写入器 %d 停止,完成 %d 次写入\n", writerID, localWrites)
|
||||
return
|
||||
case <-ticker.C:
|
||||
// 生成随机数据
|
||||
groupID := rand.Intn(config.NumGroups)
|
||||
groupName := fmt.Sprintf("group_%d", groupID)
|
||||
|
||||
data := make([]byte, config.DataSize)
|
||||
for j := range data {
|
||||
data[j] = byte(rand.Intn(256))
|
||||
}
|
||||
|
||||
metadata := fmt.Sprintf(`{"writer_id": %d, "timestamp": %d, "sequence": %d}`,
|
||||
writerID, time.Now().UnixNano(), localWrites)
|
||||
|
||||
// 执行写入
|
||||
_, err := pdb.AcceptData(groupName, data, metadata)
|
||||
atomic.AddInt64(&metrics.TotalOperations, 1)
|
||||
|
||||
if err != nil {
|
||||
atomic.AddInt64(&metrics.FailedWrites, 1)
|
||||
} else {
|
||||
atomic.AddInt64(&metrics.SuccessfulWrites, 1)
|
||||
localWrites++
|
||||
}
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 启动读取goroutine
|
||||
fmt.Println("🔍 启动读取压力测试")
|
||||
readInterval := time.Duration(int64(time.Second) / int64(config.ReadsPerSecond/config.NumReaders))
|
||||
|
||||
for i := 0; i < config.NumReaders; i++ {
|
||||
wg.Add(1)
|
||||
go func(readerID int) {
|
||||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(readInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
localReads := 0
|
||||
for {
|
||||
select {
|
||||
case <-stopChan:
|
||||
fmt.Printf("📖 读取器 %d 停止,完成 %d 次读取\n", readerID, localReads)
|
||||
return
|
||||
case <-ticker.C:
|
||||
// 随机选择组进行查询
|
||||
groupID := rand.Intn(config.NumGroups)
|
||||
groupName := fmt.Sprintf("group_%d", groupID)
|
||||
|
||||
pageReq := &pipelinedb.PageRequest{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
}
|
||||
|
||||
// 执行读取
|
||||
_, err := pdb.GetRecordsByGroup(groupName, pageReq)
|
||||
atomic.AddInt64(&metrics.TotalOperations, 1)
|
||||
|
||||
if err != nil {
|
||||
atomic.AddInt64(&metrics.FailedReads, 1)
|
||||
} else {
|
||||
atomic.AddInt64(&metrics.SuccessfulReads, 1)
|
||||
localReads++
|
||||
}
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 启动实时监控
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
lastWrites := int64(0)
|
||||
lastReads := int64(0)
|
||||
lastTime := time.Now()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopChan:
|
||||
return
|
||||
case <-ticker.C:
|
||||
currentWrites := atomic.LoadInt64(&metrics.SuccessfulWrites)
|
||||
currentReads := atomic.LoadInt64(&metrics.SuccessfulReads)
|
||||
currentTime := time.Now()
|
||||
|
||||
elapsed := currentTime.Sub(lastTime).Seconds()
|
||||
writeQPS := float64(currentWrites-lastWrites) / elapsed
|
||||
readQPS := float64(currentReads-lastReads) / elapsed
|
||||
|
||||
fmt.Printf("\n📊 实时性能 (时间: %s)\n", currentTime.Format("15:04:05"))
|
||||
fmt.Printf(" 写入QPS: %.1f (目标: %d)\n", writeQPS, config.WritesPerSecond)
|
||||
fmt.Printf(" 读取QPS: %.1f (目标: %d)\n", readQPS, config.ReadsPerSecond)
|
||||
fmt.Printf(" 总写入: %d (失败: %d)\n", currentWrites, atomic.LoadInt64(&metrics.FailedWrites))
|
||||
fmt.Printf(" 总读取: %d (失败: %d)\n", currentReads, atomic.LoadInt64(&metrics.FailedReads))
|
||||
|
||||
// 获取数据库统计
|
||||
stats, err := pdb.GetStats()
|
||||
if err == nil {
|
||||
fmt.Printf(" 数据库记录: %d\n", stats.TotalRecords)
|
||||
fmt.Printf(" 活跃组数: %d\n", len(stats.GroupStats))
|
||||
}
|
||||
|
||||
lastWrites = currentWrites
|
||||
lastReads = currentReads
|
||||
lastTime = currentTime
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 运行测试
|
||||
fmt.Printf("\n⏳ 步骤3: 运行压力测试 (%v)\n", config.TestDuration)
|
||||
time.Sleep(config.TestDuration)
|
||||
|
||||
// 停止所有goroutine
|
||||
fmt.Println("\n🛑 步骤4: 停止压力测试")
|
||||
close(stopChan)
|
||||
wg.Wait()
|
||||
|
||||
metrics.EndTime = time.Now()
|
||||
|
||||
// 最终性能报告
|
||||
fmt.Println("\n📈 步骤5: 性能报告")
|
||||
totalDuration := metrics.EndTime.Sub(metrics.StartTime)
|
||||
|
||||
fmt.Printf("🎯 测试结果:\n")
|
||||
fmt.Printf(" 测试时长: %v\n", totalDuration)
|
||||
fmt.Printf(" 总操作数: %d\n", metrics.TotalOperations)
|
||||
fmt.Printf(" 平均QPS: %.1f\n", float64(metrics.TotalOperations)/totalDuration.Seconds())
|
||||
|
||||
fmt.Printf("\n📝 写入性能:\n")
|
||||
fmt.Printf(" 成功写入: %d\n", metrics.SuccessfulWrites)
|
||||
fmt.Printf(" 失败写入: %d\n", metrics.FailedWrites)
|
||||
fmt.Printf(" 写入成功率: %.2f%%\n", float64(metrics.SuccessfulWrites)/float64(metrics.SuccessfulWrites+metrics.FailedWrites)*100)
|
||||
fmt.Printf(" 平均写入QPS: %.1f\n", float64(metrics.SuccessfulWrites)/totalDuration.Seconds())
|
||||
|
||||
fmt.Printf("\n📖 读取性能:\n")
|
||||
fmt.Printf(" 成功读取: %d\n", metrics.SuccessfulReads)
|
||||
fmt.Printf(" 失败读取: %d\n", metrics.FailedReads)
|
||||
fmt.Printf(" 读取成功率: %.2f%%\n", float64(metrics.SuccessfulReads)/float64(metrics.SuccessfulReads+metrics.FailedReads)*100)
|
||||
fmt.Printf(" 平均读取QPS: %.1f\n", float64(metrics.SuccessfulReads)/totalDuration.Seconds())
|
||||
|
||||
// 数据库最终状态
|
||||
finalStats, err := pdb.GetStats()
|
||||
if err == nil {
|
||||
fmt.Printf("\n💾 数据库状态:\n")
|
||||
fmt.Printf(" 总记录数: %d\n", finalStats.TotalRecords)
|
||||
fmt.Printf(" 总组数: %d\n", len(finalStats.GroupStats))
|
||||
fmt.Printf(" 热数据: %d\n", finalStats.HotRecords)
|
||||
fmt.Printf(" 温数据: %d\n", finalStats.WarmRecords)
|
||||
fmt.Printf(" 冷数据: %d\n", finalStats.ColdRecords)
|
||||
|
||||
fmt.Printf("\n📊 各组分布:\n")
|
||||
for group, groupStats := range finalStats.GroupStats {
|
||||
fmt.Printf(" %s: %d 条记录\n", group, groupStats.TotalRecords)
|
||||
}
|
||||
}
|
||||
|
||||
// 性能评估
|
||||
fmt.Printf("\n🏆 性能评估:\n")
|
||||
expectedWrites := float64(config.WritesPerSecond) * totalDuration.Seconds()
|
||||
expectedReads := float64(config.ReadsPerSecond) * totalDuration.Seconds()
|
||||
|
||||
writeEfficiency := float64(metrics.SuccessfulWrites) / expectedWrites * 100
|
||||
readEfficiency := float64(metrics.SuccessfulReads) / expectedReads * 100
|
||||
|
||||
fmt.Printf(" 写入效率: %.1f%% (期望: %.0f, 实际: %d)\n",
|
||||
writeEfficiency, expectedWrites, metrics.SuccessfulWrites)
|
||||
fmt.Printf(" 读取效率: %.1f%% (期望: %.0f, 实际: %d)\n",
|
||||
readEfficiency, expectedReads, metrics.SuccessfulReads)
|
||||
|
||||
if writeEfficiency > 90 && readEfficiency > 90 {
|
||||
fmt.Println(" 🎉 性能优秀!数据库在高并发下表现稳定")
|
||||
} else if writeEfficiency > 70 && readEfficiency > 70 {
|
||||
fmt.Println(" 👍 性能良好,可以承受高并发负载")
|
||||
} else {
|
||||
fmt.Println(" ⚠️ 性能需要优化,建议调整配置参数")
|
||||
}
|
||||
|
||||
fmt.Println("\n🎉 高并发压力测试完成!")
|
||||
fmt.Println("💡 这个测试验证了Pipeline Database在极限并发下的稳定性和性能")
|
||||
}
|
||||
122
examples/run_all.sh
Executable file
122
examples/run_all.sh
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Pipeline Database V4 - 运行所有示例脚本
|
||||
|
||||
echo "🚀 Pipeline Database V4 - 运行所有示例"
|
||||
echo "========================================"
|
||||
|
||||
# 示例列表
|
||||
examples=(
|
||||
"basic-usage:基础使用示例:演示数据库的基本操作"
|
||||
"group-management:组管理示例:演示多组数据管理功能"
|
||||
"external-handler:外部处理器示例:演示自定义数据处理流程"
|
||||
"data-analytics:数据分析示例:演示复杂数据分析功能"
|
||||
"concurrent-processing:并发处理示例:演示高并发数据处理"
|
||||
)
|
||||
|
||||
echo "📋 将要运行 ${#examples[@]} 个示例"
|
||||
echo ""
|
||||
|
||||
# 询问用户是否继续
|
||||
read -p "是否继续运行所有示例? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "❌ 已取消运行"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
success_count=0
|
||||
fail_count=0
|
||||
total_start=$(date +%s)
|
||||
|
||||
for i in "${!examples[@]}"; do
|
||||
IFS=':' read -r dir name desc <<< "${examples[$i]}"
|
||||
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "📍 示例 $((i+1))/${#examples[@]}: $name"
|
||||
echo "📁 目录: $dir"
|
||||
echo "📝 描述: $desc"
|
||||
echo "============================================================"
|
||||
|
||||
if [ ! -d "$dir" ]; then
|
||||
echo "❌ 目录不存在: $dir"
|
||||
((fail_count++))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ! -f "$dir/main.go" ]; then
|
||||
echo "❌ 文件不存在: $dir/main.go"
|
||||
((fail_count++))
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "🚀 开始运行..."
|
||||
echo ""
|
||||
|
||||
start_time=$(date +%s)
|
||||
|
||||
# 运行示例
|
||||
if (cd "$dir" && go run main.go); then
|
||||
end_time=$(date +%s)
|
||||
duration=$((end_time - start_time))
|
||||
echo ""
|
||||
echo "✅ 示例运行成功!"
|
||||
echo "⏱️ 运行时间: ${duration}秒"
|
||||
((success_count++))
|
||||
else
|
||||
end_time=$(date +%s)
|
||||
duration=$((end_time - start_time))
|
||||
echo ""
|
||||
echo "❌ 示例运行失败!"
|
||||
echo "⏱️ 运行时间: ${duration}秒"
|
||||
((fail_count++))
|
||||
fi
|
||||
|
||||
# 如果不是最后一个示例,等待一下
|
||||
if [ $((i+1)) -lt ${#examples[@]} ]; then
|
||||
echo ""
|
||||
echo "⏳ 等待 2 秒后运行下一个示例..."
|
||||
sleep 2
|
||||
fi
|
||||
done
|
||||
|
||||
# 总结
|
||||
total_end=$(date +%s)
|
||||
total_duration=$((total_end - total_start))
|
||||
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "🎯 运行总结"
|
||||
echo "============================================================"
|
||||
echo "✅ 成功: $success_count 个示例"
|
||||
echo "❌ 失败: $fail_count 个示例"
|
||||
echo "📊 成功率: $(echo "scale=1; $success_count * 100 / ${#examples[@]}" | bc -l)%"
|
||||
echo "⏱️ 总运行时间: ${total_duration}秒"
|
||||
|
||||
if [ $fail_count -eq 0 ]; then
|
||||
echo ""
|
||||
echo "🎉 所有示例都运行成功!"
|
||||
echo "💡 你现在已经了解了 Pipeline Database V4 的主要功能"
|
||||
echo "📚 建议接下来:"
|
||||
echo " 1. 查看示例源代码,理解实现细节"
|
||||
echo " 2. 根据你的需求修改示例"
|
||||
echo " 3. 在你的项目中集成 Pipeline Database"
|
||||
else
|
||||
echo ""
|
||||
echo "⚠️ 有 $fail_count 个示例运行失败"
|
||||
echo "🔧 建议检查:"
|
||||
echo " 1. Go 版本是否兼容 (需要 1.19+)"
|
||||
echo " 2. 依赖包是否正确安装"
|
||||
echo " 3. 文件权限是否正确"
|
||||
echo " 4. 系统资源是否充足"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📞 需要帮助?"
|
||||
echo " - 查看 README.md 了解详细信息"
|
||||
echo " - 检查项目文档和 API 参考"
|
||||
echo " - 在项目仓库提交 Issue"
|
||||
|
||||
echo ""
|
||||
echo "🙏 感谢使用 Pipeline Database V4!"
|
||||
Reference in New Issue
Block a user