geoip2_c 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +3 -4
- data/README.md +21 -3
- data/docker-compose.yml +15 -1
- data/dockerfiles/{Dockerfile-ruby2.1 → Dockerfile-ruby2.5} +1 -1
- data/dockerfiles/{Dockerfile-ruby2.2 → Dockerfile-ruby2.6} +1 -1
- data/ext/geoip2/geoip2.c +5 -3
- data/ext/geoip2/libmaxminddb/.gitignore +3 -0
- data/ext/geoip2/libmaxminddb/.travis.yml +24 -2
- data/ext/geoip2/libmaxminddb/Changes.md +39 -0
- data/ext/geoip2/libmaxminddb/README.dev.md +41 -30
- data/ext/geoip2/libmaxminddb/README.md +3 -3
- data/ext/geoip2/libmaxminddb/bin/Makefile.am +5 -0
- data/ext/geoip2/libmaxminddb/bin/mmdblookup.c +333 -15
- data/ext/geoip2/libmaxminddb/configure.ac +5 -5
- data/ext/geoip2/libmaxminddb/dev-bin/ppa-release.sh +8 -5
- data/ext/geoip2/libmaxminddb/dev-bin/release.sh +7 -0
- data/ext/geoip2/libmaxminddb/dev-bin/valgrind-all.pl +10 -3
- data/ext/geoip2/libmaxminddb/include/maxminddb.h +11 -2
- data/ext/geoip2/libmaxminddb/projects/VS12/libmaxminddb.vcxproj +3 -1
- data/ext/geoip2/libmaxminddb/projects/VS12/libmaxminddb.vcxproj.filters +7 -1
- data/ext/geoip2/libmaxminddb/src/Makefile.am +18 -2
- data/ext/geoip2/libmaxminddb/src/data-pool.c +180 -0
- data/ext/geoip2/libmaxminddb/src/data-pool.h +52 -0
- data/ext/geoip2/libmaxminddb/src/maxminddb.c +58 -48
- data/ext/geoip2/libmaxminddb/t/Makefile.am +6 -2
- data/ext/geoip2/libmaxminddb/t/bad_databases_t.c +1 -0
- data/ext/geoip2/libmaxminddb/t/basic_lookup_t.c +35 -0
- data/ext/geoip2/libmaxminddb/t/data-pool-t.c +374 -0
- data/ext/geoip2/libmaxminddb/t/external_symbols_t.pl +106 -0
- data/lib/geoip2/version.rb +1 -1
- metadata +9 -7
- data/dockerfiles/Dockerfile-ruby2.3 +0 -8
@@ -1,6 +1,7 @@
|
|
1
1
|
#if HAVE_CONFIG_H
|
2
2
|
#include <config.h>
|
3
3
|
#endif
|
4
|
+
#include "data-pool.h"
|
4
5
|
#include "maxminddb.h"
|
5
6
|
#include "maxminddb-compat-util.h"
|
6
7
|
#include <assert.h>
|
@@ -130,6 +131,9 @@ typedef struct record_info_s {
|
|
130
131
|
/* This is 128kb */
|
131
132
|
#define METADATA_BLOCK_MAX_SIZE 131072
|
132
133
|
|
134
|
+
// 64 leads us to allocating 4 KiB on a 64bit system.
|
135
|
+
#define MMDB_POOL_INIT_SIZE 64
|
136
|
+
|
133
137
|
/* *INDENT-OFF* */
|
134
138
|
/* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */
|
135
139
|
LOCAL int map_file(MMDB_s *const mmdb);
|
@@ -176,8 +180,10 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset,
|
|
176
180
|
LOCAL int get_ext_type(int raw_ext_type);
|
177
181
|
LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr,
|
178
182
|
int ptr_size);
|
179
|
-
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
183
|
+
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
184
|
+
uint32_t offset,
|
180
185
|
MMDB_entry_data_list_s *const entry_data_list,
|
186
|
+
MMDB_data_pool_s *const pool,
|
181
187
|
int depth);
|
182
188
|
LOCAL float get_ieee754_float(const uint8_t *restrict p);
|
183
189
|
LOCAL double get_ieee754_double(const uint8_t *restrict p);
|
@@ -186,7 +192,6 @@ LOCAL uint32_t get_uint24(const uint8_t *p);
|
|
186
192
|
LOCAL uint32_t get_uint16(const uint8_t *p);
|
187
193
|
LOCAL uint64_t get_uintX(const uint8_t *p, int length);
|
188
194
|
LOCAL int32_t get_sintX(const uint8_t *p, int length);
|
189
|
-
LOCAL MMDB_entry_data_list_s *new_entry_data_list(void);
|
190
195
|
LOCAL void free_mmdb_struct(MMDB_s *const mmdb);
|
191
196
|
LOCAL void free_languages_metadata(MMDB_s *mmdb);
|
192
197
|
LOCAL void free_descriptions_metadata(MMDB_s *mmdb);
|
@@ -241,7 +246,7 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
|
|
241
246
|
}
|
242
247
|
mmdb->flags = flags;
|
243
248
|
|
244
|
-
if (MMDB_SUCCESS != (status = map_file(mmdb))
|
249
|
+
if (MMDB_SUCCESS != (status = map_file(mmdb))) {
|
245
250
|
goto cleanup;
|
246
251
|
}
|
247
252
|
|
@@ -297,6 +302,15 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
|
|
297
302
|
mmdb->ipv4_start_node.node_value = 0;
|
298
303
|
mmdb->ipv4_start_node.netmask = 0;
|
299
304
|
|
305
|
+
// We do this immediately as otherwise there is a race to set
|
306
|
+
// ipv4_start_node.node_value and ipv4_start_node.netmask.
|
307
|
+
if (mmdb->metadata.ip_version == 6) {
|
308
|
+
status = find_ipv4_start_node(mmdb);
|
309
|
+
if (status != MMDB_SUCCESS) {
|
310
|
+
goto cleanup;
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
300
314
|
cleanup:
|
301
315
|
if (MMDB_SUCCESS != status) {
|
302
316
|
int saved_errno = errno;
|
@@ -361,7 +375,11 @@ LOCAL int map_file(MMDB_s *const mmdb)
|
|
361
375
|
ssize_t size;
|
362
376
|
int status = MMDB_SUCCESS;
|
363
377
|
|
364
|
-
int
|
378
|
+
int flags = O_RDONLY;
|
379
|
+
#ifdef O_CLOEXEC
|
380
|
+
flags |= O_CLOEXEC;
|
381
|
+
#endif
|
382
|
+
int fd = open(mmdb->filename, flags);
|
365
383
|
struct stat s;
|
366
384
|
if (fd < 0 || fstat(fd, &s)) {
|
367
385
|
status = MMDB_FILE_OPEN_ERROR;
|
@@ -1634,15 +1652,33 @@ int MMDB_get_metadata_as_entry_data_list(
|
|
1634
1652
|
int MMDB_get_entry_data_list(
|
1635
1653
|
MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list)
|
1636
1654
|
{
|
1637
|
-
*
|
1638
|
-
if (
|
1655
|
+
MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE);
|
1656
|
+
if (!pool) {
|
1657
|
+
return MMDB_OUT_OF_MEMORY_ERROR;
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
MMDB_entry_data_list_s *const list = data_pool_alloc(pool);
|
1661
|
+
if (!list) {
|
1662
|
+
data_pool_destroy(pool);
|
1663
|
+
return MMDB_OUT_OF_MEMORY_ERROR;
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
int const status = get_entry_data_list(start->mmdb, start->offset, list,
|
1667
|
+
pool, 0);
|
1668
|
+
|
1669
|
+
*entry_data_list = data_pool_to_list(pool);
|
1670
|
+
if (!*entry_data_list) {
|
1671
|
+
data_pool_destroy(pool);
|
1639
1672
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1640
1673
|
}
|
1641
|
-
|
1674
|
+
|
1675
|
+
return status;
|
1642
1676
|
}
|
1643
1677
|
|
1644
|
-
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
1678
|
+
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
1679
|
+
uint32_t offset,
|
1645
1680
|
MMDB_entry_data_list_s *const entry_data_list,
|
1681
|
+
MMDB_data_pool_s *const pool,
|
1646
1682
|
int depth)
|
1647
1683
|
{
|
1648
1684
|
if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) {
|
@@ -1672,7 +1708,7 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
|
|
1672
1708
|
|
1673
1709
|
int status =
|
1674
1710
|
get_entry_data_list(mmdb, last_offset, entry_data_list,
|
1675
|
-
depth);
|
1711
|
+
pool, depth);
|
1676
1712
|
if (MMDB_SUCCESS != status) {
|
1677
1713
|
DEBUG_MSG("get_entry_data_list on pointer failed.");
|
1678
1714
|
return status;
|
@@ -1685,26 +1721,22 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
|
|
1685
1721
|
{
|
1686
1722
|
uint32_t array_size = entry_data_list->entry_data.data_size;
|
1687
1723
|
uint32_t array_offset = entry_data_list->entry_data.offset_to_next;
|
1688
|
-
MMDB_entry_data_list_s *previous = entry_data_list;
|
1689
1724
|
while (array_size-- > 0) {
|
1690
|
-
MMDB_entry_data_list_s *entry_data_list_to =
|
1691
|
-
|
1692
|
-
if (
|
1725
|
+
MMDB_entry_data_list_s *entry_data_list_to =
|
1726
|
+
data_pool_alloc(pool);
|
1727
|
+
if (!entry_data_list_to) {
|
1693
1728
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1694
1729
|
}
|
1695
1730
|
|
1696
1731
|
int status =
|
1697
1732
|
get_entry_data_list(mmdb, array_offset, entry_data_list_to,
|
1698
|
-
depth);
|
1733
|
+
pool, depth);
|
1699
1734
|
if (MMDB_SUCCESS != status) {
|
1700
1735
|
DEBUG_MSG("get_entry_data_list on array element failed.");
|
1701
1736
|
return status;
|
1702
1737
|
}
|
1703
1738
|
|
1704
1739
|
array_offset = entry_data_list_to->entry_data.offset_to_next;
|
1705
|
-
while (previous->next) {
|
1706
|
-
previous = previous->next;
|
1707
|
-
}
|
1708
1740
|
}
|
1709
1741
|
entry_data_list->entry_data.offset_to_next = array_offset;
|
1710
1742
|
|
@@ -1715,45 +1747,33 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
|
|
1715
1747
|
uint32_t size = entry_data_list->entry_data.data_size;
|
1716
1748
|
|
1717
1749
|
offset = entry_data_list->entry_data.offset_to_next;
|
1718
|
-
MMDB_entry_data_list_s *previous = entry_data_list;
|
1719
1750
|
while (size-- > 0) {
|
1720
|
-
MMDB_entry_data_list_s *
|
1721
|
-
|
1722
|
-
if (NULL == entry_data_list_to) {
|
1751
|
+
MMDB_entry_data_list_s *list_key = data_pool_alloc(pool);
|
1752
|
+
if (!list_key) {
|
1723
1753
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1724
1754
|
}
|
1725
1755
|
|
1726
1756
|
int status =
|
1727
|
-
get_entry_data_list(mmdb, offset,
|
1728
|
-
depth);
|
1757
|
+
get_entry_data_list(mmdb, offset, list_key, pool, depth);
|
1729
1758
|
if (MMDB_SUCCESS != status) {
|
1730
1759
|
DEBUG_MSG("get_entry_data_list on map key failed.");
|
1731
1760
|
return status;
|
1732
1761
|
}
|
1733
1762
|
|
1734
|
-
|
1735
|
-
previous = previous->next;
|
1736
|
-
}
|
1737
|
-
|
1738
|
-
offset = entry_data_list_to->entry_data.offset_to_next;
|
1739
|
-
entry_data_list_to = previous->next =
|
1740
|
-
new_entry_data_list();
|
1763
|
+
offset = list_key->entry_data.offset_to_next;
|
1741
1764
|
|
1742
|
-
|
1765
|
+
MMDB_entry_data_list_s *list_value = data_pool_alloc(pool);
|
1766
|
+
if (!list_value) {
|
1743
1767
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1744
1768
|
}
|
1745
1769
|
|
1746
|
-
status = get_entry_data_list(mmdb, offset,
|
1770
|
+
status = get_entry_data_list(mmdb, offset, list_value, pool,
|
1747
1771
|
depth);
|
1748
1772
|
if (MMDB_SUCCESS != status) {
|
1749
1773
|
DEBUG_MSG("get_entry_data_list on map element failed.");
|
1750
1774
|
return status;
|
1751
1775
|
}
|
1752
|
-
|
1753
|
-
while (previous->next) {
|
1754
|
-
previous = previous->next;
|
1755
|
-
}
|
1756
|
-
offset = entry_data_list_to->entry_data.offset_to_next;
|
1776
|
+
offset = list_value->entry_data.offset_to_next;
|
1757
1777
|
}
|
1758
1778
|
entry_data_list->entry_data.offset_to_next = offset;
|
1759
1779
|
}
|
@@ -1832,22 +1852,12 @@ LOCAL int32_t get_sintX(const uint8_t *p, int length)
|
|
1832
1852
|
return (int32_t)get_uintX(p, length);
|
1833
1853
|
}
|
1834
1854
|
|
1835
|
-
LOCAL MMDB_entry_data_list_s *new_entry_data_list(void)
|
1836
|
-
{
|
1837
|
-
/* We need calloc here in order to ensure that the ->next pointer in the
|
1838
|
-
* struct doesn't point to some random address. */
|
1839
|
-
return calloc(1, sizeof(MMDB_entry_data_list_s));
|
1840
|
-
}
|
1841
|
-
|
1842
1855
|
void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list)
|
1843
1856
|
{
|
1844
1857
|
if (entry_data_list == NULL) {
|
1845
1858
|
return;
|
1846
1859
|
}
|
1847
|
-
|
1848
|
-
MMDB_free_entry_data_list(entry_data_list->next);
|
1849
|
-
}
|
1850
|
-
free(entry_data_list);
|
1860
|
+
data_pool_destroy(entry_data_list->pool);
|
1851
1861
|
}
|
1852
1862
|
|
1853
1863
|
void MMDB_close(MMDB_s *const mmdb)
|
@@ -12,12 +12,16 @@ libmmdbtest_la_SOURCES = maxminddb_test_helper.c
|
|
12
12
|
|
13
13
|
check_PROGRAMS = \
|
14
14
|
bad_pointers_t bad_databases_t basic_lookup_t data_entry_list_t \
|
15
|
-
data_types_t dump_t get_value_t get_value_pointer_bug_t \
|
15
|
+
data-pool-t data_types_t dump_t get_value_t get_value_pointer_bug_t \
|
16
16
|
ipv4_start_cache_t ipv6_lookup_in_ipv4_t metadata_t metadata_pointers_t \
|
17
17
|
no_map_get_value_t read_node_t threads_t version_t
|
18
18
|
|
19
|
+
data_pool_t_CFLAGS = $(CFLAGS) -I$(top_srcdir)/src
|
20
|
+
data_pool_t_LDFLAGS = $(AM_LDFLAGS) -lm
|
21
|
+
data_pool_t_SOURCES = data-pool-t.c ../src/data-pool.c
|
22
|
+
|
19
23
|
threads_t_CFLAGS = $(CFLAGS) -pthread
|
20
24
|
|
21
|
-
TESTS = $(check_PROGRAMS) compile_c++_t.pl mmdblookup_t.pl
|
25
|
+
TESTS = $(check_PROGRAMS) compile_c++_t.pl external_symbols_t.pl mmdblookup_t.pl
|
22
26
|
|
23
27
|
LDADD = libmmdbtest.la libtap/libtap.a
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#include "maxminddb_test_helper.h"
|
2
2
|
|
3
|
+
static void test_big_lookup(void);
|
4
|
+
|
3
5
|
/* These globals are gross but it's the easiest way to mix calling
|
4
6
|
* for_all_modes() and for_all_record_sizes() */
|
5
7
|
static int Current_Mode;
|
@@ -164,9 +166,42 @@ void all_record_sizes(int mode, const char *description)
|
|
164
166
|
}
|
165
167
|
}
|
166
168
|
|
169
|
+
static void test_big_lookup(void)
|
170
|
+
{
|
171
|
+
const char *const db_filename = "GeoIP2-Precision-Enterprise-Test.mmdb";
|
172
|
+
const char *const db_path = test_database_path(db_filename);
|
173
|
+
ok(db_path != NULL, "got database path");
|
174
|
+
|
175
|
+
MMDB_s * const mmdb = open_ok(db_path, MMDB_MODE_MMAP, "mmap mode");
|
176
|
+
ok(mmdb != NULL, "opened MMDB");
|
177
|
+
free((char *)db_path);
|
178
|
+
|
179
|
+
int gai_err = 0, mmdb_err = 0;
|
180
|
+
const char *const ip_address = "81.2.69.160";
|
181
|
+
MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ip_address, &gai_err,
|
182
|
+
&mmdb_err);
|
183
|
+
ok(gai_err == 0, "no getaddrinfo error");
|
184
|
+
ok(mmdb_err == MMDB_SUCCESS, "no error from maxminddb library");
|
185
|
+
ok(result.found_entry, "found IP");
|
186
|
+
|
187
|
+
MMDB_entry_data_list_s *entry_data_list = NULL;
|
188
|
+
ok(
|
189
|
+
MMDB_get_entry_data_list(&result.entry,
|
190
|
+
&entry_data_list) == MMDB_SUCCESS,
|
191
|
+
"successfully looked up entry data list"
|
192
|
+
);
|
193
|
+
ok(entry_data_list != NULL, "got an entry_data_list");
|
194
|
+
|
195
|
+
MMDB_free_entry_data_list(entry_data_list);
|
196
|
+
|
197
|
+
MMDB_close(mmdb);
|
198
|
+
free(mmdb);
|
199
|
+
}
|
200
|
+
|
167
201
|
int main(void)
|
168
202
|
{
|
169
203
|
plan(NO_PLAN);
|
170
204
|
for_all_modes(&all_record_sizes);
|
205
|
+
test_big_lookup();
|
171
206
|
done_testing();
|
172
207
|
}
|
@@ -0,0 +1,374 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <data-pool.h>
|
3
|
+
#include <inttypes.h>
|
4
|
+
#include "libtap/tap.h"
|
5
|
+
#include <math.h>
|
6
|
+
#include "maxminddb_test_helper.h"
|
7
|
+
|
8
|
+
static void test_data_pool_new(void);
|
9
|
+
static void test_data_pool_destroy(void);
|
10
|
+
static void test_data_pool_alloc(void);
|
11
|
+
static void test_data_pool_to_list(void);
|
12
|
+
static bool create_and_check_list(size_t const,
|
13
|
+
size_t const);
|
14
|
+
static void check_block_count(MMDB_entry_data_list_s const *const,
|
15
|
+
size_t const);
|
16
|
+
|
17
|
+
int main(void)
|
18
|
+
{
|
19
|
+
plan(NO_PLAN);
|
20
|
+
test_data_pool_new();
|
21
|
+
test_data_pool_destroy();
|
22
|
+
test_data_pool_alloc();
|
23
|
+
test_data_pool_to_list();
|
24
|
+
done_testing();
|
25
|
+
}
|
26
|
+
|
27
|
+
static void test_data_pool_new(void)
|
28
|
+
{
|
29
|
+
{
|
30
|
+
MMDB_data_pool_s *const pool = data_pool_new(0);
|
31
|
+
ok(!pool, "size 0 is not valid");
|
32
|
+
}
|
33
|
+
|
34
|
+
{
|
35
|
+
MMDB_data_pool_s *const pool = data_pool_new(SIZE_MAX - 10);
|
36
|
+
ok(!pool, "very large size is not valid");
|
37
|
+
}
|
38
|
+
|
39
|
+
{
|
40
|
+
MMDB_data_pool_s *const pool = data_pool_new(512);
|
41
|
+
ok(pool != NULL, "size 512 is valid");
|
42
|
+
cmp_ok(pool->size, "==", 512, "size is 512");
|
43
|
+
cmp_ok(pool->used, "==", 0, "used size is 0");
|
44
|
+
data_pool_destroy(pool);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
static void test_data_pool_destroy(void)
|
49
|
+
{
|
50
|
+
{
|
51
|
+
data_pool_destroy(NULL);
|
52
|
+
}
|
53
|
+
|
54
|
+
{
|
55
|
+
MMDB_data_pool_s *const pool = data_pool_new(512);
|
56
|
+
ok(pool != NULL, "created pool");
|
57
|
+
data_pool_destroy(pool);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
static void test_data_pool_alloc(void)
|
62
|
+
{
|
63
|
+
{
|
64
|
+
MMDB_data_pool_s *const pool = data_pool_new(1);
|
65
|
+
ok(pool != NULL, "created pool");
|
66
|
+
cmp_ok(pool->used, "==", 0, "used size starts at 0");
|
67
|
+
|
68
|
+
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
|
69
|
+
ok(entry1 != NULL, "allocated first entry");
|
70
|
+
// Arbitrary so that we can recognize it.
|
71
|
+
entry1->entry_data.offset = (uint32_t)123;
|
72
|
+
|
73
|
+
cmp_ok(pool->size, "==", 1, "size is still 1");
|
74
|
+
cmp_ok(pool->used, "==", 1, "used size is 1 after taking one");
|
75
|
+
|
76
|
+
MMDB_entry_data_list_s *const entry2 = data_pool_alloc(pool);
|
77
|
+
ok(entry2 != NULL, "got another entry");
|
78
|
+
ok(entry1 != entry2, "second entry is different from first entry");
|
79
|
+
|
80
|
+
cmp_ok(pool->size, "==", 2, "size is 2 (new block)");
|
81
|
+
cmp_ok(pool->used, "==", 1, "used size is 1 in current block");
|
82
|
+
|
83
|
+
ok(entry1->entry_data.offset == 123,
|
84
|
+
"accessing the original entry's memory is ok");
|
85
|
+
|
86
|
+
data_pool_destroy(pool);
|
87
|
+
}
|
88
|
+
|
89
|
+
{
|
90
|
+
size_t const initial_size = 10;
|
91
|
+
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
|
92
|
+
ok(pool != NULL, "created pool");
|
93
|
+
|
94
|
+
MMDB_entry_data_list_s *entry1 = NULL;
|
95
|
+
for (size_t i = 0; i < initial_size; i++) {
|
96
|
+
MMDB_entry_data_list_s *const entry = data_pool_alloc(pool);
|
97
|
+
ok(entry != NULL, "got an entry");
|
98
|
+
// Give each a unique number so we can check it.
|
99
|
+
entry->entry_data.offset = (uint32_t)i;
|
100
|
+
if (i == 0) {
|
101
|
+
entry1 = entry;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
cmp_ok(pool->size, "==", initial_size, "size is the initial size");
|
106
|
+
cmp_ok(pool->used, "==", initial_size, "used size is as expected");
|
107
|
+
|
108
|
+
MMDB_entry_data_list_s *const entry = data_pool_alloc(pool);
|
109
|
+
ok(entry != NULL, "got an entry");
|
110
|
+
entry->entry_data.offset = (uint32_t)initial_size;
|
111
|
+
|
112
|
+
cmp_ok(pool->size, "==", initial_size * 2,
|
113
|
+
"size is the initial size*2");
|
114
|
+
cmp_ok(pool->used, "==", 1, "used size is as expected");
|
115
|
+
|
116
|
+
MMDB_entry_data_list_s *const list = data_pool_to_list(pool);
|
117
|
+
|
118
|
+
MMDB_entry_data_list_s *element = list;
|
119
|
+
for (size_t i = 0; i < initial_size + 1; i++) {
|
120
|
+
ok(
|
121
|
+
element->entry_data.offset == (uint32_t)i,
|
122
|
+
"found offset %" PRIu32 ", should have %zu",
|
123
|
+
element->entry_data.offset,
|
124
|
+
i
|
125
|
+
);
|
126
|
+
element = element->next;
|
127
|
+
}
|
128
|
+
|
129
|
+
ok(entry1->entry_data.offset == (uint32_t)0,
|
130
|
+
"accessing entry1's original memory is ok after growing the pool");
|
131
|
+
|
132
|
+
data_pool_destroy(pool);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
static void test_data_pool_to_list(void)
|
137
|
+
{
|
138
|
+
{
|
139
|
+
size_t const initial_size = 16;
|
140
|
+
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
|
141
|
+
ok(pool != NULL, "created pool");
|
142
|
+
|
143
|
+
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
|
144
|
+
ok(entry1 != NULL, "got an entry");
|
145
|
+
|
146
|
+
MMDB_entry_data_list_s *const list_one_element
|
147
|
+
= data_pool_to_list(pool);
|
148
|
+
ok(list_one_element != NULL, "got a list");
|
149
|
+
ok(list_one_element == entry1,
|
150
|
+
"list's first element is the first we retrieved");
|
151
|
+
ok(list_one_element->next == NULL, "list is one element in size");
|
152
|
+
|
153
|
+
MMDB_entry_data_list_s *const entry2 = data_pool_alloc(pool);
|
154
|
+
ok(entry2 != NULL, "got another entry");
|
155
|
+
|
156
|
+
MMDB_entry_data_list_s *const list_two_elements
|
157
|
+
= data_pool_to_list(pool);
|
158
|
+
ok(list_two_elements != NULL, "got a list");
|
159
|
+
ok(list_two_elements == entry1,
|
160
|
+
"list's first element is the first we retrieved");
|
161
|
+
ok(list_two_elements->next != NULL, "list has a second element");
|
162
|
+
|
163
|
+
MMDB_entry_data_list_s *const second_element = list_two_elements->next;
|
164
|
+
ok(second_element == entry2,
|
165
|
+
"second item in list is second we retrieved");
|
166
|
+
ok(second_element->next == NULL, "list ends with the second element");
|
167
|
+
|
168
|
+
data_pool_destroy(pool);
|
169
|
+
}
|
170
|
+
|
171
|
+
{
|
172
|
+
size_t const initial_size = 1;
|
173
|
+
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
|
174
|
+
ok(pool != NULL, "created pool");
|
175
|
+
|
176
|
+
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
|
177
|
+
ok(entry1 != NULL, "got an entry");
|
178
|
+
|
179
|
+
MMDB_entry_data_list_s *const list_one_element
|
180
|
+
= data_pool_to_list(pool);
|
181
|
+
ok(list_one_element != NULL, "got a list");
|
182
|
+
ok(list_one_element == entry1,
|
183
|
+
"list's first element is the first we retrieved");
|
184
|
+
ok(list_one_element->next == NULL, "list ends with this element");
|
185
|
+
|
186
|
+
data_pool_destroy(pool);
|
187
|
+
}
|
188
|
+
|
189
|
+
{
|
190
|
+
size_t const initial_size = 2;
|
191
|
+
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
|
192
|
+
ok(pool != NULL, "created pool");
|
193
|
+
|
194
|
+
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
|
195
|
+
ok(entry1 != NULL, "got an entry");
|
196
|
+
|
197
|
+
MMDB_entry_data_list_s *const entry2 = data_pool_alloc(pool);
|
198
|
+
ok(entry2 != NULL, "got an entry");
|
199
|
+
ok(entry1 != entry2, "second entry is different from the first");
|
200
|
+
|
201
|
+
MMDB_entry_data_list_s *const list_element1 = data_pool_to_list(pool);
|
202
|
+
ok(list_element1 != NULL, "got a list");
|
203
|
+
ok(list_element1 == entry1,
|
204
|
+
"list's first element is the first we retrieved");
|
205
|
+
|
206
|
+
MMDB_entry_data_list_s *const list_element2 = list_element1->next;
|
207
|
+
ok(list_element2 == entry2,
|
208
|
+
"second element is the second we retrieved");
|
209
|
+
ok(list_element2->next == NULL, "list ends with this element");
|
210
|
+
|
211
|
+
data_pool_destroy(pool);
|
212
|
+
}
|
213
|
+
|
214
|
+
{
|
215
|
+
diag("starting test: fill one block save for one spot");
|
216
|
+
ok(
|
217
|
+
create_and_check_list(3, 2),
|
218
|
+
"fill one block save for one spot"
|
219
|
+
);
|
220
|
+
}
|
221
|
+
|
222
|
+
{
|
223
|
+
diag("starting test: fill one block");
|
224
|
+
ok(
|
225
|
+
create_and_check_list(3, 3),
|
226
|
+
"fill one block"
|
227
|
+
);
|
228
|
+
}
|
229
|
+
|
230
|
+
{
|
231
|
+
diag("starting test: fill one block and use one spot in the next block");
|
232
|
+
ok(
|
233
|
+
create_and_check_list(3, 3 + 1),
|
234
|
+
"fill one block and use one spot in the next block"
|
235
|
+
);
|
236
|
+
}
|
237
|
+
|
238
|
+
{
|
239
|
+
diag("starting test: fill two blocks save for one spot");
|
240
|
+
ok(
|
241
|
+
create_and_check_list(3, 3 + 3 * 2 - 1),
|
242
|
+
"fill two blocks save for one spot"
|
243
|
+
);
|
244
|
+
}
|
245
|
+
|
246
|
+
{
|
247
|
+
diag("starting test: fill two blocks");
|
248
|
+
ok(
|
249
|
+
create_and_check_list(3, 3 + 3 * 2),
|
250
|
+
"fill two blocks"
|
251
|
+
);
|
252
|
+
}
|
253
|
+
|
254
|
+
{
|
255
|
+
diag("starting test: fill two blocks and use one spot in the next");
|
256
|
+
ok(
|
257
|
+
create_and_check_list(3, 3 + 3 * 2 + 1),
|
258
|
+
"fill two blocks and use one spot in the next"
|
259
|
+
);
|
260
|
+
}
|
261
|
+
|
262
|
+
{
|
263
|
+
diag("starting test: fill three blocks save for one spot");
|
264
|
+
ok(
|
265
|
+
create_and_check_list(3, 3 + 3 * 2 + 3 * 2 * 2 - 1),
|
266
|
+
"fill three blocks save for one spot"
|
267
|
+
);
|
268
|
+
}
|
269
|
+
|
270
|
+
{
|
271
|
+
diag("starting test: fill three blocks");
|
272
|
+
ok(
|
273
|
+
create_and_check_list(3, 3 + 3 * 2 + 3 * 2 * 2),
|
274
|
+
"fill three blocks"
|
275
|
+
);
|
276
|
+
}
|
277
|
+
|
278
|
+
// It would be nice to have a larger number of these, but it's expensive to
|
279
|
+
// run many. We currently hardcode what this will be anyway, so varying
|
280
|
+
// this is not very interesting.
|
281
|
+
size_t const initial_sizes[] = { 1, 2, 32, 64, 128, 256 };
|
282
|
+
|
283
|
+
size_t const max_element_count = 4096;
|
284
|
+
|
285
|
+
for (size_t i = 0; i < sizeof(initial_sizes) / sizeof(initial_sizes[0]);
|
286
|
+
i++) {
|
287
|
+
size_t const initial_size = initial_sizes[i];
|
288
|
+
|
289
|
+
for (size_t element_count = 0; element_count < max_element_count;
|
290
|
+
element_count++) {
|
291
|
+
assert(create_and_check_list(initial_size, element_count));
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
// Use assert() rather than libtap as libtap is significantly slower and we run
|
297
|
+
// this frequently.
|
298
|
+
static bool create_and_check_list(size_t const initial_size,
|
299
|
+
size_t const element_count)
|
300
|
+
{
|
301
|
+
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
|
302
|
+
assert(pool != NULL);
|
303
|
+
|
304
|
+
assert(pool->used == 0);
|
305
|
+
|
306
|
+
// Hold on to the pointers as we initially see them so that we can check
|
307
|
+
// they are still valid after building the list.
|
308
|
+
MMDB_entry_data_list_s **const entry_array
|
309
|
+
= calloc(element_count, sizeof(MMDB_entry_data_list_s *));
|
310
|
+
assert(entry_array != NULL);
|
311
|
+
|
312
|
+
for (size_t i = 0; i < element_count; i++) {
|
313
|
+
MMDB_entry_data_list_s *const entry = data_pool_alloc(pool);
|
314
|
+
assert(entry != NULL);
|
315
|
+
|
316
|
+
entry->entry_data.offset = (uint32_t)i;
|
317
|
+
|
318
|
+
entry_array[i] = entry;
|
319
|
+
}
|
320
|
+
|
321
|
+
MMDB_entry_data_list_s *const list = data_pool_to_list(pool);
|
322
|
+
|
323
|
+
if (element_count == 0) {
|
324
|
+
assert(list == NULL);
|
325
|
+
data_pool_destroy(pool);
|
326
|
+
free(entry_array);
|
327
|
+
return true;
|
328
|
+
}
|
329
|
+
|
330
|
+
assert(list != NULL);
|
331
|
+
|
332
|
+
MMDB_entry_data_list_s *element = list;
|
333
|
+
for (size_t i = 0; i < element_count; i++) {
|
334
|
+
assert(element->entry_data.offset == (uint32_t)i);
|
335
|
+
|
336
|
+
assert(element == entry_array[i]);
|
337
|
+
|
338
|
+
element = element->next;
|
339
|
+
}
|
340
|
+
assert(element == NULL);
|
341
|
+
|
342
|
+
check_block_count(list, initial_size);
|
343
|
+
|
344
|
+
data_pool_destroy(pool);
|
345
|
+
free(entry_array);
|
346
|
+
return true;
|
347
|
+
}
|
348
|
+
|
349
|
+
// Use assert() rather than libtap as libtap is significantly slower and we run
|
350
|
+
// this frequently.
|
351
|
+
static void check_block_count(MMDB_entry_data_list_s const *const list,
|
352
|
+
size_t const initial_size)
|
353
|
+
{
|
354
|
+
size_t got_block_count = 0;
|
355
|
+
size_t got_element_count = 0;
|
356
|
+
|
357
|
+
MMDB_entry_data_list_s const *element = list;
|
358
|
+
while (element) {
|
359
|
+
got_element_count++;
|
360
|
+
|
361
|
+
if (element->pool) {
|
362
|
+
got_block_count++;
|
363
|
+
}
|
364
|
+
|
365
|
+
element = element->next;
|
366
|
+
}
|
367
|
+
|
368
|
+
// Because <number of elements> = <initial size> * 2^(number of blocks)
|
369
|
+
double const a = ceil((double)got_element_count / (double)initial_size);
|
370
|
+
double const b = log2(a);
|
371
|
+
size_t const expected_block_count = ((size_t)b) + 1;
|
372
|
+
|
373
|
+
assert(got_block_count == expected_block_count);
|
374
|
+
}
|