/** * get the region with a int ip address with memory binary search algorithm * * @param ip * @ */ public DataBlock memorySearch(long ip) { 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"); var region = Encoding.UTF8.GetString(dbBinStr, dataPtr + 4, dataLen - 4); return(new DataBlock(city_id, region, dataPtr)); }
/** * construct method with self-define std ip2region bianry string support * Thanks to the issue from Wendal at https://gitee.com/lionsoul/ip2region/issues/IILFL * * @param dbConfig * @param dbBinStr */ public DbSearcher(DbConfig dbConfig, byte[] dbBinStr) { this.dbConfig = dbConfig; this.dbBinStr = dbBinStr; firstIndexPtr = Util.getIntLong(dbBinStr, 0); lastIndexPtr = Util.getIntLong(dbBinStr, 4); totalIndexBlocks = (int)((lastIndexPtr - firstIndexPtr) / IndexBlock.getIndexBlockLength()) + 1; }
/** * internal method to add a new data block record * * @param raf * @param startIp * @param endIp * @param region data */ private void addDataBlock( RandomAccessFile raf, String startIp, String endIp, String region) { try { byte[] data = region.getBytes("UTF-8"); int dataPtr = 0; /*byte[] city = new byte[4]; * int city_id = getCityId(region); * Util.writeIntLong(city, 0, city_id); * dataPtr = (int)raf.getFilePointer(); * raf.write(city); * raf.write(data);*/ //check region ptr pool first if (regionPtrPool.containsKey(region)) { DataBlock dataBlock = regionPtrPool.get(region); dataPtr = dataBlock.getDataPtr(); Console.WriteLine("dataPtr: " + dataPtr + ", region: " + region); } else { byte[] city = new byte[4]; int city_id = getCityId(region); Util.writeIntLong(city, 0, city_id); dataPtr = (int)raf.getFilePointer(); raf.write(city); raf.write(data); regionPtrPool.put(region, new DataBlock(city_id, region, dataPtr)); } //add the data index blocks IndexBlock ib = new IndexBlock( Util.ip2long(startIp), Util.ip2long(endIp), dataPtr, data.Length + 4 //4 bytes for the city id ); indexPool.add(ib); } catch (Exception e) { Console.WriteLine(e); } }
/** * get the region with a int ip address with binary search algorithm * * @param ip * @ */ public DataBlock binarySearch(long ip) { int blen = IndexBlock.getIndexBlockLength(); if (totalIndexBlocks == 0) { raf.seek(0L); byte[] superBytes = new byte[8]; raf.readFully(superBytes, 0, superBytes.Length); //initialize the global vars firstIndexPtr = Util.getIntLong(superBytes, 0); lastIndexPtr = Util.getIntLong(superBytes, 4); totalIndexBlocks = (int)((lastIndexPtr - firstIndexPtr) / blen) + 1; } //search the index blocks to define the data int l = 0, h = totalIndexBlocks; byte[] buffer = new byte[blen]; long sip, eip, dataptr = 0; while (l <= h) { int m = (l + h) >> 1; raf.seek(firstIndexPtr + m * blen); //set the file pointer raf.readFully(buffer, 0, buffer.Length); sip = Util.getIntLong(buffer, 0); if (ip < sip) { h = m - 1; } else { eip = Util.getIntLong(buffer, 4); if (ip > eip) { l = m + 1; } else { dataptr = Util.getIntLong(buffer, 8); break; } } } //not matched if (dataptr == 0) { return(null); } //get the data int dataLen = (int)((dataptr >> 24) & 0xFF); int dataPtr = (int)((dataptr & 0x00FFFFFF)); raf.seek(dataPtr); byte[] data = new byte[dataLen]; raf.readFully(data, 0, data.Length); int city_id = (int)Util.getIntLong(data, 0); //String region = new String(data, 4, data.length - 4, "UTF-8"); var region = Encoding.UTF8.GetString(data, 4, data.Length - 4); return(new DataBlock(city_id, region, dataPtr)); }
/** * get the region with a int ip address with b-tree algorithm * * @param ip * @ */ public DataBlock btreeSearch(long ip) { //check and load the header if (HeaderSip == null) { raf.seek(8L); //pass the super block byte[] b = new byte[dbConfig.getTotalHeaderSize()]; // byte[] b = new byte[4096]; raf.readFully(b, 0, b.Length); //fill the header int len = b.Length >> 3, idx = 0; //b.lenght / 8 HeaderSip = new long[len]; HeaderPtr = new int[len]; long startIp, dataPtr2; for (int i = 0; i < b.Length; i += 8) { startIp = Util.getIntLong(b, i); dataPtr2 = Util.getIntLong(b, i + 4); if (dataPtr2 == 0) { break; } HeaderSip[idx] = startIp; HeaderPtr[idx] = (int)dataPtr2; idx++; } headerLength = idx; } //1. define the index block with the binary search if (ip == HeaderSip[0]) { return(getByIndexPtr(HeaderPtr[0])); } else if (ip == HeaderSip[headerLength - 1]) { return(getByIndexPtr(HeaderPtr[headerLength - 1])); } int l = 0, h = headerLength, sptr = 0, eptr = 0; while (l <= h) { int m = (l + h) >> 1; //perfetc matched, just return it if (ip == HeaderSip[m]) { if (m > 0) { sptr = HeaderPtr[m - 1]; eptr = HeaderPtr[m]; } else { sptr = HeaderPtr[m]; eptr = HeaderPtr[m + 1]; } break; } //less then the middle value if (ip < HeaderSip[m]) { if (m == 0) { sptr = HeaderPtr[m]; eptr = HeaderPtr[m + 1]; break; } else if (ip > HeaderSip[m - 1]) { sptr = HeaderPtr[m - 1]; eptr = HeaderPtr[m]; break; } h = m - 1; } else { if (m == headerLength - 1) { sptr = HeaderPtr[m - 1]; eptr = HeaderPtr[m]; break; } else if (ip <= HeaderSip[m + 1]) { sptr = HeaderPtr[m]; eptr = HeaderPtr[m + 1]; break; } l = m + 1; } } //match nothing just stop it if (sptr == 0) { return(null); } //2. search the index blocks to define the data int blockLen = eptr - sptr, blen = IndexBlock.getIndexBlockLength(); byte[] iBuffer = new byte[blockLen + blen]; //include the right border block raf.seek(sptr); raf.readFully(iBuffer, 0, iBuffer.Length); l = 0; h = blockLen / blen; long sip, eip, dataptr = 0; while (l <= h) { int m = (l + h) >> 1; int p = m * blen; sip = Util.getIntLong(iBuffer, p); if (ip < sip) { h = m - 1; } else { eip = Util.getIntLong(iBuffer, p + 4); if (ip > eip) { l = m + 1; } else { dataptr = Util.getIntLong(iBuffer, p + 8); break; } } } //not matched if (dataptr == 0) { return(null); } //3. get the data int dataLen = (int)((dataptr >> 24) & 0xFF); int dataPtr = (int)((dataptr & 0x00FFFFFF)); raf.seek(dataPtr); byte[] data = new byte[dataLen]; raf.readFully(data, 0, data.Length); int city_id = (int)Util.getIntLong(data, 0); //String region = new String(data, 4, data.Length - 4, "UTF-8"); var region = Encoding.UTF8.GetString(data, 4, data.Length); return(new DataBlock(city_id, region, dataPtr)); }
/** * make the Db file * * @param dbFile target output file path * @ */ public void make(String dbFile) { //check and load the gloabl region if (globalRegionFile != null) { Console.WriteLine("+-Try to load the global region data ..."); BufferedReader greader = new BufferedReader(new FileReader(globalRegionFile)); String gline = null; while ((gline = greader.readLine()) != null) { String[] p = gline.split(","); if (p.Length != 5) { continue; } //push the mapping globalRegionMap.put(p[2], Int32.Parse(p[0])); } greader.close(); Console.WriteLine("|--[Ok]"); } //alloc the header size BufferedReader reader = new BufferedReader(new FileReader(this.ipSrcFile)); RandomAccessFile raf = new RandomAccessFile(dbFile, "rw"); //init the db file initDbFile(raf); Console.WriteLine("+-Db file initialized."); //analysis main loop Console.WriteLine("+-Try to write the data blocks ... "); String line = null; while ((line = reader.readLine()) != null) { line = line.trim(); if (line.length() == 0) { continue; } if (line.charAt(0) == '#') { continue; } //1. get the start ip int sIdx = 0, eIdx = 0; if ((eIdx = line.indexOf('|', sIdx + 1)) == -1) { continue; } String startIp = line.substring(sIdx, eIdx); //2. get the end ip sIdx = eIdx + 1; if ((eIdx = line.indexOf('|', sIdx + 1)) == -1) { continue; } String endIp = line.substring(sIdx, eIdx); //3. get the region sIdx = eIdx + 1; String region = line.substring(sIdx); Console.WriteLine("+-Try to process item " + line); addDataBlock(raf, startIp, endIp, region); Console.WriteLine("|--[Ok]"); } Console.WriteLine("|--Data block flushed!"); Console.WriteLine("|--Data file pointer: " + raf.getFilePointer() + "\n"); //write the index bytes Console.WriteLine("+-Try to write index blocks ... "); //record the start block IndexBlock indexBlock = null; HeaderBlock hb = null; indexBlock = indexPool.getFirst(); long indexStartIp = indexBlock.getStartIp(), indexStratPtr = raf.getFilePointer(), indexEndPtr; headerPool.add(new HeaderBlock(indexStartIp, (int)(indexStratPtr))); int blockLength = IndexBlock.getIndexBlockLength(); int counter = 0, shotCounter = (dbConfig.getIndexBlockSize() / blockLength) - 1; //var indexIt = indexPool.iterator(); //while (indexIt.hasNext()) foreach (var indexIt in indexPool.iterator()) { indexBlock = indexIt; if (++counter >= shotCounter) { hb = new HeaderBlock( indexBlock.getStartIp(), (int)raf.getFilePointer() ); headerPool.add(hb); counter = 0; } //write the buffer raf.write(indexBlock.getBytes()); } //record the end block if (counter > 0) { indexBlock = indexPool.getLast(); hb = new HeaderBlock( indexBlock.getStartIp(), ((int)raf.getFilePointer()) - IndexBlock.getIndexBlockLength() ); headerPool.add(hb); } indexEndPtr = raf.getFilePointer(); Console.WriteLine("|--[Ok]"); //write the super blocks Console.WriteLine("+-Try to write the super blocks ... "); raf.seek(0L); //reset the file pointer byte[] superBuffer = new byte[8]; Util.writeIntLong(superBuffer, 0, indexStratPtr); Util.writeIntLong(superBuffer, 4, indexEndPtr - blockLength); raf.write(superBuffer); Console.WriteLine("|--[Ok]"); //write the header blocks Console.WriteLine("+-Try to write the header blocks ... "); //var headerIt = headerPool.iterator(); //while (headerIt.hasNext()) //{ // HeaderBlock headerBlock = headerIt.next(); // raf.write(headerBlock.getBytes()); //} foreach (var headerBlock in headerPool.iterator()) { raf.write(headerBlock.getBytes()); } //write the copyright and the release timestamp info Console.WriteLine("+-Try to write the copyright and release date info ... "); raf.seek(raf.length()); //Calendar cal = Calendar.getInstance(); //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); String copyright = "Created by lionsoul at " + DateTime.Now.ToString("yyyy/MM/dd"); //dateFormat.format(cal.getTime()); var timestamp = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000; raf.write((Int32)timestamp); //the unix timestamp raf.write(copyright.getBytes()); Console.WriteLine("|--[Ok]"); reader.close(); raf.close(); }