@@ -29,33 +29,112 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2929#include < string>
3030#include < utility>
3131
32- void Extract::open_file (const osmium::io::Header& header, osmium::io::overwrite output_overwrite, osmium::io::fsync sync, OptionClean const * clean) {
32+ void Extract::writer_loop () {
33+ try {
34+ while (true ) {
35+ std::unique_lock<std::mutex> lock{m_mutex};
36+ m_cv.wait (lock, [this ]{ return m_flush_pending || m_shutdown; });
37+
38+ if (m_shutdown && !m_flush_pending) {
39+ break ;
40+ }
41+
42+ // Reset m_flush_pending under the lock so that swap_and_flush()
43+ // can observe the transition to false only after the buffer has
44+ // been moved out and is no longer shared.
45+ m_clean->apply_to (m_flush_buffer);
46+ auto buf = std::move (m_flush_buffer);
47+ m_flush_buffer = osmium::memory::Buffer{buffer_size,
48+ osmium::memory::Buffer::auto_grow::no};
49+ m_flush_pending = false ;
50+ lock.unlock ();
51+ m_cv.notify_one ();
52+
53+ // The osmium Writer call (compression + I/O) runs outside the lock
54+ // so the main thread can keep filling m_fill_buffer concurrently.
55+ (*m_writer)(std::move (buf));
56+ }
57+ } catch (...) {
58+ std::unique_lock<std::mutex> lock{m_mutex};
59+ m_writer_exception = std::current_exception ();
60+ m_flush_pending = false ;
61+ m_shutdown = true ;
62+ lock.unlock ();
63+ m_cv.notify_all ();
64+ }
65+ }
66+
67+ void Extract::check_writer_exception () {
68+ if (m_writer_exception) {
69+ std::rethrow_exception (m_writer_exception);
70+ }
71+ }
72+
73+ void Extract::swap_and_flush () {
74+ std::unique_lock<std::mutex> lock{m_mutex};
75+ m_cv.wait (lock, [this ]{ return !m_flush_pending || m_shutdown; });
76+ check_writer_exception ();
77+
78+ std::swap (m_fill_buffer, m_flush_buffer);
79+ m_fill_buffer = osmium::memory::Buffer{buffer_size,
80+ osmium::memory::Buffer::auto_grow::no};
81+ m_flush_pending = true ;
82+ lock.unlock ();
83+ m_cv.notify_one ();
84+ }
85+
86+ void Extract::open_file (const osmium::io::Header& header,
87+ osmium::io::overwrite output_overwrite,
88+ osmium::io::fsync sync,
89+ OptionClean const * clean) {
3390 m_clean = clean;
34- m_writer = std::make_unique<osmium::io::Writer>(m_output_file, header, output_overwrite, sync);
91+ m_writer = std::make_unique<osmium::io::Writer>(m_output_file, header,
92+ output_overwrite, sync);
93+ m_writer_thread = std::thread{&Extract::writer_loop, this };
3594}
3695
3796void Extract::close_file () {
38- if (m_writer) {
39- if (m_buffer.committed () > 0 ) {
40- m_clean->apply_to (m_buffer);
41- (*m_writer)(std::move (m_buffer));
97+ if (!m_writer) {
98+ return ;
99+ }
100+
101+ if (m_fill_buffer.committed () > 0 ) {
102+ swap_and_flush ();
103+ }
104+
105+ {
106+ std::unique_lock<std::mutex> lock{m_mutex};
107+ m_cv.wait (lock, [this ]{ return !m_flush_pending || m_shutdown; });
108+ check_writer_exception ();
109+ m_shutdown = true ;
110+ }
111+ m_cv.notify_one ();
112+ m_writer_thread.join ();
113+
114+ check_writer_exception ();
115+ m_writer->close ();
116+ }
117+
118+ Extract::~Extract () {
119+ if (m_writer_thread.joinable ()) {
120+ {
121+ std::lock_guard<std::mutex> lock{m_mutex};
122+ m_shutdown = true ;
42123 }
43- m_writer->close ();
124+ m_cv.notify_one ();
125+ m_writer_thread.join ();
44126 }
45127}
46128
47129void Extract::write (const osmium::memory::Item& item) {
48- if (m_buffer.capacity () - m_buffer.committed () < item.padded_size ()) {
49- m_clean->apply_to (m_buffer);
50- (*m_writer)(std::move (m_buffer));
51- m_buffer = osmium::memory::Buffer{buffer_size, osmium::memory::Buffer::auto_grow::no};
130+ if (m_fill_buffer.capacity () - m_fill_buffer.committed () < item.padded_size ()) {
131+ swap_and_flush ();
52132 }
53- m_buffer .push_back (item);
133+ m_fill_buffer .push_back (item);
54134}
55135
56136std::string Extract::envelope_as_text () const {
57137 std::stringstream ss;
58138 ss << m_envelope;
59139 return ss.str ();
60140}
61-
0 commit comments