Skip to content

Commit d048e4b

Browse files
authored
Add a persistence hook based on cockroachdb/pebble. (#378)
* Implementing Pebble as a persistence database hook. * Fixed failing test cases. * Add Pebble DB configuration for file-based configuration, optimize part of the code. * Resolve test failure issues and perform code optimization. * Optimized the test cases.
1 parent 47162a3 commit d048e4b

File tree

12 files changed

+1984
-22
lines changed

12 files changed

+1984
-22
lines changed

README-CN.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ MQTT 代表 MQ Telemetry Transport。它是一种发布/订阅、非常简单和
4545
- 通过所有 [Paho互操作性测试](https://github.com/eclipse/paho.mqtt.testing/tree/master/interoperability)(MQTT v5 和 MQTT v3)。
4646
- 超过一千多个经过仔细考虑的单元测试场景。
4747
- 支持 TCP、Websocket(包括 SSL/TLS)和$SYS 服务状态监控。
48-
- 内置 基于Redis、Badger 和 Bolt 的持久化(使用Hook钩子,你也可以自己创建)。
48+
- 内置 基于Redis、Badger、Pebble 和 Bolt 的持久化(使用Hook钩子,你也可以自己创建)。
4949
- 内置基于规则的认证和 ACL 权限管理(使用Hook钩子,你也可以自己创建)。
5050

5151
### 兼容性说明(Compatibility Notes)
@@ -227,6 +227,7 @@ server := mqtt.New(&mqtt.Options{
227227
| 访问控制 | [mochi-mqtt/server/hooks/auth . Auth](hooks/auth/auth.go) | 基于规则的访问权限控制。 |
228228
| 数据持久性 | [mochi-mqtt/server/hooks/storage/bolt](hooks/storage/bolt/bolt.go) | 使用 [BoltDB](https://dbdb.io/db/boltdb) 进行持久性存储(已弃用)。 |
229229
| 数据持久性 | [mochi-mqtt/server/hooks/storage/badger](hooks/storage/badger/badger.go) | 使用 [BadgerDB](https://github.com/dgraph-io/badger) 进行持久性存储。 |
230+
| 数据持久性 | [mochi-mqtt/server/hooks/storage/pebble](hooks/storage/pebble/pebble.go) | 使用 [PebbleDB](https://github.com/cockroachdb/pebble) 进行持久性存储。 |
230231
| 数据持久性 | [mochi-mqtt/server/hooks/storage/redis](hooks/storage/redis/redis.go) | 使用 [Redis](https://redis.io) 进行持久性存储。 |
231232
| 调试跟踪 | [mochi-mqtt/server/hooks/debug](hooks/debug/debug.go) | 调试输出以查看数据包在服务端的链路追踪。 |
232233

@@ -329,9 +330,25 @@ if err != nil {
329330
```
330331
有关 Redis 钩子的工作原理或如何使用它的更多信息,请参阅 [examples/persistence/redis/main.go](examples/persistence/redis/main.go)[hooks/storage/redis](hooks/storage/redis)
331332

333+
#### Pebble DB
334+
335+
如果您更喜欢基于文件的存储,还有一个 PebbleDB 存储钩子(Hook)可用。它可以以与其他钩子大致相同的方式添加和配置(具有较少的选项)。
336+
337+
```go
338+
err := server.AddHook(new(pebble.Hook), &pebble.Options{
339+
Path: pebblePath,
340+
Mode: pebble.NoSync,
341+
})
342+
if err != nil {
343+
log.Fatal(err)
344+
}
345+
```
346+
347+
有关 pebble 钩子(Hook)的工作原理或如何使用它的更多信息,请参阅 [examples/persistence/pebble/main.go](examples/persistence/pebble/main.go)[hooks/storage/pebble](hooks/storage/pebble)
348+
332349
#### Badger DB
333350

334-
如果您更喜欢基于文件的存储,还有一个 BadgerDB 存储钩子(Hook)可用。它可以以与其他钩子大致相同的方式添加和配置(具有较少的选项)
351+
同样是基于文件的存储,还有一个 BadgerDB 存储钩子(Hook)可用。它可以以与其他钩子大致相同的方式添加和配置。
335352

336353
```go
337354
err := server.AddHook(new(badger.Hook), &badger.Options{

README.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ MQTT stands for [MQ Telemetry Transport](https://en.wikipedia.org/wiki/MQTT). It
4545
- Passes all [Paho Interoperability Tests](https://github.com/eclipse/paho.mqtt.testing/tree/master/interoperability) for MQTT v5 and MQTT v3.
4646
- Over a thousand carefully considered unit test scenarios.
4747
- TCP, Websocket (including SSL/TLS), and $SYS Dashboard listeners.
48-
- Built-in Redis, Badger, and Bolt Persistence using Hooks (but you can also make your own).
48+
- Built-in Redis, Badger, Pebble and Bolt Persistence using Hooks (but you can also make your own).
4949
- Built-in Rule-based Authentication and ACL Ledger using Hooks (also make your own).
5050

5151
### Compatibility Notes
@@ -228,6 +228,7 @@ Hooks are stackable - you can add multiple hooks to a server, and they will be r
228228
| Access Control | [mochi-mqtt/server/hooks/auth . Auth](hooks/auth/auth.go) | Rule-based access control ledger. |
229229
| Persistence | [mochi-mqtt/server/hooks/storage/bolt](hooks/storage/bolt/bolt.go) | Persistent storage using [BoltDB](https://dbdb.io/db/boltdb) (deprecated). |
230230
| Persistence | [mochi-mqtt/server/hooks/storage/badger](hooks/storage/badger/badger.go) | Persistent storage using [BadgerDB](https://github.com/dgraph-io/badger). |
231+
| Persistence | [mochi-mqtt/server/hooks/storage/pebble](hooks/storage/pebble/pebble.go) | Persistent storage using [PebbleDB](https://github.com/cockroachdb/pebble). |
231232
| Persistence | [mochi-mqtt/server/hooks/storage/redis](hooks/storage/redis/redis.go) | Persistent storage using [Redis](https://redis.io). |
232233
| Debugging | [mochi-mqtt/server/hooks/debug](hooks/debug/debug.go) | Additional debugging output to visualise packet flow. |
233234

@@ -322,8 +323,21 @@ if err != nil {
322323
```
323324
For more information on how the redis hook works, or how to use it, see the [examples/persistence/redis/main.go](examples/persistence/redis/main.go) or [hooks/storage/redis](hooks/storage/redis) code.
324325

326+
#### Pebble DB
327+
There's also a Pebble Db storage hook if you prefer file-based storage. It can be added and configured in much the same way as the other hooks (with somewhat less options).
328+
```go
329+
err := server.AddHook(new(pebble.Hook), &pebble.Options{
330+
Path: pebblePath,
331+
Mode: pebble.NoSync,
332+
})
333+
if err != nil {
334+
log.Fatal(err)
335+
}
336+
```
337+
For more information on how the pebble hook works, or how to use it, see the [examples/persistence/pebble/main.go](examples/persistence/pebble/main.go) or [hooks/storage/pebble](hooks/storage/pebble) code.
338+
325339
#### Badger DB
326-
There's also a BadgerDB storage hook if you prefer file based storage. It can be added and configured in much the same way as the other hooks (with somewhat less options).
340+
Similarly, for file-based storage, there is also a BadgerDB storage hook available. It can be added and configured in much the same way as the other hooks.
327341
```go
328342
err := server.AddHook(new(badger.Hook), &badger.Options{
329343
Path: badgerPath,

config/config.go

+10
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ package config
66

77
import (
88
"encoding/json"
9+
910
"github.com/mochi-mqtt/server/v2/hooks/auth"
1011
"github.com/mochi-mqtt/server/v2/hooks/debug"
1112
"github.com/mochi-mqtt/server/v2/hooks/storage/badger"
1213
"github.com/mochi-mqtt/server/v2/hooks/storage/bolt"
14+
"github.com/mochi-mqtt/server/v2/hooks/storage/pebble"
1315
"github.com/mochi-mqtt/server/v2/hooks/storage/redis"
1416
"github.com/mochi-mqtt/server/v2/listeners"
1517
"gopkg.in/yaml.v3"
@@ -41,6 +43,7 @@ type HookAuthConfig struct {
4143
type HookStorageConfig struct {
4244
Badger *badger.Options `yaml:"badger" json:"badger"`
4345
Bolt *bolt.Options `yaml:"bolt" json:"bolt"`
46+
Pebble *pebble.Options `yaml:"pebble" json:"pebble"`
4447
Redis *redis.Options `yaml:"redis" json:"redis"`
4548
}
4649

@@ -111,6 +114,13 @@ func (hc HookConfigs) toHooksStorage() []mqtt.HookLoadConfig {
111114
Config: hc.Storage.Redis,
112115
})
113116
}
117+
118+
if hc.Storage.Pebble != nil {
119+
hlc = append(hlc, mqtt.HookLoadConfig{
120+
Hook: new(pebble.Hook),
121+
Config: hc.Storage.Pebble,
122+
})
123+
}
114124
return hlc
115125
}
116126

config/config_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/mochi-mqtt/server/v2/hooks/auth"
1313
"github.com/mochi-mqtt/server/v2/hooks/storage/badger"
1414
"github.com/mochi-mqtt/server/v2/hooks/storage/bolt"
15+
"github.com/mochi-mqtt/server/v2/hooks/storage/pebble"
1516
"github.com/mochi-mqtt/server/v2/hooks/storage/redis"
1617
"github.com/mochi-mqtt/server/v2/listeners"
1718

@@ -210,3 +211,23 @@ func TestToHooksStorageRedis(t *testing.T) {
210211

211212
require.Equal(t, expect, th)
212213
}
214+
215+
func TestToHooksStoragePebble(t *testing.T) {
216+
hc := HookConfigs{
217+
Storage: &HookStorageConfig{
218+
Pebble: &pebble.Options{
219+
Path: "pebble",
220+
},
221+
},
222+
}
223+
224+
th := hc.toHooksStorage()
225+
expect := []mqtt.HookLoadConfig{
226+
{
227+
Hook: new(pebble.Hook),
228+
Config: hc.Storage.Pebble,
229+
},
230+
}
231+
232+
require.Equal(t, expect, th)
233+
}

examples/config/config.json

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
"enable": true
2222
},
2323
"storage": {
24+
"pebble": {
25+
"path": "pebble.db",
26+
"mode": "NoSync"
27+
},
2428
"badger": {
2529
"path": "badger.db",
2630
"gc_interval": 3,

examples/config/config.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ hooks:
1616
path: badger.db
1717
gc_interval: 3
1818
gc_discard_ratio: 0.5
19+
pebble:
20+
path: pebble.db
21+
mode: "NoSync"
1922
bolt:
2023
path: bolt.db
2124
redis:

examples/persistence/pebble/main.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
// SPDX-FileCopyrightText: 2022 mochi-mqtt, mochi-co, werbenhu
3+
// SPDX-FileContributor: werbenhu
4+
5+
package main
6+
7+
import (
8+
"log"
9+
"os"
10+
"os/signal"
11+
"syscall"
12+
13+
mqtt "github.com/mochi-mqtt/server/v2"
14+
"github.com/mochi-mqtt/server/v2/hooks/auth"
15+
"github.com/mochi-mqtt/server/v2/hooks/storage/pebble"
16+
"github.com/mochi-mqtt/server/v2/listeners"
17+
)
18+
19+
func main() {
20+
pebblePath := ".pebble"
21+
defer os.RemoveAll(pebblePath) // remove the example pebble files at the end
22+
23+
sigs := make(chan os.Signal, 1)
24+
done := make(chan bool, 1)
25+
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
26+
go func() {
27+
<-sigs
28+
done <- true
29+
}()
30+
31+
server := mqtt.New(nil)
32+
_ = server.AddHook(new(auth.AllowHook), nil)
33+
34+
err := server.AddHook(new(pebble.Hook), &pebble.Options{
35+
Path: pebblePath,
36+
Mode: pebble.NoSync,
37+
})
38+
if err != nil {
39+
log.Fatal(err)
40+
}
41+
42+
tcp := listeners.NewTCP(listeners.Config{
43+
ID: "t1",
44+
Address: ":1883",
45+
})
46+
err = server.AddListener(tcp)
47+
if err != nil {
48+
log.Fatal(err)
49+
}
50+
51+
go func() {
52+
err := server.Serve()
53+
if err != nil {
54+
log.Fatal(err)
55+
}
56+
}()
57+
58+
<-done
59+
server.Log.Warn("caught signal, stopping...")
60+
_ = server.Close()
61+
server.Log.Info("main.go finished")
62+
}

go.mod

+25-6
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,51 @@ require (
66
github.com/alicebob/miniredis/v2 v2.23.0
77
github.com/asdine/storm v2.1.2+incompatible
88
github.com/asdine/storm/v3 v3.2.1
9+
github.com/cockroachdb/pebble v1.1.0
10+
github.com/dgraph-io/badger v1.6.0
911
github.com/go-redis/redis/v8 v8.11.5
1012
github.com/gorilla/websocket v1.5.0
1113
github.com/jinzhu/copier v0.3.5
1214
github.com/rs/xid v1.4.0
13-
github.com/stretchr/testify v1.7.1
15+
github.com/stretchr/testify v1.8.1
1416
github.com/timshannon/badgerhold v1.0.0
1517
go.etcd.io/bbolt v1.3.5
1618
gopkg.in/yaml.v3 v3.0.1
1719
)
1820

1921
require (
2022
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
23+
github.com/DataDog/zstd v1.4.5 // indirect
2124
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
22-
github.com/cespare/xxhash/v2 v2.1.2 // indirect
25+
github.com/beorn7/perks v1.0.1 // indirect
26+
github.com/cespare/xxhash/v2 v2.2.0 // indirect
27+
github.com/cockroachdb/errors v1.11.1 // indirect
28+
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
29+
github.com/cockroachdb/redact v1.1.5 // indirect
30+
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
2331
github.com/davecgh/go-spew v1.1.1 // indirect
24-
github.com/dgraph-io/badger v1.6.0 // indirect
2532
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
2633
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
2734
github.com/dustin/go-humanize v1.0.0 // indirect
28-
github.com/golang/protobuf v1.5.0 // indirect
29-
github.com/golang/snappy v0.0.3 // indirect
30-
github.com/google/go-cmp v0.5.8 // indirect
35+
github.com/getsentry/sentry-go v0.18.0 // indirect
36+
github.com/gogo/protobuf v1.3.2 // indirect
37+
github.com/golang/protobuf v1.5.2 // indirect
38+
github.com/golang/snappy v0.0.4 // indirect
39+
github.com/klauspost/compress v1.15.15 // indirect
40+
github.com/kr/pretty v0.3.1 // indirect
41+
github.com/kr/text v0.2.0 // indirect
42+
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
3143
github.com/pkg/errors v0.9.1 // indirect
3244
github.com/pmezard/go-difflib v1.0.0 // indirect
45+
github.com/prometheus/client_golang v1.12.0 // indirect
46+
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
47+
github.com/prometheus/common v0.32.1 // indirect
48+
github.com/prometheus/procfs v0.7.3 // indirect
49+
github.com/rogpeppe/go-internal v1.9.0 // indirect
3350
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect
51+
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
3452
golang.org/x/net v0.17.0 // indirect
3553
golang.org/x/sys v0.13.0 // indirect
54+
golang.org/x/text v0.13.0 // indirect
3655
google.golang.org/protobuf v1.33.0 // indirect
3756
)

0 commit comments

Comments
 (0)