@@ -5,6 +5,10 @@ from murmurhash.mrmr cimport hash128_x86
55import math
66from array import array
77
8+ cimport cython
9+
10+ from libcpp.vector cimport vector
11+
812try :
913 import copy_reg
1014except ImportError :
@@ -37,48 +41,56 @@ cdef class BloomFilter:
3741 return cls (* params)
3842
3943 def add (self , key_t item ):
40- bloom_add(self .c_bloom, item)
44+ with cython.critical_section(self ):
45+ bloom_add(self .c_bloom, item)
4146
42- def __contains__ (self , item ):
43- return bloom_contains(self .c_bloom, item)
47+ def __contains__ (self , key_t item ):
48+ with cython.critical_section(self ):
49+ return bloom_contains(self .c_bloom, item)
4450
51+ # Requires external synchronization (e.g. a critical section)
4552 cdef inline bint contains(self , key_t item) nogil:
4653 return bloom_contains(self .c_bloom, item)
4754
4855 def to_bytes (self ):
49- return bloom_to_bytes(self .c_bloom)
56+ with cython.critical_section(self ):
57+ return bloom_to_bytes(self .c_bloom)
5058
5159 def from_bytes (self , bytes byte_string ):
52- bloom_from_bytes(self .mem, self .c_bloom, byte_string)
53- return self
60+ with cython.critical_section(self ):
61+ bloom_from_bytes(self .mem, self .c_bloom, byte_string)
62+ return self
63+
64+ def _roundtrip (self ):
65+ # Purely for testing, since this operation can't be done atomically
66+ # without holding a critical section the entire time.
67+ # Entering the same critical section recursively doesn't release it.
68+ # (see cpython commit 180d417)
69+ with cython.critical_section(self ):
70+ self .from_bytes(self .to_bytes())
5471
5572
5673cdef bytes bloom_to_bytes(const BloomStruct* bloom):
57- py = array(" L" )
58- py.append(bloom.hcount)
59- py.append(bloom.length)
60- py.append(bloom.seed)
74+ # local scratch buffer
75+ cdef vector[key_t] ret = vector[key_t]()
76+ ret.push_back(bloom.hcount)
77+ ret.push_back(bloom.length)
78+ ret.push_back(< key_t> bloom.seed)
6179 for i in range (bloom.length // sizeof(key_t)):
62- py.append(bloom.bitfield[i])
63- if hasattr (py, " tobytes" ):
64- return py.tobytes()
65- else :
66- # Python 2 :(
67- return py.tostring()
80+ ret.push_back(bloom.bitfield[i])
81+ # copy data in the scratch buffer into a new bytes object
82+ return (< char * > ret.data())[:3 * sizeof(key_t) + bloom.length]
6883
6984
7085cdef void bloom_from_bytes(Pool mem, BloomStruct* bloom, bytes data):
71- py = array(" L" )
72- if hasattr (py, " frombytes" ):
73- py.frombytes(data)
74- else :
75- py.fromstring(data)
76- bloom.hcount = py[0 ]
77- bloom.length = py[1 ]
78- bloom.seed = py[2 ]
86+ cdef char * c_data = data;
87+ cdef key_t* i_data = < key_t* > c_data;
88+ bloom.hcount = i_data[0 ]
89+ bloom.length = i_data[1 ]
90+ bloom.seed = < uint32_t> i_data[2 ]
7991 bloom.bitfield = < key_t* > mem.alloc(bloom.length // sizeof(key_t), sizeof(key_t))
8092 for i in range (bloom.length // sizeof(key_t)):
81- bloom.bitfield[i] = py [3 + i]
93+ bloom.bitfield[i] = i_data [3 + i]
8294
8395
8496cdef void bloom_init(Pool mem, BloomStruct* bloom, key_t hcount, key_t length, uint32_t seed) except * :
0 commit comments