geoip2_c 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|