File Coverage

blib/lib/MaxMind/DB/Writer/Tree.pm
Criterion Covered Total %
statement 142 146 97.2
branch 37 46 80.4
condition 10 13 76.9
subroutine 31 31 100.0
pod 7 9 77.7
total 227 245 92.6


line stmt bran cond sub pod time code
1             package MaxMind::DB::Writer::Tree;
2              
3 18     18   5400042 use strict;
  18         40  
  18         814  
4 18     18   102 use warnings;
  18         36  
  18         1160  
5 18     18   6734 use namespace::autoclean;
  18         282778  
  18         118  
6 18     18   7821 use autodie;
  18         209483  
  18         139  
7              
8             our $VERSION = '0.300004';
9              
10 18     18   135857 use IO::Handle;
  18         78007  
  18         1386  
11 18     18   11937 use Math::Int64 0.51;
  18         66578  
  18         163  
12 18     18   12640 use Math::Int128 0.21 qw( uint128 );
  18         53448  
  18         2718  
13 18         1264 use MaxMind::DB::Common 0.031003 qw(
14             DATA_SECTION_SEPARATOR
15             METADATA_MARKER
16 18     18   6921 );
  18         6452  
17 18     18   7094 use MaxMind::DB::Metadata;
  18         1162283  
  18         903  
18 18     18   11766 use MaxMind::DB::Writer::Serializer;
  18         423  
  18         1483  
19 18     18   207 use MaxMind::DB::Writer::Util qw( key_for_data );
  18         44  
  18         1908  
20 18     18   12771 use MooseX::Params::Validate qw( validated_list );
  18         1593504  
  18         190  
21 18     18   5967 use Sereal::Decoder qw( decode_sereal );
  18         47  
  18         1735  
22 18     18   156 use Sereal::Encoder qw( encode_sereal );
  18         3086  
  18         1044  
23              
24 18     18   122 use Moose;
  18         40  
  18         169  
25 18     18   163203 use Moose::Util::TypeConstraints;
  18         48  
  18         152  
26 18     18   49778 use MooseX::StrictConstructor;
  18         49  
  18         186  
27              
28 18     18   128143 use XSLoader;
  18         64  
  18         58826  
