@@ -16,8 +16,11 @@ import (
16
16
"github.com/cockroachdb/cockroach/pkg/base"
17
17
"github.com/cockroachdb/cockroach/pkg/cli/exit"
18
18
"github.com/cockroachdb/cockroach/pkg/clusterversion"
19
+ "github.com/cockroachdb/cockroach/pkg/roachpb"
19
20
"github.com/cockroachdb/cockroach/pkg/settings"
21
+ "github.com/cockroachdb/cockroach/pkg/settings/cluster"
20
22
"github.com/cockroachdb/cockroach/pkg/storage/disk"
23
+ "github.com/cockroachdb/cockroach/pkg/storage/minversion"
21
24
"github.com/cockroachdb/cockroach/pkg/storage/storageconfig"
22
25
"github.com/cockroachdb/cockroach/pkg/util/buildutil"
23
26
"github.com/cockroachdb/cockroach/pkg/util/envutil"
@@ -201,6 +204,54 @@ func InitEnv(
201
204
return nil , err
202
205
}
203
206
207
+ // Read the current store cluster version.
208
+ storeClusterVersion , minVerFileExists , err := minversion .GetMinVersion (e .UnencryptedFS , e .Dir )
209
+ if err != nil {
210
+ return nil , err
211
+ }
212
+
213
+ if minVerFileExists {
214
+ v := cfg .Version
215
+ if v == nil {
216
+ return nil , errors .New ("version must not be nil" )
217
+ }
218
+ // Avoid running a binary too new for this store. This is what you'd catch
219
+ // if, say, you restarted directly from v21.2 into v22.2 (bumping the min
220
+ // version) without going through v22.1 first.
221
+ //
222
+ // Note that "going through" above means that v22.1 successfully upgrades
223
+ // all existing stores. If v22.1 crashes half-way through the startup
224
+ // sequence (so now some stores have v21.2, but others v22.1) you are
225
+ // expected to run v22.1 again (hopefully without the crash this time) which
226
+ // would then rewrite all the stores.
227
+ if storeClusterVersion .Less (v .MinSupportedVersion ()) {
228
+ if storeClusterVersion .Major < clusterversion .DevOffset && v .LatestVersion ().Major >= clusterversion .DevOffset {
229
+ return nil , errors .Errorf (
230
+ "store last used with cockroach non-development version v%s " +
231
+ "cannot be opened by development version v%s" ,
232
+ storeClusterVersion , v .LatestVersion (),
233
+ )
234
+ }
235
+ return nil , errors .Errorf (
236
+ "store last used with cockroach version v%s " +
237
+ "is too old for running version v%s (which requires data from v%s or later)" ,
238
+ storeClusterVersion , v .LatestVersion (), v .MinSupportedVersion (),
239
+ )
240
+ }
241
+
242
+ // Avoid running a binary too old for this store. This protects against
243
+ // scenarios where an older binary attempts to open a store created by
244
+ // a newer version that may have incompatible data structures or formats.
245
+ if v .LatestVersion ().Less (storeClusterVersion ) {
246
+ return nil , errors .Errorf (
247
+ "store last used with cockroach version v%s is too high for running " +
248
+ "version v%s" ,
249
+ storeClusterVersion , v .LatestVersion (),
250
+ )
251
+ }
252
+ e .StoreClusterVersion = storeClusterVersion
253
+ }
254
+
204
255
// Validate and configure encryption-at-rest. If no encryption-at-rest
205
256
// configuration was provided, resolveEncryptedEnvOptions will validate that
206
257
// there is no file registry.
@@ -238,6 +289,11 @@ type Env struct {
238
289
// the store. It provides access to encryption-at-rest stats, etc.
239
290
Encryption * EncryptionEnv
240
291
292
+ // StoreClusterVersion is the version of the store as read from the
293
+ // min-version file. This value will be empty if the min-version file
294
+ // does not exist (eg, the store is being created for the first time).
295
+ StoreClusterVersion roachpb.Version
296
+
241
297
// defaultFS is the primary VFS that most users should use. If
242
298
// encryption-at-rest is enabled, this VFS will handle transparently
243
299
// encrypting and decrypting as necessary. When the Env is used as an
@@ -317,7 +373,12 @@ func (e *Env) onDiskSlow(info vfs.DiskSlowInfo) {
317
373
318
374
// InMemory constructs a new in-memory environment.
319
375
func InMemory () * Env {
320
- e , err := InitEnv (context .Background (), vfs .NewMem (), "" /* dir */ , EnvConfig {}, nil /* diskWriteStats */ )
376
+ // For in-memory environments, we create a dummy cluster settings to provide
377
+ // a version handle, since these environments don't persist version information.
378
+ settings := cluster .MakeTestingClusterSettings ()
379
+ e , err := InitEnv (context .Background (), vfs .NewMem (), "" /* dir */ , EnvConfig {
380
+ Version : settings .Version ,
381
+ }, nil /* diskWriteStats */ )
321
382
// In practice InitEnv is infallible with this configuration.
322
383
if err != nil {
323
384
panic (err )
@@ -330,7 +391,10 @@ func InMemory() *Env {
330
391
// encryption-at-rest. Since this function ignores the possibility of
331
392
// encryption-at-rest, it should only be used as a testing convenience.
332
393
func MustInitPhysicalTestingEnv (dir string ) * Env {
333
- e , err := InitEnv (context .Background (), vfs .Default , dir , EnvConfig {}, nil /* diskWriteStats */ )
394
+ settings := cluster .MakeTestingClusterSettings ()
395
+ e , err := InitEnv (context .Background (), vfs .Default , dir , EnvConfig {
396
+ Version : settings .Version ,
397
+ }, nil /* diskWriteStats */ )
334
398
if err != nil {
335
399
panic (err )
336
400
}
0 commit comments