Skip to content

Commit d6b787d

Browse files
committed
Properly fail build on fatal IO error. Remove hardcoded IO indirection.
1 parent 5ca3f4c commit d6b787d

18 files changed

+246
-176
lines changed

CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ include(${CMAKE_DIR}/pdal.cmake)
5050
include(${CMAKE_DIR}/system.cmake)
5151

5252
set(THIRD_ROOT $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/entwine/third>)
53-
message(WARNING "INCLUDING" ${THIRD_ROOT})
5453
include_directories(SYSTEM PUBLIC ${THIRD_ROOT})
5554

5655
add_subdirectory(entwine)

config/cesium-truncated.json

-13
This file was deleted.

config/cesium.json

-12
This file was deleted.

entwine/builder/builder.cpp

+53-5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Builder::Builder(
5252
bool verbose)
5353
: endpoints(endpoints)
5454
, metadata(metadata)
55+
, io(Io::create(this->metadata, this->endpoints))
5556
, manifest(manifest)
5657
, hierarchy(hierarchy)
5758
, verbose(verbose)
@@ -64,13 +65,34 @@ uint64_t Builder::run(
6465
{
6566
Pool pool(2);
6667

68+
std::string fatalError;
69+
6770
std::atomic_uint64_t counter(0);
6871
std::atomic_bool done(false);
6972
pool.add([&]() { monitor(progressInterval, counter, done); });
70-
pool.add([&]() { runInserts(threads, limit, counter); done = true; });
73+
pool.add([&]()
74+
{
75+
try
76+
{
77+
runInserts(threads, limit, counter);
78+
done = true;
79+
}
80+
catch (std::exception& e)
81+
{
82+
fatalError = e.what();
83+
done = true;
84+
}
85+
catch (...)
86+
{
87+
fatalError = "Fatal error: unknown error";
88+
done = true;
89+
}
90+
});
7191

7292
pool.join();
7393

94+
if (fatalError.size()) throw new std::runtime_error(fatalError);
95+
7496
return counter;
7597
}
7698

@@ -91,7 +113,7 @@ void Builder::runInserts(
91113
const uint64_t stolenThreads = threads.work - actualWorkThreads;
92114
const uint64_t actualClipThreads = threads.clip + stolenThreads;
93115

94-
ChunkCache cache(endpoints, metadata, hierarchy, actualClipThreads);
116+
ChunkCache cache(endpoints, metadata, *io, hierarchy, actualClipThreads);
95117
Pool pool(std::min<uint64_t>(actualWorkThreads, manifest.size()));
96118

97119
uint64_t filesInserted = 0;
@@ -101,6 +123,8 @@ void Builder::runInserts(
101123
origin < manifest.size() && (!limit || filesInserted < limit);
102124
++origin)
103125
{
126+
if (cache.fatalErrors().size()) break;
127+
104128
const auto& item = manifest.at(origin);
105129
const auto& info = item.source.info;
106130
if (!item.inserted && info.points && active.overlaps(info.bounds))
@@ -126,6 +150,24 @@ void Builder::runInserts(
126150
pool.join();
127151
cache.join();
128152

153+
// While pool errors from *input* are not fatal and just get stored and
154+
// logged as errors to note that an input file failed to be inserted,
155+
// errors reading/writing from the *output* are irrecoverably fatal. In
156+
// this case, log the error and throw, no need to save metadata since
157+
// the build is busted.
158+
const auto errors = cache.fatalErrors();
159+
if (errors.size())
160+
{
161+
if (verbose)
162+
{
163+
std::cout << "Fatal error: failed to read or write output data\n";
164+
for (const auto& e : errors) std::cout << "\t" << e << std::endl;
165+
std::cout << "Terminating fatally corrupted build..." << std::endl;
166+
}
167+
168+
throw std::runtime_error(errors.front());
169+
}
170+
129171
save(getTotal(threads));
130172
}
131173

@@ -616,7 +658,12 @@ void merge(
616658
Manifest manifest = base.manifest;
617659

618660
Builder builder(endpoints, metadata, manifest, Hierarchy(), verbose);
619-
ChunkCache cache(endpoints, builder.metadata, builder.hierarchy, threads);
661+
ChunkCache cache(
662+
endpoints,
663+
builder.metadata,
664+
*builder.io,
665+
builder.hierarchy,
666+
threads);
620667

621668
if (verbose) std::cout << "Merging" << std::endl;
622669

@@ -670,8 +717,9 @@ void mergeOne(Builder& dst, const Builder& src, ChunkCache& cache)
670717
{
671718
// TODO: Should make sure that the src/dst metadata match. For now we're
672719
// relying on the user not to have done anything weird.
673-
const auto& endpoints = dst.endpoints;
674720
const auto& metadata = dst.metadata;
721+
const auto& endpoints = dst.endpoints;
722+
auto io = Io::create(metadata, endpoints);
675723

676724
Clipper clipper(cache);
677725
const auto sharedDepth = getSharedDepth(src.metadata);
@@ -710,7 +758,7 @@ void mergeOne(Builder& dst, const Builder& src, ChunkCache& cache)
710758
});
711759

712760
const auto stem = key.toString() + getPostfix(src.metadata);
713-
io::read(metadata.dataType, metadata, endpoints, stem, table);
761+
io->read(stem, table);
714762
}
715763
}
716764
}

