rename to Java style.
This commit is contained in:
parent
37c6349f10
commit
9843232542
|
|
@ -1,47 +1,89 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DbMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// data block class
|
||||
/// </summary>
|
||||
|
||||
/**
|
||||
* data block class
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
*/
|
||||
public class DataBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// construct method
|
||||
/// </summary>
|
||||
/// <param name="cityId"></param>
|
||||
/// <param name="region"></param>
|
||||
/// <param name="dataPtr"></param>
|
||||
public DataBlock(int cityId, string region, int dataPtr)
|
||||
/**
|
||||
* city id
|
||||
*/
|
||||
private int city_id;
|
||||
|
||||
/**
|
||||
* region address
|
||||
*/
|
||||
private String region;
|
||||
|
||||
/**
|
||||
* region ptr in the db file
|
||||
*/
|
||||
private int dataPtr;
|
||||
|
||||
/**
|
||||
* construct method
|
||||
*
|
||||
* @param city_id
|
||||
* @param region region string
|
||||
* @param dataPtr data ptr
|
||||
*/
|
||||
public DataBlock(int city_id, String region, int dataPtr)
|
||||
{
|
||||
CityId = cityId;
|
||||
Region = region;
|
||||
DataPtr = dataPtr;
|
||||
this.city_id = city_id;
|
||||
this.region = region;
|
||||
this.dataPtr = dataPtr;
|
||||
}
|
||||
|
||||
public DataBlock(int cityId, string region) : this(cityId, region, 0)
|
||||
public DataBlock(int city_id, String region) : this(city_id, region, 0)
|
||||
{
|
||||
//this(city_id, region, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// city id
|
||||
/// </summary>
|
||||
public int CityId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// region address
|
||||
/// </summary>
|
||||
public string Region { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// region ptr in the db file
|
||||
/// </summary>
|
||||
public int DataPtr { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
public int getCityId()
|
||||
{
|
||||
return String.Join("|", this.CityId, this.Region, this.DataPtr);
|
||||
return city_id;
|
||||
}
|
||||
|
||||
public DataBlock setCityId(int city_id)
|
||||
{
|
||||
this.city_id = city_id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRegion()
|
||||
{
|
||||
return region;
|
||||
}
|
||||
|
||||
public DataBlock setRegion(String region)
|
||||
{
|
||||
this.region = region;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDataPtr()
|
||||
{
|
||||
return dataPtr;
|
||||
}
|
||||
|
||||
public DataBlock setDataPtr(int dataPtr)
|
||||
{
|
||||
this.dataPtr = dataPtr;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append(city_id).Append('|').Append(region).Append('|').Append(dataPtr);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DbMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// database configuration class
|
||||
/// </summary>
|
||||
|
||||
/**
|
||||
* database configuration class
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
*/
|
||||
public class DbConfig
|
||||
{
|
||||
/**
|
||||
* total header data block size
|
||||
*/
|
||||
private int totalHeaderSize;
|
||||
|
||||
/**
|
||||
* max index data block size
|
||||
* u should always choice the fastest read block size
|
||||
*/
|
||||
private int indexBlockSize;
|
||||
|
||||
/**
|
||||
* construct method
|
||||
*
|
||||
* @param totalHeaderSize
|
||||
* @throws DbMakerConfigException
|
||||
*/
|
||||
public DbConfig(int totalHeaderSize)
|
||||
{
|
||||
if (totalHeaderSize % 8 != 0)
|
||||
if ((totalHeaderSize % 8) != 0)
|
||||
{
|
||||
throw new DbMakerConfigException("totalHeaderSize must be times of 8");
|
||||
}
|
||||
|
||||
TotalHeaderSize = totalHeaderSize;
|
||||
IndexBlockSize = 8192; //4*2048
|
||||
this.totalHeaderSize = totalHeaderSize;
|
||||
this.indexBlockSize = 8192; //4 * 2048
|
||||
}
|
||||
|
||||
public DbConfig() : this(8 * 2048)
|
||||
{
|
||||
|
||||
//this(8 * 2048);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// total header data block size
|
||||
/// </summary>
|
||||
public int TotalHeaderSize { get; set; }
|
||||
/// <summary>
|
||||
/// max index data block size
|
||||
/// u should always choice the fastest read block size
|
||||
/// </summary>
|
||||
public int IndexBlockSize { get; set; }
|
||||
|
||||
public DbConfig SetTotalHeaderSize(int totalHeaderSize)
|
||||
public int getTotalHeaderSize()
|
||||
{
|
||||
this.TotalHeaderSize = totalHeaderSize;
|
||||
return totalHeaderSize;
|
||||
}
|
||||
|
||||
public DbConfig setTotalHeaderSize(int totalHeaderSize)
|
||||
{
|
||||
this.totalHeaderSize = totalHeaderSize;
|
||||
return this;
|
||||
}
|
||||
public DbConfig SetIndexBlockSize(int dataBlockSize)
|
||||
|
||||
public int getIndexBlockSize()
|
||||
{
|
||||
this.IndexBlockSize = dataBlockSize;
|
||||
return indexBlockSize;
|
||||
}
|
||||
|
||||
public DbConfig setIndexBlockSize(int dataBlockSize)
|
||||
{
|
||||
this.indexBlockSize = dataBlockSize;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
namespace DbMaker
|
||||
{
|
||||
class DbMakerConfigException : Exception
|
||||
public class DbMakerConfigException : Exception
|
||||
{
|
||||
public DbMakerConfigException(String message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DbMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// ip db searcher class (Not thread safe)
|
||||
/// </summary>
|
||||
|
||||
/**
|
||||
* ip db searcher class (Not thread safe)
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
*/
|
||||
public class DbSearcher : IDisposable
|
||||
{
|
||||
public const int BTREE_ALGORITHM = 1;
|
||||
|
|
@ -14,53 +16,57 @@ namespace DbMaker
|
|||
public const int MEMORY_ALGORITYM = 3;
|
||||
|
||||
/**
|
||||
* for memory mode
|
||||
* the original db binary string
|
||||
*/
|
||||
private byte[] dbBinStr;
|
||||
* db config
|
||||
*/
|
||||
private DbConfig dbConfig = null;
|
||||
|
||||
/**
|
||||
* super blocks info
|
||||
*/
|
||||
private long firstIndexPtr;
|
||||
* db file access handler
|
||||
*/
|
||||
private RandomAccessFile raf = null;
|
||||
|
||||
/**
|
||||
* header blocks buffer
|
||||
*/
|
||||
private long[] HeaderSip = null;
|
||||
|
||||
private int[] HeaderPtr = null;
|
||||
private int headerLength;
|
||||
private int[] HeaderPtr;
|
||||
|
||||
/**
|
||||
* header blocks buffer
|
||||
*/
|
||||
private long[] HeaderSip;
|
||||
* super blocks info
|
||||
*/
|
||||
private long firstIndexPtr = 0;
|
||||
|
||||
private long lastIndexPtr;
|
||||
private long lastIndexPtr = 0;
|
||||
private int totalIndexBlocks = 0;
|
||||
|
||||
/**
|
||||
* db file access handler
|
||||
*/
|
||||
private readonly Stream raf;
|
||||
|
||||
private int totalIndexBlocks;
|
||||
* for memory mode
|
||||
* the original db binary string
|
||||
*/
|
||||
private byte[] dbBinStr = null;
|
||||
|
||||
/**
|
||||
* construct class
|
||||
*
|
||||
* @param bdConfig
|
||||
* @param dbFile
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public DbSearcher(DbConfig dbConfig, string dbFile)
|
||||
* construct class
|
||||
*
|
||||
* @param bdConfig
|
||||
* @param dbFile
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public DbSearcher(DbConfig dbConfig, String dbFile)
|
||||
{
|
||||
this.dbConfig = dbConfig;
|
||||
raf = File.OpenRead(dbFile); //new RandomAccessFile(dbFile, "r");
|
||||
raf = new RandomAccessFile(dbFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
* 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;
|
||||
|
|
@ -68,34 +74,24 @@ namespace DbMaker
|
|||
|
||||
firstIndexPtr = Util.getIntLong(dbBinStr, 0);
|
||||
lastIndexPtr = Util.getIntLong(dbBinStr, 4);
|
||||
totalIndexBlocks = (int) ((lastIndexPtr - firstIndexPtr) / IndexBlock.GetIndexBlockLength()) + 1;
|
||||
totalIndexBlocks = (int) ((lastIndexPtr - firstIndexPtr) / IndexBlock.getIndexBlockLength()) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* db config
|
||||
*/
|
||||
public DbConfig dbConfig { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
* get the region with a int ip address with memory binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock memorySearch(long ip)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region with a int ip address with memory binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock MemorySearch(long ip)
|
||||
{
|
||||
var blen = IndexBlock.GetIndexBlockLength();
|
||||
int blen = IndexBlock.getIndexBlockLength();
|
||||
if (dbBinStr == null)
|
||||
{
|
||||
dbBinStr = new byte[(int) raf.Length];
|
||||
raf.Seek(0L, SeekOrigin.Begin);
|
||||
//raf.readFully(dbBinStr, 0, dbBinStr.length);
|
||||
raf.Read(dbBinStr, 0, dbBinStr.Length);
|
||||
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);
|
||||
|
|
@ -107,8 +103,8 @@ namespace DbMaker
|
|||
long sip, eip, dataptr = 0;
|
||||
while (l <= h)
|
||||
{
|
||||
var m = l + h >> 1;
|
||||
var p = (int) (firstIndexPtr + m * blen);
|
||||
int m = (l + h) >> 1;
|
||||
int p = (int) (firstIndexPtr + m * blen);
|
||||
|
||||
sip = Util.getIntLong(dbBinStr, p);
|
||||
if (ip < sip)
|
||||
|
|
@ -131,95 +127,89 @@ namespace DbMaker
|
|||
}
|
||||
|
||||
//not matched
|
||||
if (dataptr == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (dataptr == 0) return null;
|
||||
|
||||
//get the data
|
||||
var dataLen = (int) (dataptr >> 24 & 0xFF);
|
||||
var dataPtr = (int) (dataptr & 0x00FFFFFF);
|
||||
var city_id = (int) Util.getIntLong(dbBinStr, dataPtr);
|
||||
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);
|
||||
var region = ReadString(dbBinStr, dataPtr + 4, dataLen - 4);
|
||||
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)
|
||||
private string ReadString(byte[] bytes, int dataPtr, int dataLen)
|
||||
{
|
||||
return MemorySearch(Util.ip2long(ip));
|
||||
return Encoding.UTF8.GetString(bytes, dataPtr, dataLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region throught the ip address with memory binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock memorySearch(String ip)
|
||||
{
|
||||
return memorySearch(Util.ip2long(ip));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get by index ptr
|
||||
*
|
||||
* @param indexPtr
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock GetByIndexPtr(long ptr)
|
||||
* get by index ptr
|
||||
*
|
||||
* @param indexPtr
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock getByIndexPtr(long ptr)
|
||||
{
|
||||
raf.Seek(ptr, SeekOrigin.Begin);
|
||||
var
|
||||
buffer = new byte[12];
|
||||
//raf.readFully(buffer, 0, buffer.length);
|
||||
raf.Read(buffer, 0, buffer.Length);
|
||||
raf.seek(ptr);
|
||||
byte[] buffer = new byte[12];
|
||||
raf.readFully(buffer, 0, buffer.Length);
|
||||
//long startIp = Util.getIntLong(buffer, 0);
|
||||
//long endIp = Util.getIntLong(buffer, 4);
|
||||
var extra = Util.getIntLong(buffer, 8);
|
||||
long extra = Util.getIntLong(buffer, 8);
|
||||
|
||||
var dataLen = (int) (extra >> 24 & 0xFF);
|
||||
var dataPtr = (int) (extra & 0x00FFFFFF);
|
||||
int dataLen = (int) ((extra >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((extra & 0x00FFFFFF));
|
||||
|
||||
raf.Seek(dataPtr, SeekOrigin.Begin);
|
||||
var data = new byte[dataLen];
|
||||
//raf.readFully(data, 0, data.length);
|
||||
raf.Read(data, 0, data.Length);
|
||||
var 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);
|
||||
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 = ReadString(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
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock BTreeSearch(long ip)
|
||||
* get the region with a int ip address with b-tree algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock btreeSearch(long ip)
|
||||
{
|
||||
//check and load the header
|
||||
if (HeaderSip == null)
|
||||
{
|
||||
//raf.seek(8L); //pass the super block
|
||||
raf.Seek(8, SeekOrigin.Begin);
|
||||
var b = new byte[dbConfig.TotalHeaderSize];
|
||||
raf.seek(8L); //pass the super block
|
||||
byte[] b = new byte[dbConfig.getTotalHeaderSize()];
|
||||
// byte[] b = new byte[4096];
|
||||
//raf.readFully(b, 0, b.length);
|
||||
raf.Read(b, 0, b.Length);
|
||||
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;
|
||||
long xDataPtr = 0;
|
||||
for (var i = 0; i < b.Length; i += 8)
|
||||
HeaderPtr = new int [len];
|
||||
long startIp, xDataPtr;
|
||||
for (int i = 0; i < b.Length; i += 8)
|
||||
{
|
||||
startIp = Util.getIntLong(b, i);
|
||||
xDataPtr = Util.getIntLong(b, i + 4);
|
||||
if (xDataPtr == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (xDataPtr == 0) break;
|
||||
|
||||
HeaderSip[idx] = startIp;
|
||||
HeaderPtr[idx] = (int) xDataPtr;
|
||||
|
|
@ -232,18 +222,17 @@ namespace DbMaker
|
|||
//1. define the index block with the binary search
|
||||
if (ip == HeaderSip[0])
|
||||
{
|
||||
return GetByIndexPtr(HeaderPtr[0]);
|
||||
return getByIndexPtr(HeaderPtr[0]);
|
||||
}
|
||||
|
||||
if (ip == HeaderSip[headerLength - 1])
|
||||
else if (ip == HeaderSip[headerLength - 1])
|
||||
{
|
||||
return GetByIndexPtr(HeaderPtr[headerLength - 1]);
|
||||
return getByIndexPtr(HeaderPtr[headerLength - 1]);
|
||||
}
|
||||
|
||||
int l = 0, h = headerLength, sptr = 0, eptr = 0;
|
||||
while (l <= h)
|
||||
{
|
||||
var m = l + h >> 1;
|
||||
int m = (l + h) >> 1;
|
||||
|
||||
//perfetc matched, just return it
|
||||
if (ip == HeaderSip[m])
|
||||
|
|
@ -271,8 +260,7 @@ namespace DbMaker
|
|||
eptr = HeaderPtr[m + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
if (ip > HeaderSip[m - 1])
|
||||
else if (ip > HeaderSip[m - 1])
|
||||
{
|
||||
sptr = HeaderPtr[m - 1];
|
||||
eptr = HeaderPtr[m];
|
||||
|
|
@ -289,8 +277,7 @@ namespace DbMaker
|
|||
eptr = HeaderPtr[m];
|
||||
break;
|
||||
}
|
||||
|
||||
if (ip <= HeaderSip[m + 1])
|
||||
else if (ip <= HeaderSip[m + 1])
|
||||
{
|
||||
sptr = HeaderPtr[m];
|
||||
eptr = HeaderPtr[m + 1];
|
||||
|
|
@ -302,27 +289,21 @@ namespace DbMaker
|
|||
}
|
||||
|
||||
//match nothing just stop it
|
||||
if (sptr == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (sptr == 0) return null;
|
||||
|
||||
//2. search the index blocks to define the data
|
||||
int blockLen = eptr - sptr, blen = IndexBlock.GetIndexBlockLength();
|
||||
var
|
||||
iBuffer = new byte[blockLen + blen]; //include the right border block
|
||||
//raf.seek(sptr);
|
||||
//raf.readFully(iBuffer, 0, iBuffer.length);
|
||||
raf.Seek(sptr, SeekOrigin.Begin);
|
||||
raf.Read(iBuffer, 0, iBuffer.Length);
|
||||
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)
|
||||
{
|
||||
var m = l + h >> 1;
|
||||
var p = m * blen;
|
||||
int m = (l + h) >> 1;
|
||||
int p = m * blen;
|
||||
sip = Util.getIntLong(iBuffer, p);
|
||||
if (ip < sip)
|
||||
{
|
||||
|
|
@ -344,54 +325,48 @@ namespace DbMaker
|
|||
}
|
||||
|
||||
//not matched
|
||||
if (dataptr == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (dataptr == 0) return null;
|
||||
|
||||
//3. get the data
|
||||
var dataLen = (int) (dataptr >> 24 & 0xFF);
|
||||
var dataPtr = (int) (dataptr & 0x00FFFFFF);
|
||||
int dataLen = (int) ((dataptr >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
|
||||
|
||||
//raf.seek(dataPtr);
|
||||
var data = new byte[dataLen];
|
||||
// raf.readFully(data, 0, data.length);
|
||||
raf.Seek(dataPtr, SeekOrigin.Begin);
|
||||
raf.Read(data, 0, data.Length);
|
||||
var 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);
|
||||
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 = ReadString(data, 4, data.Length - 4);
|
||||
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
|
||||
*/
|
||||
public DataBlock BTreeSearch(string ip)
|
||||
* get the region throught the ip address with b-tree search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock btreeSearch(String ip)
|
||||
{
|
||||
return BTreeSearch(Util.ip2long(ip));
|
||||
return btreeSearch(Util.ip2long(ip));
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region with a int ip address with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock BinarySearch(long ip)
|
||||
* get the region with a int ip address with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock binarySearch(long ip)
|
||||
{
|
||||
var blen = IndexBlock.GetIndexBlockLength();
|
||||
int blen = IndexBlock.getIndexBlockLength();
|
||||
if (totalIndexBlocks == 0)
|
||||
{
|
||||
//raf.seek(0L);
|
||||
var superBytes = new byte[8];
|
||||
//raf.readFully(superBytes, 0, superBytes.length);
|
||||
raf.Seek(0, SeekOrigin.Begin);
|
||||
raf.Read(superBytes, 0, superBytes.Length);
|
||||
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);
|
||||
|
|
@ -400,16 +375,13 @@ namespace DbMaker
|
|||
|
||||
//search the index blocks to define the data
|
||||
int l = 0, h = totalIndexBlocks;
|
||||
var
|
||||
buffer = new byte[blen];
|
||||
byte[] buffer = new byte[blen];
|
||||
long sip, eip, dataptr = 0;
|
||||
while (l <= h)
|
||||
{
|
||||
var m = l + h >> 1;
|
||||
//raf.seek(firstIndexPtr + m * blen); //set the file pointer
|
||||
//raf.readFully(buffer, 0, buffer.length);
|
||||
raf.Seek(firstIndexPtr + m * blen, SeekOrigin.Begin);
|
||||
raf.Read(buffer, 0, buffer.Length);
|
||||
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)
|
||||
{
|
||||
|
|
@ -431,51 +403,61 @@ namespace DbMaker
|
|||
}
|
||||
|
||||
//not matched
|
||||
if (dataptr == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (dataptr == 0) return null;
|
||||
|
||||
//get the data
|
||||
var dataLen = (int) (dataptr >> 24 & 0xFF);
|
||||
var dataPtr = (int) (dataptr & 0x00FFFFFF);
|
||||
int dataLen = (int) ((dataptr >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
|
||||
|
||||
//raf.seek(dataPtr);
|
||||
var data = new byte[dataLen];
|
||||
//raf.readFully(data, 0, data.length);
|
||||
raf.Seek(dataPtr, SeekOrigin.Begin);
|
||||
raf.Read(data, 0, data.Length);
|
||||
raf.seek(dataPtr);
|
||||
byte[] data = new byte[dataLen];
|
||||
raf.readFully(data, 0, data.Length);
|
||||
|
||||
var 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);
|
||||
int city_id = (int) Util.getIntLong(data, 0);
|
||||
//String region = new String(data, 4, data.Length - 4, "UTF-8");
|
||||
var region = ReadString(data, 4, data.Length - 4);
|
||||
return new DataBlock(city_id, region, dataPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region throught the ip address with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock BinarySearch(string ip)
|
||||
* get the region throught the ip address with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock binarySearch(String ip)
|
||||
{
|
||||
return BinarySearch(Util.ip2long(ip));
|
||||
return binarySearch(Util.ip2long(ip));
|
||||
}
|
||||
|
||||
/**
|
||||
* get the db config
|
||||
*
|
||||
* @return DbConfig
|
||||
*/
|
||||
public DbConfig getDbConfig()
|
||||
{
|
||||
return dbConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* close the db
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void Close()
|
||||
* close the db
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void close()
|
||||
{
|
||||
HeaderSip = null; //let gc do its work
|
||||
HeaderPtr = null;
|
||||
dbBinStr = null;
|
||||
raf?.Close();
|
||||
raf.close();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,43 +1,57 @@
|
|||
namespace DbMaker
|
||||
namespace DbMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// header block class
|
||||
/// </summary>
|
||||
|
||||
/**
|
||||
* header block class
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
*/
|
||||
public class HeaderBlock
|
||||
{
|
||||
/**
|
||||
* index block start ip address
|
||||
*/
|
||||
private long indexStartIp;
|
||||
|
||||
/**
|
||||
* ip address
|
||||
*/
|
||||
private int indexPtr;
|
||||
|
||||
public HeaderBlock(long indexStartIp, int indexPtr)
|
||||
{
|
||||
IndexStartIp = indexStartIp;
|
||||
IndexPtr = indexPtr;
|
||||
this.indexStartIp = indexStartIp;
|
||||
this.indexPtr = indexPtr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// index block start ip address
|
||||
/// </summary>
|
||||
public long IndexStartIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ip address
|
||||
/// </summary>
|
||||
public int IndexPtr { get; set; }
|
||||
|
||||
public HeaderBlock SetIndexStartIp(long indexStartIp)
|
||||
public long getIndexStartIp()
|
||||
{
|
||||
IndexStartIp = indexStartIp;
|
||||
return indexStartIp;
|
||||
}
|
||||
|
||||
public HeaderBlock setIndexStartIp(long indexStartIp)
|
||||
{
|
||||
this.indexStartIp = indexStartIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HeaderBlock SetIndexPtr(int indexPtr)
|
||||
public int getIndexPtr()
|
||||
{
|
||||
IndexPtr = indexPtr;
|
||||
return indexPtr;
|
||||
}
|
||||
|
||||
public HeaderBlock setIndexPtr(int indexPtr)
|
||||
{
|
||||
this.indexPtr = indexPtr;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get the bytes for db storage
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes()
|
||||
/**
|
||||
* get the bytes for db storage
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getBytes()
|
||||
{
|
||||
/*
|
||||
* +------------+-----------+
|
||||
|
|
@ -45,11 +59,10 @@
|
|||
* +------------+-----------+
|
||||
* start ip index ptr
|
||||
*/
|
||||
byte[] b = new byte[8];
|
||||
|
||||
var b = new byte[8];
|
||||
|
||||
Util.writeIntLong(b, 0, IndexStartIp);
|
||||
Util.writeIntLong(b, 4, IndexPtr);
|
||||
Util.writeIntLong(b, 0, indexStartIp);
|
||||
Util.writeIntLong(b, 4, indexPtr);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +1,88 @@
|
|||
namespace DbMaker
|
||||
namespace DbMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// item index class
|
||||
/// </summary>
|
||||
|
||||
/**
|
||||
* item index class
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
*/
|
||||
public class IndexBlock
|
||||
{
|
||||
private static int LENGTH = 12;
|
||||
|
||||
/**
|
||||
* start ip address
|
||||
*/
|
||||
private long startIp;
|
||||
|
||||
/**
|
||||
* end ip address
|
||||
*/
|
||||
private long endIp;
|
||||
|
||||
/**
|
||||
* data ptr and data length
|
||||
*/
|
||||
private int dataPtr;
|
||||
|
||||
/**
|
||||
* data length
|
||||
*/
|
||||
private int dataLen;
|
||||
|
||||
public IndexBlock(long startIp, long endIp, int dataPtr, int dataLen)
|
||||
{
|
||||
StartIp = startIp;
|
||||
EndIp = endIp;
|
||||
DataPtr = dataPtr;
|
||||
DataLen = dataLen;
|
||||
this.startIp = startIp;
|
||||
this.endIp = endIp;
|
||||
this.dataPtr = dataPtr;
|
||||
this.dataLen = dataLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* start ip address
|
||||
*/
|
||||
public long StartIp { get; set; }
|
||||
|
||||
/**
|
||||
* end ip address
|
||||
*/
|
||||
public long EndIp { get; set; }
|
||||
|
||||
/**
|
||||
* data ptr and data length
|
||||
*/
|
||||
public int DataPtr { get; set; }
|
||||
|
||||
/**
|
||||
* data length
|
||||
*/
|
||||
public int DataLen { get; set; }
|
||||
|
||||
public IndexBlock SetStartIp(long startIp)
|
||||
public long getStartIp()
|
||||
{
|
||||
StartIp = startIp;
|
||||
return startIp;
|
||||
}
|
||||
|
||||
public IndexBlock setStartIp(long startIp)
|
||||
{
|
||||
this.startIp = startIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexBlock SetEndIp(long endIp)
|
||||
public long getEndIp()
|
||||
{
|
||||
EndIp = endIp;
|
||||
return endIp;
|
||||
}
|
||||
|
||||
public IndexBlock setEndIp(long endIp)
|
||||
{
|
||||
this.endIp = endIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexBlock SetDataPtr(int dataPtr)
|
||||
public int getDataPtr()
|
||||
{
|
||||
DataPtr = dataPtr;
|
||||
return dataPtr;
|
||||
}
|
||||
|
||||
public IndexBlock setDataPtr(int dataPtr)
|
||||
{
|
||||
this.dataPtr = dataPtr;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IndexBlock SetDataLen(int dataLen)
|
||||
public int getDataLen()
|
||||
{
|
||||
DataLen = dataLen;
|
||||
return dataLen;
|
||||
}
|
||||
|
||||
public IndexBlock setDataLen(int dataLen)
|
||||
{
|
||||
this.dataLen = dataLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static int GetIndexBlockLength()
|
||||
public static int getIndexBlockLength()
|
||||
{
|
||||
return LENGTH;
|
||||
}
|
||||
|
|
@ -69,7 +92,7 @@
|
|||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] GetBytes()
|
||||
public byte[] getBytes()
|
||||
{
|
||||
/*
|
||||
* +------------+-----------+-----------+
|
||||
|
|
@ -77,13 +100,13 @@
|
|||
* +------------+-----------+-----------+
|
||||
* start ip end ip data ptr + len
|
||||
*/
|
||||
var b = new byte[12];
|
||||
byte[] b = new byte[12];
|
||||
|
||||
Util.writeIntLong(b, 0, StartIp); //start ip
|
||||
Util.writeIntLong(b, 4, EndIp); //end ip
|
||||
Util.writeIntLong(b, 0, startIp); //start ip
|
||||
Util.writeIntLong(b, 4, endIp); //end ip
|
||||
|
||||
//write the data ptr and the length
|
||||
var mix = DataPtr | DataLen << 24 & 0xFF000000L;
|
||||
long mix = dataPtr | ((dataLen << 24) & 0xFF000000L);
|
||||
Util.writeIntLong(b, 8, mix);
|
||||
|
||||
return b;
|
||||
|
|
|
|||
|
|
@ -6,13 +6,7 @@ namespace DbMaker
|
|||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var fn = @"G:\src\ip2region\data\ip2region.db";
|
||||
using (var searcher = new DbSearcher(new DbConfig(), fn))
|
||||
{
|
||||
Console.WriteLine(searcher.BinarySearch("202.102.227.68"));
|
||||
Console.WriteLine(searcher.BTreeSearch("202.102.227.68"));
|
||||
Console.ReadLine();
|
||||
}
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DbMaker
|
||||
{
|
||||
public class RandomAccessFile : IDisposable
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
|
||||
public RandomAccessFile(String file) : this(File.OpenRead(file))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public RandomAccessFile(Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_stream?.Dispose();
|
||||
}
|
||||
|
||||
public long length()
|
||||
{
|
||||
return _stream.Length;
|
||||
}
|
||||
|
||||
public void seek(long position)
|
||||
{
|
||||
_stream.Seek(position, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public void readFully(byte[] dbBinStr, int offset, int count)
|
||||
{
|
||||
_stream.Read(dbBinStr, offset, count);
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
_stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DbMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// util class
|
||||
/// </summary>
|
||||
public static class Util
|
||||
|
||||
|
||||
/**
|
||||
* util class
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
*/
|
||||
public class Util
|
||||
{
|
||||
/**
|
||||
* write specfield bytes to a byte array start from offset
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
* @param v
|
||||
* @param bytes
|
||||
*/
|
||||
* write specfield bytes to a byte array start from offset
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
* @param v
|
||||
* @param bytes
|
||||
*/
|
||||
public static void write(byte[] b, int offset, long v, int bytes)
|
||||
{
|
||||
for (int i = 0; i < bytes; i++)
|
||||
{
|
||||
b[offset++] = (byte)((v >> (8 * i)) & 0xFF);
|
||||
//b[offset++] = (byte)((v >>> (8 * i)) & 0xFF);
|
||||
b[offset++] = (byte) ((v >> (8 * i)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,10 +38,10 @@ namespace DbMaker
|
|||
*/
|
||||
public static void writeIntLong(byte[] b, int offset, long v)
|
||||
{
|
||||
b[offset++] = (byte)((v >> 0) & 0xFF);
|
||||
b[offset++] = (byte)((v >> 8) & 0xFF);
|
||||
b[offset++] = (byte)((v >> 16) & 0xFF);
|
||||
b[offset] = (byte)((v >> 24) & 0xFF);
|
||||
b[offset++] = (byte) ((v >> 0) & 0xFF);
|
||||
b[offset++] = (byte) ((v >> 8) & 0xFF);
|
||||
b[offset++] = (byte) ((v >> 16) & 0xFF);
|
||||
b[offset] = (byte) ((v >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,14 +98,16 @@ namespace DbMaker
|
|||
*/
|
||||
public static long ip2long(String ip)
|
||||
{
|
||||
ip = ip.Trim();
|
||||
String[] ips = ip.Split('.');
|
||||
long ip1 = Int64.Parse(ips[0]);
|
||||
long ip2 = Int64.Parse(ips[1]);
|
||||
long ip3 = Int64.Parse(ips[2]);
|
||||
long ip4 = Int64.Parse(ips[3]);
|
||||
long ip2long = 1L * ip1 * 256 * 256 * 256 + ip2 * 256 * 256 + ip3 * 256 + ip4;
|
||||
return ip2long;
|
||||
throw new NotImplementedException();
|
||||
//String[] p = ip.Split("\\.");
|
||||
//if ( p.Length != 4 ) return 0;
|
||||
|
||||
//int p1 = ((Convert.ToInt32(p[0]) << 24) & 0xFF000000);
|
||||
//int p2 = ((Integer.valueOf(p[1]) << 16) & 0x00FF0000);
|
||||
//int p3 = ((Integer.valueOf(p[2]) << 8) & 0x0000FF00);
|
||||
//int p4 = ((Integer.valueOf(p[3]) << 0) & 0x000000FF);
|
||||
|
||||
//return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -116,10 +121,10 @@ namespace DbMaker
|
|||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb
|
||||
.Append((ip >> 24) & 0xFF).Append('.')
|
||||
.Append((ip >> 16) & 0xFF).Append('.')
|
||||
.Append((ip >> 8) & 0xFF).Append('.')
|
||||
.Append((ip >> 0) & 0xFF);
|
||||
.Append((ip >> 24) & 0xFF).Append('.')
|
||||
.Append((ip >> 16) & 0xFF).Append('.')
|
||||
.Append((ip >> 8) & 0xFF).Append('.')
|
||||
.Append((ip >> 0) & 0xFF);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
|
@ -135,13 +140,16 @@ namespace DbMaker
|
|||
String[] p = ip.Split("\\.");
|
||||
if (p.Length != 4) return false;
|
||||
|
||||
//for ( String pp : p ) {
|
||||
//for ( String pp : p ) {
|
||||
foreach (var pp in p)
|
||||
{
|
||||
if (pp.Length > 3) return false;
|
||||
int val = Convert.ToInt32(pp); //Integer.valueOf(pp);
|
||||
int val = Int32.Parse(pp); //Integer.valueOf(pp);
|
||||
if (val > 255) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue