Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ CHANGELOG
2GB ByteBuffer limit. Files under 2GB continue to use a single ByteBuffer
for optimal performance. Requested by nonetallt. GitHub #154. Fixed by
Silvano Cerza. GitHub #289.
* `DatabaseRecord`, `Metadata`, `Network`, and internal `DecodedValue` classes
have been converted to records. The following API changes were made:
* `DatabaseRecord.getData()` and `DatabaseRecord.getNetwork()` have been
replaced with record accessor methods `data()` and `network()`.
* `Metadata.getBuildDate()` has been renamed to `buildDate()` to follow record
naming conventions. All other simple getter methods on `Metadata` (e.g.,
`getBinaryFormatMajorVersion()`, `getDatabaseType()`, etc.) have been
replaced with their corresponding record accessor methods (e.g.,
`binaryFormatMajorVersion()`, `databaseType()`, etc.).
* `Network.getNetworkAddress()` and `Network.getPrefixLength()` have been
replaced with record accessor methods `networkAddress()` and `prefixLength()`.

3.2.0 (2025-05-28)
------------------
Expand Down
32 changes: 8 additions & 24 deletions src/main/java/com/maxmind/db/DatabaseRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
* lookup.
*
* @param <T> the type to deserialize the returned value to
* @param data the data for the record in the database. The record will be
* {@code null} if there was no data for the address in the
* database.
* @param network the network associated with the record in the database. This is
* the largest network where all of the IPs in the network have the same
* data.
*/
public final class DatabaseRecord<T> {
private final T data;
private final Network network;

public record DatabaseRecord<T>(T data, Network network) {
/**
* Create a new record.
*
Expand All @@ -20,25 +23,6 @@ public final class DatabaseRecord<T> {
* @param prefixLength the network prefix length associated with the record in the database.
*/
public DatabaseRecord(T data, InetAddress ipAddress, int prefixLength) {
this.data = data;
this.network = new Network(ipAddress, prefixLength);
}

/**
* @return the data for the record in the database. The record will be
* <code>null</code> if there was no data for the address in the
* database.
*/
public T getData() {
return data;
}

/**
* @return the network associated with the record in the database. This is
* the largest network where all of the IPs in the network have the same
* data.
*/
public Network getNetwork() {
return network;
this(data, new Network(ipAddress, prefixLength));
}
}
14 changes: 3 additions & 11 deletions src/main/java/com/maxmind/db/DecodedValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,7 @@
/**
* {@code DecodedValue} is a wrapper for the decoded value and the number of bytes used
* to decode it.
*
* @param value the decoded value
*/
public final class DecodedValue {
final Object value;

DecodedValue(Object value) {
this.value = value;
}

Object getValue() {
return value;
}
}
record DecodedValue(Object value) {}
12 changes: 6 additions & 6 deletions src/main/java/com/maxmind/db/Decoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ <T> T decode(long offset, Class<T> cls) throws IOException {
}

this.buffer.position(offset);
return cls.cast(decode(cls, null).getValue());
return cls.cast(decode(cls, null).value());
}

