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
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 0.9.1 (2026-02-18)
--------------------------
Avoid off-heap memory growth from JDK direct buffer caching (#186)

Version 0.9.0 (2026-02-06)
--------------------------
Extract ASN fields from ISP database (#183)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ can also configure an LRU (Least Recently Used) cache of variable size

## Installation

The latest version of scala-maxmind-iplookups is **0.9.0** and is compatible with Scala 2.13.
The latest version of scala-maxmind-iplookups is **0.9.1** and is compatible with Scala 2.13.

Add this to your SBT config:

```scala
val maxmindIpLookups = "com.snowplowanalytics" %% "scala-maxmind-iplookups" % "0.9.0"
val maxmindIpLookups = "com.snowplowanalytics" %% "scala-maxmind-iplookups" % "0.9.1"
```

Retrieve the `GeoLite2-City.mmdb` file from the [MaxMind downloads page][maxmind-downloads]
Expand Down Expand Up @@ -295,7 +295,7 @@ As such we recommend upgrading to version 0.4.0 as soon as possible

## Copyright and license

Copyright 2012-2022 Snowplow Analytics Ltd.
Copyright 2012-2026 Snowplow Analytics Ltd.

Licensed under the [Apache License, Version 2.0][license] (the "License");
you may not use this software except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
package com.snowplowanalytics.maxmind.iplookups

import java.io.File
import java.io.{File, FileInputStream}
import java.net.InetAddress

import cats.{Eval, Id, Monad}
Expand All @@ -21,7 +21,6 @@ import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.syntax.option._
import com.maxmind.db.CHMCache
import com.maxmind.db.Reader.FileMode
import com.maxmind.geoip2.DatabaseReader
import com.snowplowanalytics.lrumap.{CreateLruMap, LruMap}

Expand Down Expand Up @@ -226,18 +225,25 @@ class IpLookups[F[_]: Monad] private[iplookups] (
/**
* Get a LookupService from a database file
*
* Note: In MEMORY mode, .build() performs blocking I/O by reading the entire database from disk into memory.
* Opens the file as a FileInputStream and passes it to DatabaseReader's InputStream-based
* constructor. This avoids the File-based constructor which uses FileChannel.read into a heap
* ByteBuffer, causing the JDK to allocate and cache temporary direct ByteBuffers in
* thread-local storage (sun.nio.ch.Util.BufferCache), leading to off-heap memory growth.
*
* @param serviceFile The database file
* @return LookupService
*/
private def getService(serviceFile: Option[File]): Option[DatabaseReader] =
serviceFile.map { f =>
val builder = new DatabaseReader.Builder(f).fileMode(FileMode.MEMORY)
(
if (memCache) builder.withCache(new CHMCache())
else builder
).build()
val stream = new FileInputStream(f)
try {
val builder = new DatabaseReader.Builder(stream)
(
if (memCache) builder.withCache(new CHMCache())
else builder
).build()
} finally
stream.close()
}

/**
Expand Down
Loading