Skip to content

Commit 78bd2d3

Browse files
authored
Merge pull request #401 from maxmind/greg/docs-windows-memory-map-lock
Clarify Windows memory-map file locking and fix Javadoc issues
2 parents d889759 + bcd7d74 commit 78bd2d3

6 files changed

Lines changed: 93 additions & 70 deletions

File tree

README.md

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ this package directly.
4141

4242
To use the API, you must first create a `Reader` object. The constructor for
4343
the reader object takes a `File` representing your MaxMind DB. Optionally you
44-
may pass a second parameter with a `FileMode` with a value of `MEMORY_MAP` or
45-
`MEMORY`. The default mode is `MEMORY_MAP`, which maps the file to virtual
46-
memory. This often provides performance comparable to loading the file into
47-
real memory with `MEMORY`.
44+
may pass a second parameter with a `FileMode` with a value of `MEMORY_MAPPED`
45+
or `MEMORY`. The default mode is `MEMORY_MAPPED`, which maps the file to
46+
virtual memory. This often provides performance comparable to loading the file
47+
into real memory with `MEMORY`.
4848

4949
To look up an IP address, pass the address as an `InetAddress` to the `get`
5050
method on `Reader`, along with the class of the object you want to
@@ -251,16 +251,22 @@ threads.
251251

252252
### File Lock on Windows ###
253253

254-
By default, this API uses the `MEMORY_MAP` mode, which memory maps the file.
255-
On Windows, this may create an exclusive lock on the file that prevents it
256-
from being renamed or deleted. Due to the implementation of memory mapping in
257-
Java, this lock will not be released when the `DatabaseReader` is closed; it
258-
will only be released when the object and the `MappedByteBuffer` it uses are
259-
garbage collected. Older JVM versions may also not release the lock on exit.
260-
261-
To work around this problem, use the `MEMORY` mode or try upgrading your JVM
262-
version. You may also call `System.gc()` after dereferencing the
263-
`DatabaseReader` object to encourage the JVM to garbage collect sooner.
254+
By default, this API uses the `MEMORY_MAPPED` mode, which memory maps the file.
255+
On Windows, a live memory mapping may prevent the file from being renamed,
256+
replaced, or deleted. This is not a Java `FileLock`, but it can have similar
257+
effects when updating a database file in place.
258+
259+
Closing the `Reader` releases this library's reference to the mapped buffer,
260+
but Java does not provide a supported way to unmap the underlying
261+
`MappedByteBuffer` immediately. The mapping remains valid until the buffer
262+
becomes unreachable and is garbage collected. Any outstanding lookup or
263+
`Networks` iterator may also keep a duplicate buffer reachable.
264+
265+
To avoid this behavior, use the `MEMORY` mode. If you must use
266+
`MEMORY_MAPPED`, close and dereference the `Reader` and any iterators that were
267+
created from it before replacing the file. You may call `System.gc()` to
268+
encourage earlier cleanup, but garbage collection is not guaranteed to run
269+
immediately.
264270

265271
### Packaging Database in a JAR ###
266272

lychee.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# lychee './**/*.md' './src/**/*.java' './pom.xml'
66

77
# Include URL fragments in checks
8-
include_fragments = true
8+
include_fragments = "full"
99

1010
# Don't allow any redirects, so links that have moved are surfaced and updated
1111
# to their canonical destination.

mise.lock

