Skip to content

Commit 765591d

Browse files
committed
Reduced file I/O
1 parent 19d6e21 commit 765591d

File tree

3 files changed

+88
-103
lines changed

3 files changed

+88
-103
lines changed

LICENSE.TXT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2021 IP2Location.com
3+
Copyright (c) 2022 IP2Location.com
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[![Go Report Card](https://goreportcard.com/badge/github.com/ip2location/ip2proxy-go)](https://goreportcard.com/report/github.com/ip2location/ip2proxy-go)
1+
[![Go Report Card](https://goreportcard.com/badge/github.com/ip2location/ip2proxy-go)](https://goreportcard.com/report/github.com/ip2location/ip2proxy-go/v3)
22

33
# IP2Proxy Go Package
44

@@ -17,7 +17,7 @@ To install this module type the following:
1717

1818
```bash
1919

20-
go get github.com/ip2location/ip2proxy-go
20+
go get github.com/ip2location/ip2proxy-go/v3
2121

2222
```
2323

@@ -56,7 +56,7 @@ package main
5656

5757
import (
5858
"fmt"
59-
"github.com/ip2location/ip2proxy-go"
59+
"github.com/ip2location/ip2proxy-go/v3"
6060
)
6161

6262
func main() {
@@ -112,7 +112,7 @@ package main
112112

113113
import (
114114
"fmt"
115-
"github.com/ip2location/ip2proxy-go"
115+
"github.com/ip2location/ip2proxy-go/v3"
116116
)
117117

118118
func main() {

ip2proxy.go

Lines changed: 83 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ type ip2proxyMeta struct {
3232
ipV4DatabaseAddr uint32
3333
ipV6DatabaseCount uint32
3434
ipV6DatabaseAddr uint32
35+
ipV4Indexed bool
36+
ipV6Indexed bool
3537
ipV4IndexBaseAddr uint32
3638
ipV6IndexBaseAddr uint32
3739
ipV4ColumnSize uint32
@@ -109,7 +111,7 @@ var lastSeenPosition = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11}
109111
var threatPosition = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12}
110112
var providerPosition = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13}
111113

112-
const moduleVersion string = "3.3.2"
114+
const moduleVersion string = "3.4.0"
113115

114116
var maxIPV4Range = big.NewInt(4294967295)
115117
var maxIPV6Range = big.NewInt(0)
@@ -184,13 +186,13 @@ func (d *DB) checkIP(ip string) (ipType uint32, ipNum *big.Int, ipIndex uint32)
184186
}
185187
}
186188
if ipType == 4 {
187-
if d.meta.ipV4IndexBaseAddr > 0 {
189+
if d.meta.ipV4Indexed {
188190
ipNumTmp.Rsh(ipNum, 16)
189191
ipNumTmp.Lsh(ipNumTmp, 3)
190192
ipIndex = uint32(ipNumTmp.Add(ipNumTmp, big.NewInt(int64(d.meta.ipV4IndexBaseAddr))).Uint64())
191193
}
192194
} else if ipType == 6 {
193-
if d.meta.ipV6IndexBaseAddr > 0 {
195+
if d.meta.ipV6Indexed {
194196
ipNumTmp.Rsh(ipNum, 112)
195197
ipNumTmp.Lsh(ipNumTmp, 3)
196198
ipIndex = uint32(ipNumTmp.Add(ipNumTmp, big.NewInt(int64(d.meta.ipV6IndexBaseAddr))).Uint64())
@@ -211,6 +213,17 @@ func (d *DB) readUint8(pos int64) (uint8, error) {
211213
return retVal, nil
212214
}
213215

216+
// read row
217+
func (d *DB) readRow(pos uint32, size uint32) ([]byte, error) {
218+
pos2 := int64(pos)
219+
data := make([]byte, size)
220+
_, err := d.f.ReadAt(data, pos2-1)
221+
if err != nil {
222+
return nil, err
223+
}
224+
return data, nil
225+
}
226+
214227
// read unsigned 32-bit integer from slices
215228
func (d *DB) readUint32Row(row []byte, pos uint32) uint32 {
216229
var retVal uint32
@@ -236,6 +249,19 @@ func (d *DB) readUint32(pos uint32) (uint32, error) {
236249
return retVal, nil
237250
}
238251

252+
// read unsigned 128-bit integer from slices
253+
func (d *DB) readUint128Row(row []byte, pos uint32) *big.Int {
254+
retVal := big.NewInt(0)
255+
data := row[pos : pos+16]
256+
257+
// little endian to big endian
258+
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
259+
data[i], data[j] = data[j], data[i]
260+
}
261+
retVal.SetBytes(data)
262+
return retVal
263+
}
264+
239265
// read unsigned 128-bit integer
240266
func (d *DB) readUint128(pos uint32) (*big.Int, error) {
241267
pos2 := int64(pos)
@@ -257,19 +283,15 @@ func (d *DB) readUint128(pos uint32) (*big.Int, error) {
257283
// read string
258284
func (d *DB) readStr(pos uint32) (string, error) {
259285
pos2 := int64(pos)
286+
readLen := 256 // max size of string field + 1 byte for the length
260287
var retVal string
261-
lenByte := make([]byte, 1)
262-
_, err := d.f.ReadAt(lenByte, pos2)
263-
if err != nil {
264-
return "", err
265-
}
266-
strLen := lenByte[0]
267-
data := make([]byte, strLen)
268-
_, err = d.f.ReadAt(data, pos2+1)
288+
data := make([]byte, readLen)
289+
_, err := d.f.ReadAt(data, pos2)
269290
if err != nil {
270291
return "", err
271292
}
272-
retVal = string(data[:strLen])
293+
strLen := data[0]
294+
retVal = string(data[1:(strLen + 1)])
273295
return retVal, nil
274296
}
275297

@@ -302,67 +324,42 @@ func OpenDBWithReader(reader dbReader) (*DB, error) {
302324

303325
db.f = reader
304326

327+
var row []byte
305328
var err error
306-
db.meta.databaseType, err = db.readUint8(1)
307-
if err != nil {
308-
return fatal(db, err)
309-
}
310-
db.meta.databaseColumn, err = db.readUint8(2)
311-
if err != nil {
312-
return fatal(db, err)
313-
}
314-
db.meta.databaseYear, err = db.readUint8(3)
315-
if err != nil {
316-
return fatal(db, err)
317-
}
318-
db.meta.databaseMonth, err = db.readUint8(4)
319-
if err != nil {
320-
return fatal(db, err)
321-
}
322-
db.meta.databaseDay, err = db.readUint8(5)
323-
if err != nil {
324-
return fatal(db, err)
325-
}
326-
db.meta.ipV4DatabaseCount, err = db.readUint32(6)
327-
if err != nil {
328-
return fatal(db, err)
329-
}
330-
db.meta.ipV4DatabaseAddr, err = db.readUint32(10)
331-
if err != nil {
332-
return fatal(db, err)
333-
}
334-
db.meta.ipV6DatabaseCount, err = db.readUint32(14)
335-
if err != nil {
336-
return fatal(db, err)
337-
}
338-
db.meta.ipV6DatabaseAddr, err = db.readUint32(18)
339-
if err != nil {
340-
return fatal(db, err)
341-
}
342-
db.meta.ipV4IndexBaseAddr, err = db.readUint32(22)
343-
if err != nil {
344-
return fatal(db, err)
345-
}
346-
db.meta.ipV6IndexBaseAddr, err = db.readUint32(26)
347-
if err != nil {
348-
return fatal(db, err)
349-
}
350-
db.meta.productCode, err = db.readUint8(30)
351-
if err != nil {
352-
return fatal(db, err)
353-
}
354-
db.meta.productType, err = db.readUint8(31)
355-
if err != nil {
356-
return fatal(db, err)
357-
}
358-
db.meta.fileSize, err = db.readUint32(32)
329+
readLen := uint32(64) // 64-byte header
330+
331+
row, err = db.readRow(1, readLen)
359332
if err != nil {
360333
return fatal(db, err)
361334
}
335+
db.meta.databaseType = row[0]
336+
db.meta.databaseColumn = row[1]
337+
db.meta.databaseYear = row[2]
338+
db.meta.databaseMonth = row[3]
339+
db.meta.databaseDay = row[4]
340+
db.meta.ipV4DatabaseCount = db.readUint32Row(row, 5)
341+
db.meta.ipV4DatabaseAddr = db.readUint32Row(row, 9)
342+
db.meta.ipV6DatabaseCount = db.readUint32Row(row, 13)
343+
db.meta.ipV6DatabaseAddr = db.readUint32Row(row, 17)
344+
db.meta.ipV4IndexBaseAddr = db.readUint32Row(row, 21)
345+
db.meta.ipV6IndexBaseAddr = db.readUint32Row(row, 25)
346+
db.meta.productCode = row[29]
347+
db.meta.productType = row[30]
348+
db.meta.fileSize = db.readUint32Row(row, 31)
349+
362350
// check if is correct BIN (should be 2 for IP2Proxy BIN file), also checking for zipped file (PK being the first 2 chars)
363351
if (db.meta.productCode != 2 && db.meta.databaseYear >= 21) || (db.meta.databaseType == 80 && db.meta.databaseColumn == 75) { // only BINs from Jan 2021 onwards have this byte set
364352
return fatal(db, errors.New(msgInvalidBin))
365353
}
354+
355+
if db.meta.ipV4IndexBaseAddr > 0 {
356+
db.meta.ipV4Indexed = true
357+
}
358+
359+
if db.meta.ipV6DatabaseCount > 0 && db.meta.ipV6IndexBaseAddr > 0 {
360+
db.meta.ipV6Indexed = true
361+
}
362+
366363
db.meta.ipV4ColumnSize = uint32(db.meta.databaseColumn << 2) // 4 bytes each column
367364
db.meta.ipV6ColumnSize = uint32(16 + ((db.meta.databaseColumn - 1) << 2)) // 4 bytes each column, except IPFrom column which is 16 bytes
368365

@@ -793,8 +790,11 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
793790
var high uint32
794791
var mid uint32
795792
var rowOffset uint32
796-
var rowOffset2 uint32
797793
var countryPos uint32
794+
var firstCol uint32 = 4 // 4 bytes for ip from
795+
var row []byte
796+
var fullRow []byte
797+
var readLen uint32
798798
ipFrom := big.NewInt(0)
799799
ipTo := big.NewInt(0)
800800
maxIP := big.NewInt(0)
@@ -809,6 +809,7 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
809809
x = loadMessage(msgIPV6Unsupported)
810810
return x, nil
811811
}
812+
firstCol = 16 // 16 bytes for ip from
812813
baseAddr = d.meta.ipV6DatabaseAddr
813814
high = d.meta.ipV6DatabaseCount
814815
maxIP = maxIPV6Range
@@ -817,14 +818,12 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
817818

818819
// reading index
819820
if ipIndex > 0 {
820-
low, err = d.readUint32(ipIndex)
821-
if err != nil {
822-
return x, err
823-
}
824-
high, err = d.readUint32(ipIndex + 4)
821+
row, err = d.readRow(ipIndex, 8) // 4 bytes each for IP From and IP To
825822
if err != nil {
826823
return x, err
827824
}
825+
low = d.readUint32Row(row, 0)
826+
high = d.readUint32Row(row, 4)
828827
}
829828

830829
if ipNo.Cmp(maxIP) >= 0 {
@@ -834,43 +833,29 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
834833
for low <= high {
835834
mid = ((low + high) >> 1)
836835
rowOffset = baseAddr + (mid * colSize)
837-
rowOffset2 = rowOffset + colSize
836+
837+
// reading IP From + whole row + next IP From
838+
readLen = colSize + firstCol
839+
fullRow, err = d.readRow(rowOffset, readLen)
840+
if err != nil {
841+
return x, err
842+
}
838843

839844
if ipType == 4 {
840-
ipFrom32, err := d.readUint32(rowOffset)
841-
if err != nil {
842-
return x, err
843-
}
845+
ipFrom32 := d.readUint32Row(fullRow, 0)
844846
ipFrom = big.NewInt(int64(ipFrom32))
845847

846-
ipTo32, err := d.readUint32(rowOffset2)
847-
if err != nil {
848-
return x, err
849-
}
848+
ipTo32 := d.readUint32Row(fullRow, colSize)
850849
ipTo = big.NewInt(int64(ipTo32))
851850
} else {
852-
ipFrom, err = d.readUint128(rowOffset)
853-
if err != nil {
854-
return x, err
855-
}
851+
ipFrom = d.readUint128Row(fullRow, 0)
856852

857-
ipTo, err = d.readUint128(rowOffset2)
858-
if err != nil {
859-
return x, err
860-
}
853+
ipTo = d.readUint128Row(fullRow, colSize)
861854
}
862855

863856
if ipNo.Cmp(ipFrom) >= 0 && ipNo.Cmp(ipTo) < 0 {
864-
var firstCol uint32 = 4 // 4 bytes for ip from
865-
if ipType == 6 {
866-
firstCol = 16 // 16 bytes for ipv6
867-
}
868-
869-
row := make([]byte, colSize-firstCol) // exclude the ip from field
870-
_, err := d.f.ReadAt(row, int64(rowOffset+firstCol-1))
871-
if err != nil {
872-
return x, err
873-
}
857+
rowLen := colSize - firstCol
858+
row = fullRow[firstCol:(firstCol + rowLen)] // extract the actual row data
874859

875860
if d.proxyTypeEnabled {
876861
if mode&proxyType != 0 || mode&isProxy != 0 {

0 commit comments

Comments
 (0)