Skip to content

Commit 3763b56

Browse files
authored
feat(storages): add embedded olric (#30)
1 parent 638c93d commit 3763b56

File tree

6 files changed

+326
-12
lines changed

6 files changed

+326
-12
lines changed

.github/workflows/static.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,9 @@ jobs:
6363
uses: golangci/golangci-lint-action@v3
6464
with:
6565
working-directory: ${{ matrix.submodules }}
66+
- name: Install olric
67+
run: go install github.com/buraksezer/olric/cmd/[email protected]
68+
- name: Run olric in detached mode
69+
run: olricd -c olric/docker/olric.yml &
6670
- name: unit tests
6771
run: go test -v -race ./${{ matrix.submodules }}

compose.test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,12 @@ services:
2727
- 4222:4222
2828
- 6222:6222
2929
- 8222:8222
30+
31+
olric:
32+
build:
33+
context: ./olric/docker
34+
target: olric
35+
restart: on-failure
36+
ports:
37+
- 3320:3320
38+
- 3322:3322

olric/docker/Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM golang:latest as olric
2+
3+
RUN mkdir -p src/github.com/buraksezer
4+
WORKDIR /go/src/github.com/buraksezer
5+
6+
# RUN git clone https://github.com/buraksezer/olric
7+
# WORKDIR /go/src/github.com/buraksezer/olric/cmd/olricd
8+
COPY ./olric.yml olricd-local.yaml
9+
# COPY ./olric.yml /etc/olricd.yaml
10+
RUN go install github.com/buraksezer/olric/cmd/[email protected]
11+
12+
EXPOSE 3320 3322
13+
14+
CMD ["olricd", "-c", "olricd-local.yaml"]

olric/docker/olric.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
olricd:
2+
bindAddr: localhost
3+
bindPort: 3320
4+
# keepAlivePeriod: 300s
5+
# bootstrapTimeout: 5s
6+
# partitionCount: 271
7+
# replicaCount: 1
8+
# writeQuorum: 1
9+
# readQuorum: 1
10+
# readRepair: false
11+
# replicationMode: 0
12+
# memberCountQuorum: 1
13+
# routingTablePushInterval: 1m
14+
# enableClusterEventsChannel: true
15+
16+
# client:
17+
# dialTimeout: 5s
18+
# readTimeout: 3s
19+
# writeTimeout: 3s
20+
# idleTimeout: 5m
21+
# idleCheckFrequency: 1m
22+
23+
logging:
24+
verbosity: 6
25+
level: DEBUG
26+
output: stderr
27+
28+
memberlist:
29+
environment: lan
30+
bindAddr: localhost
31+
bindPort: 3322
32+
enableCompression: false
33+
joinRetryInterval: 1s
34+
maxJoinAttempts: 10
35+
36+
dmaps:
37+
engine:
38+
name: kvstore
39+
config:
40+
tableSize: 524288

olric/olric.go

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@ import (
66
"errors"
77
"fmt"
88
"net/http"
9+
"os"
910
"strings"
1011
"sync"
1112
"time"
1213

1314
"github.com/buraksezer/olric"
1415
"github.com/buraksezer/olric/config"
1516
"github.com/darkweak/storages/core"
16-
lz4 "github.com/pierrec/lz4/v4"
17+
"github.com/google/uuid"
18+
"github.com/pierrec/lz4/v4"
19+
"gopkg.in/yaml.v3"
1720
)
1821

1922
// Olric provider type.
2023
type Olric struct {
21-
*olric.ClusterClient
24+
olric.Client
2225
dm *sync.Pool
2326
stale time.Duration
2427
logger core.Logger
@@ -27,15 +30,121 @@ type Olric struct {
2730
configuration config.Client
2831
}
2932

33+
func tryToLoadConfiguration(olricInstance *config.Config, olricConfiguration core.CacheProvider, logger core.Logger) (*config.Config, bool) {
34+
var err error
35+
36+
isAlreadyLoaded := false
37+
38+
if olricConfiguration.Configuration == nil && olricConfiguration.Path != "" {
39+
if olricInstance, err = config.Load(olricConfiguration.Path); err == nil {
40+
isAlreadyLoaded = true
41+
}
42+
} else if olricConfiguration.Configuration != nil {
43+
tmpFile := "/tmp/" + uuid.NewString() + ".yml"
44+
yamlConfig, _ := yaml.Marshal(olricConfiguration.Configuration)
45+
46+
defer func() {
47+
if err = os.RemoveAll(tmpFile); err != nil {
48+
logger.Error("Impossible to remove the temporary file")
49+
}
50+
}()
51+
52+
if err = os.WriteFile(
53+
tmpFile,
54+
yamlConfig,
55+
0o600,
56+
); err != nil {
57+
logger.Error("Impossible to create the embedded Olric config from the given one")
58+
}
59+
60+
if olricInstance, err = config.Load(tmpFile); err == nil {
61+
isAlreadyLoaded = true
62+
} else {
63+
logger.Error("Impossible to create the embedded Olric config from the given one")
64+
}
65+
}
66+
67+
return olricInstance, isAlreadyLoaded
68+
}
69+
70+
func newEmbeddedOlric(olricConfiguration core.CacheProvider, logger core.Logger) (*olric.EmbeddedClient, error) {
71+
var olricInstance *config.Config
72+
73+
var loaded bool
74+
75+
if olricInstance, loaded = tryToLoadConfiguration(olricInstance, olricConfiguration, logger); !loaded {
76+
olricInstance = config.New("local")
77+
olricInstance.DMaps.MaxInuse = 512 << 20
78+
}
79+
80+
started, cancel := context.WithCancel(context.Background())
81+
olricInstance.Started = func() {
82+
logger.Error("Embedded Olric is ready")
83+
84+
defer cancel()
85+
}
86+
87+
olricDB, err := olric.New(olricInstance)
88+
if err != nil {
89+
return nil, err
90+
}
91+
92+
errCh := make(chan error, 1)
93+
defer func() {
94+
close(errCh)
95+
}()
96+
97+
go func(cdb *olric.Olric) {
98+
if err = cdb.Start(); err != nil {
99+
errCh <- err
100+
}
101+
}(olricDB)
102+
103+
select {
104+
case err = <-errCh:
105+
case <-started.Done():
106+
}
107+
108+
dbClient := olricDB.NewEmbeddedClient()
109+
110+
logger.Info("Embedded Olric is ready for this node.")
111+
112+
return dbClient, nil
113+
}
114+
30115
// Factory function create new Olric instance.
31116
func Factory(olricConfiguration core.CacheProvider, logger core.Logger, stale time.Duration) (core.Storer, error) {
117+
if olricConfiguration.URL == "" && olricConfiguration.Configuration != nil {
118+
if olricCfg, ok := olricConfiguration.Configuration.(map[string]interface{}); ok {
119+
if mode, found := olricCfg["mode"]; found && mode.(string) == "local" {
120+
logger.Debug("Olric configuration URL is empty, trying to load olric in embedded mode")
121+
122+
client, err := newEmbeddedOlric(olricConfiguration, logger)
123+
if err != nil {
124+
logger.Error("Impossible to setup Embedded Olric instance")
125+
126+
return nil, err
127+
}
128+
129+
return &Olric{
130+
Client: client,
131+
dm: nil,
132+
stale: stale,
133+
logger: logger,
134+
configuration: config.Client{},
135+
addresses: strings.Split(olricConfiguration.URL, ","),
136+
}, nil
137+
}
138+
}
139+
}
140+
32141
client, err := olric.NewClusterClient(strings.Split(olricConfiguration.URL, ","))
33142
if err != nil {
34143
logger.Errorf("Impossible to connect to Olric, %v", err)
35144
}
36145

37146
return &Olric{
38-
ClusterClient: client,
147+
Client: client,
39148
dm: nil,
40149
stale: stale,
41150
logger: logger,
@@ -290,31 +399,27 @@ func (provider *Olric) DeleteMany(key string) {
290399

291400
// Init method will initialize Olric provider if needed.
292401
func (provider *Olric) Init() error {
293-
dmap := sync.Pool{
402+
provider.dm = &sync.Pool{
294403
New: func() interface{} {
295-
dmap, _ := provider.ClusterClient.NewDMap("souin-map")
404+
dmap, _ := provider.Client.NewDMap("souin-map")
296405

297406
return dmap
298407
},
299408
}
300409

301-
provider.dm = &dmap
302-
303410
return nil
304411
}
305412

306413
// Reset method will reset or close provider.
307414
func (provider *Olric) Reset() error {
308-
provider.ClusterClient.Close(context.Background())
309-
310-
return nil
415+
return provider.Client.Close(context.Background())
311416
}
312417

313418
func (provider *Olric) Reconnect() {
314419
provider.reconnecting = true
315420

316421
if c, err := olric.NewClusterClient(provider.addresses, olric.WithConfig(&provider.configuration)); err == nil && c != nil {
317-
provider.ClusterClient = c
422+
provider.Client = c
318423
provider.reconnecting = false
319424
} else {
320425
time.Sleep(10 * time.Second)

0 commit comments

Comments
 (0)