Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public String toString() {
private final AtomicLong relationsProcessed = new AtomicLong(0);
private final AtomicLong h3CellsGenerated = new AtomicLong(0);

private volatile int mergedThreadDatabasesTotal;
private final AtomicLong mergedThreadDatabasesProcessed = new AtomicLong(0);
private final AtomicLong mergedEntriesProcessed = new AtomicLong(0);

private volatile String currentPhase = "Initializing";
private volatile boolean running = true;
private final long startTime = System.currentTimeMillis();
Expand Down Expand Up @@ -129,6 +133,30 @@ public void addH3CellsGenerated(long count) {
h3CellsGenerated.addAndGet(count);
}

public void setMergedThreadCount(int count) {
this.mergedThreadDatabasesTotal = count;
}

public int getMergedThreadDatabasesTotal() {
return mergedThreadDatabasesTotal;
}

public long getMergedThreadDatabasesProcessed() {
return mergedThreadDatabasesProcessed.get();
}

public void incrementMergedThreadDatabasesProcessed() {
mergedThreadDatabasesProcessed.incrementAndGet();
}

public long getMergedEntriesProcessed() {
return mergedEntriesProcessed.get();
}

public void incrementMergedEntriesProcessed() {
mergedEntriesProcessed.incrementAndGet();
}

public String getCurrentPhase() {
return currentPhase;
}
Expand Down Expand Up @@ -247,6 +275,15 @@ public void startProgressReporter() {
if (getErrorsTotal() > 0) {
sb.append(String.format(" │ \033[31mErrors:\033[0m %d", getErrorsTotal()));
}
} else if (phase.contains("Merging")) {
long dbsProcessed = mergedThreadDatabasesProcessed.get();
int dbsTotal = mergedThreadDatabasesTotal;
long entriesProcessed = mergedEntriesProcessed.get();
long entriesPerSec = phaseSeconds > 0 ? (long) (entriesProcessed / phaseSeconds) : 0;
sb.append(String.format("\033[1;36m[%s]\033[0m \033[1mMerging H3 thread DBs\033[0m", formatTime(elapsed)));
sb.append(String.format(" │ \033[32mDBs:\033[0m %d/%d", dbsProcessed, dbsTotal));
sb.append(String.format(" │ \033[36mEntries:\033[0m %s \033[33m(%s/s)\033[0m",
formatCompactNumber(entriesProcessed), formatCompactRate(entriesPerSec)));
} else {
sb.append(String.format("\033[1;36m[%s]\033[0m %s", formatTime(elapsed), phase));
}
Expand Down Expand Up @@ -277,6 +314,8 @@ public void printFinalStatistics() {
double totalSeconds = totalTime / 1000.0;
double phase1Seconds = Math.max(0.001, phase1Duration / 1000.0);
double phase2Seconds = Math.max(0.001, phase2Duration / 1000.0);
long phase3Duration = totalTime - phase1Duration - phase2Duration;
double phase3Seconds = Math.max(0.001, phase3Duration / 1000.0);

System.out.printf("\n\033[1;37mTotal Import Time:\033[0m \033[1;33m%s\033[0m%n%n", formatTime(getTotalTime()));

Expand All @@ -299,6 +338,9 @@ public void printFinalStatistics() {
System.out.printf("│ \033[33mH3 Cells Generated\033[0m │ %15s │ %13s/s │%n",
formatCompactNumber(getH3CellsGenerated()),
formatCompactNumber((long) (getH3CellsGenerated() / phase2Seconds)));
System.out.printf("│ \033[36mH3 Entries Merged\033[0m │ %15s │ %13s/s │%n",
formatCompactNumber(getMergedEntriesProcessed()),
formatCompactNumber((long) (getMergedEntriesProcessed() / phase3Seconds)));
System.out.println("└──────────────────────┴─────────────────┴─────────────────┘");

if (h3OsmSizeBytes > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
* Reads a pre-filtered boundaries_only.pbf (Nodes -> Ways -> Relations ordered)
* and produces three RocksDB databases for offline mobile lookup:
* - h3_to_osm: H3_CELL_ID (uint64) -> List[OSM_ID] (raw byte array)
* - region_metadata: OSM_ID -> [total cell count (long), h3 resolution (int)] (12 bytes)
* - region_metadata: OSM_ID -> [total cell count (long), h3 resolution (int), admin_level (int)] (16 bytes)
* - region_geometry: OSM_ID -> simplified WKB (bytes)
*/
@Service
Expand Down Expand Up @@ -275,7 +275,7 @@ public void importBoundaries(List<String> pbfPaths, String outputDir) throws Exc
stats.addH3CellsGenerated(totalCells);

startTime = System.currentTimeMillis();
tmpRegionMeta.put(wo, longToBytes(stub.osmId()), cellMetaToBytes(totalCells, resolution));
tmpRegionMeta.put(wo, longToBytes(stub.osmId()), cellMetaToBytes(totalCells, resolution, stub.adminLevel()));
if (stub.adminLevel() <= 3) {
logger.debug("H3 Cells written to tmpRegionMeta in {}ms for OSM ID: {}", System.currentTimeMillis() - startTime, stub.osmId());
}
Expand Down Expand Up @@ -304,11 +304,13 @@ public void importBoundaries(List<String> pbfPaths, String outputDir) throws Exc

// Merge per-thread H3 DBs into the final h3_to_osm
stats.setCurrentPhase(3, "3.1: Merging H3 thread DBs");
stats.setMergedThreadCount(threads);
for (int t = 0; t < threads; t++) {
if (Files.exists(threadH3Paths[t])) {
try (RocksDB threadDb = RocksDB.open(cacheOpts, threadH3Paths[t].toString())) {
copyH3Db(threadDb, h3ToOsm);
}
stats.incrementMergedThreadDatabasesProcessed();
cleanup(threadH3Paths[t]);
}
}
Expand Down Expand Up @@ -367,6 +369,7 @@ private void copyH3Db(RocksDB source, RocksDB target) throws RocksDBException {
target.put(wo, key, merged);
}
it.next();
this.stats.incrementMergedEntriesProcessed();
}
}
}
Expand Down Expand Up @@ -579,10 +582,11 @@ private long[] bytesToLongArray(byte[] b) {
return arr;
}

private byte[] cellMetaToBytes(long cellCount, int resolution) {
return ByteBuffer.allocate(12).order(ByteOrder.BIG_ENDIAN)
private byte[] cellMetaToBytes(long cellCount, int resolution, int adminLevel) {
return ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN)
.putLong(cellCount)
.putInt(resolution)
.putInt(adminLevel)
.array();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,18 @@ void testRegionMetadataFormat() throws RocksDBException {
assertEquals(8, key.length, "Region metadata key should be 8 bytes (OSM ID)");

byte[] val = it.value();
assertEquals(12, val.length, "Value should be 12 bytes (8-byte cell count + 4-byte resolution)");
assertEquals(16, val.length, "Value should be 16 bytes (8-byte cell count + 4-byte resolution + 4-byte admin level)");

ByteBuffer bb = ByteBuffer.wrap(val).order(ByteOrder.BIG_ENDIAN);
long cellCount = bb.getLong();
int resolution = bb.getInt();
int adminLevel = bb.getInt();

assertTrue(cellCount > 0, "Cell count should be positive, got: " + cellCount);
assertTrue(resolution >= 4 && resolution <= 9,
"Resolution should be between 4 and 9, got: " + resolution);
assertTrue(adminLevel >= 1 && adminLevel <= 11,
"Admin level should be between 2 and 11, got: " + adminLevel);

int count = 0;
it.seekToFirst();
Expand All @@ -167,17 +170,20 @@ void testAllRegionMetadataEntriesHaveValidResolution() throws RocksDBException {
int checked = 0;
while (it.isValid()) {
byte[] val = it.value();
assertEquals(12, val.length,
"Every region_metadata entry should be 12 bytes");
assertEquals(16, val.length,
"Every region_metadata entry should be 16 bytes");

ByteBuffer bb = ByteBuffer.wrap(val).order(ByteOrder.BIG_ENDIAN);
long cellCount = bb.getLong();
int resolution = bb.getInt();
int adminLevel = bb.getInt();

assertTrue(cellCount > 0,
"Cell count should be positive for entry " + checked);
assertTrue(resolution >= 4 && resolution <= 9,
"Resolution should be 4-9 for entry " + checked + ", got: " + resolution);
assertTrue(adminLevel >= 1 && adminLevel <= 11,
"Admin level should be 2-11 for entry " + checked + ", got: " + adminLevel);

checked++;
it.next();
Expand Down
Loading