entwine/builder/builder.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ struct Builder
6363

6464
Endpoints endpoints;
6565
Metadata metadata;
66+
std::unique_ptr<Io> io;
67+
6668
Manifest manifest;
6769
Hierarchy hierarchy;
6870
bool verbose = true;

entwine/builder/chunk-cache.cpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ ChunkCache::Info ChunkCache::latchInfo()
3333
ChunkCache::ChunkCache(
3434
const Endpoints& endpoints,
3535
const Metadata& metadata,
36+
const Io& io,
3637
Hierarchy& hierarchy,
3738
const uint64_t threads)
3839
: m_endpoints(endpoints)
3940
, m_metadata(metadata)
41+
, m_io(io)
4042
, m_hierarchy(hierarchy)
4143
, m_pool(threads)
4244
{ }
@@ -113,7 +115,7 @@ Chunk& ChunkCache::addRef(const ChunkKey& ck, Clipper& clipper)
113115
// case, we'll need to reinitialize the resident chunk from its
114116
// remote source. Our newly added reference will keep it from
115117
// being erased.
116-
ref.assign(m_metadata, ck, m_hierarchy);
118+
ref.assign(m_metadata, m_io, ck, m_hierarchy);
117119
assert(ref.exists());
118120

119121
{
@@ -152,7 +154,7 @@ Chunk& ChunkCache::addRef(const ChunkKey& ck, Clipper& clipper)
152154
auto insertion = slice.emplace(
153155
std::piecewise_construct,
154156
std::forward_as_tuple(ck.position()),
155-
std::forward_as_tuple(m_metadata, ck, m_hierarchy));
157+
std::forward_as_tuple(m_metadata, m_io, ck, m_hierarchy));
156158

157159
{
158160
SpinGuard lock(infoSpin);
@@ -265,7 +267,18 @@ void ChunkCache::maybePurge(const uint64_t maxCacheSize)
265267
// Don't hold any locks while we do this, since it may block. We
266268
// only want to block the calling thread in this case, not the
267269
// whole system.
268-
m_pool.add([this, dxyz]() { maybeSerialize(dxyz); });
270+
m_pool.add([this, dxyz]()
271+
{
272+
try
273+
{
274+
maybeSerialize(dxyz);
275+
}
276+
catch (std::exception& e)
277+
{
278+
std::lock_guard<std::mutex> lock(m_errorsMutex);
279+
m_errors.push_back(e.what());
280+
}
281+
});
269282

270283
ownedLock.lock();
271284
}

entwine/builder/chunk-cache.hpp

+26-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#pragma once
1212

1313
#include <array>
14+
#include <mutex>
15+
#include <string>
16+
#include <vector>
1417

1518
#include <entwine/builder/chunk.hpp>
1619
#include <entwine/builder/hierarchy.hpp>
@@ -26,8 +29,12 @@ class Clipper;
2629
class ReffedChunk
2730
{
2831
public:
29-
ReffedChunk(const Metadata& m, const ChunkKey& ck, const Hierarchy& h)
30-
: m_chunk(makeUnique<Chunk>(m, ck, h))
32+
ReffedChunk(
33+
const Metadata& m,
34+
const Io& io,
35+
const ChunkKey& ck,
36+
const Hierarchy& h)
37+
: m_chunk(makeUnique<Chunk>(m, io, ck, h))
3138
{ }
3239

3340
SpinLock& spin() { return m_spin; }
@@ -48,10 +55,14 @@ class ReffedChunk
4855

4956
void reset() { m_chunk.reset(); }
5057
bool exists() { return !!m_chunk; }
51-
void assign(const Metadata& m, const ChunkKey& ck, const Hierarchy& h)
58+
void assign(
59+
const Metadata& m,
60+
const Io& io,
61+
const ChunkKey& ck,
62+
const Hierarchy& h)
5263
{
5364
assert(!exists());
54-
m_chunk = makeUnique<Chunk>(m, ck, h);
65+
m_chunk = makeUnique<Chunk>(m, io, ck, h);
5566
}
5667

5768
private:
@@ -66,6 +77,7 @@ class ChunkCache
6677
ChunkCache(
6778
const Endpoints& endpoints,
6879
const Metadata& Metadata,
80+
const Io& io,
6981
Hierarchy& hierarchy,
7082
uint64_t threads);
7183

@@ -85,6 +97,12 @@ class ChunkCache
8597

8698
static Info latchInfo();
8799

100+
std::vector<std::string> fatalErrors() const
101+
{
102+
std::lock_guard<std::mutex> lock(m_errorsMutex);
103+
return m_errors;
104+
}
105+
88106
private:
89107
Chunk& addRef(const ChunkKey& ck, Clipper& clipper);
90108
void maybeSerialize(const Dxyz& dxyz);
@@ -93,13 +111,17 @@ class ChunkCache
93111

94112
const Endpoints& m_endpoints;
95113
const Metadata& m_metadata;
114+
const Io& m_io;
96115
Hierarchy& m_hierarchy;
97116
Pool m_pool;
98117
const uint64_t m_cacheSize = 64;
99118

100119
std::array<SpinLock, maxDepth> m_spins;
101120
std::array<std::map<Xyz, ReffedChunk>, maxDepth> m_slices;
102121

122+
mutable std::mutex m_errorsMutex;
123+
std::vector<std::string> m_errors;
124+
103125
SpinLock m_ownedSpin;
104126
std::set<Dxyz> m_owned;
105127
};

entwine/builder/chunk.cpp

+8-9
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@
1919
namespace entwine
2020
{
2121

22-
Chunk::Chunk(const Metadata& m, const ChunkKey& ck, const Hierarchy& hierarchy)
22+
Chunk::Chunk(
23+
const Metadata& m,
24+
const Io& io,
25+
const ChunkKey& ck,
26+
const Hierarchy& hierarchy)
2327
: m_metadata(m)
28+
, m_io(io)
2429
, m_span(m_metadata.span)
2530
, m_pointSize(getPointSize(m_metadata.absoluteSchema))
2631
, m_chunkKey(ck)
@@ -173,13 +178,7 @@ uint64_t Chunk::save(const Endpoints& endpoints) const
173178
const auto filename =
174179
m_chunkKey.toString() + getPostfix(m_metadata, m_chunkKey.depth());
175180

176-
io::write(
177-
m_metadata.dataType,
178-
m_metadata,
179-
endpoints,
180-
filename,
181-
table,
182-
m_chunkKey.bounds());
181+
m_io.write(filename, table, m_chunkKey.bounds());
183182

184183
return np;
185184
}
@@ -208,7 +207,7 @@ void Chunk::load(
208207
const auto filename =
209208
m_chunkKey.toString() + getPostfix(m_metadata, m_chunkKey.depth());
210209

211-
io::read(m_metadata.dataType, m_metadata, endpoints, filename, table);
210+
m_io.read(filename, table);
212211
}
213212

214213
} // namespace entwine

entwine/builder/chunk.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <entwine/builder/hierarchy.hpp>
1818
#include <entwine/builder/overflow.hpp>
19+
#include <entwine/io/io.hpp>
1920
#include <entwine/third/arbiter/arbiter.hpp>
2021
#include <entwine/types/endpoints.hpp>
2122
#include <entwine/types/vector-point-table.hpp>
@@ -36,7 +37,11 @@ struct VoxelTube
3637
class Chunk
3738
{
3839
public:
39-
Chunk(const Metadata& m, const ChunkKey& ck, const Hierarchy& hierarchy);
40+
Chunk(
41+
const Metadata& m,
42+
const Io& io,
43+
const ChunkKey& ck,
44+
const Hierarchy& hierarchy);
4045

4146
bool insert(ChunkCache& cache, Clipper& clipper, Voxel& voxel, Key& key);
4247
uint64_t save(const Endpoints& endpoints) const;
@@ -65,6 +70,7 @@ class Chunk
6570
void doOverflow(ChunkCache& cache, Clipper& clipper, uint64_t dir);
6671

6772
const Metadata& m_metadata;
73+
const Io& m_io;
6874
const uint64_t m_span;
6975
const uint64_t m_pointSize;
7076
const ChunkKey m_chunkKey;

0 commit comments

Comments
 (0)