From fa16a4a45d4632aa10c73d7cb92672d1f5233a68 Mon Sep 17 00:00:00 2001 From: lionsoul2014 Date: Fri, 6 Mar 2026 14:27:19 +0800 Subject: [PATCH] non-contiguous and disorder ip range supports --- maker/java/pom.xml | 2 +- .../org/lionsoul/ip2region/xdb/Maker.java | 54 +++++++++++++++---- .../org/lionsoul/ip2region/xdb/Segment.java | 18 +++++-- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/maker/java/pom.xml b/maker/java/pom.xml index db3f0de..18e77a6 100644 --- a/maker/java/pom.xml +++ b/maker/java/pom.xml @@ -4,7 +4,7 @@ org.lionsoul ip2region-maker - 3.0.0 + 3.1.0 jar ip2region diff --git a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Maker.java b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Maker.java index b7a1938..350cdc1 100644 --- a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Maker.java +++ b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Maker.java @@ -57,6 +57,8 @@ import java.io.*; import java.nio.charset.Charset; import java.util.*; +import org.lionsoul.ip2region.xdb.Segment.IterateAction; + public class Maker { // constants define public static final int VersionNo = 3; // 2 for XDB 2.0, 3 for XDB 3.0 @@ -108,7 +110,7 @@ public class Maker { /// } this.bytesCharset = Charset.forName("utf-8"); - this.segments = new LinkedList(); + this.segments = new ArrayList(); this.dstHandle = new RandomAccessFile(dstPath, "rw"); this.indexPolicy = policy; this.regionPool = new HashMap(); @@ -156,8 +158,9 @@ public class Maker { private void loadSegments() throws Exception { log.infof("try to load the segments ... "); final long tStart = System.currentTimeMillis(); - Segment.iterate(srcFile, new Segment.IterateAction() { + final IterateAction itAct = new Segment.IterateAction() { private Segment last = null; + private boolean sorting = false; @Override public void before(String line) { @@ -177,21 +180,50 @@ public class Maker { } if (last != null && !seg.after(last)) { - throw new Exception("discontinuous data segment: last.eip(" - + Util.ipToString(last.endIP)+")+1 != seg.sip("+ Util.ipToString(seg.startIP) + ", "+ seg.region +")"); - } + // throw new Exception("discontinuous data segment: last.eip(" + // + Util.ipToString(last.endIP)+")+1 != seg.sip("+ Util.ipToString(seg.startIP) + ", "+ seg.region +")"); - // allow empty region - // if (region.length() < 1) { - // throw new Exception("empty region info for segment `"+seg+"`"); - // } + // @Note: If the continuity is disrupted, + // we will sort all these segments later. + sorting = true; + } segments.add(seg); last = seg; } - }); - log.infof("all segments loaded, length: %d, elapsed: %d ms", segments.size(), System.currentTimeMillis() - tStart); + public boolean sorting() { + return sorting; + } + }; + + // load iterate all the segments + Segment.iterate(srcFile, itAct); + final boolean sorting = itAct.sorting(); + + // check and sort all the segments + if (sorting) { + log.infof("try to sort all the segments based on its start ip ..."); + segments.sort((o1, o2) -> {return Util.ipCompare(o1.startIP, o2.startIP);}); + + log.infof("try to check if there is overlap in the segments ..."); + Segment last = null; + for (final Segment seg : segments) { + // check the order of the data segment + if (last != null && !seg.after(last)) { + throw new Exception("overlap checking: last.eip(" + + Util.ipToString(last.endIP)+") >= seg.sip("+ Util.ipToString(seg.startIP) + ", "+ seg.region +")"); + } + + // reset the last + last = seg; + } + } + + log.infof( + "all segments loaded, length: %d, sorting: %s, elapsed: %d ms", + segments.size(), sorting ? "true" : "false", System.currentTimeMillis() - tStart + ); } // init the maker diff --git a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Segment.java b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Segment.java index 1ab808c..4effb7d 100644 --- a/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Segment.java +++ b/maker/java/src/main/java/org/lionsoul/ip2region/xdb/Segment.java @@ -98,11 +98,18 @@ public class Segment { return Util.ipCompare(ip, startIP) >= 0 && Util.ipCompare(ip, endIP) <= 0; } - // check if the current segment just after the specified one. - public boolean after(final Segment last) { + // check if the current segment just right behind the specified one. + // which mean last.endIP + 1 = this.startIP + public boolean rightBehind(final Segment last) { return Util.ipCompare(Util.ipAddOne(last.endIP), startIP) == 0; } + // check if the current segment is after the specified one. + // which means last.endIP < this.startIP + public boolean after(final Segment last) { + return Util.ipCompare(last.endIP, startIP) < 0; + } + // parser the Segment from an input string public static Segment parse(String input) throws Exception { final String[] ps = input.trim().split("\\|", 3); @@ -121,6 +128,11 @@ public class Segment { // static class to handler the iterate callback public static interface IterateAction { + // need sort all the iterated segments ? + default boolean sorting() { + return false; + } + public void before(final String line); public String filter(final String region); public void handle(final Segment seg) throws Exception; @@ -186,7 +198,7 @@ public class Segment { // check and automatic merging the Consecutive Segments, which means: // 1, region info is the same // 2, last.eip+1 = cur.sip - if (last.region.equals(seg.region) && seg.after(last)) { + if (last.region.equals(seg.region) && seg.rightBehind(last)) { // last.endIP = seg.endIP; System.arraycopy(seg.endIP, 0, last.endIP, 0, seg.endIP.length); continue;