@@ -99,6 +99,9 @@ pub struct TableData {
99
99
100
100
/// Mutable memtable memory size limitation
101
101
mutable_limit : AtomicU32 ,
102
+ /// Mutable memtable memory usage ratio of the write buffer size.
103
+ mutable_limit_write_buffer_ratio : f32 ,
104
+
102
105
/// Options of this table
103
106
///
104
107
/// Most modification to `opts` can be done by replacing the old options
@@ -174,8 +177,18 @@ impl Drop for TableData {
174
177
}
175
178
176
179
#[ inline]
177
- fn get_mutable_limit ( opts : & TableOptions ) -> u32 {
178
- opts. write_buffer_size / 8 * 7
180
+ fn compute_mutable_limit (
181
+ write_buffer_size : u32 ,
182
+ mutable_limit_write_buffer_size_ratio : f32 ,
183
+ ) -> u32 {
184
+ assert ! (
185
+ mutable_limit_write_buffer_size_ratio >= 0.0
186
+ && mutable_limit_write_buffer_size_ratio <= 1.0
187
+ ) ;
188
+
189
+ let limit = write_buffer_size as f32 * mutable_limit_write_buffer_size_ratio;
190
+ // This is safe because the limit won't be larger than the write_buffer_size.
191
+ limit as u32
179
192
}
180
193
181
194
impl TableData {
@@ -188,6 +201,7 @@ impl TableData {
188
201
request : CreateTableRequest ,
189
202
table_opts : TableOptions ,
190
203
purger : & FilePurger ,
204
+ preflush_write_buffer_size_ratio : f32 ,
191
205
mem_usage_collector : CollectorRef ,
192
206
) -> Result < Self > {
193
207
// FIXME(yingwen): Validate TableOptions, such as bucket_duration >=
@@ -197,13 +211,18 @@ impl TableData {
197
211
let purge_queue = purger. create_purge_queue ( space_id, request. table_id ) ;
198
212
let current_version = TableVersion :: new ( purge_queue) ;
199
213
let metrics = Metrics :: default ( ) ;
214
+ let mutable_limit = AtomicU32 :: new ( compute_mutable_limit (
215
+ table_opts. write_buffer_size ,
216
+ preflush_write_buffer_size_ratio,
217
+ ) ) ;
200
218
201
219
Ok ( Self {
202
220
id : request. table_id ,
203
221
name : request. table_name ,
204
222
schema : Mutex :: new ( request. table_schema ) ,
205
223
space_id,
206
- mutable_limit : AtomicU32 :: new ( get_mutable_limit ( & table_opts) ) ,
224
+ mutable_limit,
225
+ mutable_limit_write_buffer_ratio : preflush_write_buffer_size_ratio,
207
226
opts : ArcSwap :: new ( Arc :: new ( table_opts) ) ,
208
227
memtable_factory,
209
228
mem_usage_collector,
@@ -225,20 +244,26 @@ impl TableData {
225
244
pub fn recover_from_add (
226
245
add_meta : AddTableMeta ,
227
246
purger : & FilePurger ,
228
- mem_usage_collector : CollectorRef ,
229
247
shard_id : ShardId ,
248
+ preflush_write_buffer_size_ratio : f32 ,
249
+ mem_usage_collector : CollectorRef ,
230
250
) -> Result < Self > {
231
251
let memtable_factory = Arc :: new ( SkiplistMemTableFactory ) ;
232
252
let purge_queue = purger. create_purge_queue ( add_meta. space_id , add_meta. table_id ) ;
233
253
let current_version = TableVersion :: new ( purge_queue) ;
234
254
let metrics = Metrics :: default ( ) ;
255
+ let mutable_limit = AtomicU32 :: new ( compute_mutable_limit (
256
+ add_meta. opts . write_buffer_size ,
257
+ preflush_write_buffer_size_ratio,
258
+ ) ) ;
235
259
236
260
Ok ( Self {
237
261
id : add_meta. table_id ,
238
262
name : add_meta. table_name ,
239
263
schema : Mutex :: new ( add_meta. schema ) ,
240
264
space_id : add_meta. space_id ,
241
- mutable_limit : AtomicU32 :: new ( get_mutable_limit ( & add_meta. opts ) ) ,
265
+ mutable_limit,
266
+ mutable_limit_write_buffer_ratio : preflush_write_buffer_size_ratio,
242
267
opts : ArcSwap :: new ( Arc :: new ( add_meta. opts ) ) ,
243
268
memtable_factory,
244
269
mem_usage_collector,
@@ -307,8 +332,11 @@ impl TableData {
307
332
/// Update table options.
308
333
#[ inline]
309
334
pub fn set_table_options ( & self , opts : TableOptions ) {
310
- self . mutable_limit
311
- . store ( get_mutable_limit ( & opts) , Ordering :: Relaxed ) ;
335
+ let mutable_limit = compute_mutable_limit (
336
+ opts. write_buffer_size ,
337
+ self . mutable_limit_write_buffer_ratio ,
338
+ ) ;
339
+ self . mutable_limit . store ( mutable_limit, Ordering :: Relaxed ) ;
312
340
self . opts . store ( Arc :: new ( opts) )
313
341
}
314
342
@@ -399,7 +427,7 @@ impl TableData {
399
427
/// Returns true if the memory usage of this table reaches flush threshold
400
428
///
401
429
/// REQUIRE: Do in write worker
402
- pub fn should_flush_table ( & self ) -> bool {
430
+ pub fn should_flush_table ( & self , serial_exec : & mut TableOpSerialExecutor ) -> bool {
403
431
// Fallback to usize::MAX if Failed to convert arena_block_size into
404
432
// usize (overflow)
405
433
let max_write_buffer_size = self
@@ -416,8 +444,9 @@ impl TableData {
416
444
let mutable_usage = self . current_version . mutable_memory_usage ( ) ;
417
445
let total_usage = self . current_version . total_memory_usage ( ) ;
418
446
447
+ let in_flush = serial_exec. flush_scheduler ( ) . is_in_flush ( ) ;
419
448
// Inspired by https://github.com/facebook/rocksdb/blob/main/include/rocksdb/write_buffer_manager.h#L94
420
- if mutable_usage > mutable_limit {
449
+ if mutable_usage > mutable_limit && !in_flush {
421
450
info ! (
422
451
"TableData should flush, table:{}, table_id:{}, mutable_usage:{}, mutable_limit: {}, total_usage:{}, max_write_buffer_size:{}" ,
423
452
self . name, self . id, mutable_usage, mutable_limit, total_usage, max_write_buffer_size
@@ -660,7 +689,15 @@ pub mod tests {
660
689
let purger = FilePurgerMocker :: mock ( ) ;
661
690
let collector = Arc :: new ( NoopCollector ) ;
662
691
663
- TableData :: new ( space_id, create_request, table_opts, & purger, collector) . unwrap ( )
692
+ TableData :: new (
693
+ space_id,
694
+ create_request,
695
+ table_opts,
696
+ & purger,
697
+ 0.75 ,
698
+ collector,
699
+ )
700
+ . unwrap ( )
664
701
}
665
702
}
666
703
@@ -734,4 +771,33 @@ pub mod tests {
734
771
TimeRange :: bucket_of ( now_ts, table_options:: DEFAULT_SEGMENT_DURATION ) . unwrap ( ) ;
735
772
assert_eq ! ( time_range, mem_state. time_range) ;
736
773
}
774
+
775
+ #[ test]
776
+ fn test_compute_mutable_limit ( ) {
777
+ // Build the cases for compute_mutable_limit.
778
+ let cases = vec ! [
779
+ ( 80 , 0.8 , 64 ) ,
780
+ ( 80 , 0.5 , 40 ) ,
781
+ ( 80 , 0.1 , 8 ) ,
782
+ ( 80 , 0.0 , 0 ) ,
783
+ ( 80 , 1.0 , 80 ) ,
784
+ ( 0 , 0.8 , 0 ) ,
785
+ ( 0 , 0.5 , 0 ) ,
786
+ ( 0 , 0.1 , 0 ) ,
787
+ ( 0 , 0.0 , 0 ) ,
788
+ ( 0 , 1.0 , 0 ) ,
789
+ ] ;
790
+
791
+ for ( write_buffer_size, ratio, expected) in cases {
792
+ let limit = compute_mutable_limit ( write_buffer_size, ratio) ;
793
+ assert_eq ! ( expected, limit) ;
794
+ }
795
+ }
796
+
797
+ #[ should_panic]
798
+ #[ test]
799
+ fn test_compute_mutable_limit_panic ( ) {
800
+ compute_mutable_limit ( 80 , 1.1 ) ;
801
+ compute_mutable_limit ( 80 , -0.1 ) ;
802
+ }
737
803
}
0 commit comments