Skip to content

Commit c86f174

Browse files
authored
[4.4] Fix bufferviews + rewrite timeouts on send (#843)
* Fixes `BufferError: Existing exports of data: object cannot be re-sized` exceptions masking erroneous flows in the driver's code. * Correctly rewrites socket timeouts on sending
1 parent f25015c commit c86f174

File tree

3 files changed

+26
-24
lines changed

3 files changed

+26
-24
lines changed

neo4j/io/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import logging
4444
from logging import getLogger
4545
from random import choice
46+
import socket
4647
from threading import (
4748
Condition,
4849
RLock,
@@ -52,6 +53,7 @@
5253
from neo4j._exceptions import (
5354
BoltError,
5455
BoltHandshakeError,
56+
SocketDeadlineExceeded,
5557
)
5658
from neo4j._deadline import (
5759
connection_deadline,
@@ -509,11 +511,12 @@ def _append(self, signature, fields=(), response=None):
509511
self.responses.append(response)
510512

511513
def _send_all(self):
512-
data = self.outbox.view()
513-
if data:
514+
with self.outbox.view() as data:
515+
if not data:
516+
return
514517
try:
515518
self.socket.sendall(data)
516-
except OSError as error:
519+
except (OSError, socket.timeout, SocketDeadlineExceeded) as error:
517520
self._set_defunct_write(error)
518521
self.outbox.clear()
519522

neo4j/io/_common.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -114,22 +114,21 @@ def _chunk_data(self):
114114
)
115115
num_chunks = num_full_chunks + bool(chunk_rest)
116116

117-
data_view = memoryview(self._raw_data)
118-
header_start = len(self._chunked_data)
119-
data_start = header_start + 2
120-
raw_data_start = 0
121-
for i in range(num_chunks):
122-
chunk_size = min(data_len - raw_data_start,
123-
self._max_chunk_size)
124-
self._chunked_data[header_start:data_start] = struct_pack(
125-
">H", chunk_size
126-
)
127-
self._chunked_data[data_start:(data_start + chunk_size)] = \
128-
data_view[raw_data_start:(raw_data_start + chunk_size)]
129-
header_start += chunk_size + 2
117+
with memoryview(self._raw_data) as data_view:
118+
header_start = len(self._chunked_data)
130119
data_start = header_start + 2
131-
raw_data_start += chunk_size
132-
del data_view
120+
raw_data_start = 0
121+
for i in range(num_chunks):
122+
chunk_size = min(data_len - raw_data_start,
123+
self._max_chunk_size)
124+
self._chunked_data[header_start:data_start] = struct_pack(
125+
">H", chunk_size
126+
)
127+
self._chunked_data[data_start:(data_start + chunk_size)] = \
128+
data_view[raw_data_start:(raw_data_start + chunk_size)]
129+
header_start += chunk_size + 2
130+
data_start = header_start + 2
131+
raw_data_start += chunk_size
133132
self._raw_data.clear()
134133

135134
def wrap_message(self):

neo4j/packstream.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -477,9 +477,9 @@ def receive(self, sock, n_bytes):
477477
end = self.used + n_bytes
478478
if end > len(self.data):
479479
self.data += bytearray(end - len(self.data))
480-
view = memoryview(self.data)
481-
while self.used < end:
482-
n = sock.recv_into(view[self.used:end], end - self.used)
483-
if n == 0:
484-
raise OSError("No data")
485-
self.used += n
480+
with memoryview(self.data) as view:
481+
while self.used < end:
482+
n = sock.recv_into(view[self.used:end], end - self.used)
483+
if n == 0:
484+
raise OSError("No data")
485+
self.used += n

0 commit comments

Comments
 (0)