private <T> DecodedValue decode(CacheKey<T> key) throws IOException {
Expand Down Expand Up @@ -300,7 +300,7 @@ private <T, V> List<V> decodeArray(
}

for (int i = 0; i < size; i++) {
Object e = this.decode(elementClass, null).getValue();
Object e = this.decode(elementClass, null).value();
array.add(elementClass.cast(e));
}

Expand Down Expand Up @@ -360,8 +360,8 @@ private <T, V> Map<String, V> decodeMapIntoMap(
}

for (int i = 0; i < size; i++) {
String key = (String) this.decode(String.class, null).getValue();
Object value = this.decode(valueClass, null).getValue();
String key = (String) this.decode(String.class, null).value();
Object value = this.decode(valueClass, null).value();
try {
map.put(key, valueClass.cast(value));
} catch (ClassCastException e) {
Expand Down Expand Up @@ -412,7 +412,7 @@ private <T> Object decodeMapIntoObject(int size, Class<T> cls)

Object[] parameters = new Object[parameterTypes.length];
for (int i = 0; i < size; i++) {
String key = (String) this.decode(String.class, null).getValue();
String key = (String) this.decode(String.class, null).value();

Integer parameterIndex = parameterIndexes.get(key);
if (parameterIndex == null) {
Expand All @@ -424,7 +424,7 @@ private <T> Object decodeMapIntoObject(int size, Class<T> cls)
parameters[parameterIndex] = this.decode(
parameterTypes[parameterIndex],
parameterGenericTypes[parameterIndex]
).getValue();
).value();
}

try {
Expand Down
187 changes: 39 additions & 148 deletions src/main/java/com/maxmind/db/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,171 +7,62 @@

/**
* {@code Metadata} holds data associated with the database itself.
*
* @param binaryFormatMajorVersion The major version number for the database's
* binary format.
* @param binaryFormatMinorVersion The minor version number for the database's
* binary format.
* @param buildEpoch The date of the database build.
* @param databaseType A string that indicates the structure of each
* data record associated with an IP address.
* The actual definition of these structures is
* left up to the database creator.
* @param languages List of languages supported by the database.
* @param description Map from language code to description in that
* language.
* @param ipVersion Whether the database contains IPv4 or IPv6
* address data. The only possible values are 4
* and 6.
* @param nodeCount The number of nodes in the search tree.
* @param recordSize The number of bits in a record in the search
* tree. Note that each node consists of two
* records.
*/
public final class Metadata {
private final int binaryFormatMajorVersion;
private final int binaryFormatMinorVersion;

private final BigInteger buildEpoch;

private final String databaseType;

private final Map<String, String> description;

private final int ipVersion;

private final List<String> languages;

private final int nodeByteSize;

private final long nodeCount;

private final int recordSize;

private final long searchTreeSize;

public record Metadata(
@MaxMindDbParameter(name = "binary_format_major_version") int binaryFormatMajorVersion,
@MaxMindDbParameter(name = "binary_format_minor_version") int binaryFormatMinorVersion,
@MaxMindDbParameter(name = "build_epoch") BigInteger buildEpoch,
@MaxMindDbParameter(name = "database_type") String databaseType,
@MaxMindDbParameter(name = "languages") List<String> languages,
@MaxMindDbParameter(name = "description") Map<String, String> description,
@MaxMindDbParameter(name = "ip_version") int ipVersion,
@MaxMindDbParameter(name = "node_count") long nodeCount,
@MaxMindDbParameter(name = "record_size") int recordSize
) {
/**
* Constructs a {@code Metadata} object.
*
* @param binaryFormatMajorVersion The major version number for the database's
* binary format.
* @param binaryFormatMinorVersion The minor version number for the database's
* binary format.
* @param buildEpoch The date of the database build.
* @param databaseType A string that indicates the structure of each
* data record associated with an IP address.
* The actual definition of these structures is
* left up to the database creator.
* @param languages List of languages supported by the database.
* @param description Map from language code to description in that
* language.
* @param ipVersion Whether the database contains IPv4 or IPv6
* address data. The only possible values are 4
* and 6.
* @param nodeCount The number of nodes in the search tree.
* @param recordSize The number of bits in a record in the search
* tree. Note that each node consists of two
* records.
* Compact constructor for the Metadata record.
*/
@MaxMindDbConstructor
public Metadata(
@MaxMindDbParameter(name = "binary_format_major_version") int binaryFormatMajorVersion,
@MaxMindDbParameter(name = "binary_format_minor_version") int binaryFormatMinorVersion,
@MaxMindDbParameter(name = "build_epoch") BigInteger buildEpoch,
@MaxMindDbParameter(name = "database_type") String databaseType,
@MaxMindDbParameter(name = "languages") List<String> languages,
@MaxMindDbParameter(name = "description") Map<String, String> description,
@MaxMindDbParameter(name = "ip_version") int ipVersion,
@MaxMindDbParameter(name = "node_count") long nodeCount,
@MaxMindDbParameter(name = "record_size") int recordSize) {
this.binaryFormatMajorVersion = binaryFormatMajorVersion;
this.binaryFormatMinorVersion = binaryFormatMinorVersion;
this.buildEpoch = buildEpoch;
this.databaseType = databaseType;
this.languages = languages;
this.description = description;
this.ipVersion = ipVersion;
this.nodeCount = nodeCount;
this.recordSize = recordSize;

this.nodeByteSize = this.recordSize / 4;
this.searchTreeSize = this.nodeCount * this.nodeByteSize;
}

/**
* @return the major version number for the database's binary format.
*/
public int getBinaryFormatMajorVersion() {
return this.binaryFormatMajorVersion;
}

/**
* @return the minor version number for the database's binary format.
*/
public int getBinaryFormatMinorVersion() {
return this.binaryFormatMinorVersion;
}
public Metadata {}

/**
* @return the date of the database build.
*/
public Date getBuildDate() {
return new Date(this.buildEpoch.longValue() * 1000);
}

/**
* @return a string that indicates the structure of each data record
* associated with an IP address. The actual definition of these
* structures is left up to the database creator.
*/
public String getDatabaseType() {
return this.databaseType;
}

/**
* @return map from language code to description in that language.
*/
public Map<String, String> getDescription() {
return this.description;
}

/**
* @return whether the database contains IPv4 or IPv6 address data. The only
* possible values are 4 and 6.
*/
public int getIpVersion() {
return this.ipVersion;
}

/**
* @return list of languages supported by the database.
*/
public List<String> getLanguages() {
return this.languages;
public Date buildDate() {
return new Date(buildEpoch.longValue() * 1000);
}

/**
* @return the nodeByteSize
*/
int getNodeByteSize() {
return this.nodeByteSize;
}

/**
* @return the number of nodes in the search tree.
*/
long getNodeCount() {
return this.nodeCount;
}

/**
* @return the number of bits in a record in the search tree. Note that each
* node consists of two records.
*/
int getRecordSize() {
return this.recordSize;
int nodeByteSize() {
return recordSize / 4;
}

/**
* @return the searchTreeSize
*/
long getSearchTreeSize() {
return this.searchTreeSize;
}

/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Metadata [binaryFormatMajorVersion="
+ this.binaryFormatMajorVersion + ", binaryFormatMinorVersion="
+ this.binaryFormatMinorVersion + ", buildEpoch="
+ this.buildEpoch + ", databaseType=" + this.databaseType
+ ", description=" + this.description + ", ipVersion="
+ this.ipVersion + ", nodeCount=" + this.nodeCount
+ ", recordSize=" + this.recordSize + "]";
long searchTreeSize() {
return nodeCount * nodeByteSize();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was calculated once before and just returned, whereas now we run this (and the above one) every time, right? Is that okay? I think there's a Network method in the same position.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Network method was an intentional compromise. The previous lazy loading had race conditions and it didn't seem that beneficial. This one would probably make sense to calculate only once though.

}
}
Loading