@@ -165,52 +165,10 @@ impl ImpactedBlocks {
165
165
ImpactedBlocks :: InclusiveRange ( first_impacted, last_impacted)
166
166
}
167
167
168
- pub fn intersection ( & self , other : & ImpactedBlocks ) -> ImpactedBlocks {
169
- let ImpactedBlocks :: InclusiveRange ( fst_self, lst_self) = self else {
170
- return ImpactedBlocks :: Empty ;
171
- } ;
172
-
173
- let ImpactedBlocks :: InclusiveRange ( fst_other, lst_other) = other else {
174
- return ImpactedBlocks :: Empty ;
175
- } ;
176
-
177
- let fst = fst_self. max ( fst_other) ;
178
- let lst = lst_self. min ( lst_other) ;
179
- if lst >= fst {
180
- ImpactedBlocks :: InclusiveRange ( * fst, * lst)
181
- } else {
182
- ImpactedBlocks :: Empty
183
- }
184
- }
185
-
186
- pub fn union ( & self , other : & ImpactedBlocks ) -> ImpactedBlocks {
187
- let ImpactedBlocks :: InclusiveRange ( fst_self, lst_self) = self else {
188
- return * other;
189
- } ;
190
-
191
- let ImpactedBlocks :: InclusiveRange ( fst_other, lst_other) = other else {
192
- return * self ;
193
- } ;
194
- let fst = fst_self. min ( fst_other) ;
195
- let lst = lst_self. max ( lst_other) ;
196
- ImpactedBlocks :: InclusiveRange ( * fst, * lst)
197
- }
198
-
199
168
pub fn is_empty ( & self ) -> bool {
200
169
self == & ImpactedBlocks :: Empty
201
170
}
202
171
203
- /// Return true if this list of impacted blocks overlaps with another.
204
- pub fn conflicts ( & self , other : & ImpactedBlocks ) -> bool {
205
- !self . intersection ( other) . is_empty ( )
206
- }
207
-
208
- pub fn fully_contains ( & self , other : & ImpactedBlocks ) -> bool {
209
- !self . is_empty ( )
210
- && !other. is_empty ( )
211
- && self . intersection ( other) == * other
212
- }
213
-
214
172
/// Return a range of impacted extents
215
173
pub fn extents ( & self ) -> Option < RangeInclusive < u32 > > {
216
174
match self {
@@ -240,8 +198,8 @@ impl ImpactedBlocks {
240
198
}
241
199
}
242
200
243
- /// Given a global offset and number of blocks, compute a list of individually
244
- /// impacted blocks:
201
+ /// Given a global offset and number of blocks, compute a range of impacted
202
+ /// blocks:
245
203
///
246
204
/// |eid0 |eid1
247
205
/// |───────────────────────────────────────────────│
@@ -255,14 +213,8 @@ impl ImpactedBlocks {
255
213
/// The example offset and length above spans 7 blocks over two extents (where
256
214
/// the numbers at the bottom of the diagram are block numbers).
257
215
///
258
- /// Return an ImpactedBlocks object that stores which extents are impacted,
259
- /// along with the specific blocks in those extents. For the above example, the
260
- /// hashmap inside ImpactedBlocks would be:
261
- ///
262
- /// blocks = {
263
- /// eid0 -> [2, 3, 4, 5],
264
- /// eid1 -> [0, 1, 2],
265
- /// }
216
+ /// Return an ImpactedBlocks object that stores the affected region as a range
217
+ /// of [`ImpactedAddr`] values (which are `(ExtentId, BlockOffset)` tuples)
266
218
pub fn extent_from_offset (
267
219
ddef : & RegionDefinition ,
268
220
offset : BlockIndex ,
@@ -778,37 +730,10 @@ mod test {
778
730
)
779
731
}
780
732
781
- /// Map the ImpactedBlocks to the full range of possible values
782
- fn reify_impacted_blocks_without_region (
783
- test_iblocks : ArbitraryImpactedBlocks ,
784
- ) -> ImpactedBlocks {
785
- reify_impacted_blocks ( test_iblocks, u32:: MAX , usize:: MAX )
786
- }
787
-
788
733
fn region_def_strategy ( ) -> impl Strategy < Value = RegionDefinition > {
789
734
any :: < ArbitraryRegionDefinition > ( ) . prop_map ( reify_region_definition)
790
735
}
791
736
792
- /// Generate a random region definition, and a pair of ImpactedBlocks ranges
793
- /// that fit within it
794
- fn region_and_impacted_pair_strategy (
795
- ) -> impl Strategy < Value = ( RegionDefinition , ImpactedBlocks , ImpactedBlocks ) >
796
- {
797
- any :: < (
798
- ArbitraryRegionDefinition ,
799
- ArbitraryImpactedBlocks ,
800
- ArbitraryImpactedBlocks ,
801
- ) > ( )
802
- . prop_map ( |( test_ddef, test_iblocks_a, test_iblocks_b) | {
803
- let ddef = reify_region_definition ( test_ddef) ;
804
- let iblocks_a =
805
- reify_impacted_blocks_in_region ( test_iblocks_a, & ddef) ;
806
- let iblocks_b =
807
- reify_impacted_blocks_in_region ( test_iblocks_b, & ddef) ;
808
- ( ddef, iblocks_a, iblocks_b)
809
- } )
810
- }
811
-
812
737
/// Generate a random region definition, and a single ImpactedBlocks range
813
738
/// within it.
814
739
fn region_and_impacted_blocks_strategy (
@@ -823,126 +748,6 @@ mod test {
823
748
)
824
749
}
825
750
826
- fn any_impacted_blocks_strategy ( ) -> impl Strategy < Value = ImpactedBlocks > {
827
- any :: < ArbitraryImpactedBlocks > ( )
828
- . prop_map ( reify_impacted_blocks_without_region)
829
- }
830
-
831
- #[ proptest]
832
- fn intersection_produces_less_than_or_equal_block_count (
833
- #[ strategy( region_and_impacted_pair_strategy( ) ) ]
834
- region_and_impacted_pair : (
835
- RegionDefinition ,
836
- ImpactedBlocks ,
837
- ImpactedBlocks ,
838
- ) ,
839
- ) {
840
- let ( ddef, iblocks_a, iblocks_b) = region_and_impacted_pair;
841
- let intersection = iblocks_a. intersection ( & iblocks_b) ;
842
-
843
- let len_a = iblocks_a. len ( & ddef) ;
844
- let len_b = iblocks_b. len ( & ddef) ;
845
- let len_intersection = intersection. len ( & ddef) ;
846
-
847
- prop_assert ! ( len_intersection <= len_a) ;
848
- prop_assert ! ( len_intersection <= len_b) ;
849
- }
850
-
851
- #[ proptest]
852
- fn union_produces_greater_than_or_equal_block_count (
853
- #[ strategy( region_and_impacted_pair_strategy( ) ) ]
854
- region_and_impacted_pair : (
855
- RegionDefinition ,
856
- ImpactedBlocks ,
857
- ImpactedBlocks ,
858
- ) ,
859
- ) {
860
- let ( ddef, iblocks_a, iblocks_b) = region_and_impacted_pair;
861
- let union = iblocks_a. union ( & iblocks_b) ;
862
-
863
- let len_a = iblocks_a. len ( & ddef) ;
864
- let len_b = iblocks_b. len ( & ddef) ;
865
- let len_union = union. len ( & ddef) ;
866
-
867
- prop_assert ! ( len_union >= len_a) ;
868
- prop_assert ! ( len_union >= len_b) ;
869
- }
870
-
871
- #[ proptest]
872
- fn intersection_with_empty_is_empty (
873
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks : ImpactedBlocks ,
874
- ) {
875
- // a . Empty == Empty
876
- prop_assert_eq ! (
877
- iblocks. intersection( & ImpactedBlocks :: Empty ) ,
878
- ImpactedBlocks :: Empty
879
- ) ;
880
- }
881
-
882
- #[ proptest]
883
- fn union_with_empty_is_identity (
884
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks : ImpactedBlocks ,
885
- ) {
886
- // a . Empty == a
887
- prop_assert_eq ! ( iblocks. union ( & ImpactedBlocks :: Empty ) , iblocks) ;
888
- }
889
-
890
- #[ proptest]
891
- fn intersection_is_commutative (
892
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_a : ImpactedBlocks ,
893
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_b : ImpactedBlocks ,
894
- ) {
895
- // a . b == b . a
896
- prop_assert_eq ! (
897
- iblocks_a. intersection( & iblocks_b) ,
898
- iblocks_b. intersection( & iblocks_a)
899
- ) ;
900
- }
901
-
902
- #[ proptest]
903
- fn union_is_commutative (
904
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_a : ImpactedBlocks ,
905
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_b : ImpactedBlocks ,
906
- ) {
907
- // a . b == b . a
908
- prop_assert_eq ! (
909
- iblocks_a. union ( & iblocks_b) ,
910
- iblocks_b. union ( & iblocks_a)
911
- ) ;
912
- }
913
-
914
- #[ proptest]
915
- fn intersection_is_associative (
916
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_a : ImpactedBlocks ,
917
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_b : ImpactedBlocks ,
918
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_c : ImpactedBlocks ,
919
- ) {
920
- // a . (b . c)
921
- let l = iblocks_a. intersection ( & iblocks_b. intersection ( & iblocks_c) ) ;
922
-
923
- // (a . b) . c
924
- let r = iblocks_a. intersection ( & iblocks_b) . intersection ( & iblocks_c) ;
925
-
926
- // a . (b . c) == (a . b) . c
927
- prop_assert_eq ! ( l, r) ;
928
- }
929
-
930
- #[ proptest]
931
- fn union_is_associative (
932
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_a : ImpactedBlocks ,
933
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_b : ImpactedBlocks ,
934
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_c : ImpactedBlocks ,
935
- ) {
936
- // a . (b . c)
937
- let l = iblocks_a. union ( & iblocks_b. union ( & iblocks_c) ) ;
938
-
939
- // (a . b) . c
940
- let r = iblocks_a. union ( & iblocks_b) . union ( & iblocks_c) ;
941
-
942
- // a . (b . c) == (a . b) . c
943
- prop_assert_eq ! ( l, r) ;
944
- }
945
-
946
751
#[ proptest]
947
752
fn iblocks_from_offset_is_empty_for_zero_blocks (
948
753
#[ strategy( 1 ..=u64 :: MAX ) ] extent_size : u64 ,
@@ -1058,135 +863,6 @@ mod test {
1058
863
) ;
1059
864
}
1060
865
1061
- #[ proptest]
1062
- fn iblocks_conflicts_is_commutative (
1063
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_a : ImpactedBlocks ,
1064
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks_b : ImpactedBlocks ,
1065
- ) {
1066
- // a . b == b . a
1067
- prop_assert_eq ! (
1068
- iblocks_a. conflicts( & iblocks_b) ,
1069
- iblocks_b. conflicts( & iblocks_a)
1070
- ) ;
1071
- }
1072
-
1073
- #[ proptest]
1074
- fn empty_impacted_blocks_never_conflict (
1075
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks : ImpactedBlocks ,
1076
- ) {
1077
- prop_assert ! ( !iblocks. conflicts( & ImpactedBlocks :: Empty ) ) ;
1078
- }
1079
-
1080
- #[ proptest]
1081
- fn overlapping_impacted_blocks_should_conflict (
1082
- // 4 random points, we'll make two overlapping ranges out of them
1083
- point_a : ( u32 , u64 ) ,
1084
- point_b : ( u32 , u64 ) ,
1085
- point_c : ( u32 , u64 ) ,
1086
- point_d : ( u32 , u64 ) ,
1087
- ) {
1088
- // First we need to sort the points so we can use them correctly.
1089
- let mut sorted_points = [ point_a, point_b, point_c, point_d] ;
1090
- sorted_points. sort ( ) ;
1091
- let ( eid_a, block_a) = sorted_points[ 0 ] ;
1092
- let ( eid_b, block_b) = sorted_points[ 1 ] ;
1093
- let ( eid_c, block_c) = sorted_points[ 2 ] ;
1094
- let ( eid_d, block_d) = sorted_points[ 3 ] ;
1095
-
1096
- // After sorting, if we make ranges from the pairs (a,c) and (b,d)
1097
- // then they are guaranteed to overlap.
1098
- let iblocks_a = ImpactedBlocks :: new (
1099
- ImpactedAddr {
1100
- extent_id : ExtentId ( eid_a) ,
1101
- block : BlockOffset ( block_a) ,
1102
- } ,
1103
- ImpactedAddr {
1104
- extent_id : ExtentId ( eid_c) ,
1105
- block : BlockOffset ( block_c) ,
1106
- } ,
1107
- ) ;
1108
-
1109
- let iblocks_b = ImpactedBlocks :: new (
1110
- ImpactedAddr {
1111
- extent_id : ExtentId ( eid_b) ,
1112
- block : BlockOffset ( block_b) ,
1113
- } ,
1114
- ImpactedAddr {
1115
- extent_id : ExtentId ( eid_d) ,
1116
- block : BlockOffset ( block_d) ,
1117
- } ,
1118
- ) ;
1119
-
1120
- // And thus they should conflict
1121
- prop_assert ! ( iblocks_a. conflicts( & iblocks_b) ,
1122
- "These overlapping ImpactedBlocks should conflict, but don't:\n {:?}\n {:?}" ,
1123
- iblocks_a,
1124
- iblocks_b) ;
1125
- }
1126
-
1127
- #[ proptest]
1128
- fn nothing_contains_empty (
1129
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks : ImpactedBlocks ,
1130
- ) {
1131
- prop_assert ! ( !iblocks. fully_contains( & ImpactedBlocks :: Empty ) ) ;
1132
- }
1133
-
1134
- #[ proptest]
1135
- fn empty_contains_nothing (
1136
- #[ strategy( any_impacted_blocks_strategy( ) ) ] iblocks : ImpactedBlocks ,
1137
- ) {
1138
- prop_assert ! ( !ImpactedBlocks :: Empty . fully_contains( & iblocks) ) ;
1139
- }
1140
-
1141
- const U32_U64_MAX : u128 = ( ( u32:: MAX as u128 ) << 64 ) | ( u64:: MAX as u128 ) ;
1142
- #[ proptest]
1143
- fn subregions_are_contained (
1144
- // proptest doesn't implement strategies for tuple-ranges for some
1145
- // reason, so I'm using a u128 in place of a (u32, u64)
1146
- #[ strategy( 0 ..=U32_U64_MAX ) ] outer_start : u128 ,
1147
- #[ strategy( #outer_start..=U32_U64_MAX ) ] outer_end : u128 ,
1148
-
1149
- // Inner must be within outer
1150
- #[ strategy( #outer_start ..= #outer_end) ] inner_start : u128 ,
1151
- #[ strategy( #inner_start ..= #outer_end) ] inner_end : u128 ,
1152
- ) {
1153
- let ( outer_eid_a, outer_block_a) =
1154
- ( ( outer_start >> 64 ) as u32 , outer_start as u64 ) ;
1155
- let ( outer_eid_b, outer_block_b) =
1156
- ( ( outer_end >> 64 ) as u32 , outer_end as u64 ) ;
1157
- let ( inner_eid_a, inner_block_a) =
1158
- ( ( inner_start >> 64 ) as u32 , inner_start as u64 ) ;
1159
- let ( inner_eid_b, inner_block_b) =
1160
- ( ( inner_end >> 64 ) as u32 , inner_end as u64 ) ;
1161
-
1162
- let outer_iblocks = ImpactedBlocks :: new (
1163
- ImpactedAddr {
1164
- extent_id : ExtentId ( outer_eid_a) ,
1165
- block : BlockOffset ( outer_block_a) ,
1166
- } ,
1167
- ImpactedAddr {
1168
- extent_id : ExtentId ( outer_eid_b) ,
1169
- block : BlockOffset ( outer_block_b) ,
1170
- } ,
1171
- ) ;
1172
-
1173
- let inner_iblocks = ImpactedBlocks :: new (
1174
- ImpactedAddr {
1175
- extent_id : ExtentId ( inner_eid_a) ,
1176
- block : BlockOffset ( inner_block_a) ,
1177
- } ,
1178
- ImpactedAddr {
1179
- extent_id : ExtentId ( inner_eid_b) ,
1180
- block : BlockOffset ( inner_block_b) ,
1181
- } ,
1182
- ) ;
1183
-
1184
- prop_assert ! ( outer_iblocks. fully_contains( & inner_iblocks) ,
1185
- "Outer ImpactedBlocks does not contain inner ImpactedBlocks:\n Outer: {:?}\n Inner: {:?}" ,
1186
- outer_iblocks,
1187
- inner_iblocks) ;
1188
- }
1189
-
1190
866
#[ proptest]
1191
867
/// We have a manual test of extent_from_offset above, but here's another
1192
868
/// for good measure. We'll generate an ImpactedBlocks in a region, and then
0 commit comments