1
1
// Copyright 2021 Oxide Computer Company
2
2
use anyhow:: { bail, Result } ;
3
+ use schemars:: JsonSchema ;
3
4
use serde:: { Deserialize , Serialize } ;
4
5
use uuid:: Uuid ;
5
6
@@ -17,7 +18,16 @@ use super::*;
17
18
* downstairs expects Block { 2, 12 }.
18
19
*/
19
20
#[ derive(
20
- Deserialize , Serialize , Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord ,
21
+ Deserialize ,
22
+ Serialize ,
23
+ Copy ,
24
+ Clone ,
25
+ Debug ,
26
+ PartialEq ,
27
+ Eq ,
28
+ JsonSchema ,
29
+ PartialOrd ,
30
+ Ord ,
21
31
) ]
22
32
pub struct Block {
23
33
// Value could mean a size or offset
@@ -118,7 +128,7 @@ impl Block {
118
128
}
119
129
}
120
130
121
- #[ derive( Deserialize , Serialize , Copy , Clone , Debug , PartialEq ) ]
131
+ #[ derive( Deserialize , Serialize , Copy , Clone , Debug , JsonSchema , PartialEq ) ]
122
132
pub struct RegionDefinition {
123
133
/**
124
134
* The size of each block in bytes. Must be a power of 2, minimum 512.
@@ -170,6 +180,55 @@ impl RegionDefinition {
170
180
} )
171
181
}
172
182
183
+ // Compare two RegionDefinitions and verify they are compatible.
184
+ // compatible is valid if all fields are the same, expect for the
185
+ // UUID. The UUID should be different.
186
+ pub fn compatible (
187
+ self ,
188
+ other : RegionDefinition ,
189
+ ) -> Result < ( ) , CrucibleError > {
190
+ // These fields should be the same.
191
+ if self . block_size != other. block_size {
192
+ return Err ( CrucibleError :: RegionIncompatible (
193
+ "block_size" . to_string ( ) ,
194
+ ) ) ;
195
+ }
196
+ if self . extent_size != other. extent_size {
197
+ return Err ( CrucibleError :: RegionIncompatible (
198
+ "extent_size" . to_string ( ) ,
199
+ ) ) ;
200
+ }
201
+ if self . extent_count != other. extent_count {
202
+ return Err ( CrucibleError :: RegionIncompatible (
203
+ "extent_count" . to_string ( ) ,
204
+ ) ) ;
205
+ }
206
+ if self . encrypted != other. encrypted {
207
+ return Err ( CrucibleError :: RegionIncompatible (
208
+ "encrypted" . to_string ( ) ,
209
+ ) ) ;
210
+ }
211
+ if self . database_read_version != other. database_read_version {
212
+ return Err ( CrucibleError :: RegionIncompatible (
213
+ "database_read_version" . to_string ( ) ,
214
+ ) ) ;
215
+ }
216
+ if self . database_write_version != other. database_write_version {
217
+ return Err ( CrucibleError :: RegionIncompatible (
218
+ "database_write_version" . to_string ( ) ,
219
+ ) ) ;
220
+ }
221
+
222
+ // If the UUIDs are the same, this is invalid.
223
+ if self . uuid == other. uuid {
224
+ return Err ( CrucibleError :: RegionIncompatible (
225
+ "UUIDs are the same" . to_string ( ) ,
226
+ ) ) ;
227
+ }
228
+
229
+ Ok ( ( ) )
230
+ }
231
+
173
232
pub fn database_read_version ( & self ) -> usize {
174
233
self . database_read_version
175
234
}
@@ -489,4 +548,113 @@ mod test {
489
548
*/
490
549
assert ! ( rd. validate_io( Block :: new( 1 , 9 ) , 2048 ) . is_err( ) ) ;
491
550
}
551
+
552
+ fn test_rd ( ) -> RegionDefinition {
553
+ RegionDefinition {
554
+ block_size : 512 ,
555
+ extent_size : Block :: new ( 10 , 9 ) ,
556
+ extent_count : 8 ,
557
+ uuid : Uuid :: new_v4 ( ) ,
558
+ encrypted : false ,
559
+ database_read_version : DATABASE_READ_VERSION ,
560
+ database_write_version : DATABASE_WRITE_VERSION ,
561
+ }
562
+ }
563
+
564
+ #[ test]
565
+ fn test_region_compare_block ( ) {
566
+ let mut rd1 = test_rd ( ) ;
567
+ let rd2 = test_rd ( ) ;
568
+
569
+ // Basic positive test first.
570
+ assert_eq ! ( rd1. compatible( rd2) , Ok ( ( ) ) ) ;
571
+
572
+ rd1. block_size = 4096 ;
573
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
574
+
575
+ let rd1 = test_rd ( ) ;
576
+ let mut rd2 = test_rd ( ) ;
577
+ rd2. block_size = 4096 ;
578
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
579
+ }
580
+
581
+ #[ test]
582
+ fn test_region_compare_extent_size ( ) {
583
+ let mut rd1 = test_rd ( ) ;
584
+ let rd2 = test_rd ( ) ;
585
+
586
+ rd1. extent_size = Block :: new ( 2 , 9 ) ;
587
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
588
+
589
+ let rd1 = test_rd ( ) ;
590
+ let mut rd2 = test_rd ( ) ;
591
+ rd2. extent_size = Block :: new ( 2 , 9 ) ;
592
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
593
+ }
594
+
595
+ #[ test]
596
+ fn test_region_compare_extent_count ( ) {
597
+ let mut rd1 = test_rd ( ) ;
598
+ let rd2 = test_rd ( ) ;
599
+
600
+ rd1. extent_count = 9 ;
601
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
602
+
603
+ let rd1 = test_rd ( ) ;
604
+ let mut rd2 = test_rd ( ) ;
605
+ rd2. extent_count = 9 ;
606
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
607
+ }
608
+
609
+ #[ test]
610
+ fn test_region_compare_uuid ( ) {
611
+ // Verify region compare, UUIDs must be different
612
+ let mut rd1 = test_rd ( ) ;
613
+ let rd2 = test_rd ( ) ;
614
+
615
+ rd1. uuid = rd2. uuid ;
616
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
617
+ }
618
+
619
+ #[ test]
620
+ fn test_region_compare_encrypted ( ) {
621
+ let mut rd1 = test_rd ( ) ;
622
+ let rd2 = test_rd ( ) ;
623
+
624
+ rd1. encrypted = true ;
625
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
626
+
627
+ let rd1 = test_rd ( ) ;
628
+ let mut rd2 = test_rd ( ) ;
629
+ rd2. encrypted = true ;
630
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
631
+ }
632
+
633
+ #[ test]
634
+ fn test_region_compare_db_read_version ( ) {
635
+ let mut rd1 = test_rd ( ) ;
636
+ let rd2 = test_rd ( ) ;
637
+
638
+ rd1. database_read_version = DATABASE_READ_VERSION + 1 ;
639
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
640
+
641
+ let rd1 = test_rd ( ) ;
642
+ let mut rd2 = test_rd ( ) ;
643
+ rd2. database_read_version = DATABASE_READ_VERSION + 1 ;
644
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
645
+ }
646
+
647
+ #[ test]
648
+ fn test_region_compare_db_write_version ( ) {
649
+ let mut rd1 = test_rd ( ) ;
650
+ let rd2 = test_rd ( ) ;
651
+
652
+ rd1. database_write_version = DATABASE_WRITE_VERSION + 1 ;
653
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
654
+
655
+ let rd1 = test_rd ( ) ;
656
+ let mut rd2 = test_rd ( ) ;
657
+ rd2. database_write_version = DATABASE_WRITE_VERSION + 1 ;
658
+ assert ! ( rd1. compatible( rd2) . is_err( ) ) ;
659
+ }
492
660
}
0 commit comments