Lines changed: 50 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/com/maxmind/db/CHMCache.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public CHMCache() {
2727
* Creates a new cache with the specified capacity.
2828
*
2929
* @param capacity
30-
* the maximum number of elements the cache can hold before
31-
* starting to evict them
30+
* the maximum number of elements the cache can hold before it
31+
* stops accepting new entries
3232
*/
3333
public CHMCache(int capacity) {
3434
this.capacity = capacity;

src/main/java/com/maxmind/db/Networks.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ public final class Networks<T> implements Iterator<DatabaseRecord<T>> {
4848
}
4949

5050
/**
51-
* Returns the next DataRecord.
51+
* Returns the next DatabaseRecord.
5252
*
53-
* @return The next DataRecord.
53+
* @return The next DatabaseRecord.
5454
* @throws NetworksIterationException An exception when iterating over the networks.
5555
*/
5656
@Override

src/main/java/com/maxmind/db/Reader.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ public enum FileMode {
3838
* The default file mode. This maps the database to virtual memory. This
3939
* often provides similar performance to loading the database into real
4040
* memory without the overhead.
41+
*
42+
* <p>On Windows, a live memory mapping may prevent the database file
43+
* from being renamed, replaced, or deleted until the mapped buffer is
44+
* garbage collected.
4145
*/
4246
MEMORY_MAPPED,
4347
/**
44-
* Loads the database into memory when the reader is constructed.
48+
* Loads the database into memory when the reader is constructed. This
49+
* avoids keeping a live memory mapping of the database file.
4550
*/
4651
MEMORY
4752
}
@@ -240,11 +245,11 @@ long record = traverseResult[0];
240245
* in an IPv6 database. networks() iterates over the canonical locations and
241246
* not the aliases. To include the aliases, you can set includeAliasedNetworks to true.
242247
*
243-
* @param <T> Represents the data type(e.g., Map, HastMap, etc.).
248+
* @param <T> Represents the data type(e.g., Map, HashMap, etc.).
244249
* @param typeParameterClass The type of data returned by the iterator.
245250
* @return Networks The Networks iterator.
246251
* @throws InvalidNetworkException Exception for using an IPv6 network in ipv4-only database.
247-
* @throws ClosedDatabaseException Exception for a closed databased.
252+
* @throws ClosedDatabaseException Exception for a closed database.
248253
* @throws InvalidDatabaseException Exception for an invalid database.
249254
*/
250255
public <T> Networks<T> networks(Class<T> typeParameterClass) throws
@@ -259,11 +264,11 @@ public <T> Networks<T> networks(Class<T> typeParameterClass) throws
259264
* separately. To set the iteration over the IPv4 networks once, use the
260265
* includeAliasedNetworks option.
261266
*
262-
* @param <T> Represents the data type(e.g., Map, HastMap, etc.).
267+
* @param <T> Represents the data type(e.g., Map, HashMap, etc.).
263268
* @param includeAliasedNetworks Enable including aliased networks.
264269
* @return Networks The Networks iterator.
265270
* @throws InvalidNetworkException Exception for using an IPv6 network in ipv4-only database.
266-
* @throws ClosedDatabaseException Exception for a closed databased.
271+
* @throws ClosedDatabaseException Exception for a closed database.
267272
* @throws InvalidDatabaseException Exception for an invalid database.
268273
*/
269274
public <T> Networks<T> networks(
@@ -326,13 +331,13 @@ private long findIpV4StartNode(Buffer buffer)
326331
* separately. To only iterate over the IPv4 networks once, use the
327332
* includeAliasedNetworks option.
328333
*
329-
* @param <T> Represents the data type(e.g., Map, HastMap, etc.).
334+
* @param <T> Represents the data type(e.g., Map, HashMap, etc.).
330335
* @param network Specifies the network to be iterated.
331336
* @param includeAliasedNetworks Boolean for including aliased networks.
332337
* @param typeParameterClass The type of data returned by the iterator.
333338
* @return Networks
334339
* @throws InvalidNetworkException Exception for using an IPv6 network in ipv4-only database.
335-
* @throws ClosedDatabaseException Exception for a closed databased.
340+
* @throws ClosedDatabaseException Exception for a closed database.
336341
* @throws InvalidDatabaseException Exception for an invalid database.
337342
*/
338343
public <T> Networks<T> networksWithin(
@@ -497,10 +502,12 @@ public Metadata getMetadata() {
497502
* </p>
498503
* <p>
499504
* If you are using <code>FileMode.MEMORY_MAPPED</code>, this will
500-
* <em>not</em> unmap the underlying file due to a limitation in Java's
501-
* <code>MappedByteBuffer</code>. It will however set the reference to
502-
* the buffer to <code>null</code>, allowing the garbage collector to
503-
* collect it.
505+
* release this reader's reference to the mapped buffer, allowing the
506+
* garbage collector to collect it when no other references remain. Java
507+
* does not provide a supported way to unmap a
508+
* <code>MappedByteBuffer</code> immediately. On Windows, this means the
509+
* database file may remain unavailable for rename, replacement, or
510+
* deletion until the mapped buffer is garbage collected.
504511
* </p>
505512
*
506513
* @throws IOException if an I/O error occurs.

0 commit comments

Comments
 (0)