@@ -3016,6 +3016,92 @@ def test_path_resurrection
3016
3016
} ,
3017
3017
)
3018
3018
end
3019
+
3020
+ def test_next_rotation_occurs_very_fast_while_old_TW_still_waiting_rotate_wait
3021
+ config = config_element (
3022
+ "ROOT" ,
3023
+ "" ,
3024
+ {
3025
+ "path" => "#{ @tmp_dir } /tail.txt*" ,
3026
+ "pos_file" => "#{ @tmp_dir } /tail.pos" ,
3027
+ "tag" => "t1" ,
3028
+ "format" => "none" ,
3029
+ "read_from_head" => "true" ,
3030
+ "follow_inodes" => "true" ,
3031
+ "rotate_wait" => "3s" ,
3032
+ "refresh_interval" => "1h" ,
3033
+ # stat_watcher often calls `TailWatcher::on_notify` faster than creating a new log file,
3034
+ # so disable it in order to reproduce the same condition stably.
3035
+ "enable_stat_watcher" => "false" ,
3036
+ }
3037
+ )
3038
+ d = create_driver ( config , false )
3039
+
3040
+ tail_watchers = [ ]
3041
+ stub . proxy ( d . instance ) . setup_watcher do |tw |
3042
+ tail_watchers . append ( tw )
3043
+ mock . proxy ( tw ) . close . once # Note: Currently, there is no harm in duplicate calls.
3044
+ tw
3045
+ end
3046
+
3047
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "wb" ) { |f | f . puts "file1 log1" }
3048
+
3049
+ d . run ( expect_records : 6 , timeout : 15 ) do
3050
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file1 log2" }
3051
+
3052
+ sleep 1.5 # Need to be larger than 1s (the interval of watch_timer)
3053
+
3054
+ FileUtils . move ( "#{ @tmp_dir } /tail.txt0" , "#{ @tmp_dir } /tail.txt" + "1" )
3055
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "wb" ) { |f | f . puts "file2 log1" }
3056
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file2 log2" }
3057
+
3058
+ sleep 1.5 # Need to be larger than 1s (the interval of watch_timer)
3059
+
3060
+ # Rotate again (Old TailWatcher waiting rotate_wait also calls update_watcher)
3061
+ [ 1 , 0 ] . each do |i |
3062
+ FileUtils . move ( "#{ @tmp_dir } /tail.txt#{ i } " , "#{ @tmp_dir } /tail.txt#{ i + 1 } " )
3063
+ end
3064
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "wb" ) { |f | f . puts "file3 log1" }
3065
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file3 log2" }
3066
+
3067
+ # Wait rotate_wait to confirm that TailWatcher.close is not called in duplicate.
3068
+ # (Note: Currently, there is no harm in duplicate calls)
3069
+ sleep 4
3070
+ end
3071
+
3072
+ inode_0 = tail_watchers [ 0 ] &.ino
3073
+ inode_1 = tail_watchers [ 1 ] &.ino
3074
+ inode_2 = tail_watchers [ 2 ] &.ino
3075
+ record_values = d . events . collect { |event | event [ 2 ] [ "message" ] } . sort
3076
+ position_entries = [ ]
3077
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.pos" , "r" ) do |f |
3078
+ f . readlines ( chomp : true ) . each do |line |
3079
+ values = line . split ( "\t " )
3080
+ position_entries . append ( [ values [ 0 ] , values [ 1 ] , values [ 2 ] . to_i ( 16 ) ] )
3081
+ end
3082
+ end
3083
+
3084
+ assert_equal (
3085
+ {
3086
+ record_values : [ "file1 log1" , "file1 log2" , "file2 log1" , "file2 log2" , "file3 log1" , "file3 log2" ] ,
3087
+ tail_watcher_paths : [ "#{ @tmp_dir } /tail.txt0" , "#{ @tmp_dir } /tail.txt0" , "#{ @tmp_dir } /tail.txt0" ] ,
3088
+ tail_watcher_inodes : [ inode_0 , inode_1 , inode_2 ] ,
3089
+ tail_watcher_io_handler_opened_statuses : [ false , false , false ] ,
3090
+ position_entries : [
3091
+ [ "#{ @tmp_dir } /tail.txt0" , "0000000000000016" , inode_0 ] ,
3092
+ [ "#{ @tmp_dir } /tail.txt0" , "0000000000000016" , inode_1 ] ,
3093
+ [ "#{ @tmp_dir } /tail.txt0" , "0000000000000016" , inode_2 ] ,
3094
+ ] ,
3095
+ } ,
3096
+ {
3097
+ record_values : record_values ,
3098
+ tail_watcher_paths : tail_watchers . collect { |tw | tw . path } ,
3099
+ tail_watcher_inodes : tail_watchers . collect { |tw | tw . ino } ,
3100
+ tail_watcher_io_handler_opened_statuses : tail_watchers . collect { |tw | tw . instance_variable_get ( :@io_handler ) &.opened? || false } ,
3101
+ position_entries : position_entries
3102
+ } ,
3103
+ )
3104
+ end
3019
3105
end
3020
3106
3021
3107
sub_test_case "Update watchers for rotation without follow_inodes" do
@@ -3084,9 +3170,6 @@ def test_refreshTW_during_rotation
3084
3170
sleep 3
3085
3171
3086
3172
Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file3 log2" }
3087
-
3088
- # Wait `rotate_wait` for file2 to make sure to close all IO handlers
3089
- sleep 3
3090
3173
end
3091
3174
3092
3175
inode_0 = tail_watchers [ 0 ] &.ino
@@ -3121,5 +3204,85 @@ def test_refreshTW_during_rotation
3121
3204
} ,
3122
3205
)
3123
3206
end
3207
+
3208
+ def test_next_rotation_occurs_very_fast_while_old_TW_still_waiting_rotate_wait
3209
+ config = config_element (
3210
+ "ROOT" ,
3211
+ "" ,
3212
+ {
3213
+ "path" => "#{ @tmp_dir } /tail.txt0" ,
3214
+ "pos_file" => "#{ @tmp_dir } /tail.pos" ,
3215
+ "tag" => "t1" ,
3216
+ "format" => "none" ,
3217
+ "read_from_head" => "true" ,
3218
+ "rotate_wait" => "3s" ,
3219
+ "refresh_interval" => "1h" ,
3220
+ }
3221
+ )
3222
+ d = create_driver ( config , false )
3223
+
3224
+ tail_watchers = [ ]
3225
+ stub . proxy ( d . instance ) . setup_watcher do |tw |
3226
+ tail_watchers . append ( tw )
3227
+ mock . proxy ( tw ) . close . once # Note: Currently, there is no harm in duplicate calls.
3228
+ tw
3229
+ end
3230
+
3231
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "wb" ) { |f | f . puts "file1 log1" }
3232
+
3233
+ d . run ( expect_records : 6 , timeout : 15 ) do
3234
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file1 log2" }
3235
+
3236
+ sleep 1.5 # Need to be larger than 1s (the interval of watch_timer)
3237
+
3238
+ FileUtils . move ( "#{ @tmp_dir } /tail.txt0" , "#{ @tmp_dir } /tail.txt" + "1" )
3239
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "wb" ) { |f | f . puts "file2 log1" }
3240
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file2 log2" }
3241
+
3242
+ sleep 1.5 # Need to be larger than 1s (the interval of watch_timer)
3243
+
3244
+ # Rotate again (Old TailWatcher waiting rotate_wait also calls update_watcher)
3245
+ [ 1 , 0 ] . each do |i |
3246
+ FileUtils . move ( "#{ @tmp_dir } /tail.txt#{ i } " , "#{ @tmp_dir } /tail.txt#{ i + 1 } " )
3247
+ end
3248
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "wb" ) { |f | f . puts "file3 log1" }
3249
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.txt0" , "ab" ) { |f | f . puts "file3 log2" }
3250
+
3251
+ # Wait rotate_wait to confirm that TailWatcher.close is not called in duplicate.
3252
+ # (Note: Currently, there is no harm in duplicate calls)
3253
+ sleep 4
3254
+ end
3255
+
3256
+ inode_0 = tail_watchers [ 0 ] &.ino
3257
+ inode_1 = tail_watchers [ 1 ] &.ino
3258
+ inode_2 = tail_watchers [ 2 ] &.ino
3259
+ record_values = d . events . collect { |event | event [ 2 ] [ "message" ] } . sort
3260
+ position_entries = [ ]
3261
+ Fluent ::FileWrapper . open ( "#{ @tmp_dir } /tail.pos" , "r" ) do |f |
3262
+ f . readlines ( chomp : true ) . each do |line |
3263
+ values = line . split ( "\t " )
3264
+ position_entries . append ( [ values [ 0 ] , values [ 1 ] , values [ 2 ] . to_i ( 16 ) ] )
3265
+ end
3266
+ end
3267
+
3268
+ assert_equal (
3269
+ {
3270
+ record_values : [ "file1 log1" , "file1 log2" , "file2 log1" , "file2 log2" , "file3 log1" , "file3 log2" ] ,
3271
+ tail_watcher_paths : [ "#{ @tmp_dir } /tail.txt0" , "#{ @tmp_dir } /tail.txt0" , "#{ @tmp_dir } /tail.txt0" ] ,
3272
+ tail_watcher_inodes : [ inode_0 , inode_1 , inode_2 ] ,
3273
+ tail_watcher_io_handler_opened_statuses : [ false , false , false ] ,
3274
+ position_entries : [
3275
+ [ "#{ @tmp_dir } /tail.txt0" , "0000000000000016" , inode_2 ] ,
3276
+ ] ,
3277
+ } ,
3278
+ {
3279
+ record_values : record_values ,
3280
+ tail_watcher_paths : tail_watchers . collect { |tw | tw . path } ,
3281
+ tail_watcher_inodes : tail_watchers . collect { |tw | tw . ino } ,
3282
+ tail_watcher_io_handler_opened_statuses : tail_watchers . collect { |tw | tw . instance_variable_get ( :@io_handler ) &.opened? || false } ,
3283
+ position_entries : position_entries
3284
+ } ,
3285
+ )
3286
+ end
3124
3287
end
3125
3288
end
0 commit comments