Skip to content

Commit f531998

Browse files
committed
RDBC-1048: SaveChanges dropping batch results after time series and not propagating cluster transaction index
When a SaveChanges batch contained a time series operation followed by other operations (PUT, PATCH), all results after the time series entry were silently skipped. Documents modified later in the same batch did not get their metadata updated, leaving change vectors and timestamps stale. Additionally, the cluster transaction index was never propagated back to the document store after SaveChanges, breaking read-your-writes consistency across sessions in cluster deployments.
1 parent bf31258 commit f531998

3 files changed

Lines changed: 39 additions & 3 deletions

File tree

ravendb/documents/operations/batch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ def get_command_type(obj_node: dict) -> CommandType:
127127
elif command_type == CommandType.COUNTERS:
128128
self._handle_counters(batch_result)
129129
elif command_type == CommandType.TIME_SERIES:
130-
break # todo: RavenDB-13474 add to time series cache
130+
continue # todo: RavenDB-13474 add to time series cache
131131
elif command_type == CommandType.TIME_SERIES_COPY or command_type == CommandType.BATCH_PATCH:
132-
break
132+
continue
133133
else:
134134
raise ValueError(f"Command {command_type} is not supported")
135135

ravendb/documents/session/document_session_operations/in_memory_document_session_operations.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,9 +1818,10 @@ def _get_operation_result(self, object_type: Type[_T], result: _T) -> _T:
18181818
# todo: cast result on object_type
18191819
raise TypeError(f"Unable to cast {result.__class__.__name__} to {object_type.__name__}")
18201820

1821-
# todo: implement method below
18221821
def update_session_after_save_changes(self, result: BatchCommandResult):
18231822
returned_transaction_index = result.transaction_index
1823+
if returned_transaction_index is not None:
1824+
self.session_info.last_cluster_transaction_index = returned_transaction_index
18241825

18251826
def _process_query_parameters(
18261827
self, object_type: type, index_name: str, collection_name: str, conventions: DocumentConventions

ravendb/tests/session_tests/test_time_series.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import unittest
2+
13
from ravendb.tests.test_base import TestBase, User
24
from datetime import datetime, timedelta
35

@@ -65,3 +67,36 @@ def test_time_series_cache(self):
6567

6668
tsf.get(base + timedelta(days=2), base + timedelta(days=6))
6769
self.assertEqual(session.advanced.number_of_requests, 4)
70+
71+
def test_batch_processes_all_results_after_time_series(self):
72+
with self.store.open_session() as session:
73+
session.store(User("users/ts-target", "Target"))
74+
session.save_changes()
75+
76+
with self.store.open_session() as session:
77+
session.store(User("users/new-doc", "NewDoc"))
78+
tsf = session.time_series_for("users/ts-target", "HeartRate")
79+
tsf.append_single(datetime.now(), 70, "watch")
80+
session.save_changes()
81+
82+
with self.store.open_session() as session:
83+
new_doc = session.load("users/new-doc", User)
84+
self.assertIsNotNone(new_doc, "PUT after time series operation must be processed.")
85+
self.assertEqual(new_doc.name, "NewDoc")
86+
87+
88+
class TestBatchResultProcessing(unittest.TestCase):
89+
def test_batch_does_not_break_after_time_series(self):
90+
import inspect
91+
from ravendb.documents.operations.batch import BatchOperation
92+
src = inspect.getsource(BatchOperation)
93+
lines = src.split("\n")
94+
for i, line in enumerate(lines):
95+
if "CommandType.TIME_SERIES" in line:
96+
for j in range(i + 1, min(i + 3, len(lines))):
97+
next_line = lines[j].strip()
98+
if next_line and not next_line.startswith("#"):
99+
self.assertNotEqual(next_line, "break",
100+
"Batch processing uses 'break' after TIME_SERIES, "
101+
"dropping all subsequent results. Must use 'continue'.")
102+
break

0 commit comments

Comments
 (0)