IP parsing C accelerated, use bytes everywhere

This commit is contained in:
Geoffrey Frogeye 2019-12-09 08:55:34 +01:00
parent 7937496882
commit 55877be891
Signed by: geoffrey
GPG key ID: D8A7ECA00A8CD3DD
6 changed files with 73 additions and 21 deletions

View file

@ -7,7 +7,7 @@ import typing
import ipaddress
import enum
import time
import pprint
import ctypes
"""
Utility functions to interact with the database.
@ -20,6 +20,8 @@ C = None # Cursor
TIME_DICT: typing.Dict[str, float] = dict()
TIME_LAST = time.perf_counter()
TIME_STEP = 'start'
ACCEL = ctypes.cdll.LoadLibrary('./libaccel.so')
ACCEL_IP4_BUF = ctypes.create_unicode_buffer('Z'*32, 32)
def time_step(step: str) -> None:
@ -127,9 +129,12 @@ def ip_flat(address: ipaddress.IPv4Address) -> str:
return ''.join(map(str, ip_get_bits(address)))
def ip4_flat(address: str) -> str:
return '{:08b}{:08b}{:08b}{:08b}'.format(
*[int(c) for c in address.split('.')])
def ip4_flat(address: bytes) -> typing.Optional[str]:
carg = ctypes.c_char_p(address)
ret = ACCEL.ip4_flat(carg, ACCEL_IP4_BUF)
if ret != 0:
return None
return ACCEL_IP4_BUF.value
RULE_IP4NETWORK_COMMAND = \
@ -165,23 +170,22 @@ FEED_A_COMMAND_UPSERT = \
'WHERE updated=0 OR firstparty<?'
def feed_a(name: str, value_ip: str) -> None:
def feed_a(name: bytes, value_ip: bytes) -> None:
assert C
assert CONN
time_step('a_flat')
try:
value = ip4_flat(value_ip)
except (ValueError, IndexError):
value_dec = ip4_flat(value_ip)
if value_dec is None:
# Malformed IPs
return
time_step('a_fetch')
C.execute(FEED_A_COMMAND_FETCH, (value,))
C.execute(FEED_A_COMMAND_FETCH, (value_dec,))
base = C.fetchone()
time_step('a_fetch_confirm')
if not base:
return
b_key, b_firstparty = base
if not value.startswith(b_key):
if not value_dec.startswith(b_key):
return
name = name[::-1]
time_step('a_upsert')
@ -212,23 +216,25 @@ FEED_CNAME_COMMAND_UPSERT = \
'WHERE updated=0 OR firstparty<?'
def feed_cname(name: str, value: str) -> None:
def feed_cname(name: bytes, value: bytes) -> None:
assert C
assert CONN
time_step('cname_decode')
value = value[::-1]
value_dec = value.decode()
time_step('cname_fetch')
C.execute(FEED_CNAME_COMMAND_FETCH, (value,))
C.execute(FEED_CNAME_COMMAND_FETCH, (value_dec,))
base = C.fetchone()
time_step('cname_fetch_confirm')
if not base:
# Should only happen at an extremum of the database
return
b_key, b_type, b_firstparty = base
matching = b_key == value[:len(b_key)] and (
len(value) == len(b_key)
matching = b_key == value_dec[:len(b_key)] and (
len(value_dec) == len(b_key)
or (
b_type == RowType.DomainTree.value
and value[len(b_key)] == '.'
and value_dec[len(b_key)] == '.'
)
)
if not matching: