From a5df8ff87c26f064837922c26f227c781ff41053 Mon Sep 17 00:00:00 2001 From: lionsoul <狮子的魂> Date: Thu, 30 Jun 2016 20:19:17 +0800 Subject: [PATCH] add DbSearcher#memorySearch interface --- .../org/lionsoul/ip2region/DbSearcher.java | 127 ++++++++++++++---- .../lionsoul/ip2region/test/TestSearcher.java | 51 ++++++- 2 files changed, 146 insertions(+), 32 deletions(-) diff --git a/binding/java/src/org/lionsoul/ip2region/DbSearcher.java b/binding/java/src/org/lionsoul/ip2region/DbSearcher.java index dace1df..5bc8e8f 100644 --- a/binding/java/src/org/lionsoul/ip2region/DbSearcher.java +++ b/binding/java/src/org/lionsoul/ip2region/DbSearcher.java @@ -11,51 +11,124 @@ import java.io.RandomAccessFile; */ public class DbSearcher { - public static final int BTREE_ALGORITHM = 1; - public static final int BIN_ALGORITHM = 2; - + public static final int BTREE_ALGORITHM = 1; + public static final int BINARY_ALGORITHM = 2; + public static final int MEMORY_ALGORITYM = 3; + /** * db config */ private DbConfig dbConfig = null; - + /** * db file access handler */ private RandomAccessFile raf = null; - + /** * header blocks buffer */ private long[] HeaderSip = null; private int[] HeaderPtr = null; private int headerLength; - + /** * super blocks info */ private long firstIndexPtr = 0; private long lastIndexPtr = 0; private int totalIndexBlocks = 0; - + + /** + * for memory mode + * the original db binary string + */ + private byte[] dbBinStr = null; + /** * construct class * - * @param bdConfig - * @param dbFile - * @throws FileNotFoundException + * @param bdConfig + * @param dbFile + * @throws FileNotFoundException */ public DbSearcher( DbConfig dbConfig, String dbFile ) throws FileNotFoundException { this.dbConfig = dbConfig; raf = new RandomAccessFile(dbFile, "r"); } + + /** + * get the region with a int ip address with memory binary search algorithm + * + * @param ip + * @throws IOException + */ + public DataBlock memorySearch(long ip) throws IOException + { + int blen = IndexBlock.getIndexBlockLength(); + if ( dbBinStr == null ) { + dbBinStr = new byte[(int)raf.length()]; + raf.seek(0L); + raf.readFully(dbBinStr, 0, dbBinStr.length); + + //initialize the global vars + firstIndexPtr = Util.getIntLong(dbBinStr, 0); + lastIndexPtr = Util.getIntLong(dbBinStr, 4); + totalIndexBlocks = (int)((lastIndexPtr - firstIndexPtr)/blen) + 1; + } + + //search the index blocks to define the data + int l = 0, h = totalIndexBlocks; + long sip, eip, dataptr = 0; + while ( l <= h ) { + int m = (l + h) >> 1; + int p = (int)(firstIndexPtr + m * blen); + + sip = Util.getIntLong(dbBinStr, p); + if ( ip < sip ) { + h = m - 1; + } else { + eip = Util.getIntLong(dbBinStr, p + 4); + if ( ip > eip ) { + l = m + 1; + } else { + dataptr = Util.getIntLong(dbBinStr, p + 8); + break; + } + } + } + + //not matched + if ( dataptr == 0 ) return null; + + //get the data + int dataLen = (int)((dataptr >> 24) & 0xFF); + int dataPtr = (int)((dataptr & 0x00FFFFFF)); + int city_id = (int)Util.getIntLong(dbBinStr, dataPtr); + String region = new String(dbBinStr, dataPtr + 4, dataLen - 4, "UTF-8"); + + return new DataBlock(city_id, region, dataPtr); + } + /** + * get the region throught the ip address with memory binary search algorithm + * + * @param ip + * @return DataBlock + * @throws IOException + */ + public DataBlock memorySearch( String ip ) throws IOException + { + return memorySearch(Util.ip2long(ip)); + } + + /** * get by index ptr * - * @param indexPtr - * @throws IOException + * @param indexPtr + * @throws IOException */ public DataBlock getByIndexPtr( long ptr ) throws IOException { @@ -78,11 +151,11 @@ public class DbSearcher return new DataBlock(city_id, region, dataPtr); } - + /** * get the region with a int ip address with b-tree algorithm * - * @param ip + * @param ip * @throws IOException */ public DataBlock btreeSearch( long ip ) throws IOException @@ -206,23 +279,23 @@ public class DbSearcher return new DataBlock(city_id, region, dataPtr); } - + /** * get the region throught the ip address with b-tree search algorithm * - * @param ip - * @return DataBlock - * @throws IOException + * @param ip + * @return DataBlock + * @throws IOException */ public DataBlock btreeSearch( String ip ) throws IOException { return btreeSearch(Util.ip2long(ip)); } - + /** * get the region with a int ip address with binary search algorithm * - * @param ip + * @param ip * @throws IOException */ public DataBlock binarySearch( long ip ) throws IOException @@ -276,13 +349,13 @@ public class DbSearcher return new DataBlock(city_id, region, dataPtr); } - + /** * get the region throught the ip address with binary search algorithm * - * @param ip - * @return DataBlock - * @throws IOException + * @param ip + * @return DataBlock + * @throws IOException */ public DataBlock binarySearch( String ip ) throws IOException { @@ -292,13 +365,13 @@ public class DbSearcher /** * get the db config * - * @return DbConfig + * @return DbConfig */ public DbConfig getDbConfig() { return dbConfig; } - + /** * close the db * @@ -308,6 +381,8 @@ public class DbSearcher { HeaderSip = null; //let gc do its work HeaderPtr = null; + dbBinStr = null; raf.close(); } + } diff --git a/binding/java/src/org/lionsoul/ip2region/test/TestSearcher.java b/binding/java/src/org/lionsoul/ip2region/test/TestSearcher.java index 0717da3..aa7354e 100644 --- a/binding/java/src/org/lionsoul/ip2region/test/TestSearcher.java +++ b/binding/java/src/org/lionsoul/ip2region/test/TestSearcher.java @@ -4,6 +4,8 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.lionsoul.ip2region.DataBlock; import org.lionsoul.ip2region.DbConfig; @@ -25,23 +27,45 @@ public class TestSearcher return; } - int algorithm = DbSearcher.BTREE_ALGORITHM; File file = new File(argv[0]); if ( file.exists() == false ) { System.out.println("Error: Invalid ip2region.db file"); return; } + int algorithm = DbSearcher.BTREE_ALGORITHM; + String algoName = "B-tree"; if ( argv.length > 1 ) { - if ( argv[1].equalsIgnoreCase("binary")) algorithm = DbSearcher.BIN_ALGORITHM; + if ( argv[1].equalsIgnoreCase("binary")) { + algoName = "Binary"; + algorithm = DbSearcher.BINARY_ALGORITHM; + } else if ( argv[1].equalsIgnoreCase("memory") ) { + algoName = "Memory"; + algorithm = DbSearcher.MEMORY_ALGORITYM; + } } try { - System.out.println("initializing "+((algorithm==2)?"Binary":"B-tree")+" ... "); + System.out.println("initializing "+algoName+" ... "); DbConfig config = new DbConfig(); - DbSearcher seacher = new DbSearcher(config, argv[0]); + DbSearcher searcher = new DbSearcher(config, argv[0]); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + //define the method + Method method = null; + switch ( algorithm ) + { + case DbSearcher.BTREE_ALGORITHM: + method = searcher.getClass().getMethod("btreeSearch", String.class); + break; + case DbSearcher.BINARY_ALGORITHM: + method = searcher.getClass().getMethod("binarySearch", String.class); + break; + case DbSearcher.MEMORY_ALGORITYM: + method = searcher.getClass().getMethod("memorySearch", String.class); + break; + } + System.out.println("+----------------------------------+"); System.out.println("| ip2region test shell |"); System.out.println("| Author: chenxin619315@gmail.com |"); @@ -62,13 +86,13 @@ public class TestSearcher } sTime = System.nanoTime(); - dataBlock = algorithm==2 ? seacher.binarySearch(line) : seacher.btreeSearch(line); + dataBlock = (DataBlock) method.invoke(searcher, line); cTime = (System.nanoTime() - sTime) / 1000000; System.out.printf("%s in %.5f millseconds\n", dataBlock, cTime); } reader.close(); - seacher.close(); + searcher.close(); System.out.println("+--Bye"); } catch (IOException e) { // TODO Auto-generated catch block @@ -76,6 +100,21 @@ public class TestSearcher } catch (DbMakerConfigException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } }