Skip to content

Commit e41aa9c

Browse files
author
marc
committed
core: switching env for encryption support.
This is to be contrasted to the preamble method in cockroachdb#20124. This method is discussed in the `Custom env for encryption state` section of the [Encryption RFC](cockroachdb#19785) When encryption is enabled, use a switching env that can redirect each Env method to one of: * base env for plaintext (same format as currently, no overhead) * encrypted env (with or without preamble) for encrypted files The switching env will hold the list of encrypted files to know which env to pick.
1 parent 56685a6 commit e41aa9c

File tree

9 files changed

+104
-23
lines changed

9 files changed

+104
-23
lines changed

c-deps/libroach/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ project(roachlib)
2323
add_library(roach
2424
db.cc
2525
encoding.cc
26+
env_switching.cc
2627
eventlistener.cc
2728
protos/roachpb/data.pb.cc
2829
protos/roachpb/internal.pb.cc

c-deps/libroach/db.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "protos/storage/engine/enginepb/mvcc.pb.h"
3434
#include "db.h"
3535
#include "encoding.h"
36+
#include "env_switching.h"
3637
#include "eventlistener.h"
3738
#include "keys.h"
3839

@@ -89,6 +90,7 @@ struct DBEngine {
8990
};
9091

9192
struct DBImpl : public DBEngine {
93+
std::unique_ptr<rocksdb::Env> switching_env;
9294
std::unique_ptr<rocksdb::Env> memenv;
9395
std::unique_ptr<rocksdb::DB> rep_deleter;
9496
std::shared_ptr<rocksdb::Cache> block_cache;
@@ -98,8 +100,9 @@ struct DBImpl : public DBEngine {
98100
// and Env will be deleted when the DBImpl is deleted. It is ok to
99101
// pass NULL for the Env.
100102
DBImpl(rocksdb::DB* r, rocksdb::Env* m, std::shared_ptr<rocksdb::Cache> bc,
101-
std::shared_ptr<DBEventListener> event_listener)
103+
std::shared_ptr<DBEventListener> event_listener, rocksdb::Env* s_env)
102104
: DBEngine(r),
105+
switching_env(s_env),
103106
memenv(m),
104107
rep_deleter(r),
105108
block_cache(bc),
@@ -1697,14 +1700,20 @@ DBStatus DBOpen(DBEngine **db, DBSlice dir, DBOptions db_opts) {
16971700
options.env = memenv.get();
16981701
}
16991702

1703+
std::unique_ptr<rocksdb::Env> switching_env;
1704+
if (db_opts.use_switching_env) {
1705+
switching_env.reset(NewSwitchingEnv(options.env));
1706+
options.env = switching_env.get();
1707+
}
1708+
17001709
rocksdb::DB *db_ptr;
17011710
rocksdb::Status status = rocksdb::DB::Open(options, ToString(dir), &db_ptr);
17021711
if (!status.ok()) {
17031712
return ToDBStatus(status);
17041713
}
17051714
*db = new DBImpl(db_ptr, memenv.release(),
17061715
db_opts.cache != nullptr ? db_opts.cache->rep : nullptr,
1707-
event_listener);
1716+
event_listener, switching_env.release());
17081717
return kSuccess;
17091718
}
17101719

c-deps/libroach/env_switching.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
#include "env_switching.h"
16+
17+
// SwitchingEnv switches between a base_env (usually a Env::Default or MemEnv) and an encrypted env.
18+
// SwitchingEnv (EnvWrapper)
19+
// PLAIN ENCRYPTED
20+
// | |
21+
// | encrypted_env (EnvWrapper)
22+
// | |
23+
// base_env (Env)
24+
// Any unimplemented methods are called on the base_env.
25+
class SwitchingEnv : public rocksdb::EnvWrapper {
26+
public:
27+
SwitchingEnv(rocksdb::Env* base_env) : rocksdb::EnvWrapper(base_env) { }
28+
};
29+
30+
rocksdb::Env* NewSwitchingEnv(rocksdb::Env* base_env) {
31+
return new SwitchingEnv(base_env ? base_env : rocksdb::Env::Default());
32+
}

c-deps/libroach/env_switching.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
#pragma once
16+
17+
#include <rocksdb/env.h>
18+
19+
// Returns a new SwitchingEnv using the passed-in env as the base.
20+
rocksdb::Env* NewSwitchingEnv(rocksdb::Env* base_env);

c-deps/libroach/include/libroach.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ typedef struct {
7171
bool logging_enabled;
7272
int num_cpu;
7373
int max_open_files;
74+
bool use_switching_env;
7475
} DBOptions;
7576

7677
// Create a new cache with the specified size.

pkg/storage/engine/rocksdb.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ var minWALSyncInterval = settings.RegisterDurationSetting(
6868
0*time.Millisecond,
6969
)
7070

71+
// TODO(mberhault): enterprise encryption flags will dictate the need for the
72+
// switching env format. Until then, use an env variable.
73+
var useSwitchingEnv = envutil.EnvOrDefaultBool("COCKROACH_USE_SWITCHING_ENV", false)
74+
7175
//export rocksDBLog
7276
func rocksDBLog(s *C.char, n C.int) {
7377
// Note that rocksdb logging is only enabled if log.V(3) is true
@@ -401,28 +405,40 @@ func (r *RocksDB) String() string {
401405
}
402406

403407
func (r *RocksDB) open() error {
404-
var ver storageVersion
408+
var existingVersion, newVersion storageVersion
405409
if len(r.cfg.Dir) != 0 {
406410
log.Infof(context.TODO(), "opening rocksdb instance at %q", r.cfg.Dir)
407411

408412
// Check the version number.
409413
var err error
410-
if ver, err = getVersion(r.cfg.Dir); err != nil {
414+
if existingVersion, err = getVersion(r.cfg.Dir); err != nil {
411415
return err
412416
}
413-
if ver < versionMinimum || ver > versionCurrent {
417+
if existingVersion < versionMinimum || existingVersion > versionCurrent {
414418
// Instead of an error, we should call a migration if possible when
415419
// one is needed immediately following the DBOpen call.
416420
return fmt.Errorf("incompatible rocksdb data version, current:%d, on disk:%d, minimum:%d",
417-
versionCurrent, ver, versionMinimum)
421+
versionCurrent, existingVersion, versionMinimum)
422+
}
423+
424+
if existingVersion != versionCurrent {
425+
if useSwitchingEnv {
426+
newVersion = versionCurrent
427+
} else {
428+
// If the switching env is not needed, use the older version. This allows downgrade to binaries unaware
429+
// of versionSwitchingEnv.
430+
// TODO(mberhault): once enough releases supporting versionSwitchingEnv have passed, we can upgrade
431+
// to it without worry.
432+
newVersion = versionBeta20160331
433+
}
418434
}
419435
} else {
420436
if log.V(2) {
421437
log.Infof(context.TODO(), "opening in memory rocksdb instance")
422438
}
423439

424440
// In memory dbs are always current.
425-
ver = versionCurrent
441+
existingVersion = versionCurrent
426442
}
427443

428444
blockSize := envutil.EnvOrDefaultBytes("COCKROACH_ROCKSDB_BLOCK_SIZE", defaultBlockSize)
@@ -434,20 +450,21 @@ func (r *RocksDB) open() error {
434450

435451
status := C.DBOpen(&r.rdb, goToCSlice([]byte(r.cfg.Dir)),
436452
C.DBOptions{
437-
cache: r.cache.cache,
438-
block_size: C.uint64_t(blockSize),
439-
wal_ttl_seconds: C.uint64_t(walTTL),
440-
logging_enabled: C.bool(log.V(3)),
441-
num_cpu: C.int(runtime.NumCPU()),
442-
max_open_files: C.int(maxOpenFiles),
453+
cache: r.cache.cache,
454+
block_size: C.uint64_t(blockSize),
455+
wal_ttl_seconds: C.uint64_t(walTTL),
456+
logging_enabled: C.bool(log.V(3)),
457+
num_cpu: C.int(runtime.NumCPU()),
458+
max_open_files: C.int(maxOpenFiles),
459+
use_switching_env: C.bool(useSwitchingEnv),
443460
})
444461
if err := statusToError(status); err != nil {
445462
return errors.Wrap(err, "could not open rocksdb instance")
446463
}
447464

448-
// Update or add the version file if needed.
449-
if ver < versionCurrent {
450-
if err := writeVersionFile(r.cfg.Dir); err != nil {
465+
// Update or add the version file if needed and if on-disk.
466+
if len(r.cfg.Dir) != 0 && existingVersion != newVersion {
467+
if err := writeVersionFile(r.cfg.Dir, newVersion); err != nil {
451468
return err
452469
}
453470
}

pkg/storage/engine/rocksdb_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ func TestRocksDBOpenWithVersions(t *testing.T) {
225225
{false, Version{}, ""},
226226
{true, Version{versionCurrent}, ""},
227227
{true, Version{versionMinimum}, ""},
228-
{true, Version{-1}, "incompatible rocksdb data version, current:1, on disk:-1, minimum:0"},
229-
{true, Version{2}, "incompatible rocksdb data version, current:1, on disk:2, minimum:0"},
228+
{true, Version{-1}, "incompatible rocksdb data version, current:2, on disk:-1, minimum:0"},
229+
{true, Version{3}, "incompatible rocksdb data version, current:2, on disk:3, minimum:0"},
230230
}
231231

232232
for i, testCase := range testCases {

pkg/storage/engine/version.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ type storageVersion int
2727
const (
2828
versionNoFile storageVersion = iota
2929
versionBeta20160331
30+
versionSwitchingEnv
3031
)
3132

3233
const (
3334
versionFilename = "COCKROACHDB_VERSION"
3435
versionFilenameTemp = "COCKROACHDB_VERSION_TEMP"
3536
versionMinimum = versionNoFile
36-
versionCurrent = versionBeta20160331
37+
versionCurrent = versionSwitchingEnv
3738
)
3839

3940
// Version stores all the version information for all stores and is used as
@@ -67,11 +68,11 @@ func getVersion(dir string) (storageVersion, error) {
6768
return ver.Version, nil
6869
}
6970

70-
// writeVersionFile overwrites the version file to contain the latest version.
71-
func writeVersionFile(dir string) error {
71+
// writeVersionFile overwrites the version file to contain the specified version.
72+
func writeVersionFile(dir string, ver storageVersion) error {
7273
tempFilename := filepath.Join(dir, versionFilenameTemp)
7374
filename := getVersionFilename(dir)
74-
b, err := json.Marshal(Version{versionCurrent})
75+
b, err := json.Marshal(Version{ver})
7576
if err != nil {
7677
return err
7778
}

pkg/storage/engine/version_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func TestVersions(t *testing.T) {
4848
}
4949

5050
// Write the current versions to the file.
51-
if err := writeVersionFile(dir); err != nil {
51+
if err := writeVersionFile(dir, versionCurrent); err != nil {
5252
t.Fatal(err)
5353
}
5454
ver, err = getVersion(dir)

0 commit comments

Comments
 (0)