@@ -496,7 +496,11 @@ cdef class Buffer
496
496
497
497
498
498
cdef void_int may_flush_on_row_complete(Buffer buffer , Sender sender) except - 1 :
499
- if sender._auto_flush_enabled:
499
+ cdef bint flush = False
500
+ if sender._auto_flush_mode == auto_flush_row_count:
501
+ if line_sender_buffer_row_count(buffer ._impl) >= sender._auto_flush_watermark:
502
+ sender.flush(buffer )
503
+ elif sender._auto_flush_mode == auto_flush_byte_count:
500
504
if len (buffer ) >= sender._auto_flush_watermark:
501
505
sender.flush(buffer )
502
506
@@ -1208,6 +1212,46 @@ _FLUSH_FMT = ('{} - See https://py-questdb-client.readthedocs.io/en/'
1208
1212
' /troubleshooting.html#inspecting-and-debugging-errors#flush-failed' )
1209
1213
1210
1214
1215
+ class AutoFlush :
1216
+ """
1217
+ Auto flush mode.
1218
+
1219
+ Use one of ``AutoFlush.Disabled``, ``AutoFlush.RowCount`` or
1220
+ ``AutoFlush.ByteCount``.
1221
+ """
1222
+
1223
+ class Disabled :
1224
+ """
1225
+ Auto flush disabled.
1226
+ Call ``flush()`` manually.
1227
+ """
1228
+ pass
1229
+
1230
+ class RowCount :
1231
+ """
1232
+ Auto flush after a number of rows.
1233
+ """
1234
+ def __init__ (self , value: int ):
1235
+ if value < 0 :
1236
+ raise ValueError (' value must be a positive integer.' )
1237
+ self .value = value
1238
+
1239
+ class ByteCount :
1240
+ """
1241
+ Auto flush after a number of bytes.
1242
+ """
1243
+ def __init__ (self , value: int ):
1244
+ if value < 0 :
1245
+ raise ValueError (' value must be a positive integer.' )
1246
+ self .value = value
1247
+
1248
+
1249
+ cdef enum auto_flush_mode_t:
1250
+ auto_flush_disabled,
1251
+ auto_flush_row_count,
1252
+ auto_flush_byte_count,
1253
+
1254
+
1211
1255
cdef class Sender:
1212
1256
"""
1213
1257
A sender is a client that inserts rows into QuestDB via the ILP protocol.
@@ -1265,19 +1309,25 @@ cdef class Sender:
1265
1309
You can control this behavior by setting the ``auto_flush`` argument.
1266
1310
1267
1311
.. code-block:: python
1312
+ from questdb.ingress import AutoFlush
1268
1313
1269
- # Never flushes automatically.
1270
- sender = Sender('localhost', 9009, auto_flush=False)
1271
- sender = Sender('localhost', 9009, auto_flush=None) # Ditto.
1272
- sender = Sender('localhost', 9009, auto_flush=0) # Ditto.
1314
+ # Flushes automatically after 600 rows (the default).
1315
+ sender = Sender('localhost', 9009)
1316
+ sender = Sender('localhost', 9009, auto_flush=AutoFlush.RowCount(600)) # Ditto.
1317
+
1318
+ # Flushes automatically after each row.
1319
+ sender = Sender('localhost', 9009, auto_flush=AutoFlush.RowCount(1))
1273
1320
1274
1321
# Flushes automatically when the buffer reaches 1KiB.
1275
- sender = Sender('localhost', 9009, auto_flush=1024)
1322
+ sender = Sender('localhost', 9009, auto_flush=AutoFlush.ByteCount( 1024) )
1276
1323
1277
- # Flushes automatically after every row.
1278
- sender = Sender('localhost', 9009, auto_flush=True)
1279
- sender = Sender('localhost', 9009, auto_flush=1) # Ditto.
1324
+ # Disabled: Never flushes automatically.
1325
+ sender = Sender('localhost', 9009, auto_flush=AutoFlush.Disabled)
1280
1326
1327
+ When auto-flushing is disabled, you must call ``sender.flush()`` manually.
1328
+ Note that when exiting a ``with sender:`` block, the sender will
1329
+ automatically flush the buffer. This is *not* disabled by setting
1330
+ ``auto_flush=AutoFlush.Disabled``.
1281
1331
1282
1332
**Authentication and TLS Encryption**
1283
1333
@@ -1348,9 +1398,9 @@ cdef class Sender:
1348
1398
* ``max_name_length`` (``int``): Maximum length of a table or column name.
1349
1399
*See Buffer's constructor for more details.*
1350
1400
1351
- * ``auto_flush`` (``bool`` or ``int``) : Whether to automatically flush the
1352
- buffer when it reaches a certain byte-size watermark.
1353
- *Default: 64512 (63KiB) .*
1401
+ * ``auto_flush``: Whether to automatically flush the
1402
+ buffer when it reaches a certain row-count or byte-count watermark.
1403
+ *Default: 600 rows .*
1354
1404
*See above for details.*
1355
1405
1356
1406
**HTTP-only keyword-only constructor arguments for the Sender(..)**
@@ -1359,9 +1409,9 @@ cdef class Sender:
1359
1409
the rows in the batch are for the same table.
1360
1410
Setting ``transactional=True`` will prevent flushing batches of rows
1361
1411
with mixed table names.
1362
- To fully control transactions, you also need to set ``auto_flush=False``
1363
- or buffered lines may be flushed automatically and thus split across
1364
- multiple transactions.
1412
+ To fully control transactions, you also need to set
1413
+ ``auto_flush=AutoFlush.Disabled`` or buffered lines may be flushed
1414
+ automatically and thus split across multiple transactions.
1365
1415
If ``transactional=False`` (default), the client will send the batch
1366
1416
as-is to the server even if it contains rows for multiple tables.
1367
1417
In such case the server may end up committing some rows and not others.
@@ -1390,8 +1440,8 @@ cdef class Sender:
1390
1440
cdef line_sender_opts* _opts
1391
1441
cdef line_sender* _impl
1392
1442
cdef Buffer _buffer
1393
- cdef bint _auto_flush_enabled
1394
- cdef ssize_t _auto_flush_watermark
1443
+ cdef auto_flush_mode_t _auto_flush_mode
1444
+ cdef size_t _auto_flush_watermark
1395
1445
cdef size_t _init_capacity
1396
1446
cdef size_t _max_name_len
1397
1447
@@ -1407,7 +1457,7 @@ cdef class Sender:
1407
1457
uint64_t read_timeout = 15000 ,
1408
1458
uint64_t init_capacity = 65536 , # 64KiB
1409
1459
uint64_t max_name_len = 127 ,
1410
- object auto_flush = 64512 , # 63KiB
1460
+ object auto_flush = None , # AutoFlush.RowCount(600)
1411
1461
bint transactional = False ,
1412
1462
uint32_t max_retries = 3 ,
1413
1463
uint64_t retry_interval = 100 , # milliseconds
@@ -1443,6 +1493,8 @@ cdef class Sender:
1443
1493
1444
1494
cdef qdb_pystr_buf* b
1445
1495
1496
+ cdef ssize_t auto_flush_watermark = 0
1497
+
1446
1498
self ._opts = NULL
1447
1499
self ._impl = NULL
1448
1500
@@ -1532,13 +1584,30 @@ cdef class Sender:
1532
1584
line_sender_opts_retry_interval(self ._opts, retry_interval)
1533
1585
line_sender_opts_min_throughput(self ._opts, min_throughput)
1534
1586
1535
- self ._auto_flush_enabled = not not auto_flush
1536
- self ._auto_flush_watermark = int (auto_flush) \
1537
- if self ._auto_flush_enabled else 0
1538
- if self ._auto_flush_watermark < 0 :
1587
+
1588
+ # Parse `auto_flush` argument.
1589
+ if auto_flush is None :
1590
+ self ._auto_flush_mode = auto_flush_row_count
1591
+ auto_flush_watermark = 600
1592
+ elif auto_flush is AutoFlush.Disabled:
1593
+ self ._auto_flush_mode = auto_flush_disabled
1594
+ auto_flush_watermark = 0
1595
+ elif isinstance (auto_flush, AutoFlush.RowCount):
1596
+ self ._auto_flush_mode = auto_flush_row_count
1597
+ auto_flush_watermark = auto_flush.value
1598
+ elif isinstance (auto_flush, AutoFlush.ByteCount):
1599
+ self ._auto_flush_mode = auto_flush_byte_count
1600
+ auto_flush_watermark = auto_flush.value
1601
+ else :
1602
+ raise TypeError (
1603
+ ' auto_flush must be AutoFlush.Disabled, '
1604
+ ' AutoFlush.RowCount or AutoFlush.ByteCount, '
1605
+ f' not {_fqn(type(auto_flush))}' )
1606
+ if auto_flush_watermark < 0 :
1539
1607
raise ValueError (
1540
- ' auto_flush_watermark must be >= 0, '
1541
- f' not {self._auto_flush_watermark}' )
1608
+ ' auto_flush watermark must be >= 0, '
1609
+ f' not {auto_flush_watermark}' )
1610
+ self ._auto_flush_watermark = auto_flush_watermark
1542
1611
1543
1612
qdb_pystr_buf_clear(b)
1544
1613
@@ -1678,8 +1747,9 @@ cdef class Sender:
1678
1747
may have been transmitted to the server already.
1679
1748
"""
1680
1749
cdef auto_flush_t af = auto_flush_blank()
1681
- if self ._auto_flush_enabled :
1750
+ if self ._auto_flush_mode :
1682
1751
af.sender = self ._impl
1752
+ af.mode = self ._auto_flush_mode
1683
1753
af.watermark = self ._auto_flush_watermark
1684
1754
_dataframe(
1685
1755
af,
0 commit comments