29              
30             ## no critic (ProhibitCallsToUnexportedSubs)
31             XSLoader::load( __PACKAGE__, $VERSION );
32             ## use critic
33              
34             warnings::warnif(
35             'deprecated',
36             'MaxMind::DB::Writer::Tree is deprecated and should no longer be used',
37             );
38              
39             has ip_version => (
40             is => 'ro',
41             isa => 'Int',
42             required => 1,
43             );
44              
45             #<<<
46             my $RecordSizeType = subtype
47             as 'Int',
48             where { ( $_ % 4 == 0 ) && $_ >= 24 && $_ <= 128 },
49             message {
50             'The record size must be a number from 24-128 that is divisible by 4';
51             };
52             #>>>
53              
54             has record_size => (
55             is => 'ro',
56             isa => $RecordSizeType,
57             required => 1,
58             );
59              
60             my $MergeStrategyEnum
61             = enum( [qw( add-only-if-parent-exists none recurse toplevel )] );
62              
63             has merge_strategy => (
64             is => 'ro',
65             isa => $MergeStrategyEnum,
66             lazy => 1,
67             default => 'none',
68             );
69              
70             has remove_reserved_networks => (
71             is => 'ro',
72             isa => 'Bool',
73             default => 1,
74             );
75              
76             has _tree => (
77             is => 'ro',
78             lazy => 1,
79             builder => '_build_tree',
80             predicate => '_has_tree',
81             );
82              
83             # All records in the tree will point to a value of this type in the data
84             # section.
85             has _root_data_type => (
86             is => 'ro',
87             isa => 'Str', # XXX - should make sure it's valid type
88             init_arg => 'root_data_type',
89             default => 'map',
90             );
91              
92             has map_key_type_callback => (
93             is => 'ro',
94             isa => 'CodeRef',
95             required => 1,
96             );
97              
98             has database_type => (
99             is => 'ro',
100             isa => 'Str',
101             required => 1,
102             );
103              
104             has languages => (
105             is => 'ro',
106             isa => 'ArrayRef[Str]',
107             default => sub { [] },
108             );
109              
110             has description => (
111             is => 'ro',
112             isa => 'HashRef[Str]',
113             required => 1,
114             );
115              
116             has alias_ipv6_to_ipv4 => (
117             is => 'ro',
118             isa => 'Bool',
119             default => 0,
120             );
121              
122             has _serializer => (
123             is => 'ro',
124             isa => 'MaxMind::DB::Writer::Serializer',
125             init_arg => undef,
126             lazy => 1,
127             builder => '_build_serializer',
128             );
129              
130             # This is an attribute so that we can explicitly set it from test code when we
131             # want to compare the binary output for two trees that we want to be
132             # identical.
133             has _build_epoch => (
134             is => 'rw',
135             writer => '_set_build_epoch',
136             isa => 'Int',
137             lazy => 1,
138             default => sub { time() },
139             );
140              
141             around BUILDARGS => sub {
142             my $orig = shift;
143             my $class = shift;
144             my $args = $class->$orig(@_);
145              
146             if ( exists $args->{merge_record_collisions} ) {
147             warn
148             'merge_record_collisions is deprecated. Use merge_strategy instead.';
149             }
150              
151             return $args unless exists $args->{merge_record_collisions};
152              
153             my $merge_record_collisions = delete $args->{merge_record_collisions};
154              
155             if ( $args->{merge_strategy}
156             && !( $args->{merge_strategy} eq 'none' xor $merge_record_collisions )
157             ) {
158             die sprintf(
159             'merge_strategy cannot be "%s" if merge_record_collisions is "%s"',
160             $args->{merge_strategy}, $args->{merge_record_collisions}
161             );
162             }
163              
164             $args->{merge_strategy} //=
165             $merge_record_collisions ? 'toplevel' : 'none';
166              
167             return $args;
168             };
169              
170             # The XS code expects $self->{_tree} to be populated.
171             sub BUILD {
172 203     203 0 9554 $_[0]->_tree();
173             }
174              
175             sub _build_tree {
176 174     174   398 my $self = shift;
177              
178 174         7462 return _create_tree(
179             $self->ip_version,
180             $self->record_size,
181             $self->merge_strategy,
182             $self->alias_ipv6_to_ipv4,
183             $self->remove_reserved_networks,
184             );
185             }
186              
187             sub merge_record_collisions {
188 2     2 1 171 warn
189             'merge_record_collisions is deprecated and will be removed in a future release';
190              
191 2         118 return $_[0]->merge_strategy ne 'none';
192             }
193              
194             sub insert_network {
195 105270     105270 1 31977223 my $self = shift;
196 105270         190785 my $network = shift;
197 105270         169029 my $data = shift;
198 105270   100     462140 my $args = shift // {};
199              
200 105270         821244 my ( $ip_address, $prefix_length ) = split qr{/}, $network, 2;
201              
202 105270 100 33     23328262 if ( !defined $prefix_length
      66        
      100        
203             || int($prefix_length) != $prefix_length
204             || $prefix_length < 0
205             || $prefix_length > 128 ) {
206 2         15 die "Invalid network inserted: $network";
207             }
208              
209 105268 100       214232 my $merge_strategy = %{$args} ? $self->_merge_strategy($args) : q{};
  105268         301994  
210              
211 105268         399695 $self->_insert_network(
212             $ip_address,
213             $prefix_length,
214             key_for_data($data),
215             $data,
216             $merge_strategy,
217             );
218 105254         792859 return;
219             }
220              
221             sub insert_range {
222 849     849 1 536441 my $self = shift;
223 849         1499 my $start_ip_address = shift;
224 849         1157 my $end_ip_address = shift;
225 849         1307 my $data = shift;
226 849   100     3274 my $args = shift // {};
227              
228 849 100       1214 my $merge_strategy = %{$args} ? $self->_merge_strategy($args) : q{};
  849         2006  
229              
230 849         2862 $self->_insert_range(
231             $start_ip_address,
232             $end_ip_address,
233             key_for_data($data),
234             $data,
235             $merge_strategy,
236             );
237 846         132494 return;
238             }
239              
240             sub _merge_strategy {
241 19     19   38 my $self = shift;
242 19         36 my $args = shift;
243              
244 19 100       133 if ( ( $args->{insert_only_if_parent_exists} ? 1 : 0 )
    100          
    100          
    50          
245             + ( $args->{force_overwrite} ? 1 : 0 )
246             + ( $args->{merge_strategy} ? 1 : 0 ) > 1 ) {
247 0         0 die 'Only one of merge_strategy, force_overwrite, or '
248             . 'insert_only_if_parent_exists can be set at a time';
249             }
250              
251 19 100       62 if ( $args->{insert_only_if_parent_exists} ) {
252 2         40 warn 'The argument insert_only_if_parent_exists is deprecated. '
253             . 'Use the merge_strategy "add-if-parent-exists" instead.';
254 2         17 return 'add-only-if-parent-exists';
255             }
256              
257 17 100       45 if ( $args->{force_overwrite} ) {
258 2         48 warn 'The argument force_overwrite is deprecated. '
259             . 'Use the merge_strategy "none" instead.';
260 2         36 return 'none';
261             }
262              
263 15 50       46 return undef unless $args->{merge_strategy};
264              
265             die "Unknown merge strategy: $args->{merge_strategy}"
266 15 50       162 unless $MergeStrategyEnum->check( $args->{merge_strategy} );
267              
268 15         1632 return $args->{merge_strategy};
269             }
270              
271             sub remove_network {
272 2     2 1 563992 my $self = shift;
273 2         20 my $network = shift;
274 2         40 my ( $ip_address, $prefix_length ) = split qr{/}, $network, 2;
275              
276 2         133 $self->_remove_network(
277             $ip_address,
278             $prefix_length,
279             );
280              
281 2         8 return;
282             }
283              
284             sub _build_serializer {
285 35     35   92 my $self = shift;
286              
287 35         1591 return MaxMind::DB::Writer::Serializer->new(
288             map_key_type_callback => $self->map_key_type_callback(),
289             );
290             }
291              
292             sub write_tree {
293 37     37 1 28128 my $self = shift;
294 37         119 my $output = shift;
295              
296 37         1906 $self->_write_search_tree(
297             $output,
298             $self->_root_data_type(),
299             $self->_serializer(),
300             );
301              
302             $output->print(
303             DATA_SECTION_SEPARATOR,
304 37         195 ${ $self->_serializer()->buffer() },
  37         2227  
305             METADATA_MARKER,
306             $self->_encoded_metadata(),
307             );
308             }
309              
310             {
311             my %key_types = (
312             binary_format_major_version => 'uint16',
313             binary_format_minor_version => 'uint16',
314             build_epoch => 'uint64',
315             database_type => 'utf8_string',
316             description => 'map',
317             ip_version => 'uint16',
318             languages => [ 'array', 'utf8_string' ],
319             node_count => 'uint32',
320             record_size => 'uint16',
321             );
322              
323             my $type_callback = sub {
324             return $key_types{ $_[0] } || 'utf8_string';
325             };
326              
327             sub _encoded_metadata {
328 37     37   96 my $self = shift;
329              
330 37         1616 my $metadata = MaxMind::DB::Metadata->new(
331             binary_format_major_version => 2,
332             binary_format_minor_version => 0,
333             build_epoch => uint128( $self->_build_epoch() ),
334             database_type => $self->database_type(),
335             description => $self->description(),
336             ip_version => $self->ip_version(),
337             languages => $self->languages(),
338             node_count => $self->node_count(),
339             record_size => $self->record_size(),
340             );
341              
342 37         77211 my $serializer = MaxMind::DB::Writer::Serializer->new(
343             map_key_type_callback => $type_callback,
344             );
345              
346 37         245 $serializer->store_data( 'map', $metadata->metadata_to_encode() );
347              
348 37         201 return ${ $serializer->buffer() };
  37         1518  
349             }
350             }
351              
352             {
353             my %do_not_freeze = map { $_ => 1 } qw(
354             map_key_type_callback
355             _tree
356             );
357              
358             sub freeze_tree {
359 30     30 1 36148 my $self = shift;
360 30         73 my $filename = shift;
361              
362 30         124 my %constructor_params;
363 30         379 for my $attr ( $self->meta()->get_all_attributes() ) {
364 390 100       5532 next unless $attr->init_arg();
365 360 100       1347 next if $do_not_freeze{ $attr->name() };
366              
367 300         911 my $reader = $attr->get_read_method();
368 300         16010 $constructor_params{ $attr->init_arg() } = $self->$reader();
369             }
370              
371 30         791 my $frozen = encode_sereal( \%constructor_params );
372 30         54143 $self->_freeze_tree( $filename, $frozen, length $frozen );
373              
374 30         421 return;
375             }
376             }
377              
378             sub new_from_frozen_tree {
379 29     29 1 163 my $class = shift;
380             my (
381 29         561 $filename, $callback, $database_type, $description, $merge_strategy,
382             $record_size
383             )
384             = validated_list(
385             \@_,
386             filename => { isa => 'Str' },
387             map_key_type_callback => { isa => 'CodeRef' },
388             database_type => { isa => 'Str', optional => 1 },
389             description => { isa => 'HashRef[Str]', optional => 1 },
390             merge_strategy => { isa => $MergeStrategyEnum, optional => 1 },
391             record_size => { isa => $RecordSizeType, optional => 1 },
392             );
393              
394             ## no critic (InputOutput::RequireBriefOpen)
395 29 50       21547 open my $fh, '<:raw', $filename or die $!;
396 29         11993 my $packed_params_size;
397 29 50       155 unless ( read( $fh, $packed_params_size, 4 ) == 4 ) {
398 0         0 die "Could not read 4 bytes from $filename: $!";
399             }
400              
401 29         7483 my $params_size = unpack( 'L', $packed_params_size );
402 29         75 my $frozen_params;
403 29 50       119 unless ( read( $fh, $frozen_params, $params_size ) == $params_size ) {
404 0         0 die "Could not read $params_size bytes from $filename: $!";
405             }
406 29 50       1693 close $fh or die $!;
407              
408 29         6314 my $params = decode_sereal($frozen_params);
409              
410 29 100       159 $params->{database_type} = $database_type if defined $database_type;
411 29 100       113 $params->{description} = $description if defined $description;
412 29 100       100 $params->{record_size} = $record_size if defined $record_size;
413              
414 29 100       128 if ( defined $merge_strategy ) {
    50          
415 12         42 $params->{merge_strategy} = $merge_strategy;
416             }
417             elsif ( $params->{merge_record_collisions} ) {
418              
419             # This is for backwards compatibility with frozen trees created before
420             # "merge_strategy" was added.
421 0         0 $params->{merge_strategy} = 'toplevel';
422             }
423              
424             my $tree = _thaw_tree(
425             $filename,
426             $params_size + 4,
427 29         440511 @{$params}{
428 29         87 qw(
429             ip_version
430             record_size
431             merge_strategy
432             alias_ipv6_to_ipv4
433             remove_reserved_networks
434             )
435             },
436             );
437              
438             return $class->new(
439 29         154 %{$params},
  29         2137  
440             map_key_type_callback => $callback,
441             _tree => $tree,
442             );
443             }
444              
445             sub DEMOLISH {
446 203     203 0 549 my $self = shift;
447              
448 203 50       10427 $self->_free_tree()
449             if $self->_has_tree();
450              
451 203         839 return;
452             }
453              
454             __PACKAGE__->meta()->make_immutable();
455              
456             1;
457              
458             # ABSTRACT: DEPRECATED Tree representing a MaxMind DB database in memory - then write it to a file
459              
460             __END__
461              
462             =pod
463              
464             =encoding UTF-8
465              
466             =head1 NAME
467              
468             MaxMind::DB::Writer::Tree - DEPRECATED Tree representing a MaxMind DB database in memory - then write it to a file
469              
470             =head1 VERSION
471              
472             version 0.300004
473              
474             =head1 SYNOPSIS
475              
476             use MaxMind::DB::Writer::Tree;
477              
478             my %types = (
479             color => 'utf8_string',
480             dogs => [ 'array', 'utf8_string' ],
481             size => 'uint16',
482             );
483              
484             my $tree = MaxMind::DB::Writer::Tree->new(
485             ip_version => 6,
486             record_size => 24,
487             database_type => 'My-IP-Data',
488             languages => ['en'],
489             description => { en => 'My database of IP data' },
490             map_key_type_callback => sub { $types{ $_[0] } },
491             );
492              
493             $tree->insert_network(
494             '8.8.8.0/24',
495             {
496             color => 'blue',
497             dogs => [ 'Fido', 'Ms. Pretty Paws' ],
498             size => 42,
499             },
500             );
501              
502             open my $fh, '>:raw', '/path/to/my-ip-data.mmdb';
503             $tree->write_tree($fh);
504              
505             =head1 DESCRIPTION
506              
507             This is the main class you'll use to write L<MaxMind DB database
508             files|http://maxmind.github.io/MaxMind-DB/>. This class represents the
509             database in memory. Once you've created the full tree you can write to a file.
510              
511             =head1 API
512              
513             This class provides the following methods:
514              
515             =head2 MaxMind::DB::Writer::Tree->new()
516              
517             This creates a new tree object. The constructor accepts the following
518             parameters:
519              
520             =over 4
521              
522             =item * ip_version
523              
524             The IP version for the database. It must be 4 or 6.
525              
526             This parameter is required.
527              
528             =item * record_size
529              
530             This is the record size in I<bits>. This should be one of 24, 28, 32 (in
531             theory any number divisible by 4 up to 128 will work but the available readers
532             all expect 24-32).
533              
534             This parameter is required.
535              
536             =item * database_type
537              
538             This is a string containing the database type. This can be anything,
539             really. MaxMind uses strings like "GeoIP2-City", "GeoIP2-Country", etc.
540              
541             This parameter is required.
542              
543             =item * languages
544              
545             This should be an array reference of languages used in the database, like
546             "en", "zh-TW", etc. This is useful as metadata for database readers and end users.
547              
548             This parameter is optional.
549              
550             =item * description
551              
552             This is a hashref where the keys are language names and the values are
553             descriptions of the database in that language. For example, you might have
554             something like:
555              
556             {
557             en => 'My IP data',
558             fr => q{Mon Data d'IP},
559             }
560              
561             This parameter is required.
562              
563             =item * map_key_type_callback
564              
565             This is a subroutine reference that is called in order to determine how to
566             store each value in a map (hash) data structure. See L<DATA TYPES> below for
567             more details.
568              
569             This parameter is required.
570              
571             =item * merge_record_collisions
572              
573             By default, when an insert collides with a previous insert, the new data
574             simply overwrites the old data where the two networks overlap.
575              
576             If this is set to true, then on a collision, the writer will merge the old
577             data with the new data. The merge strategy employed is controlled by the
578             C<merge_strategy> attribute, described below.
579              
580             This parameter is optional. It defaults to false unless C<merge_strategy> is
581             set to something other than C<none>.
582              
583             This parameter is deprecated. New code should just set C<merge_strategy>
584             directly.
585              
586             B<This parameter is deprecated. Use C<merge_strategy> instead.>
587              
588             =item * merge_strategy
589              
590             Controls what merge strategy is employed.
591              
592             =over 8
593              
594             =item * none
595              
596             No merging will be done. C<merge_record_collisions> must either be not set or
597             set to false.
598              
599             =item * toplevel
600              
601             If both data structures are hashrefs then the data from the top level keys in
602             the new data structure are copied over to the existing data structure,
603             potentially replacing any existing values for existing keys completely.
604              
605             =item * recurse
606              
607             Recursively merges the new data structure with the old data structure. Hash
608             values and array elements are either - in the case of simple values - replaced
609             with the new values, or - in the case of complex structures - have their values
610             recursively merged.
611              
612             For example if this data is originally inserted for an IP range:
613              
614             {
615             families => [ {
616             husband => 'Fred',
617             wife => 'Wilma',
618             }, ],
619             year => 1960,
620             }
621              
622             And then this subsequent data is inserted for a range covered by the previous
623             IP range:
624              
625             {
626             families => [ {
627             wife => 'Wilma',
628             child => 'Pebbles',
629             }, {
630             husband => 'Barney',
631             wife => 'Betty',
632             child => 'Bamm-Bamm',
633             }, ],
634             company => 'Hanna-Barbera Productions',
635             }
636              
637             Then querying within the range will produce the results:
638              
639             {
640             families => [ {
641             husband => 'Fred',
642             wife => 'Wilma', # note replaced value
643             child => 'Pebbles',
644             }, {
645             husband => 'Barney',
646             wife => 'Betty',
647             child => 'Bamm-Bamm',
648             }, ],
649             year => 1960,
650             company => 'Hanna-Barbera Productions',
651             }
652              
653             =item * add-only-if-parent-exists
654              
655             With this merge strategy, data will only be inserted when there is already a
656             record for the network (or sub-network). Similarly, when merging the data
657             record with an existing data record, no new hash or array references will be
658             created within the data record for the new data. For instance, if the original
659             data record is C<{parent_a => {sibling => 1}}> and C<{parent_a => {child_a =>
660             1}, parent_b => {child_b => 1}}> is inserted, only C<child_a>, not C<child_b>,
661             will appear in the merged record.
662              
663             This option is intended to be used when inserting data that supplements
664             existing data but that is not independently useful.
665              
666             =back
667              
668             In all merge strategies attempting to merge two differing data structures
669             causes an exception.
670              
671             This parameter is optional. If C<merge_record_collisions> is true, this
672             defaults to C<toplevel>; otherwise, it defaults to C<none>.
673              
674             =item * alias_ipv6_to_ipv4
675              
676             If this is true then the final database will map some IPv6 ranges to the IPv4
677             range. These ranges are:
678              
679             =over 8
680              
681             =item * ::ffff:0:0/96
682              
683             This is the IPv4-mapped IPv6 range
684              
685             =item * 2001::/32
686              
687             This is the Teredo range. Note that lookups for Teredo ranges will find the
688             Teredo server's IPv4 address, not the client's IPv4.
689              
690             =item * 2002::/16
691              
692             This is the 6to4 range
693              
694             =back
695              
696             When aliasing is enabled, insertions into the aliased locations will throw an
697             exception. Inserting a network containing them does not throw an exception, but
698             no information will be stored for the aliased locations.
699              
700             To insert an IPv4 address, insert it using IPv4 notation or insert
701             directly into ::/96.
702              
703             Aliased nodes are I<not> followed when merging nodes. Only merges into the
704             original IPv4 location, ::/96, will be followed.
705              
706             This parameter is optional. It defaults to false.
707              
708             =item * remove_reserved_networks
709              
710             If this is true, reserved networks may not be inserted.
711              
712             Attempts to insert these networks or any inside them will be silently ignored.
713             Inserting a network containing them does not throw an exception, but no
714             information will be stored for the reserved sections.
715              
716             Reserved networks that are globally routable to an individual device, such as
717             Teredo, may still be added.
718              
719             This parameter is optional. It defaults to true.
720              
721             =back
722              
723             =head2 $tree->insert_network( $network, $data, $additional_args )
724              
725             This method expects two parameters. The first is a network in CIDR notation.
726             The second can be any Perl data structure (except a coderef, glob, or
727             filehandle).
728              
729             The C<$data> payload is encoded according to the L<MaxMind DB database format
730             spec|http://maxmind.github.io/MaxMind-DB/>. The short overview is that
731             anything that can be encoded in JSON can be stored in an MMDB file. It can
732             also handle unsigned 64-bit and 128-bit integers if they are passed as
733             L<Math::UInt128|Math::Int128> objects.
734              
735             C<$additional_args> is a hash reference containing additional arguments that
736             change the behavior of the insert. The following arguments are supported:
737              
738             =over 3
739              
740             =item * C<merge_strategy>
741              
742             When set, the tree's default merge strategy will be overridden for the
743             insertion with this merge strategy.
744              
745             =item * C<force_overwrite>
746              
747             This make the merge strategy for the insert C<none>.
748              
749             B<This option is deprecated.>
750              
751             =item * C<insert_only_if_parent_exists>
752              
753             This make the merge strategy for the insert C<add-only-if-parent-exists>.
754              
755             B<This option is deprecated.>
756              
757             =back
758              
759             =head3 Insert Order, Merging, and Overwriting
760              
761             When C<merge_strategy> is I<none>, the last insert "wins". This
762             means that if you insert C<1.2.3.255/32> and then C<1.2.3.0/24>, the data for
763             C<1.2.3.255/24> will overwrite the data you previously inserted for
764             C<1.2.3.255/232>. On the other hand, if you insert C<1.2.3.255/32> last, then
765             the tree will be split so that the C<1.2.3.0 - 1.2.3.254> range has different
766             data than C<1.2.3.255>.
767              
768             In this scenario, if you want to make sure that no data is overwritten then
769             you need to sort your input by network prefix length.
770              
771             When C<merge_strategy> is not I<none>, then records will be merged based on
772             the particular strategy. For instance, the C<1.2.3.255/32> network will end up
773             with its data plus the data provided for the C<1.2.3.0/24> network, while
774             C<1.2.3.0 - 1.2.3.254> will have the expected data. The merge strategy can be
775             changed on a per-insert basis by using the C<merge_strategy> argument when
776             inserting a network as discussed above.
777              
778             =head2 $tree->insert_range( $first_ip, $last_ip, $data, $additional_args )
779              
780             This method is similar to C<insert_network()>, except that it takes an IP
781             range rather than a network. The first parameter is the first IP address in
782             the range. The second is the last IP address in the range. The third is a
783             Perl data structure containing the data to be inserted. The final parameter
784             are additional arguments, as outlined for C<insert_network()>.
785              
786             =head2 $tree->remove_network( $network )
787              
788             This method removes the network from the database. It takes one parameter, the
789             network in CIDR notation.
790              
791             =head2 $tree->write_tree($fh)
792              
793             Given a filehandle, this method writes the contents of the tree as a MaxMind
794             DB database to that filehandle.
795              
796             =head2 $tree->iterate($object)
797              
798             This method iterates over the tree by calling methods on the passed
799             object. The object must have at least one of the following three methods:
800             C<process_empty_record>, C<process_node_record>, C<process_data_record>.
801              
802             The iteration is done in depth-first order, which means that it visits each
803             network in order.
804              
805             Each method on the object is called with the following position parameters:
806              
807             =over 4
808              
809             =item
810              
811             The node number as a 64-bit number.
812              
813             =item
814              
815             A boolean indicating whether or not this is the right or left record for the
816             node. True for right, false for left.
817              
818             =item
819              
820             The first IP number in the node's network as a 128-bit number.
821              
822             =item
823              
824             The prefix length for the node's network.
825              
826             =item
827              
828             The first IP number in the record's network as a 128-bit number.
829              
830             =item
831              
832             The prefix length for the record's network.
833              
834             =back
835              
836             If the record is a data record, the final argument will be the Perl data
837             structure associated with the record.
838              
839             The record's network is what matches with a given data structure for data
840             records.
841              
842             For node (and alias) records, the final argument will be the number of the
843             node that this record points to.
844              
845             For empty records, there are no additional arguments.
846              
847             =head2 $tree->freeze_tree($filename)
848              
849             Given a file name, this method freezes the tree to that file. Unlike the
850             C<write_tree()> method, this method does write out a MaxMind DB file. Instead,
851             it writes out something that can be quickly thawed via the C<<
852             MaxMind::DB::Writer::Tree->new_from_frozen_tree >> constructor. This is useful if
853             you want to pass the in-memory representation of the tree between processes.
854              
855             =head2 $tree->ip_version()
856              
857             Returns the tree's IP version, as passed to the constructor.
858              
859             =head2 $tree->record_size()
860              
861             Returns the tree's record size, as passed to the constructor.
862              
863             =head2 $tree->merge_record_collisions()
864              
865             Returns a boolean indicating whether the tree will merge colliding records, as
866             determined by the merge strategy.
867              
868             B<This is deprecated.>
869              
870             =head2 $tree->merge_strategy()
871              
872             Returns the merge strategy used when two records collide.
873              
874             =head2 $tree->map_key_type_callback()
875              
876             Returns the callback used to determine the type of a map's values, as passed
877             to the constructor.
878              
879             =head2 $tree->database_type()
880              
881             Returns the tree's database type, as passed to the constructor.
882              
883             =head2 $tree->languages()
884              
885             Returns the tree's languages, as passed to the constructor.
886              
887             =head2 $tree->description()
888              
889             Returns the tree's description hashref, as passed to the constructor.
890              
891             =head2 $tree->alias_ipv6_to_ipv4()
892              
893             Returns a boolean indicating whether the tree will alias some IPv6 ranges to
894             their corresponding IPv4 ranges when the tree is written to disk.
895              
896             =head2 MaxMind::DB::Writer::Tree->new_from_frozen_tree()
897              
898             This method constructs a tree from a file containing a frozen tree.
899              
900             This method accepts the following parameters:
901              
902             =over 4
903              
904             =item * filename
905              
906             The filename containing the frozen tree.
907              
908             This parameter is required.
909              
910             =item * map_key_type_callback
911              
912             This is a subroutine reference that is called in order to determine how to
913             store each value in a map (hash) data structure. See L<DATA TYPES> below for
914             more details.
915              
916             This needs to be passed because subroutine references cannot be reliably
917             serialized and restored between processes.
918              
919             This parameter is required.
920              
921             =item * database_type
922              
923             Override the C<<database_type>> of the frozen tree. This accepts a string of
924             the same form as the C<<new()>> constructor.
925              
926             This parameter is optional.
927              
928             =item * description
929              
930             Override the C<<description>> of the frozen tree. This accepts a hashref of
931             the same form as the C<<new()>> constructor.
932              
933             This parameter is optional.
934              
935             =item * merge_strategy
936              
937             Override the C<<merge_strategy>> setting for the frozen tree.
938              
939             This parameter is optional.
940              
941             =back
942              
943             =head2 Caveat for Freeze/Thaw
944              
945             The frozen tree is more or less the raw C data structures written to disk. As
946             such, it is very much not portable, and your ability to thaw a tree on a
947             machine not identical to the one on which it was written is not guaranteed.
948              
949             In addition, there is no guarantee that the freeze/thaw format will be stable
950             across different versions of this module.
951              
952             =head1 DATA TYPES
953              
954             The MaxMind DB file format is strongly typed. Because Perl is not strongly
955             typed, you will need to explicitly specify the types for each piece of
956             data. Currently, this class assumes that your top-level data structure for an
957             IP address will always be a map (hash). You can then provide a
958             C<map_key_type_callback> subroutine that will be called as the data is
959             serialized. This callback is given a key name and is expected to return that
960             key's data type.
961              
962             Let's use the following structure as an example:
963              
964             {
965             names => {
966             en => 'United States',
967             es => 'Estados Unidos',
968             },
969             population => 319_000_000,
970             fizzle_factor => 65.7294,
971             states => [ 'Alabama', 'Alaska', ... ],
972             }
973              
974             Given this data structure, our C<map_key_type_callback> might look something like this:
975              
976             my %types = (
977             names => 'map',
978             en => 'utf8_string',
979             es => 'utf8_string',
980             population => 'uint32',
981             fizzle_factor => 'double',
982             states => [ 'array', 'utf8_string' ],
983             );
984              
985             sub {
986             my $key = shift;
987             return $type{$key};
988             }
989              
990             If the callback returns C<undef>, the serialization code will throw an
991             error. Note that for an array we return a 2 element arrayref where the first
992             element is C<'array'> and the second element is the type of content in the
993             array.
994              
995             The valid types are:
996              
997             =over 4
998              
999             =item * utf8_string
1000              
1001             =item * uint16
1002              
1003             =item * uint32
1004              
1005             =item * uint64
1006              
1007             =item * uint128
1008              
1009             =item * int32
1010              
1011             =item * double
1012              
1013             64 bits of precision.
1014              
1015             =item * float
1016              
1017             32 bits of precision.
1018              
1019             =item * boolean
1020              
1021             =item * map
1022              
1023             =item * array
1024              
1025             =back
1026              
1027             =head1 SUPPORT
1028              
1029             Bugs may be submitted through L<https://github.com/maxmind/MaxMind-DB-Writer-perl/issues>.
1030              
1031             =head1 AUTHORS
1032              
1033             =over 4
1034              
1035             =item *
1036              
1037             Olaf Alders <oalders@maxmind.com>
1038              
1039             =item *
1040              
1041             Greg Oschwald <goschwald@maxmind.com>
1042              
1043             =item *
1044              
1045             Dave Rolsky <drolsky@maxmind.com>
1046              
1047             =item *
1048              
1049             Mark Fowler <mfowler@maxmind.com>
1050              
1051             =back
1052              
1053             =head1 COPYRIGHT AND LICENSE
1054              
1055             This software is copyright (c) 2023 by MaxMind, Inc.
1056              
1057             This is free software; you can redistribute it and/or modify it under
1058             the same terms as the Perl 5 programming language system itself.
1059              
1060             =cut