kopia lustrzana https://github.com/onthegomap/planetiler
simplify and improve performance of node map
rodzic
61eb58f427
commit
15a3659db6
|
@ -16,10 +16,10 @@ The `flatmap-core` module includes the following software:
|
|||
- org.geotools:gt-epsg-hsql
|
||||
(LGPL, [BSD for HSQL](https://github.com/geotools/geotools/blob/main/licenses/HSQL.md)
|
||||
, [EPSG](https://github.com/geotools/geotools/blob/main/licenses/EPSG.md))
|
||||
- org.mapdb:mapdb (Apache license)
|
||||
- org.msgpack:msgpack-core (Apache license)
|
||||
- org.xerial:sqlite-jdbc (Apache license)
|
||||
- com.ibm.icu:icu4j ([ICU license](https://github.com/unicode-org/icu/blob/main/icu4c/LICENSE))
|
||||
- com.google.guava:guava (Apache license)
|
||||
- Adapted code:
|
||||
- `DouglasPeuckerSimplifier` from [JTS](https://github.com/locationtech/jts) (EDL)
|
||||
- `OsmMultipolygon` from [imposm3](https://github.com/omniscale/imposm3) (Apache license)
|
||||
|
|
|
@ -24,4 +24,44 @@
|
|||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<!-- for fatjar assembly descriptor -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.onthegomap</groupId>
|
||||
<artifactId>flatmap-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Multi-Release>true</Multi-Release>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>fatjar</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -4,7 +4,6 @@ import static io.prometheus.client.Collector.NANOSECONDS_PER_SECOND;
|
|||
|
||||
import com.onthegomap.flatmap.collection.LongLongMap;
|
||||
import com.onthegomap.flatmap.stats.Counter;
|
||||
import com.onthegomap.flatmap.stats.ProcessInfo;
|
||||
import com.onthegomap.flatmap.stats.ProgressLoggers;
|
||||
import com.onthegomap.flatmap.stats.Stats;
|
||||
import com.onthegomap.flatmap.util.FileUtils;
|
||||
|
@ -21,20 +20,9 @@ public class LongLongMapBench {
|
|||
public static void main(String[] args) throws InterruptedException {
|
||||
Path path = Path.of("./llmaptest");
|
||||
FileUtils.delete(path);
|
||||
LongLongMap map = switch (args[0]) {
|
||||
case "sparsemem2" -> LongLongMap.newInMemorySparseArray2();
|
||||
case "sparsearraymemory" -> LongLongMap.newInMemorySparseArray();
|
||||
case "hppc" -> new LongLongMap.HppcMap();
|
||||
case "array" -> new LongLongMap.Array();
|
||||
|
||||
case "sparse2" -> LongLongMap.newFileBackedSparseArray2(path);
|
||||
case "sqlite" -> LongLongMap.newSqlite(path);
|
||||
case "sparsearray" -> LongLongMap.newFileBackedSparseArray(path);
|
||||
case "mapdb" -> LongLongMap.newFileBackedSortedTable(path);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + args[0]);
|
||||
};
|
||||
long entries = Long.parseLong(args[1]);
|
||||
int readers = Integer.parseInt(args[2]);
|
||||
LongLongMap map = LongLongMap.from(args[0], args[1], path);
|
||||
long entries = Long.parseLong(args[2]);
|
||||
int readers = Integer.parseInt(args[3]);
|
||||
|
||||
class LocalCounter {
|
||||
|
||||
|
@ -59,7 +47,8 @@ public class LongLongMapBench {
|
|||
}).awaitAndLog(loggers, Duration.ofSeconds(10));
|
||||
|
||||
map.get(1);
|
||||
System.err.println("Storage: " + Format.formatStorage(map.fileSize(), false));
|
||||
System.err.println("Storage: " + Format.formatStorage(map.bytesOnDisk(), false));
|
||||
System.err.println("RAM: " + Format.formatStorage(map.estimateMemoryUsageBytes(), false));
|
||||
|
||||
Counter.Readable readCount = Counter.newMultiThreadCounter();
|
||||
loggers = new ProgressLoggers("read")
|
||||
|
@ -110,13 +99,14 @@ public class LongLongMapBench {
|
|||
args[1],
|
||||
args[2],
|
||||
args[3],
|
||||
Format.formatStorage(ProcessInfo.getMaxMemoryBytes(), false),
|
||||
Format.formatStorage(map.fileSize(), false),
|
||||
Format.formatStorage(map.estimateMemoryUsageBytes(), false),
|
||||
Format.formatStorage(map.bytesOnDisk(), false),
|
||||
Format.formatStorage(FileUtils.size(path), false),
|
||||
writeRate.get(),
|
||||
readRate
|
||||
)
|
||||
);
|
||||
FileUtils.delete(path);
|
||||
Thread.sleep(100);
|
||||
System.exit(0);
|
||||
}
|
||||
|
|
|
@ -45,11 +45,6 @@
|
|||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.34.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapdb</groupId>
|
||||
<artifactId>mapdb</artifactId>
|
||||
<version>3.0.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.msgpack</groupId>
|
||||
<artifactId>msgpack-core</artifactId>
|
||||
|
@ -120,6 +115,11 @@
|
|||
<artifactId>icu4j</artifactId>
|
||||
<version>69.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>30.1.1-jre</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -34,13 +34,13 @@ public class FlatMapRunner {
|
|||
|
||||
private final Timers.Finishable overallTimer;
|
||||
private final Arguments arguments;
|
||||
private Stats stats;
|
||||
private final Stats stats;
|
||||
private Profile profile = null;
|
||||
private CommonParams config;
|
||||
private FeatureSort featureDb;
|
||||
private FeatureGroup featureMap;
|
||||
private OsmInputFile osmInputFile;
|
||||
private Path tmpDir;
|
||||
private final Path tmpDir;
|
||||
private Path output;
|
||||
private boolean overwrite = false;
|
||||
private boolean ran = false;
|
||||
|
@ -59,16 +59,7 @@ public class FlatMapRunner {
|
|||
}
|
||||
|
||||
private LongLongMap getLongLongMap() {
|
||||
return switch (config.longLongMap()) {
|
||||
case "mapdb" -> LongLongMap.newFileBackedSortedTable(nodeDbPath);
|
||||
case "sparsearray" -> LongLongMap.newFileBackedSparseArray(nodeDbPath);
|
||||
case "sparsemem2" -> LongLongMap.newInMemorySparseArray2();
|
||||
case "sparse2" -> LongLongMap.newFileBackedSparseArray2(nodeDbPath);
|
||||
case "ramsparsearray" -> LongLongMap.newInMemorySparseArray();
|
||||
case "ramarray" -> LongLongMap.newArrayBacked();
|
||||
case "sqlite" -> LongLongMap.newSqlite(nodeDbPath);
|
||||
default -> throw new IllegalStateException("Unexpected llmap value: " + config.longLongMap());
|
||||
};
|
||||
return LongLongMap.from(config.nodeMapType(), config.nodeMapStorage(), nodeDbPath);
|
||||
}
|
||||
|
||||
public FlatMapRunner addOsmSource(String name, Path defaultPath) {
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package com.onthegomap.flatmap.collection;
|
||||
|
||||
import com.onthegomap.flatmap.util.DiskBacked;
|
||||
import com.onthegomap.flatmap.util.MemoryEstimator;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
interface AppendStore extends Closeable, MemoryEstimator.HasEstimate, DiskBacked {
|
||||
|
||||
long size();
|
||||
|
||||
default void checkIndex(long index) {
|
||||
if (index >= size()) {
|
||||
throw new IndexOutOfBoundsException("index: " + index + " size: " + size());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default long estimateMemoryUsageBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
default long bytesOnDisk() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface Ints extends AppendStore {
|
||||
|
||||
void writeInt(int value);
|
||||
|
||||
int getInt(long index);
|
||||
}
|
||||
|
||||
interface Longs extends AppendStore {
|
||||
|
||||
void writeLong(long value);
|
||||
|
||||
long getLong(long index);
|
||||
}
|
||||
|
||||
final class SmallLongs implements Longs {
|
||||
|
||||
private static final int BITS = 31;
|
||||
private static final long MASK = (1L << BITS) - 1L;
|
||||
private final Ints[] ints = new Ints[10];
|
||||
private long numWritten = 0;
|
||||
|
||||
SmallLongs(IntFunction<Ints> supplier) {
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
ints[i] = supplier.apply(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(long value) {
|
||||
int block = (int) (value >>> BITS);
|
||||
int offset = (int) (value & MASK);
|
||||
ints[block].writeInt(offset);
|
||||
numWritten++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(long index) {
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
Ints slab = ints[i];
|
||||
long size = slab.size();
|
||||
if (index < slab.size()) {
|
||||
return slab.getInt(index) + (((long) i) << BITS);
|
||||
}
|
||||
index -= size;
|
||||
}
|
||||
throw new ArrayIndexOutOfBoundsException("index: " + index + " size: " + size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return numWritten;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
for (var child : ints) {
|
||||
child.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateMemoryUsageBytes() {
|
||||
return Stream.of(ints).mapToLong(AppendStore::estimateMemoryUsageBytes).sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long bytesOnDisk() {
|
||||
return Stream.of(ints).mapToLong(AppendStore::bytesOnDisk).sum();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package com.onthegomap.flatmap.collection;
|
||||
|
||||
import com.onthegomap.flatmap.util.FileUtils;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
|
||||
abstract class AppendStoreMmap implements AppendStore {
|
||||
|
||||
final DataOutputStream outputStream;
|
||||
final int segmentBits;
|
||||
final long segmentMask;
|
||||
final long segmentBytes;
|
||||
private final Path path;
|
||||
long outIdx = 0;
|
||||
private volatile MappedByteBuffer[] segments;
|
||||
private volatile FileChannel channel;
|
||||
|
||||
AppendStoreMmap(Path path) {
|
||||
this(path, 1 << 20); // 1MB
|
||||
}
|
||||
|
||||
AppendStoreMmap(Path path, long segmentSizeBytes) {
|
||||
segmentBits = (int) (Math.log(segmentSizeBytes) / Math.log(2));
|
||||
segmentMask = (1L << segmentBits) - 1;
|
||||
segmentBytes = segmentSizeBytes;
|
||||
if (segmentSizeBytes % 8 != 0 || (1L << segmentBits != segmentSizeBytes)) {
|
||||
throw new IllegalArgumentException("segment size must be a multiple of 8 and power of 2: " + segmentSizeBytes);
|
||||
}
|
||||
this.path = path;
|
||||
try {
|
||||
this.outputStream = new DataOutputStream(new BufferedOutputStream(Files.newOutputStream(path), 50_000));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Could not create SequentialWriteRandomReadFile output stream", e);
|
||||
}
|
||||
}
|
||||
|
||||
MappedByteBuffer[] getSegments() {
|
||||
MappedByteBuffer[] result = segments;
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
if ((result = segments) == null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
channel = FileChannel.open(path, StandardOpenOption.READ);
|
||||
int segmentCount = (int) (outIdx / segmentBytes + 1);
|
||||
result = new MappedByteBuffer[segmentCount];
|
||||
int i = 0;
|
||||
for (long segmentStart = 0; segmentStart < outIdx; segmentStart += segmentBytes) {
|
||||
long segmentEnd = Math.min(segmentBytes, outIdx - segmentStart);
|
||||
result[i++] = channel.map(FileChannel.MapMode.READ_ONLY, segmentStart, segmentEnd);
|
||||
}
|
||||
segments = result;
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Failed preparing SequentialWriteRandomReadFile for reads", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
outputStream.close();
|
||||
synchronized (this) {
|
||||
if (channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
if (segments != null) {
|
||||
Arrays.fill(segments, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long bytesOnDisk() {
|
||||
return FileUtils.size(path);
|
||||
}
|
||||
|
||||
static class Ints extends AppendStoreMmap implements AppendStore.Ints {
|
||||
|
||||
Ints(Path path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
Ints(Path path, long segmentSizeBytes) {
|
||||
super(path, segmentSizeBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt(int value) {
|
||||
try {
|
||||
outputStream.writeInt(value);
|
||||
outIdx += 4;
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Error writing int", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(long index) {
|
||||
checkIndex(index);
|
||||
MappedByteBuffer[] segments = getSegments();
|
||||
long byteOffset = index << 2;
|
||||
int idx = (int) (byteOffset >>> segmentBits);
|
||||
int offset = (int) (byteOffset & segmentMask);
|
||||
return segments[idx].getInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return outIdx >>> 2;
|
||||
}
|
||||
}
|
||||
|
||||
static class Longs extends AppendStoreMmap implements AppendStore.Longs {
|
||||
|
||||
Longs(Path path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
Longs(Path path, long segmentSizeBytes) {
|
||||
super(path, segmentSizeBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(long value) {
|
||||
try {
|
||||
outputStream.writeLong(value);
|
||||
outIdx += 8;
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Error writing long", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(long index) {
|
||||
checkIndex(index);
|
||||
MappedByteBuffer[] segments = getSegments();
|
||||
long byteOffset = index << 3;
|
||||
int idx = (int) (byteOffset >>> segmentBits);
|
||||
int offset = (int) (byteOffset & segmentMask);
|
||||
return segments[idx].getLong(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return outIdx >>> 3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package com.onthegomap.flatmap.collection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
abstract class AppendStoreRam<T> implements AppendStore {
|
||||
|
||||
final List<T> arrays;
|
||||
long size = 0;
|
||||
final int slabSize;
|
||||
final int slabBits;
|
||||
final long slabMask;
|
||||
|
||||
|
||||
AppendStoreRam(int segmentSizeBytes) {
|
||||
this.slabBits = (int) (Math.log(segmentSizeBytes) / Math.log(2));
|
||||
if (1 << slabBits != segmentSizeBytes) {
|
||||
throw new IllegalArgumentException("Segment size must be a power of 2: " + segmentSizeBytes);
|
||||
}
|
||||
this.slabSize = (1 << slabBits);
|
||||
this.slabMask = slabSize - 1;
|
||||
this.arrays = new ArrayList<>();
|
||||
}
|
||||
|
||||
T writeSlab() {
|
||||
long idx = size++;
|
||||
int slabIdx = (int) (idx >>> slabBits);
|
||||
while (arrays.size() <= slabIdx) {
|
||||
arrays.add(newSlab());
|
||||
}
|
||||
return arrays.get(slabIdx);
|
||||
}
|
||||
|
||||
abstract T newSlab();
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
arrays.clear();
|
||||
}
|
||||
|
||||
static class Ints extends AppendStoreRam<int[]> implements AppendStore.Ints {
|
||||
|
||||
Ints() {
|
||||
this(1 << 20); // 1MB
|
||||
}
|
||||
|
||||
Ints(int segmentSizeBytes) {
|
||||
super(segmentSizeBytes >>> 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
int[] newSlab() {
|
||||
return new int[slabSize];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt(int value) {
|
||||
int offset = (int) (size & slabMask);
|
||||
writeSlab()[offset] = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(long index) {
|
||||
checkIndex(index);
|
||||
int slabIdx = (int) (index >>> slabBits);
|
||||
int offset = (int) (index & slabMask);
|
||||
int[] slab = arrays.get(slabIdx);
|
||||
return slab[offset];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateMemoryUsageBytes() {
|
||||
return arrays.size() * (slabSize * 4L + 24L + 8);
|
||||
}
|
||||
}
|
||||
|
||||
static class Longs extends AppendStoreRam<long[]> implements AppendStore.Longs {
|
||||
|
||||
Longs() {
|
||||
this(1 << 20); // 1MB
|
||||
}
|
||||
|
||||
Longs(int segmentSizeBytes) {
|
||||
super(segmentSizeBytes >>> 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long[] newSlab() {
|
||||
return new long[slabSize];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLong(long value) {
|
||||
int offset = (int) (size & slabMask);
|
||||
writeSlab()[offset] = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(long index) {
|
||||
checkIndex(index);
|
||||
int slabIdx = (int) (index >>> slabBits);
|
||||
int offset = (int) (index & slabMask);
|
||||
return arrays.get(slabIdx)[offset];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateMemoryUsageBytes() {
|
||||
return arrays.size() * (slabSize * 8L + 24L + 8);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ import java.util.function.Supplier;
|
|||
import java.util.zip.Deflater;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -116,10 +115,15 @@ class ExternalMergeSort implements FeatureSort {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long getStorageSize() {
|
||||
public long bytesOnDisk() {
|
||||
return FileUtils.directorySize(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateMemoryUsageBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static <T> T time(AtomicLong timer, Supplier<T> func) {
|
||||
long start = System.nanoTime();
|
||||
try {
|
||||
|
@ -156,7 +160,7 @@ class ExternalMergeSort implements FeatureSort {
|
|||
|
||||
ProgressLoggers loggers = new ProgressLoggers("sort")
|
||||
.addPercentCounter("chunks", chunks.size(), doneCounter)
|
||||
.addFileSize(this::getStorageSize)
|
||||
.addFileSize(this)
|
||||
.newLine()
|
||||
.addProcessStats()
|
||||
.newLine()
|
||||
|
@ -176,7 +180,7 @@ class ExternalMergeSort implements FeatureSort {
|
|||
return features.get();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@Override
|
||||
public Iterator<Entry> iterator() {
|
||||
assert sorted;
|
||||
|
@ -357,7 +361,7 @@ class ExternalMergeSort implements FeatureSort {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull PeekableScanner o) {
|
||||
public int compareTo(PeekableScanner o) {
|
||||
return next.compareTo(o.next);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.onthegomap.flatmap.geo.TileCoord;
|
|||
import com.onthegomap.flatmap.render.RenderedFeature;
|
||||
import com.onthegomap.flatmap.stats.Stats;
|
||||
import com.onthegomap.flatmap.util.CommonStringEncoder;
|
||||
import com.onthegomap.flatmap.util.DiskBacked;
|
||||
import com.onthegomap.flatmap.util.LayerStats;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -32,7 +33,8 @@ import org.msgpack.value.ValueFactory;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class FeatureGroup implements Consumer<FeatureSort.Entry>, Iterable<FeatureGroup.TileFeatures> {
|
||||
public final class FeatureGroup implements Consumer<FeatureSort.Entry>, Iterable<FeatureGroup.TileFeatures>,
|
||||
DiskBacked {
|
||||
|
||||
public static final int Z_ORDER_BITS = 23;
|
||||
public static final int Z_ORDER_MAX = (1 << (Z_ORDER_BITS - 1)) - 1;
|
||||
|
@ -277,8 +279,9 @@ public final class FeatureGroup implements Consumer<FeatureSort.Entry>, Iterable
|
|||
};
|
||||
}
|
||||
|
||||
public long getStorageSize() {
|
||||
return sorter.getStorageSize();
|
||||
@Override
|
||||
public long bytesOnDisk() {
|
||||
return sorter.bytesOnDisk();
|
||||
}
|
||||
|
||||
public FeatureSort sorter() {
|
||||
|
|
|
@ -2,15 +2,16 @@ package com.onthegomap.flatmap.collection;
|
|||
|
||||
import com.onthegomap.flatmap.config.CommonParams;
|
||||
import com.onthegomap.flatmap.stats.Stats;
|
||||
import com.onthegomap.flatmap.util.DiskBacked;
|
||||
import com.onthegomap.flatmap.util.MemoryEstimator;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface FeatureSort extends Iterable<FeatureSort.Entry> {
|
||||
public interface FeatureSort extends Iterable<FeatureSort.Entry>, DiskBacked, MemoryEstimator.HasEstimate {
|
||||
|
||||
static FeatureSort newExternalMergeSort(Path tempDir, CommonParams config, Stats stats) {
|
||||
return new ExternalMergeSort(tempDir, config, stats);
|
||||
|
@ -40,11 +41,16 @@ public interface FeatureSort extends Iterable<FeatureSort.Entry> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long getStorageSize() {
|
||||
public long estimateMemoryUsageBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public long bytesOnDisk() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<Entry> iterator() {
|
||||
return list.iterator();
|
||||
|
@ -66,12 +72,10 @@ public interface FeatureSort extends Iterable<FeatureSort.Entry> {
|
|||
|
||||
void add(Entry newEntry);
|
||||
|
||||
long getStorageSize();
|
||||
|
||||
record Entry(long sortKey, byte[] value) implements Comparable<Entry> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Entry o) {
|
||||
public int compareTo(Entry o) {
|
||||
return Long.compare(sortKey, o.sortKey);
|
||||
}
|
||||
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -15,11 +15,10 @@ public record CommonParams(
|
|||
boolean deferIndexCreation,
|
||||
boolean optimizeDb,
|
||||
boolean emitTilesInOrder,
|
||||
int mbtilesFeatureMultiplier,
|
||||
int mbtilesMinTilesPerBatch,
|
||||
boolean forceOverwrite,
|
||||
boolean gzipTempStorage,
|
||||
String longLongMap,
|
||||
String nodeMapType,
|
||||
String nodeMapStorage,
|
||||
|
||||
// computed
|
||||
Envelope worldBounds,
|
||||
|
@ -35,11 +34,10 @@ public record CommonParams(
|
|||
boolean deferIndexCreation,
|
||||
boolean optimizeDb,
|
||||
boolean emitTilesInOrder,
|
||||
int mbtilesFeatureMultiplier,
|
||||
int mbtilesMinTilesPerBatch,
|
||||
boolean forceOverwrite,
|
||||
boolean gzipTempStorage,
|
||||
String longLongMap
|
||||
String nodeMapType,
|
||||
String nodeMapStorage
|
||||
) {
|
||||
this(
|
||||
latLonBounds,
|
||||
|
@ -50,11 +48,10 @@ public record CommonParams(
|
|||
deferIndexCreation,
|
||||
optimizeDb,
|
||||
emitTilesInOrder,
|
||||
mbtilesFeatureMultiplier,
|
||||
mbtilesMinTilesPerBatch,
|
||||
forceOverwrite,
|
||||
gzipTempStorage,
|
||||
longLongMap,
|
||||
nodeMapType,
|
||||
nodeMapStorage,
|
||||
|
||||
// computed
|
||||
GeoUtils.toWorldBounds(latLonBounds),
|
||||
|
@ -95,11 +92,10 @@ public record CommonParams(
|
|||
arguments.get("defer_mbtiles_index_creation", "add index to mbtiles file after finished writing", false),
|
||||
arguments.get("optimize_db", "optimize mbtiles after writing", false),
|
||||
arguments.get("emit_tiles_in_order", "emit tiles in index order", true),
|
||||
arguments.integer("mbtiles_feature_multiplier", "mbtiles feature multiplier", 100),
|
||||
arguments.integer("mbtiles_min_tiles_per_batch", "min tiles per batch", 1),
|
||||
arguments.get("force", "force overwriting output file", false),
|
||||
arguments.get("gzip_temp", "gzip temporary feature storage (uses more CPU, but less disk space)", false),
|
||||
arguments.get("llmap", "type of long long map", "mapdb")
|
||||
arguments.get("nodemap_type", "type of node location map: noop, sortedtable, or sparsearray", "sortedtable"),
|
||||
arguments.get("nodemap_storage", "storage for location map: mmap or ram", "mmap")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.algorithm.Area;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.jts.geom.CoordinateSequence;
|
||||
|
@ -357,7 +356,7 @@ public class GeoUtils {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull PolyAndArea o) {
|
||||
public int compareTo(PolyAndArea o) {
|
||||
return -Double.compare(area, o.area);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.onthegomap.flatmap.geo;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.geom.Geometry;
|
||||
import org.locationtech.jts.geom.GeometryCollection;
|
||||
import org.locationtech.jts.geom.Point;
|
||||
|
@ -48,7 +47,7 @@ public class PolygonIndex<T> {
|
|||
return result.isEmpty() ? null : result.get(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
private List<T> getContaining(Point point, List<?> items) {
|
||||
List<T> result = new ArrayList<>(items.size());
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.onthegomap.flatmap.geo;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.jts.geom.CoordinateXY;
|
||||
|
||||
|
@ -83,7 +82,7 @@ public record TileCoord(int encoded, int x, int y, int z) implements Comparable<
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull TileCoord o) {
|
||||
public int compareTo(TileCoord o) {
|
||||
return Long.compare(encoded, o.encoded);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.OptionalInt;
|
|||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.DoubleStream;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.jts.geom.Envelope;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -514,7 +513,7 @@ public final class Mbtiles implements Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull TileEntry o) {
|
||||
public int compareTo(TileEntry o) {
|
||||
return tile.compareTo(o.tile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.onthegomap.flatmap.geo.TileCoord;
|
|||
import com.onthegomap.flatmap.stats.Counter;
|
||||
import com.onthegomap.flatmap.stats.ProgressLoggers;
|
||||
import com.onthegomap.flatmap.stats.Stats;
|
||||
import com.onthegomap.flatmap.util.DiskBacked;
|
||||
import com.onthegomap.flatmap.util.FileUtils;
|
||||
import com.onthegomap.flatmap.util.Format;
|
||||
import com.onthegomap.flatmap.util.LayerStats;
|
||||
|
@ -30,7 +31,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.atomic.LongAccumulator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -90,7 +90,7 @@ public class MbtilesWriter {
|
|||
}
|
||||
}
|
||||
|
||||
public static void writeOutput(FeatureGroup features, Mbtiles output, LongSupplier fileSize, Profile profile,
|
||||
public static void writeOutput(FeatureGroup features, Mbtiles output, DiskBacked fileSize, Profile profile,
|
||||
CommonParams config, Stats stats) {
|
||||
var timer = stats.startStage("mbtiles");
|
||||
MbtilesWriter writer = new MbtilesWriter(features, output, config, profile, stats,
|
||||
|
@ -130,7 +130,7 @@ public class MbtilesWriter {
|
|||
.addRatePercentCounter("features", features.numFeatures(), writer.featuresProcessed)
|
||||
.addRateCounter("tiles", writer::tilesEmitted)
|
||||
.addFileSize(fileSize)
|
||||
.add(" features ").addFileSize(features::getStorageSize)
|
||||
.add(" features ").addFileSize(features)
|
||||
.newLine()
|
||||
.addProcessStats()
|
||||
.newLine()
|
||||
|
|
|
@ -12,7 +12,6 @@ import com.onthegomap.flatmap.worker.WorkerPipeline;
|
|||
import java.io.Closeable;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.geom.Envelope;
|
||||
|
||||
public abstract class Reader implements Closeable {
|
||||
|
@ -63,7 +62,7 @@ public abstract class Reader implements Closeable {
|
|||
var loggers = new ProgressLoggers(sourceName)
|
||||
.addRatePercentCounter("read", featureCount, featuresRead)
|
||||
.addRateCounter("write", featuresWritten)
|
||||
.addFileSize(writer::getStorageSize)
|
||||
.addFileSize(writer)
|
||||
.newLine()
|
||||
.addProcessStats()
|
||||
.newLine()
|
||||
|
@ -78,7 +77,7 @@ public abstract class Reader implements Closeable {
|
|||
timer.stop();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
private FeatureRenderer getFeatureRenderer(FeatureGroup writer, CommonParams config,
|
||||
Consumer<FeatureSort.Entry> next) {
|
||||
var encoder = writer.newRenderedFeatureEncoder();
|
||||
|
|
|
@ -37,7 +37,6 @@ import java.util.Map;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.jts.geom.CoordinateList;
|
||||
import org.locationtech.jts.geom.CoordinateSequence;
|
||||
|
@ -105,7 +104,7 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
|
|||
|
||||
var loggers = new ProgressLoggers("osm_pass1")
|
||||
.addRateCounter("nodes", PASS1_NODES, true)
|
||||
.addFileSize(nodeDb::fileSize)
|
||||
.addFileSize(nodeDb)
|
||||
.addRateCounter("ways", PASS1_WAYS, true)
|
||||
.addRateCounter("rels", PASS1_RELATIONS, true)
|
||||
.newLine()
|
||||
|
@ -214,11 +213,11 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
|
|||
|
||||
var logger = new ProgressLoggers("osm_pass2")
|
||||
.addRatePercentCounter("nodes", PASS1_NODES.get(), nodesProcessed)
|
||||
.addFileSize(nodeDb::fileSize)
|
||||
.addFileSize(nodeDb)
|
||||
.addRatePercentCounter("ways", PASS1_WAYS.get(), waysProcessed)
|
||||
.addRatePercentCounter("rels", PASS1_RELATIONS.get(), relsProcessed)
|
||||
.addRateCounter("features", () -> writer.sorter().size())
|
||||
.addFileSize(writer::getStorageSize)
|
||||
.addFileSize(writer)
|
||||
.newLine()
|
||||
.addProcessStats()
|
||||
.addInMemoryObject("hppc", this)
|
||||
|
@ -267,7 +266,6 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
|
|||
return new WaySourceFeature(way, closed, area, nodeCache, rels);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<RelationMember<RelationInfo>> getRelationMembership(long id) {
|
||||
LongArrayList relationIds = wayToRelations.get(id);
|
||||
List<RelationMember<RelationInfo>> rels = null;
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.onthegomap.flatmap.geo.GeoUtils;
|
|||
import com.onthegomap.flatmap.geo.GeometryException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.algorithm.Area;
|
||||
import org.locationtech.jts.geom.CoordinateSequence;
|
||||
import org.locationtech.jts.geom.CoordinateSequences;
|
||||
|
@ -82,7 +81,7 @@ class CoordinateSequenceExtractor {
|
|||
return GeoUtils.combineLineStrings(lineStrings);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
static Geometry reassemblePolygons(List<List<CoordinateSequence>> groups) throws GeometryException {
|
||||
int numGeoms = groups.size();
|
||||
if (numGeoms == 1) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.onthegomap.flatmap.stats;
|
|||
import static com.onthegomap.flatmap.util.Format.*;
|
||||
|
||||
import com.graphhopper.util.Helper;
|
||||
import com.onthegomap.flatmap.util.DiskBacked;
|
||||
import com.onthegomap.flatmap.util.Format;
|
||||
import com.onthegomap.flatmap.util.MemoryEstimator;
|
||||
import com.onthegomap.flatmap.worker.WorkQueue;
|
||||
|
@ -185,8 +186,8 @@ public class ProgressLoggers {
|
|||
};
|
||||
}
|
||||
|
||||
public ProgressLoggers addFileSize(LongSupplier longSupplier) {
|
||||
loggers.add(string(() -> " " + padRight(formatBytes(longSupplier.getAsLong(), false), 5)));
|
||||
public ProgressLoggers addFileSize(DiskBacked longSupplier) {
|
||||
loggers.add(string(() -> " " + padRight(formatBytes(longSupplier.bytesOnDisk(), false), 5)));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ public class PrometheusStats implements Stats {
|
|||
this.osBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
}
|
||||
|
||||
private Map<Long, ProcessInfo.ThreadState> threads = new ConcurrentSkipListMap<>();
|
||||
private final Map<Long, ProcessInfo.ThreadState> threads = new ConcurrentSkipListMap<>();
|
||||
|
||||
public List<MetricFamilySamples> collect() {
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.onthegomap.flatmap.util;
|
||||
|
||||
public interface DiskBacked {
|
||||
|
||||
long bytesOnDisk();
|
||||
}
|
|
@ -80,6 +80,14 @@ public class FileUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void createDirectory(Path path) {
|
||||
try {
|
||||
Files.createDirectories(path);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Unable to create directories " + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void createParentDirectories(Path path) {
|
||||
try {
|
||||
if (Files.isDirectory(path)) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.onthegomap.flatmap.util;
|
||||
|
||||
import com.carrotsearch.hppc.ByteArrayList;
|
||||
import com.carrotsearch.hppc.IntArrayList;
|
||||
import com.carrotsearch.hppc.IntObjectHashMap;
|
||||
import com.carrotsearch.hppc.LongArrayList;
|
||||
import com.carrotsearch.hppc.LongHashSet;
|
||||
|
@ -37,6 +39,14 @@ public class MemoryEstimator {
|
|||
return object == null ? 0 : (24L + 8L * object.buffer.length);
|
||||
}
|
||||
|
||||
public static long size(IntArrayList object) {
|
||||
return object == null ? 0 : (24L + 4L * object.buffer.length);
|
||||
}
|
||||
|
||||
public static long size(ByteArrayList object) {
|
||||
return object == null ? 0 : (24L + object.buffer.length);
|
||||
}
|
||||
|
||||
public static long size(String string) {
|
||||
return string == null ? 0 : 54 + string.getBytes().length;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public interface ZoomFunction<T> extends IntFunction<T> {
|
|||
|
||||
class MeterThresholds implements ZoomFunction<Number> {
|
||||
|
||||
private TreeMap<Integer, Number> levels = new TreeMap<>();
|
||||
private final TreeMap<Integer, Number> levels = new TreeMap<>();
|
||||
|
||||
public MeterThresholds put(int zoom, double meters) {
|
||||
levels.put(zoom, GeoUtils.metersToPixelAtEquator(zoom, meters));
|
||||
|
|
|
@ -14,7 +14,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -38,7 +37,7 @@ public class Worker {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(@NotNull Runnable r) {
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r,
|
||||
namePrefix + threadNumber.getAndIncrement(),
|
||||
0);
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package com.onthegomap.flatmap.collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
public class AppendStoreTest {
|
||||
|
||||
static abstract class IntsTest {
|
||||
|
||||
protected AppendStore.Ints store;
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
public void writeThenRead(int num) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
store.writeInt(i + 1);
|
||||
}
|
||||
for (int i = 0; i < num; i++) {
|
||||
assertEquals(i + 1, store.getInt(i));
|
||||
}
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> store.getInt(num));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> store.getInt(num + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBig() {
|
||||
store.writeInt(Integer.MAX_VALUE);
|
||||
store.writeInt(Integer.MAX_VALUE - 1);
|
||||
store.writeInt(Integer.MAX_VALUE - 2);
|
||||
assertEquals(Integer.MAX_VALUE, store.getInt(0));
|
||||
assertEquals(Integer.MAX_VALUE - 1, store.getInt(1));
|
||||
assertEquals(Integer.MAX_VALUE - 2, store.getInt(2));
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class LongsTest {
|
||||
|
||||
protected AppendStore.Longs store;
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
public void writeThenRead(int num) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
store.writeLong(i + 1);
|
||||
}
|
||||
for (int i = 0; i < num; i++) {
|
||||
assertEquals(i + 1, store.getLong(i));
|
||||
}
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> store.getLong(num));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> store.getLong(num + 1));
|
||||
}
|
||||
|
||||
private static final long maxInt = Integer.MAX_VALUE;
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {maxInt - 1, maxInt, maxInt + 1, 2 * maxInt - 1, 2 * maxInt, 5 * maxInt - 1, 5 * maxInt + 1})
|
||||
public void readBig(long value) {
|
||||
store.writeLong(value);
|
||||
assertEquals(value, store.getLong(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class RamInt extends IntsTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.store = new AppendStoreRam.Ints(4 << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static class MMapInt extends IntsTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path path) {
|
||||
this.store = new AppendStoreMmap.Ints(path.resolve("ints"), 4 << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static class RamLong extends LongsTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.store = new AppendStoreRam.Longs(4 << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static class MMapLong extends LongsTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path path) {
|
||||
this.store = new AppendStoreMmap.Longs(path.resolve("longs"), 4 << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static class MMapSmallLong extends LongsTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path path) {
|
||||
this.store = new AppendStore.SmallLongs((i) -> new AppendStoreMmap.Ints(path.resolve("smalllongs" + i), 4 << 2));
|
||||
}
|
||||
}
|
||||
|
||||
static class RamSmallLong extends LongsTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.store = new AppendStore.SmallLongs((i) -> new AppendStoreRam.Ints(4 << 2));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,10 +3,8 @@ package com.onthegomap.flatmap.collection;
|
|||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
public abstract class LongLongMapTest {
|
||||
|
||||
|
@ -72,67 +70,24 @@ public abstract class LongLongMapTest {
|
|||
assertArrayEquals(expected, result);
|
||||
}
|
||||
|
||||
public static class SortedTableFileTest extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path dir) {
|
||||
this.map = LongLongMap.newFileBackedSortedTable(dir.resolve("test-node-db-sorted"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class SortedTableMemoryTest extends LongLongMapTest {
|
||||
public static class SortedTable extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.map = LongLongMap.newInMemorySortedTable();
|
||||
this.map = new LongLongMap.SortedTable(
|
||||
new AppendStore.SmallLongs(
|
||||
i -> new AppendStoreRam.Ints()
|
||||
),
|
||||
new AppendStoreRam.Longs()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SparseArrayTest extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path dir) {
|
||||
this.map = LongLongMap.newFileBackedSparseArray(dir.resolve("test-sparse-array"), 80, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SparseArrayMemoryTest extends LongLongMapTest {
|
||||
public static class SparseArray3 extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.map = LongLongMap.newInMemorySparseArray(80, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayTest extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.map = LongLongMap.newArrayBacked();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SqliteTest extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path dir) {
|
||||
this.map = LongLongMap.newSqlite(dir.resolve("sqlite-long-long-map-test"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpareArray2Memory extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.map = new LongLongMap.SparseArray2Memory();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SparseArray2 extends LongLongMapTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path dir) {
|
||||
this.map = new LongLongMap.SparseArray2(dir.resolve("temp-sparse-array-2"));
|
||||
this.map = new LongLongMap.SparseArray(new AppendStoreRam.Longs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class OsmReaderTest {
|
|||
};
|
||||
private final Stats stats = Stats.inMemory();
|
||||
private final Profile profile = new Profile.NullProfile();
|
||||
private final LongLongMap longLongMap = LongLongMap.newInMemoryHashMap();
|
||||
private final LongLongMap nodeMap = LongLongMap.newInMemorySortedTable();
|
||||
|
||||
private static Profile newProfile(
|
||||
Function<OsmElement.Relation, List<OsmReader.RelationInfo>> processRelation) {
|
||||
|
@ -645,7 +645,7 @@ public class OsmReaderTest {
|
|||
record TestRelInfo(long id, String name) implements OsmReader.RelationInfo {}
|
||||
OsmReader reader = new OsmReader(
|
||||
osmSource,
|
||||
longLongMap,
|
||||
nodeMap,
|
||||
new Profile.NullProfile() {
|
||||
@Override
|
||||
public List<OsmReader.RelationInfo> preprocessOsmRelation(OsmElement.Relation relation) {
|
||||
|
@ -678,7 +678,7 @@ public class OsmReaderTest {
|
|||
private OsmReader newOsmReader() {
|
||||
return new OsmReader(
|
||||
osmSource,
|
||||
longLongMap,
|
||||
nodeMap,
|
||||
profile,
|
||||
stats
|
||||
);
|
||||
|
|
|
@ -33,8 +33,8 @@ public class ToiletsOverlay implements Profile {
|
|||
|
||||
@Override
|
||||
public void processFeature(SourceFeature sourceFeature, FeatureCollector features) {
|
||||
if (sourceFeature.hasTag("amenity", "toilets")) {
|
||||
features.centroid("toilets")
|
||||
if (sourceFeature.isPoint() && sourceFeature.hasTag("amenity", "toilets")) {
|
||||
features.point("toilets")
|
||||
.setZoomRange(0, 14)
|
||||
// to limit toilets displayed at lower zoom levels:
|
||||
// 1) set a z-order that defines a priority ordering of toilets. For mountains you might use "elevation"
|
||||
|
|
|
@ -67,7 +67,7 @@ public class ToiletsProfileTest {
|
|||
assertContains("openstreetmap.org/copyright", metadata.get("attribution"));
|
||||
|
||||
TestUtils.assertNumFeatures(mbtiles, "toilets", 14, Map.of(), GeoUtils.WORLD_LAT_LON_BOUNDS,
|
||||
36, Point.class);
|
||||
34, Point.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ public class Generate {
|
|||
emitTableDefinitions(tables, packageName, output);
|
||||
}
|
||||
|
||||
private static String GENERATED_FILE_HEADER = """
|
||||
private static final String GENERATED_FILE_HEADER = """
|
||||
/*
|
||||
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors.
|
||||
All rights reserved.
|
||||
|
|
|
@ -576,8 +576,7 @@ public class OpenMapTilesSchema {
|
|||
public static final String CLASS = "class";
|
||||
/**
|
||||
* <p>The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the park
|
||||
* (point
|
||||
* features only).</p>
|
||||
* (point features only).</p>
|
||||
*/
|
||||
public static final String NAME = "name";
|
||||
/** <p>English name <code>name:en</code> if available, otherwise <code>name</code> (point features only).</p> */
|
||||
|
@ -664,8 +663,7 @@ public class OpenMapTilesSchema {
|
|||
public static final String DISPUTED_NAME = "disputed_name";
|
||||
/**
|
||||
* <p>ISO2 code of country, which wants to see the boundary line. For country boundaries only (<code>admin_level
|
||||
* =
|
||||
* 2</code>).</p>
|
||||
* = 2</code>).</p>
|
||||
*/
|
||||
public static final String CLAIMED_BY = "claimed_by";
|
||||
|
||||
|
@ -784,9 +782,8 @@ public class OpenMapTilesSchema {
|
|||
|
||||
/**
|
||||
* <p>Distinguish between more and less important roads or railways and roads under construction. Class is
|
||||
* derived
|
||||
* from the value of the <a href="http://wiki.openstreetmap.org/wiki/Key:highway"><code>highway</code></a>, <a
|
||||
* href="http://wiki.openstreetmap.org/wiki/Key:construction"><code>construction</code></a>, <a
|
||||
* derived from the value of the <a href="http://wiki.openstreetmap.org/wiki/Key:highway"><code>highway</code></a>,
|
||||
* <a href="http://wiki.openstreetmap.org/wiki/Key:construction"><code>construction</code></a>, <a
|
||||
* href="http://wiki.openstreetmap.org/wiki/Key:railway"><code>railway</code></a>, <a
|
||||
* href="http://wiki.openstreetmap.org/wiki/Key:aerialway"><code>aerialway</code></a>, <a
|
||||
* href="http://wiki.openstreetmap.org/wiki/Key:route"><code>route</code></a> tag (for shipping ways), or <a
|
||||
|
@ -1058,8 +1055,7 @@ public class OpenMapTilesSchema {
|
|||
|
||||
/**
|
||||
* <p>All <a href="http://wiki.openstreetmap.org/wiki/Buildings">OSM Buildings</a>. All building tags are imported
|
||||
* (<a
|
||||
* href="http://wiki.openstreetmap.org/wiki/Key:building"><code>building= </code></a>). The buildings are not yet
|
||||
* (<a href="http://wiki.openstreetmap.org/wiki/Key:building"><code>building= </code></a>). The buildings are not yet
|
||||
* ready for 3D rendering support and any help to improve this is welcomed.</p>
|
||||
*/
|
||||
public interface Building extends Layer {
|
||||
|
@ -1194,8 +1190,7 @@ public class OpenMapTilesSchema {
|
|||
public static final String NAME_DE = "name_de";
|
||||
/**
|
||||
* <p>The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:ref"><code>ref</code></a> tag of the motorway or
|
||||
* its
|
||||
* network.</p>
|
||||
* its network.</p>
|
||||
*/
|
||||
public static final String REF = "ref";
|
||||
/**
|
||||
|
@ -1440,9 +1435,8 @@ public class OpenMapTilesSchema {
|
|||
* city (derived from population and city class). You can use the <strong>rank</strong> to limit density of labels
|
||||
* or improve the text hierarchy. The rank value is a combination of the Natural Earth <code>scalerank</code>,
|
||||
* <code>labelrank</code> and <code>datarank</code> values for countries and states and for cities consists out
|
||||
* of
|
||||
* a shifted Natural Earth <code>scalerank</code> combined with a local rank within a grid for cities that do not
|
||||
* have a Natural Earth <code>scalerank</code>.</p>
|
||||
* of a shifted Natural Earth <code>scalerank</code> combined with a local rank within a grid for cities that do
|
||||
* not have a Natural Earth <code>scalerank</code>.</p>
|
||||
*/
|
||||
public static final String RANK = "rank";
|
||||
}
|
||||
|
@ -1472,9 +1466,8 @@ public class OpenMapTilesSchema {
|
|||
|
||||
/**
|
||||
* <p>Everything in OpenStreetMap which contains a <code>addr:housenumber</code> tag useful for labelling
|
||||
* housenumbers
|
||||
* on a map. This adds significant size to <em>z14</em>. For buildings the centroid of the building is used as
|
||||
* housenumber.</p>
|
||||
* housenumbers on a map. This adds significant size to <em>z14</em>. For buildings the centroid of the building is
|
||||
* used as housenumber.</p>
|
||||
*/
|
||||
public interface Housenumber extends Layer {
|
||||
|
||||
|
@ -1593,10 +1586,9 @@ public class OpenMapTilesSchema {
|
|||
public static final String SUBCLASS = "subclass";
|
||||
/**
|
||||
* <p>The POIs are ranked ascending according to their importance within a grid. The <code>rank</code> value
|
||||
* shows
|
||||
* the local relative importance of a POI within it's cell in the grid. This can be used to reduce label density
|
||||
* at <em>z14</em>. Since all POIs already need to be contained at <em>z14</em> you can use <code>less than
|
||||
* rank=10</code> epxression to limit POIs. At some point like <em>z17</em> you can show all POIs.</p>
|
||||
* shows the local relative importance of a POI within it's cell in the grid. This can be used to reduce label
|
||||
* density at <em>z14</em>. Since all POIs already need to be contained at <em>z14</em> you can use <code>less
|
||||
* than rank=10</code> epxression to limit POIs. At some point like <em>z17</em> you can show all POIs.</p>
|
||||
*/
|
||||
public static final String RANK = "rank";
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.jts.geom.Geometry;
|
||||
import org.locationtech.jts.geom.LineString;
|
||||
|
@ -313,7 +312,7 @@ public class Boundary implements
|
|||
return FeatureMerge.mergeLineStrings(items, 1, tolerance, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
private BorderingRegions getBorderingRegions(
|
||||
LongObjectMap<PreparedGeometry> countryBoundaries,
|
||||
Set<Long> allRegions,
|
||||
|
@ -368,7 +367,7 @@ public class Boundary implements
|
|||
return new BorderingRegions(leftCountry, rightCountry);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
private LongObjectMap<PreparedGeometry> prepareRegionPolygons() {
|
||||
LOGGER.info("Creating polygons for " + regionGeometries.size() + " boundaries");
|
||||
LongObjectMap<PreparedGeometry> countryBoundaries = new GHLongObjectHashMap<>();
|
||||
|
|
|
@ -68,8 +68,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.locationtech.jts.geom.Geometry;
|
||||
import org.locationtech.jts.geom.prep.PreparedGeometry;
|
||||
import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
|
||||
|
@ -108,7 +106,7 @@ public class TransportationName implements
|
|||
private final boolean z13Paths;
|
||||
private final Stats stats;
|
||||
private PreparedGeometry greatBritain = null;
|
||||
private AtomicBoolean loggedNoGb = new AtomicBoolean(false);
|
||||
private final AtomicBoolean loggedNoGb = new AtomicBoolean(false);
|
||||
|
||||
public TransportationName(Translations translations, Arguments args, Stats stats) {
|
||||
this.stats = stats;
|
||||
|
@ -250,7 +248,6 @@ public class TransportationName implements
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RouteRelation getRouteRelation(Tables.OsmHighwayLinestring element,
|
||||
List<OsmReader.RelationMember<RouteRelation>> relations, String ref) {
|
||||
RouteRelation relation = relations.stream()
|
||||
|
@ -330,7 +327,7 @@ public class TransportationName implements
|
|||
}
|
||||
|
||||
private static record RouteRelation(
|
||||
@NotNull String ref,
|
||||
String ref,
|
||||
RouteNetwork network,
|
||||
long id
|
||||
) implements OsmReader.RelationInfo {
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.StreamSupport;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractLayerTest {
|
||||
|
||||
|
@ -134,7 +133,7 @@ public abstract class AbstractLayerTest {
|
|||
return polygonFeatureWithArea(1, props);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
protected ReaderFeature lineFeatureWithRelation(List<OsmReader.RelationInfo> relationInfos,
|
||||
Map<String, Object> map) {
|
||||
return new ReaderFeature(
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.onthegomap.flatmap.reader.ReaderFeature;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LandcoverTest extends AbstractLayerTest {
|
||||
|
@ -181,7 +180,7 @@ public class LandcoverTest extends AbstractLayerTest {
|
|||
), 6);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
private VectorTileEncoder.Feature feature(org.locationtech.jts.geom.Polygon geom, Map<String, Object> m) {
|
||||
return new VectorTileEncoder.Feature(
|
||||
"landcover",
|
||||
|
|
Ładowanie…
Reference in New Issue