@@ -54,13 +54,37 @@ var db = try maxminddb.Reader.mmap(allocator, db_path, .{ .ipv4_index_first_n_bi
5454defer db.close();
5555```
5656
57- Use ` ArenaAllocator ` for best performance, see [ benchmarks] ( ./benchmarks/ ) .
57+ Each ` lookup ` result owns an arena with all decoded allocations.
58+ Call ` deinit() ` to free it or use ` ArenaAllocator ` with ` reset() ` ,
59+ see [ benchmarks] ( ./benchmarks/lookup.zig ) .
60+
61+ ``` zig
62+ if (try db.lookup(maxminddb.geolite2.City, allocator, ip, .{})) |result| {
63+ defer result.deinit();
64+ std.debug.print("{f} {s}\n", .{ result.network, result.value.city.names.?.get("en").? });
65+ }
66+
67+ var arena = std.heap.ArenaAllocator.init(allocator);
68+ defer arena.deinit();
69+
70+ const arena_allocator = arena.allocator();
71+ for (ips) |ip| {
72+ if (try db.lookup(maxminddb.geolite2.City, arena_allocator, ip, .{})) |result| {
73+ std.debug.print("{f} {s}\n", .{ result.network, result.value.city.names.?.get("en").? });
74+ }
75+
76+ _ = arena.reset(.retain_capacity);
77+ }
78+ ```
5879
5980If you don't need all the fields, use ` .only ` to decode only the top-level fields you want.
6081
6182``` zig
6283const fields = &.{ "city", "country" };
63- const city = try db.lookup(allocator, maxminddb.geolite2.City, ip, .{ .only = fields });
84+ if (try db.lookup(maxminddb.geolite2.City, allocator, ip, .{ .only = fields })) |result| {
85+ defer result.deinit();
86+ std.debug.print("{f} {s}\n", .{ result.network, result.value.city.names.?.get("en").? });
87+ }
6488```
6589
6690Alternatively, define your own struct with only the fields you need.
@@ -74,36 +98,42 @@ const MyCity = struct {
7498 } = .{},
7599};
76100
77- const city = try db.lookup(allocator, MyCity, ip, .{});
101+ if (try db.lookup(MyCity, allocator, ip, .{})) |result| {
102+ defer result.deinit();
103+ std.debug.print("{s}\n", .{result.value.city.names.en});
104+ }
78105```
79106
80107Use ` any.Value ` to decode any record without knowing the schema.
81108
82109``` zig
83- const result = try db.lookup(allocator, maxminddb.any.Value, ip, .{ .only = fields });
84- if (result) |r| {
110+ if ( try db.lookup(maxminddb.any.Value, allocator, ip, .{ .only = fields })) |result| {
111+ defer result.deinit();
85112 // Formats as compact JSON.
86- std.debug.print("{f}\n", .{r .value});
113+ std.debug.print("{f}\n", .{result .value});
87114}
88115```
89116
90- Use a ` Cache ` to skip decoding when different IPs resolve to the same record.
117+ Use ` lookupWithCache ` to skip decoding when different IPs resolve to the same record.
118+ The cache owns decoded memory, so results don't need to be individually freed.
91119
92120``` zig
93- var cache: maxminddb.Cache(maxminddb.geolite2.City) = .{};
121+ var cache = try maxminddb.Cache(maxminddb.geolite2.City).init(allocator, .{}) ;
94122defer cache.deinit();
95123
96- const city = try db.lookup(allocator, maxminddb.geolite2.City, ip, .{ .cache = &cache });
124+ if (try db.lookupWithCache(maxminddb.geolite2.City, &cache, ip, .{})) |result| {
125+ std.debug.print("{f} {s}\n", .{ result.network, result.value.city.names.?.get("en").? });
126+ }
97127```
98128
99129Here are reference results on Apple M2 Pro (1M random IPv4 lookups against GeoLite2-City
100130with ` ipv4_index_first_n_bits = 16 ` ):
101131
102- | Type | Default | ` .only ` | ` Cache ` |
103- | --- | --- | --- | --- |
104- | ` geolite2.City ` | ~ 1,284 ,000 | ~ 1,348,000 | ~ 1,474 ,000 |
105- | ` MyCity ` | ~ 1,383,000 | | |
106- | ` any.Value ` | ~ 1,254,000 | ~ 1,349,000 | |
132+ | Type | Default | ` .only ` | ` Cache ` |
133+ | --- | --- | --- | --- |
134+ | ` geolite2.City ` | ~ 1,420 ,000 | ~ 1,348,000 | ~ 1,565 ,000 |
135+ | ` MyCity ` | ~ 1,383,000 | | |
136+ | ` any.Value ` | ~ 1,254,000 | ~ 1,349,000 | |
107137
108138<details >
109139
@@ -237,42 +267,45 @@ Lookups Per Second (avg):1315986.2950186788
237267
238268</details >
239269
240- Use ` within() ` to iterate over all networks in the database.
241- A ` Cache ` avoids re-decoding networks that share the same record.
270+ Use ` scan ` to iterate over all networks in the database.
242271
243272``` zig
244- var cache: maxminddb.Cache(maxminddb.any.Value) = .{};
273+ var it = try db.scan(maxminddb.any.Value, allocator, maxminddb.Network.all_ipv6, .{});
274+
275+ while (try it.next()) |item| {
276+ defer item.deinit();
277+ std.debug.print("{f} {f}\n", .{ item.network, item.value });
278+ }
279+ ```
280+
281+ Use ` scanWithCache ` to avoid re-decoding networks that share the same record.
282+ The cache owns decoded memory, so results don't need to be individually freed.
283+
284+ ``` zig
285+ var cache = try maxminddb.Cache(maxminddb.any.Value).init(allocator, .{});
245286defer cache.deinit();
246287
247- var it = try db.within(
248- allocator,
249- maxminddb.any.Value,
250- maxminddb.Network.all_ipv6,
251- .{ .cache = &cache },
252- );
253- defer it.deinit();
288+ var it = try db.scanWithCache(maxminddb.any.Value, &cache, maxminddb.Network.all_ipv6, .{});
254289
255290while (try it.next()) |item| {
256- std.debug.print("{f} {f}\n", .{item.network, item.value});
291+ std.debug.print("{f} {f}\n", .{ item.network, item.value });
257292}
258293```
259294
260- Without a cache each result owns its memory and must be freed with ` item.deinit() ` .
261-
262295Here are reference results on Apple M2 Pro (full GeoLite2-City scan using ` any.Value ` ):
263296
264- | Mode | Records/sec |
265- | --- | --- |
266- | Default | ~ 1,235 ,000 |
267- | ` Cache ` | ~ 2,900 ,000 |
297+ | Mode | Records/sec |
298+ | --- | --- |
299+ | Default | ~ 1,295 ,000 |
300+ | ` Cache ` | ~ 2,930 ,000 |
268301
269302<details >
270303
271304<summary >no cache (any.Value)</summary >
272305
273306``` sh
274307$ for i in $( seq 1 10) ; do
275- zig build benchmark_within -Doptimize=ReleaseFast -- GeoLite2-City.mmdb \
308+ zig build benchmark_scan -Doptimize=ReleaseFast -- GeoLite2-City.mmdb \
276309 2>&1 | grep ' Records Per Second'
277310 done
278311
@@ -296,7 +329,7 @@ Records Per Second: 1246311.587919839
296329
297330``` sh
298331$ for i in $( seq 1 10) ; do
299- zig build benchmark_within_cache -Doptimize=ReleaseFast -- GeoLite2-City.mmdb \
332+ zig build benchmark_scan_cache -Doptimize=ReleaseFast -- GeoLite2-City.mmdb \
300333 2>&1 | grep ' Records Per Second'
301334 done
302335
0 commit comments