passenger 5.0.1 → 5.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +10 -0
- data/CHANGELOG +12 -0
- data/CONTRIBUTING.md +10 -0
- data/CONTRIBUTORS +1 -0
- data/Gemfile +10 -10
- data/build/basics.rb +5 -1
- data/build/common_library.rb +33 -55
- data/build/debian.rb +2 -4
- data/build/packaging.rb +3 -3
- data/build/preprocessor.rb +3 -204
- data/debian.template/{control.template → control.erb} +18 -18
- data/debian.template/{locations.ini.template → locations.ini.erb} +0 -0
- data/debian.template/{passenger-dev.install.template → passenger-dev.install.erb} +0 -0
- data/debian.template/passenger-doc.install.erb +2 -0
- data/debian.template/{passenger.install.template → passenger.install.erb} +0 -0
- data/debian.template/{rules.template → rules.erb} +24 -23
- data/doc/users_guide_snippets/tips.txt +9 -1
- data/ext/common/Constants.h +3 -1
- data/ext/common/ServerKit/Channel.h +22 -4
- data/ext/common/ServerKit/Context.h +3 -1
- data/ext/common/ServerKit/FdSinkChannel.h +9 -1
- data/ext/common/ServerKit/FdSourceChannel.h +9 -1
- data/ext/common/ServerKit/FileBufferedChannel.h +19 -7
- data/ext/common/Utils/SystemMetricsCollector.h +0 -1
- data/ext/common/Utils/VariantMap.h +22 -1
- data/ext/common/agents/HelperAgent/Main.cpp +15 -0
- data/ext/common/agents/HelperAgent/OptionParser.h +6 -1
- data/ext/common/agents/HelperAgent/RequestHandler.h +3 -0
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/common_library.rb +13 -5
- data/lib/phusion_passenger/config/restart_app_command.rb +8 -4
- data/lib/phusion_passenger/constants.rb +1 -0
- data/lib/phusion_passenger/standalone/command.rb +1 -1
- data/lib/phusion_passenger/standalone/start_command.rb +8 -0
- data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +1 -0
- data/test/cxx/ServerKit/FileBufferedChannelTest.cpp +179 -4
- metadata +8 -8
- metadata.gz.asc +7 -7
- data/debian.template/passenger-doc.install.template +0 -2
@@ -527,6 +527,8 @@ initializeNonPrivilegedWorkingObjects() {
|
|
527
527
|
two.serverKitContext->secureModePassword = wo->password;
|
528
528
|
two.serverKitContext->defaultFileBufferedChannelConfig.bufferDir =
|
529
529
|
options.get("data_buffer_dir");
|
530
|
+
two.serverKitContext->defaultFileBufferedChannelConfig.threshold =
|
531
|
+
options.getUint("file_buffer_threshold");
|
530
532
|
|
531
533
|
UPDATE_TRACE_POINT();
|
532
534
|
two.requestHandler = new RequestHandler(two.serverKitContext, agentsOptions, i + 1);
|
@@ -979,6 +981,7 @@ setAgentsOptionsDefaults() {
|
|
979
981
|
options.setDefault("sticky_sessions_cookie_name", DEFAULT_STICKY_SESSIONS_COOKIE_NAME);
|
980
982
|
options.setDefaultBool("turbocaching", true);
|
981
983
|
options.setDefault("data_buffer_dir", getSystemTempDir());
|
984
|
+
options.setDefaultUint("file_buffer_threshold", DEFAULT_FILE_BUFFERED_CHANNEL_THRESHOLD);
|
982
985
|
options.setDefaultInt("response_buffer_high_watermark", DEFAULT_RESPONSE_BUFFER_HIGH_WATERMARK);
|
983
986
|
options.setDefaultBool("selfchecks", false);
|
984
987
|
options.setDefaultBool("server_graceful_exit", true);
|
@@ -1068,6 +1071,18 @@ sanityCheckOptions() {
|
|
1068
1071
|
ok = false;
|
1069
1072
|
#endif
|
1070
1073
|
}
|
1074
|
+
if (options.has("max_request_time")) {
|
1075
|
+
if (options.getInt("max_request_time", false, 0) < 1) {
|
1076
|
+
fprintf(stderr, "ERROR: the value passed to --max-request-time must be at least 1.\n");
|
1077
|
+
ok = false;
|
1078
|
+
}
|
1079
|
+
#ifndef PASSENGER_IS_ENTERPRISE
|
1080
|
+
fprintf(stderr, "ERROR: the --max-request-time option is only supported in "
|
1081
|
+
PROGRAM_NAME " Enterprise.\nYou are currently using the open source "
|
1082
|
+
PROGRAM_NAME ". Buy " PROGRAM_NAME " Enterprise here: https://www.phusionpassenger.com/enterprise\n");
|
1083
|
+
ok = false;
|
1084
|
+
#endif
|
1085
|
+
}
|
1071
1086
|
if (RequestHandler::parseBenchmarkMode(options.get("benchmark_mode", false))
|
1072
1087
|
== RequestHandler::BM_UNKNOWN)
|
1073
1088
|
{
|
@@ -125,7 +125,9 @@ serverUsage() {
|
|
125
125
|
printf(" --min-instances N Minimum number of application processes. Default: 1\n");
|
126
126
|
printf("\n");
|
127
127
|
printf("Request handling options (optional):\n");
|
128
|
-
printf(" --
|
128
|
+
printf(" --max-request-time Abort requests that take too much time (Enterprise\n");
|
129
|
+
printf(" only)\n");
|
130
|
+
printf(" --sticky-sessions Enable sticky sessions\n");
|
129
131
|
printf(" --sticky-sessions-cookie-name NAME\n");
|
130
132
|
printf(" Cookie name to use for sticky sessions.\n");
|
131
133
|
printf(" Default: " DEFAULT_STICKY_SESSIONS_COOKIE_NAME "\n");
|
@@ -273,6 +275,9 @@ parseServerOption(int argc, const char *argv[], int &i, VariantMap &options) {
|
|
273
275
|
} else if (p.isFlag(argv[i], '\0', "--disable-friendly-error-pages")) {
|
274
276
|
options.setBool("friendly_error_pages", false);
|
275
277
|
i++;
|
278
|
+
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-request-time")) {
|
279
|
+
options.setInt("max_request_time", atoi(argv[i + 1]));
|
280
|
+
i += 2;
|
276
281
|
} else if (p.isFlag(argv[i], '\0', "--sticky-sessions")) {
|
277
282
|
options.setBool("sticky_sessions", true);
|
278
283
|
i++;
|
data/lib/phusion_passenger.rb
CHANGED
@@ -30,7 +30,7 @@ module PhusionPassenger
|
|
30
30
|
|
31
31
|
PACKAGE_NAME = 'passenger'
|
32
32
|
# Run 'rake ext/common/Constants.h' after changing this number.
|
33
|
-
VERSION_STRING = '5.0.
|
33
|
+
VERSION_STRING = '5.0.2'
|
34
34
|
|
35
35
|
PREFERRED_NGINX_VERSION = '1.6.2'
|
36
36
|
NGINX_SHA256_CHECKSUM = 'b5608c2959d3e7ad09b20fc8f9e5bd4bc87b3bc8ba5936a513c04ed8f1391a18'
|
@@ -100,8 +100,11 @@ class CommonLibraryBuilder
|
|
100
100
|
return link_objects.join(' ')
|
101
101
|
end
|
102
102
|
|
103
|
-
def enable_optimizations!
|
103
|
+
def enable_optimizations!(lto = false)
|
104
104
|
@default_optimization_level = "-O"
|
105
|
+
if lto
|
106
|
+
@default_optimization_level << " -flto"
|
107
|
+
end
|
105
108
|
end
|
106
109
|
|
107
110
|
def define_tasks(extra_compiler_flags = nil)
|
@@ -132,7 +135,7 @@ private
|
|
132
135
|
file(object_file => dependencies_for(options)) do
|
133
136
|
case options[:optimize]
|
134
137
|
when :light
|
135
|
-
optimize = "-
|
138
|
+
optimize = "-O"
|
136
139
|
when true, :heavy
|
137
140
|
optimize = "-O2"
|
138
141
|
when :very_heavy
|
@@ -142,14 +145,19 @@ private
|
|
142
145
|
else
|
143
146
|
raise "Unknown optimization level #{options[:optimize]}"
|
144
147
|
end
|
145
|
-
if options[:strict_aliasing] == false
|
148
|
+
if options[:strict_aliasing] == false # and not nil
|
146
149
|
optimize = "#{optimize} -fno-strict-aliasing"
|
150
|
+
# Disable link-time optimization so that we can no-strict-aliasing
|
151
|
+
# works: http://stackoverflow.com/a/25765338/20816
|
152
|
+
optimize.sub!(/-flto/, "")
|
147
153
|
end
|
148
154
|
ensure_directory_exists(File.dirname(object_file))
|
155
|
+
# We put 'optimize' at the end of the command string so that it overrides
|
156
|
+
# the default optimization level embedded in 'cflags'.
|
149
157
|
if source_file =~ /\.c$/
|
150
|
-
compile_c(source_file, "#{
|
158
|
+
compile_c(source_file, "#{cflags} #{optimize} -o #{object_file}".strip)
|
151
159
|
else
|
152
|
-
compile_cxx(source_file, "#{
|
160
|
+
compile_cxx(source_file, "#{cxxflags} #{optimize} -o #{object_file}".strip)
|
153
161
|
end
|
154
162
|
end
|
155
163
|
end
|
@@ -158,12 +158,16 @@ module PhusionPassenger
|
|
158
158
|
def select_app_group_name_interactively
|
159
159
|
colors = PhusionPassenger::Utils::AnsiColors.new
|
160
160
|
|
161
|
+
choices = query_group_names
|
162
|
+
if choices.size == 1
|
163
|
+
# No running apps
|
164
|
+
abort_app_not_found "#{PROGRAM_NAME} is currently not serving any applications."
|
165
|
+
end
|
166
|
+
|
161
167
|
puts "Please select the application to restart."
|
162
168
|
puts colors.ansi_colorize("<gray>Tip: re-run this command with --help to learn how to automate it.</gray>")
|
163
169
|
puts colors.ansi_colorize("<dgray>If the menu doesn't display correctly, press '!'</dgray>")
|
164
170
|
puts
|
165
|
-
|
166
|
-
choices = query_group_names
|
167
171
|
menu = PhusionPassenger::Utils::TerminalChoiceMenu.new(choices, :single_choice)
|
168
172
|
begin
|
169
173
|
index, name = menu.query
|
@@ -205,7 +209,7 @@ module PhusionPassenger
|
|
205
209
|
:method => restart_method)
|
206
210
|
response = @instance.http_request("agents.s/server_admin", request)
|
207
211
|
if response.code.to_i / 100 == 2
|
208
|
-
|
212
|
+
response.body
|
209
213
|
else
|
210
214
|
STDERR.puts "*** An error occured while communicating with the #{PROGRAM_NAME} server:"
|
211
215
|
STDERR.puts response.body
|
@@ -228,7 +232,7 @@ module PhusionPassenger
|
|
228
232
|
request.basic_auth("ro_admin", obtain_read_only_admin_password(@instance))
|
229
233
|
response = @instance.http_request("agents.s/server_admin", request)
|
230
234
|
if response.code.to_i / 100 == 2
|
231
|
-
|
235
|
+
REXML::Document.new(response.body)
|
232
236
|
else
|
233
237
|
STDERR.puts "*** An error occured while querying the #{PROGRAM_NAME} server:"
|
234
238
|
STDERR.puts response.body
|
@@ -72,6 +72,7 @@ module PhusionPassenger
|
|
72
72
|
MESSAGE_SERVER_MAX_PASSWORD_SIZE = 100
|
73
73
|
POOL_HELPER_THREAD_STACK_SIZE = 1024 * 256
|
74
74
|
DEFAULT_MBUF_CHUNK_SIZE = 16 * 32
|
75
|
+
DEFAULT_FILE_BUFFERED_CHANNEL_THRESHOLD = 1024 * 128
|
75
76
|
SERVER_KIT_MAX_SERVER_ENDPOINTS = 4
|
76
77
|
|
77
78
|
# Time limits
|
@@ -37,7 +37,7 @@ module PhusionPassenger
|
|
37
37
|
|
38
38
|
def parse_options
|
39
39
|
load_and_merge_global_options(@options)
|
40
|
-
@parsed_options =
|
40
|
+
@parsed_options = self.class.create_default_options
|
41
41
|
@parser = self.class.create_option_parser(@parsed_options)
|
42
42
|
begin
|
43
43
|
@original_argv = @argv.dup
|
@@ -94,6 +94,9 @@ module PhusionPassenger
|
|
94
94
|
################# Configuration loading, option parsing and initialization ###################
|
95
95
|
|
96
96
|
def self.create_option_parser(options)
|
97
|
+
# Clear @parsed_options so that #remerge_all_options works.
|
98
|
+
options.clear
|
99
|
+
|
97
100
|
# If you add or change an option, make sure to update the following places too:
|
98
101
|
# lib/phusion_passenger/standalone/start_command/builtin_engine.rb, #build_daemon_controller_options
|
99
102
|
# resources/templates/config/standalone.erb
|
@@ -245,6 +248,10 @@ module PhusionPassenger
|
|
245
248
|
|
246
249
|
opts.separator ""
|
247
250
|
opts.separator "Request handling options:"
|
251
|
+
opts.on("--max-request-time SECONDS", "Abort requests that take too much time#{nl}" +
|
252
|
+
"(Enterprise only)") do |val|
|
253
|
+
options[:max_request_time] = val
|
254
|
+
end
|
248
255
|
opts.on("--sticky-sessions", "Enable sticky sessions") do
|
249
256
|
options[:sticky_sessions] = true
|
250
257
|
end
|
@@ -311,6 +318,7 @@ module PhusionPassenger
|
|
311
318
|
if value !~ /=.+/
|
312
319
|
abort "*** ERROR: invalid --ctl format: #{value}"
|
313
320
|
end
|
321
|
+
options[:ctls] ||= []
|
314
322
|
options[:ctls] << value
|
315
323
|
end
|
316
324
|
opts.on("--binaries-url-root URL", String,
|
@@ -139,6 +139,7 @@ module PhusionPassenger
|
|
139
139
|
add_param(command, :min_instances, "--min-instances")
|
140
140
|
add_enterprise_param(command, :concurrency_model, "--concurrency-model")
|
141
141
|
add_enterprise_param(command, :thread_count, "--app-thread-count")
|
142
|
+
add_enterprise_param(command, :max_request_time, "--max-request-time")
|
142
143
|
add_enterprise_flag_param(command, :rolling_restarts, "--rolling-restarts")
|
143
144
|
add_enterprise_flag_param(command, :resist_deployment_errors, "--resist-deployment-errors")
|
144
145
|
add_enterprise_flag_param(command, :debugger, "--debugger")
|
@@ -24,6 +24,7 @@ namespace tut {
|
|
24
24
|
int toConsume;
|
25
25
|
bool endConsume;
|
26
26
|
unsigned int counter;
|
27
|
+
unsigned int buffersFlushed;
|
27
28
|
string log;
|
28
29
|
|
29
30
|
ServerKit_FileBufferedChannelTest()
|
@@ -32,19 +33,21 @@ namespace tut {
|
|
32
33
|
channel(&context),
|
33
34
|
toConsume(CONSUME_FULLY),
|
34
35
|
endConsume(false),
|
35
|
-
counter(0)
|
36
|
+
counter(0),
|
37
|
+
buffersFlushed(0)
|
36
38
|
{
|
37
39
|
initializeLibeio();
|
38
40
|
channel.setDataCallback(dataCallback);
|
41
|
+
channel.setBuffersFlushedCallback(buffersFlushedCallback);
|
39
42
|
channel.setHooks(this);
|
40
43
|
Hooks::impl = NULL;
|
41
44
|
Hooks::userData = NULL;
|
42
45
|
}
|
43
46
|
|
44
47
|
~ServerKit_FileBufferedChannelTest() {
|
48
|
+
bg.stop(); // Prevent any runLater callbacks from running.
|
45
49
|
channel.deinitialize(); // Cancel any event loop next tick callbacks.
|
46
50
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
47
|
-
bg.stop();
|
48
51
|
shutdownLibeio();
|
49
52
|
}
|
50
53
|
|
@@ -76,6 +79,13 @@ namespace tut {
|
|
76
79
|
}
|
77
80
|
}
|
78
81
|
|
82
|
+
static void buffersFlushedCallback(FileBufferedChannel *channel) {
|
83
|
+
ServerKit_FileBufferedChannelTest *self = (ServerKit_FileBufferedChannelTest *)
|
84
|
+
channel->getHooks();
|
85
|
+
boost::lock_guard<boost::mutex> l(self->syncher);
|
86
|
+
self->buffersFlushed++;
|
87
|
+
}
|
88
|
+
|
79
89
|
void feedChannel(const string &data) {
|
80
90
|
bg.safe->runLater(boost::bind(&ServerKit_FileBufferedChannelTest::_feedChannel,
|
81
91
|
this, data));
|
@@ -550,6 +560,144 @@ namespace tut {
|
|
550
560
|
}
|
551
561
|
|
552
562
|
TEST_METHOD(33) {
|
563
|
+
set_test_name("Suppose that a data chunk from disk is being passed to the callback. "
|
564
|
+
"If the callback consumes the chunk immediately and is willing to accept "
|
565
|
+
"further data, then the FileBufferedChannel will repeat this process with the "
|
566
|
+
"next chunk from disk");
|
567
|
+
|
568
|
+
// Setup a FileBufferedChannel in the in-file mode.
|
569
|
+
toConsume = -1;
|
570
|
+
context.defaultFileBufferedChannelConfig.threshold = 1;
|
571
|
+
startLoop();
|
572
|
+
feedChannel("hello");
|
573
|
+
feedChannel("world!");
|
574
|
+
EVENTUALLY(5,
|
575
|
+
result = getChannelMode() == FileBufferedChannel::IN_FILE_MODE;
|
576
|
+
);
|
577
|
+
EVENTUALLY(5,
|
578
|
+
result = getChannelWriterState() == FileBufferedChannel::WS_INACTIVE;
|
579
|
+
);
|
580
|
+
ensure_equals(getChannelBytesBuffered(), 0u);
|
581
|
+
|
582
|
+
// Consume the initial "hello" so that the FileBufferedChannel starts
|
583
|
+
// reading "world" from disk. When "world" is read, we first consume
|
584
|
+
// "world" only, then "!" too.
|
585
|
+
context.defaultFileBufferedChannelConfig.maxDiskChunkReadSize = sizeof("world") - 1;
|
586
|
+
toConsume = CONSUME_FULLY;
|
587
|
+
channelConsumed(sizeof("hello") - 1, false);
|
588
|
+
EVENTUALLY(5,
|
589
|
+
LOCK();
|
590
|
+
result = log ==
|
591
|
+
"Data: hello\n"
|
592
|
+
"Data: world\n"
|
593
|
+
"Data: !\n";
|
594
|
+
);
|
595
|
+
}
|
596
|
+
|
597
|
+
TEST_METHOD(34) {
|
598
|
+
set_test_name("Suppose that a data chunk from disk is being passed to the callback. "
|
599
|
+
"If the callback consumes the chunk asynchronously, and is willing "
|
600
|
+
"to accept further data, then the FileBufferedChannel will repeat this process "
|
601
|
+
"with the next chunk from disk after the channel has become idle");
|
602
|
+
|
603
|
+
// Setup a FileBufferedChannel in the in-file mode.
|
604
|
+
toConsume = -1;
|
605
|
+
context.defaultFileBufferedChannelConfig.threshold = 1;
|
606
|
+
startLoop();
|
607
|
+
feedChannel("hello");
|
608
|
+
feedChannel("world!");
|
609
|
+
EVENTUALLY(5,
|
610
|
+
result = getChannelMode() == FileBufferedChannel::IN_FILE_MODE;
|
611
|
+
);
|
612
|
+
EVENTUALLY(5,
|
613
|
+
result = getChannelWriterState() == FileBufferedChannel::WS_INACTIVE;
|
614
|
+
);
|
615
|
+
ensure_equals(getChannelBytesBuffered(), 0u);
|
616
|
+
|
617
|
+
// Consume the initial "hello" so that the FileBufferedChannel starts
|
618
|
+
// reading "world" from disk.
|
619
|
+
context.defaultFileBufferedChannelConfig.maxDiskChunkReadSize = sizeof("world") - 1;
|
620
|
+
channelConsumed(sizeof("hello") - 1, false);
|
621
|
+
EVENTUALLY(5,
|
622
|
+
LOCK();
|
623
|
+
result = log ==
|
624
|
+
"Data: hello\n";
|
625
|
+
);
|
626
|
+
// We haven't consumed "world" yet, so the FileBufferedChannel should
|
627
|
+
// be waiting for it to become idle.
|
628
|
+
EVENTUALLY(5,
|
629
|
+
result = getChannelReaderState() == FileBufferedChannel::RS_WAITING_FOR_CHANNEL_IDLE;
|
630
|
+
);
|
631
|
+
|
632
|
+
// Now consume "world".
|
633
|
+
channelConsumed(sizeof("world") - 1, false);
|
634
|
+
EVENTUALLY(5,
|
635
|
+
LOCK();
|
636
|
+
result = log ==
|
637
|
+
"Data: hello\n"
|
638
|
+
"Data: world\n";
|
639
|
+
);
|
640
|
+
// We haven't consumed "!" yet, so the FileBufferedChannel should
|
641
|
+
// be waiting for it to become idle.
|
642
|
+
EVENTUALLY(5,
|
643
|
+
result = getChannelReaderState() == FileBufferedChannel::RS_WAITING_FOR_CHANNEL_IDLE;
|
644
|
+
);
|
645
|
+
|
646
|
+
// Now consume "!".
|
647
|
+
channelConsumed(sizeof("!") - 1, false);
|
648
|
+
EVENTUALLY(5,
|
649
|
+
LOCK();
|
650
|
+
result = log ==
|
651
|
+
"Data: hello\n"
|
652
|
+
"Data: world\n"
|
653
|
+
"Data: !\n";
|
654
|
+
);
|
655
|
+
}
|
656
|
+
|
657
|
+
TEST_METHOD(35) {
|
658
|
+
set_test_name("Suppose that a data chunk from disk is being passed to the callback. "
|
659
|
+
"If the callback consumes the chunk immediately, but is not willing "
|
660
|
+
"to accept further data, then the FileBufferedChannel will terminate");
|
661
|
+
|
662
|
+
// Setup a FileBufferedChannel in the in-file mode.
|
663
|
+
toConsume = -1;
|
664
|
+
context.defaultFileBufferedChannelConfig.threshold = 1;
|
665
|
+
startLoop();
|
666
|
+
feedChannel("hello");
|
667
|
+
feedChannel("world!");
|
668
|
+
EVENTUALLY(5,
|
669
|
+
result = getChannelMode() == FileBufferedChannel::IN_FILE_MODE;
|
670
|
+
);
|
671
|
+
EVENTUALLY(5,
|
672
|
+
result = getChannelWriterState() == FileBufferedChannel::WS_INACTIVE;
|
673
|
+
);
|
674
|
+
ensure_equals(getChannelBytesBuffered(), 0u);
|
675
|
+
|
676
|
+
// Consume the initial "hello" so that the FileBufferedChannel starts
|
677
|
+
// reading "world" from disk. When it is read, we will consume it fully
|
678
|
+
// while ending the channel.
|
679
|
+
context.defaultFileBufferedChannelConfig.maxDiskChunkReadSize = sizeof("world") - 1;
|
680
|
+
toConsume = CONSUME_FULLY;
|
681
|
+
endConsume = true;
|
682
|
+
channelConsumed(sizeof("hello") - 1, false);
|
683
|
+
EVENTUALLY(5,
|
684
|
+
LOCK();
|
685
|
+
result = log ==
|
686
|
+
"Data: hello\n"
|
687
|
+
"Data: world\n";
|
688
|
+
);
|
689
|
+
EVENTUALLY(5,
|
690
|
+
result = getChannelReaderState() == FileBufferedChannel::RS_TERMINATED;
|
691
|
+
);
|
692
|
+
SHOULD_NEVER_HAPPEN(100,
|
693
|
+
LOCK();
|
694
|
+
result = log !=
|
695
|
+
"Data: hello\n"
|
696
|
+
"Data: world\n";
|
697
|
+
);
|
698
|
+
}
|
699
|
+
|
700
|
+
TEST_METHOD(36) {
|
553
701
|
set_test_name("If there is no unread data on disk, it passes the next "
|
554
702
|
"in-memory buffer to the callback");
|
555
703
|
|
@@ -596,7 +744,7 @@ namespace tut {
|
|
596
744
|
);
|
597
745
|
}
|
598
746
|
|
599
|
-
TEST_METHOD(
|
747
|
+
TEST_METHOD(37) {
|
600
748
|
set_test_name("Upon feeding EOF, the EOF is passed to the callback after "
|
601
749
|
"all on-disk and in-memory data is passed");
|
602
750
|
|
@@ -658,7 +806,7 @@ namespace tut {
|
|
658
806
|
);
|
659
807
|
}
|
660
808
|
|
661
|
-
TEST_METHOD(
|
809
|
+
TEST_METHOD(38) {
|
662
810
|
set_test_name("Upon feeding an error, it switches to the error mode immediately "
|
663
811
|
"and it doesn't call the callback");
|
664
812
|
|
@@ -737,6 +885,33 @@ namespace tut {
|
|
737
885
|
);
|
738
886
|
}
|
739
887
|
|
888
|
+
TEST_METHOD(41) {
|
889
|
+
set_test_name("It calls the buffersFlushedCallback if the switching happens while "
|
890
|
+
"there are buffers in memory that haven't been written to disk yet");
|
891
|
+
|
892
|
+
toConsume = -1;
|
893
|
+
context.defaultFileBufferedChannelConfig.threshold = 1;
|
894
|
+
context.defaultFileBufferedChannelConfig.delayInFileModeSwitching = 1000;
|
895
|
+
startLoop();
|
896
|
+
|
897
|
+
feedChannel("hello");
|
898
|
+
feedChannel("world!");
|
899
|
+
EVENTUALLY(5,
|
900
|
+
result = getChannelMode() == FileBufferedChannel::IN_FILE_MODE;
|
901
|
+
);
|
902
|
+
ensure_equals(getChannelBytesBuffered(), 11u);
|
903
|
+
|
904
|
+
channelConsumed(sizeof("hello") - 1, false);
|
905
|
+
channelConsumed(sizeof("world!") - 1, false);
|
906
|
+
EVENTUALLY(5,
|
907
|
+
result = getChannelMode() == FileBufferedChannel::IN_MEMORY_MODE;
|
908
|
+
);
|
909
|
+
EVENTUALLY(5,
|
910
|
+
LOCK();
|
911
|
+
result = buffersFlushed == 1;
|
912
|
+
);
|
913
|
+
}
|
914
|
+
|
740
915
|
|
741
916
|
/***** When stopped *****/
|
742
917
|
|