mm_file_io_c: don't flush on close by default

When closing files that were opened for writing, cached data will not
be flushed to storage automatically anymore. This reverts the
workaround implemented for #2469. A new option was added to both
programs (`--flush-on-close`) that re-enables flushing for people who
are affected by data loss such as described in #2469.

The reason is that automatic flushing causes long delays in processing
queues when the output by mkvmerge/mkvextract isn't the final product but
just an intermediate result to be processed further.

Implements #2480.
parent f3e1688a
# Version ?
## New features and enhancements
* mkvmerge, mkvextract: when closing files that were opened for writing,
cached data will not be flushed to storage automatically anymore. This
reverts the workaround implemented for #2469. A new option was added to both
programs (`--flush-on-close`) that re-enables flushing for people who are
affected by data loss such as described in #2469.
The reason is that automatic flushing causes long delays in processing
queues when the output by mkvmerge/mkvextract isn't the final product but
just an intermediate result to be processed further.
Implements #2480.
## Build system changes
* Qt 5.4.0 or newer has required (up from 5.3.0) since version 30.0.0; I just
......
......@@ -132,6 +132,18 @@
</listitem>
</varlistentry>
<varlistentry id="mkvextract.description.flush_on_close">
<term><option>--flush-on-close</option></term>
<listitem>
<para>
Tells the program to flush all data cached in memory to storage when closing files opened for writing.
This can be used to prevent data loss on power outages or to circumvent certain problems in the operating system or drivers.
The downside is that multiplexing will take longer as mkvmerge will wait until all data has been written to the storage before exiting.
See issues #2469 and #2480 on the MKVToolNix bug tracker for in-depth discussions on the pros and cons.
</para>
</listitem>
</varlistentry>
<varlistentry id="mkvextract.description.common.ui_language">
<term><option>--ui-language</option> <parameter>code</parameter></term>
<listitem>
......
......@@ -2094,6 +2094,18 @@ $ mkvmerge -o out.mkv '(' file.mkv ')'</screen>
</listitem>
</varlistentry>
<varlistentry id="mkvmerge.description.flush_on_close">
<term><option>--flush-on-close</option></term>
<listitem>
<para>
Tells the program to flush all data cached in memory to storage when closing files opened for writing.
This can be used to prevent data loss on power outages or to circumvent certain problems in the operating system or drivers.
The downside is that multiplexing will take longer as mkvmerge will wait until all data has been written to the storage before exiting.
See issues #2469 and #2480 on the MKVToolNix bug tracker for in-depth discussions on the pros and cons.
</para>
</listitem>
</varlistentry>
<varlistentry id="mkvmerge.description.ui_language">
<term><option>--ui-language</option> <parameter>code</parameter></term>
<listitem>
......
......@@ -181,6 +181,7 @@ parser_c::add_common_options() {
OPT("command-line-charset=<charset>", YT("Charset for strings on the command line"));
OPT("output-charset=<cset>", YT("Output messages in this charset"));
OPT("r|redirect-output=<file>", YT("Redirects all messages into this file."));
OPT("flush-on-close", YT("Flushes all cached data to storage when closing a file opened for writing."));
OPT("@option-file.json", YT("Reads additional command line options from the specified JSON file (see man page)."));
OPT("h|help", YT("Show this help."));
OPT("V|version", YT("Show version information."));
......
......@@ -190,6 +190,10 @@ handle_common_args(std::vector<std::string> &args,
g_gui_mode = true;
args.erase(args.begin() + i, args.begin() + i + 1);
} else if (args[i] == "--flush-on-close") {
mm_file_io_c::enable_flushing_on_close(true);
args.erase(args.begin() + i, args.begin() + i + 1);
} else
++i;
}
......
......@@ -26,9 +26,6 @@ public:
mm_file_io_c(const std::string &path, const open_mode mode = MODE_READ);
virtual ~mm_file_io_c();
static void prepare_path(const std::string &path);
static memory_cptr slurp(std::string const &file_name);
virtual uint64 getFilePointer();
#if defined(SYS_WINDOWS)
virtual uint64 get_real_file_pointer();
......@@ -41,10 +38,16 @@ public:
virtual std::string get_file_name() const;
public:
static void prepare_path(const std::string &path);
static memory_cptr slurp(std::string const &file_name);
static void setup();
static void cleanup();
static mm_io_cptr open(const std::string &path, const open_mode mode = MODE_READ);
static void enable_flushing_on_close(bool enable);
protected:
virtual uint32 _read(void *buffer, size_t size);
virtual size_t _write(const void *buffer, size_t size);
......
......@@ -17,6 +17,8 @@
#include "common/mm_file_io.h"
#include "common/mm_file_io_p.h"
bool mm_file_io_private_c::ms_flush_on_close = false;
mm_file_io_c::mm_file_io_c(std::string const &path,
open_mode const mode)
: mm_io_c{*new mm_file_io_private_c{path, mode}}
......@@ -90,3 +92,8 @@ mm_file_io_c::open(const std::string &path,
const open_mode mode) {
return mm_io_cptr(new mm_file_io_c(path, mode));
}
void
mm_file_io_c::enable_flushing_on_close(bool enable) {
mm_file_io_private_c::ms_flush_on_close = enable;
}
......@@ -107,7 +107,7 @@ mm_file_io_c::close() {
auto p = p_func();
if (p->file) {
if (p->mode != MODE_READ)
if (mm_file_io_private_c::ms_flush_on_close && (p->mode != MODE_READ))
fflush(p->file);
fclose(p->file);
......
......@@ -82,7 +82,7 @@ mm_file_io_c::close() {
auto p = p_func();
if (p->file) {
if (p->mode != MODE_READ)
if (mm_file_io_private_c::ms_flush_on_close && (p->mode != MODE_READ))
FlushFileBuffers(p->file);
CloseHandle(p->file);
......
......@@ -34,4 +34,7 @@ public:
#endif
explicit mm_file_io_private_c(std::string const &p_file_name, open_mode const p_mode);
public:
static bool ms_flush_on_close;
};
......@@ -365,6 +365,8 @@ set_usage() {
usage_text += Y(" --output-charset <cset> Output messages in this charset\n");
usage_text += Y(" -r, --redirect-output <file>\n"
" Redirects all messages into this file.\n");
usage_text += Y(" --flush-on-close Flushes all cached data to storage when closing\n"
" a file opened for writing.\n");
usage_text += Y(" --debug <topic> Turns on debugging output for 'topic'.\n");
usage_text += Y(" --engage <feature> Turns on experimental feature 'feature'.\n");
usage_text += Y(" @option-file.json Reads additional command line options from\n"
......
......@@ -52,6 +52,12 @@ AdditionalCommandLineOptionsDialog::AdditionalCommandLineOptionsDialog(QWidget *
QY("This causes bigger overhead but allows precise seeking and extraction."),
QY("If the magical value -1 is used then mkvmerge will use sample precision even if a video track is present.") });
add(Q("--flush-on-close"), false, global,
{ QY("Tells mkvmerge to flush all data cached in memory to storage when closing files opened for writing."),
QY("This can be used to prevent data loss on power outages or to circumvent certain problems in the operating system or drivers."),
QY("The downside is that multiplexing will take longer as mkvmerge will wait until all data has been written to the storage before exiting."),
QY("See issues #2469 and #2480 on the MKVToolNix bug tracker for in-depth discussions on the pros and cons.") });
auto hacks = m_ui->gridDevelopmentHacks;
add(Q("--engage space_after_chapters"), false, hacks, { QY("Leave additional space (EbmlVoid) in the destination file after the chapters.") });
......
......@@ -513,3 +513,4 @@ T_664generate_chapters_interval_first_video_timestamp_bigger_than_0:0d0a9cb9f421
T_665X_aac_program_config_element_in_audio_specific_config:32f312ca1c84ae94c3a90a9c8ff831cf-0838937c228386349fc661bbbae05924:passed:20181121-165428:0.020161455
T_666propedit_update_cues_after_cluster_was_moved:1098cab0332aefe8275b885f0dba7069:passed:20181124-150141:0.066928999
T_667ogg_chapters_use_name_template:8b5c27fdfb8d79b438d179c4845ed460-d30883a76d12e95ddf60efe3b4f6fe0c:passed:20181125-222443:0.019091945
T_668flush_on_close:7087ba97938d8b341e678f8ad6d40e36-e811bbfaa7fabc16d14310db3092dbe3:passed:20190110-220105:0.03641201
#!/usr/bin/ruby -w
# T_668flush_on_close
describe "mkvmerge, mkvextract / flushing on close"
test_merge "data/subtitles/srt/ven.srt", :args => "--flush-on-close"
test "extraction" do
extract "data/mkv/complex.mkv", 8 => tmp, :args => "--flush-on-close"
hash_tmp
end
......@@ -277,7 +277,7 @@ class SimpleTest
mode = options[:mode] || :tracks
command = "../src/mkvextract --engage no_variable_data #{args.first} #{mode} " + options.keys.select { |key| key.is_a?(Numeric) }.sort.collect { |key| "#{key}:#{options[key]}" }.join(' ')
command += options[:args] if options.key?(:args)
command += " #{options[:args]}" if options.key?(:args)
self.sys command, :exit_code => options[:exit_code], :no_result => options[:no_result]
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment