use custom container (#305)

This commit is contained in:
zerninv 2024-01-11 20:53:51 +00:00 committed by GitHub
parent 5c23f6f224
commit 0e420f99e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -24,7 +24,6 @@ import java.util.*;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.stream.Collectors;
public class CalculateAverage_zerninv { public class CalculateAverage_zerninv {
private static final String FILE = "./measurements.txt"; private static final String FILE = "./measurements.txt";
@ -91,9 +90,9 @@ public class CalculateAverage_zerninv {
} }
private static Map<String, MeasurementAggregation> calcForChunk(FileChannel channel, long begin, long end) throws IOException { private static Map<String, MeasurementAggregation> calcForChunk(FileChannel channel, long begin, long end) throws IOException {
var results = new HashMap<CityWrapper, MeasurementAggregation>(10_000);
var mbb = channel.map(FileChannel.MapMode.READ_ONLY, begin, end - begin); var mbb = channel.map(FileChannel.MapMode.READ_ONLY, begin, end - begin);
int cityOffset, hashCode, temperatureOffset, temperature; var results = new MeasurementContainer(mbb);
int cityOffset, cityNameSize, hashCode, temperatureOffset, temperature;
byte b; byte b;
while (mbb.hasRemaining()) { while (mbb.hasRemaining()) {
@ -104,7 +103,7 @@ public class CalculateAverage_zerninv {
} }
temperatureOffset = mbb.position(); temperatureOffset = mbb.position();
CityWrapper city = new CityWrapper(mbb, cityOffset, temperatureOffset - cityOffset - 1, hashCode); cityNameSize = temperatureOffset - cityOffset - 1;
temperature = 0; temperature = 0;
while ((b = mbb.get()) != LINE_SEPARATOR) { while ((b = mbb.get()) != LINE_SEPARATOR) {
@ -115,32 +114,22 @@ public class CalculateAverage_zerninv {
if (mbb.get(temperatureOffset) == MINUS) { if (mbb.get(temperatureOffset) == MINUS) {
temperature *= -1; temperature *= -1;
} }
results.put(cityOffset, cityNameSize, hashCode, (short) temperature);
var result = results.get(city);
if (result != null) {
result.addTemperature(temperature);
} }
else { return results.toStringMap();
results.put(city, new MeasurementAggregation().addTemperature(temperature));
}
}
return results.entrySet()
.stream()
.collect(Collectors.toMap(entry -> entry.getKey().toString(), Map.Entry::getValue));
} }
private static final class MeasurementAggregation { private static final class MeasurementAggregation {
private long sum; private long sum;
private int count; private int count;
private int min = Integer.MAX_VALUE; private short min;
private int max = Integer.MIN_VALUE; private short max;
public MeasurementAggregation addTemperature(int temperature) { public MeasurementAggregation(long sum, int count, short min, short max) {
sum += temperature; this.sum = sum;
count++; this.count = count;
min = Math.min(temperature, min); this.min = min;
max = Math.max(temperature, max); this.max = max;
return this;
} }
public void merge(MeasurementAggregation o) { public void merge(MeasurementAggregation o) {
@ -149,8 +138,8 @@ public class CalculateAverage_zerninv {
} }
sum += o.sum; sum += o.sum;
count += o.count; count += o.count;
min = Math.min(min, o.min); min = min < o.min ? min : o.min;
max = Math.max(max, o.max); max = max > o.max ? max : o.max;
} }
@Override @Override
@ -159,39 +148,77 @@ public class CalculateAverage_zerninv {
} }
} }
private record CityWrapper(MappedByteBuffer mbb, int begin, int size, int hash) { private static final class MeasurementContainer {
private static final int SIZE = 1024 * 16;
@Override private final MappedByteBuffer mbb;
public boolean equals(Object o) { private final int[] offsets = new int[SIZE];
if (this == o) { private final int[] sizes = new int[SIZE];
return true; private final int[] hashes = new int[SIZE];
}
if (o == null || getClass() != o.getClass()) { private final long[] sums = new long[SIZE];
return false; private final int[] counts = new int[SIZE];
private final short[] mins = new short[SIZE];
private final short[] maxs = new short[SIZE];
private MeasurementContainer(MappedByteBuffer mbb) {
this.mbb = mbb;
Arrays.fill(mins, Short.MAX_VALUE);
Arrays.fill(maxs, Short.MIN_VALUE);
} }
CityWrapper that = (CityWrapper) o; public void put(int offset, int size, int hash, short value) {
if (hash != that.hash || size != that.size) { int i = findIdx(offset, size, hash);
return false; offsets[i] = offset;
sizes[i] = size;
hashes[i] = hash;
sums[i] += value;
counts[i]++;
if (value < mins[i]) {
mins[i] = value;
} }
for (int i = 0; i < size; i++) { if (value > maxs[i]) {
if (mbb.get(begin + i) != mbb.get(that.begin + i)) { maxs[i] = value;
}
}
public Map<String, MeasurementAggregation> toStringMap() {
var result = new HashMap<String, MeasurementAggregation>();
for (int i = 0; i < SIZE; i++) {
if (counts[i] != 0) {
var key = createString(offsets[i], sizes[i]);
result.put(key, new MeasurementAggregation(sums[i], counts[i], mins[i], maxs[i]));
}
}
return result;
}
private int findIdx(int offset, int size, int hash) {
int i = Math.abs(hash % SIZE);
while (counts[i] != 0) {
if (hashes[i] == hash && sizes[i] == size && isEqual(i, offset)) {
break;
}
i = (i + 1) % SIZE;
}
return i;
}
private boolean isEqual(int index, int offset) {
for (int i = 0; i < sizes[index]; i++) {
if (mbb.get(offsets[index] + i) != mbb.get(offset + i)) {
return false; return false;
} }
} }
return true; return true;
} }
@Override private String createString(int offset, int size) {
public int hashCode() {
return hash;
}
@Override
public String toString() {
byte[] arr = new byte[size]; byte[] arr = new byte[size];
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
arr[i] = mbb.get(begin + i); arr[i] = mbb.get(offset + i);
} }
return new String(arr); return new String(arr);
} }