Skip to content

Commit 6554157

Browse files
committed
Merge branch 'master' into feature/leave-command
2 parents 2205911 + 6dc51f0 commit 6554157

File tree

9 files changed

+203
-9
lines changed

9 files changed

+203
-9
lines changed

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func init() {
204204
f.StringVar(&arangodJSPath, "server.js-dir", "/usr/share/arangodb3/js", "Path of arango JS folder")
205205
f.StringVar(&rrPath, "server.rr", "", "Path of rr")
206206
f.IntVar(&serverThreads, "server.threads", 0, "Adjust server.threads of each server")
207-
f.StringVar(&serverStorageEngine, "server.storage-engine", "mmfiles", "Type of storage engine to use (mmfiles|rocksdb) (3.2 and up)")
207+
f.StringVar(&serverStorageEngine, "server.storage-engine", "", "Type of storage engine to use (mmfiles|rocksdb) (3.2 and up)")
208208
f.StringVar(&rocksDBEncryptionKeyFile, "rocksdb.encryption-keyfile", "", "Key file used for RocksDB encryption. (Enterprise Edition 3.2 and up)")
209209

210210
f.StringVar(&dockerEndpoint, "docker.endpoint", "unix:///var/run/docker.sock", "Endpoint used to reach the docker daemon")

service/arangod_config_builder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import (
4747

4848
// createArangodConf creates an arangod.conf file in the given host directory if it does not yet exists.
4949
// The arangod.conf file contains all settings that are considered static for the lifetime of the server.
50-
func createArangodConf(log zerolog.Logger, bsCfg BootstrapConfig, myHostDir, myContainerDir, myPort string, serverType ServerType) ([]Volume, configFile, error) {
50+
func createArangodConf(log zerolog.Logger, bsCfg BootstrapConfig, myHostDir, myContainerDir, myPort string, serverType ServerType, features DatabaseFeatures) ([]Volume, configFile, error) {
5151
hostConfFileName := filepath.Join(myHostDir, arangodConfFileName)
5252
containerConfFileName := filepath.Join(myContainerDir, arangodConfFileName)
5353
volumes := addVolume(nil, hostConfFileName, containerConfFileName, true)
@@ -80,8 +80,8 @@ func createArangodConf(log zerolog.Logger, bsCfg BootstrapConfig, myHostDir, myC
8080
serverSection.Settings["authentication"] = "true"
8181
serverSection.Settings["jwt-secret"] = bsCfg.JwtSecret
8282
}
83-
if bsCfg.ServerStorageEngine == "rocksdb" {
84-
serverSection.Settings["storage-engine"] = "rocksdb"
83+
if features.HasStorageEngineOption() {
84+
serverSection.Settings["storage-engine"] = bsCfg.ServerStorageEngine
8585
}
8686
config := configFile{
8787
serverSection,

service/bootstrap_master.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ func (s *Service) bootstrapMaster(ctx context.Context, runner Runner, config Con
4343
s.log.Fatal().Msgf("Port %d is already in use", containerHTTPPort)
4444
}
4545

46+
// Select storage engine
47+
storageEngine := bsCfg.ServerStorageEngine
48+
if storageEngine == "" {
49+
storageEngine = s.DatabaseFeatures().DefaultStorageEngine()
50+
bsCfg.ServerStorageEngine = storageEngine
51+
}
52+
s.log.Info().Msgf("Using storage engine '%s'", bsCfg.ServerStorageEngine)
53+
4654
// Create initial cluster configuration
4755
hasAgent := boolFromRef(bsCfg.StartAgent, !s.mode.IsSingleMode())
4856
hasDBServer := boolFromRef(bsCfg.StartDBserver, true)
@@ -55,7 +63,7 @@ func (s *Service) bootstrapMaster(ctx context.Context, runner Runner, config Con
5563
hasAgent, hasDBServer, hasCoordinator, hasResilientSingle,
5664
hasSyncMaster, hasSyncWorker,
5765
s.IsSecure()),
58-
bsCfg.AgencySize)
66+
bsCfg.AgencySize, storageEngine)
5967
s.learnOwnAddress = config.OwnAddress == ""
6068

6169
// Start HTTP listener

service/bootstrap_slave.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,13 @@ func (s *Service) bootstrapSlave(peerAddress string, runner Runner, config Confi
103103
s.log.Fatal().Msg("Master responsed with cluster config that does not contain my ID, please check master")
104104
return
105105
}
106+
if result.ServerStorageEngine == "" {
107+
s.log.Fatal().Msg("Master responsed with cluster config that does not contain a ServerStorageEngine, please update master first")
108+
return
109+
}
106110
// Save cluster config
107111
s.myPeers = result
112+
bsCfg.ServerStorageEngine = result.ServerStorageEngine
108113
break
109114
}
110115

@@ -149,6 +154,7 @@ func (s *Service) bootstrapSlave(peerAddress string, runner Runner, config Confi
149154
}
150155

151156
s.log.Info().Msgf("Serving as slave with ID '%s' on %s:%d...", s.id, config.OwnAddress, s.announcePort)
157+
s.log.Info().Msgf("Using storage engine '%s'", bsCfg.ServerStorageEngine)
152158
s.saveSetup()
153159
s.startRunning(runner, config, bsCfg)
154160
}

service/cluster_config.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type ClusterConfig struct {
4444
AgencySize int // Number of agents
4545
LastModified *time.Time `json:"LastModified,omitempty"` // Time of last modification
4646
PortOffsetIncrement int `json:"PortOffsetIncrement,omitempty"` // Increment of port offsets for peers on same address
47+
ServerStorageEngine string `json:ServerStorageEngine,omitempty"` // Storage engine being used
4748
}
4849

4950
// PeerByID returns a peer with given id & true, or false if not found.
@@ -79,10 +80,11 @@ func (p ClusterConfig) AllAgents() []Peer {
7980
}
8081

8182
// Initialize a new cluster configuration
82-
func (p *ClusterConfig) Initialize(initialPeer Peer, agencySize int) {
83+
func (p *ClusterConfig) Initialize(initialPeer Peer, agencySize int, storageEngine string) {
8384
p.AllPeers = []Peer{initialPeer}
8485
p.AgencySize = agencySize
8586
p.PortOffsetIncrement = portOffsetIncrementNew
87+
p.ServerStorageEngine = storageEngine
8688
p.updateLastModified()
8789
}
8890

service/database_features.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package service
24+
25+
import driver "github.com/arangodb/go-driver"
26+
27+
// DatabaseFeatures provides information about the features provided by the
28+
// database in a given version.
29+
type DatabaseFeatures driver.Version
30+
31+
const (
32+
v32 driver.Version = "3.2.0"
33+
v34 driver.Version = "3.4.0"
34+
)
35+
36+
// NewDatabaseFeatures returns a new DatabaseFeatures based on
37+
// the given version.
38+
func NewDatabaseFeatures(version driver.Version) DatabaseFeatures {
39+
return DatabaseFeatures(version)
40+
}
41+
42+
// HasStorageEngineOption returns true when `server.storage-engine`
43+
// option is supported.
44+
func (v DatabaseFeatures) HasStorageEngineOption() bool {
45+
return driver.Version(v).CompareTo(v32) >= 0
46+
}
47+
48+
// DefaultStorageEngine returns the default storage engine (mmfiles|rocksdb).
49+
func (v DatabaseFeatures) DefaultStorageEngine() string {
50+
if driver.Version(v).CompareTo(v34) >= 0 {
51+
return "rocksdb"
52+
}
53+
return "mmfiles"
54+
}

service/runtime_server_manager.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,16 @@ type runtimeServerManagerContext interface {
8282
// IsLocalSlave returns true if this peer is running as a local slave
8383
IsLocalSlave() bool
8484

85+
// DatabaseFeatures returns the detected database features.
86+
DatabaseFeatures() DatabaseFeatures
87+
8588
// Stop the peer
8689
Stop()
8790
}
8891

8992
// startServer starts a single Arangod/Arangosync server of the given type.
9093
func startServer(ctx context.Context, log zerolog.Logger, runtimeContext runtimeServerManagerContext, runner Runner,
91-
config Config, bsCfg BootstrapConfig, myHostAddress string, serverType ServerType, restart int) (Process, bool, error) {
94+
config Config, bsCfg BootstrapConfig, myHostAddress string, serverType ServerType, features DatabaseFeatures, restart int) (Process, bool, error) {
9295
myPort, err := runtimeContext.serverPort(serverType)
9396
if err != nil {
9497
return nil, false, maskAny(err)
@@ -145,7 +148,7 @@ func startServer(ctx context.Context, log zerolog.Logger, runtimeContext runtime
145148
var containerSecretFileName string
146149
if processType == ProcessTypeArangod {
147150
var err error
148-
confVolumes, arangodConfig, err = createArangodConf(log, bsCfg, myHostDir, myContainerDir, strconv.Itoa(myPort), serverType)
151+
confVolumes, arangodConfig, err = createArangodConf(log, bsCfg, myHostDir, myContainerDir, strconv.Itoa(myPort), serverType, features)
149152
if err != nil {
150153
return nil, false, maskAny(err)
151154
}
@@ -237,7 +240,8 @@ func (s *runtimeServerManager) runServer(ctx context.Context, log zerolog.Logger
237240
for {
238241
myHostAddress := myPeer.Address
239242
startTime := time.Now()
240-
p, portInUse, err := startServer(ctx, log, runtimeContext, runner, config, bsCfg, myHostAddress, serverType, restart)
243+
features := runtimeContext.DatabaseFeatures()
244+
p, portInUse, err := startServer(ctx, log, runtimeContext, runner, config, bsCfg, myHostAddress, serverType, features, restart)
241245
if err != nil {
242246
log.Error().Err(err).Msgf("Error while starting %s", serverType)
243247
if !portInUse {

service/service.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ type Service struct {
214214
runtimeServerManager runtimeServerManager
215215
runtimeClusterManager runtimeClusterManager
216216
upgradeManager UpgradeManager
217+
databaseFeatures DatabaseFeatures
217218
}
218219

219220
// NewService creates a new Service instance from the given config.
@@ -257,6 +258,22 @@ const (
257258
arangodJWTSecretFileName = "arangod.jwtsecret"
258259
)
259260

261+
// detectDatabaseFeatures queries the database version and sets the
262+
// databaseFeatures field.
263+
func (s *Service) detectDatabaseFeatures(ctx context.Context) error {
264+
v, err := s.DatabaseVersion(ctx)
265+
if err != nil {
266+
return maskAny(err)
267+
}
268+
s.databaseFeatures = NewDatabaseFeatures(v)
269+
return nil
270+
}
271+
272+
// DatabaseFeatures returns the detected database features.
273+
func (s *Service) DatabaseFeatures() DatabaseFeatures {
274+
return s.databaseFeatures
275+
}
276+
260277
// IsSecure returns true when the cluster is using SSL for connections, false otherwise.
261278
func (s *Service) IsSecure() bool {
262279
if s.sslKeyFile != "" {
@@ -1177,6 +1194,17 @@ func (s *Service) Run(rootCtx context.Context, bsCfg BootstrapConfig, myPeers Cl
11771194
runner, s.cfg, s.allowSameDataDir = s.cfg.CreateRunner(s.log)
11781195
s.runner = runner
11791196

1197+
// Detect database version
1198+
ctx := context.Background()
1199+
if err := s.detectDatabaseFeatures(ctx); err != nil {
1200+
return errors.Wrap(err, "Failed to detect database features")
1201+
}
1202+
1203+
// Check storage engine
1204+
if err := s.validateStorageEngine(bsCfg.ServerStorageEngine, s.DatabaseFeatures()); err != nil {
1205+
return maskAny(err)
1206+
}
1207+
11801208
// Start a rotate log file time
11811209
if s.cfg.LogRotateInterval > 0 {
11821210
go s.runRotateLogFiles(rootCtx)
@@ -1186,6 +1214,13 @@ func (s *Service) Run(rootCtx context.Context, bsCfg BootstrapConfig, myPeers Cl
11861214
if shouldRelaunch {
11871215
s.myPeers = myPeers
11881216
s.log.Info().Msgf("Relaunching service with id '%s' on %s:%d...", s.id, s.cfg.OwnAddress, s.announcePort)
1217+
storageEngine, err := s.readActualStorageEngine()
1218+
if err != nil {
1219+
return maskAny(err)
1220+
}
1221+
s.myPeers.ServerStorageEngine = storageEngine
1222+
bsCfg.ServerStorageEngine = storageEngine
1223+
s.log.Info().Msgf("Using storage engine '%s'", bsCfg.ServerStorageEngine)
11891224
s.startHTTPServer(s.cfg)
11901225
wg := &sync.WaitGroup{}
11911226
if bsCfg.StartLocalSlaves {

service/storage_engine.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package service
24+
25+
import (
26+
"fmt"
27+
"io/ioutil"
28+
"path/filepath"
29+
"strings"
30+
)
31+
32+
// validateStorageEngine checks if the given storage engine is a valid one.
33+
// Empty is still allowed.
34+
func (s *Service) validateStorageEngine(storageEngine string, features DatabaseFeatures) error {
35+
switch storageEngine {
36+
case "":
37+
// Not set yet. We'll choose one later
38+
return nil
39+
case "mmfiles":
40+
// Always OK
41+
return nil
42+
case "rocksdb":
43+
if !features.HasStorageEngineOption() {
44+
return maskAny(fmt.Errorf("RocksDB storage engine is not support for this database version"))
45+
}
46+
return nil
47+
default:
48+
return maskAny(fmt.Errorf("Unknown storage engine '%s'", storageEngine))
49+
}
50+
}
51+
52+
// readActualStorageEngine reads the actually used storage engine from
53+
// the database directory.
54+
func (s *Service) readActualStorageEngine() (string, error) {
55+
features := s.DatabaseFeatures()
56+
if !features.HasStorageEngineOption() {
57+
// ENGINE file does not exist
58+
return features.DefaultStorageEngine(), nil
59+
}
60+
61+
_, _, mode := s.ClusterConfig()
62+
var serverType ServerType
63+
if mode.IsClusterMode() {
64+
// Read engine from dbserver data directory
65+
serverType = ServerTypeDBServer
66+
} else if mode.IsActiveFailoverMode() {
67+
// Read engine from agent data directory
68+
serverType = ServerTypeAgent
69+
} else {
70+
// Read engine from single server data directory
71+
serverType = ServerTypeSingle
72+
}
73+
// Get directory
74+
dataDir, err := s.serverHostDir(serverType)
75+
if err != nil {
76+
return "", maskAny(err)
77+
}
78+
// Read ENGINE file
79+
engine, err := ioutil.ReadFile(filepath.Join(dataDir, "data", "ENGINE"))
80+
if err != nil {
81+
return "", maskAny(err)
82+
}
83+
storageEngine := strings.ToLower(strings.TrimSpace(string(engine)))
84+
return storageEngine, nil
85+
}

0 commit comments

Comments
 (0)