From deb4cd5e00a3c60d449de3f855dc552aa7436ff5 Mon Sep 17 00:00:00 2001 From: Mark Syms Date: Tue, 6 Aug 2024 14:27:18 +0100 Subject: [PATCH] CA-396751: write updated RRDD data before headers Ensure that the updated data and metadata are written before the headers are updated otherwise xcp-rrdd might start reading the data block before all the data is populated and thus run off the end of the data. Signed-off-by: Mark Syms --- ocaml/xcp-rrdd/scripts/rrdd/rrdd.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ocaml/xcp-rrdd/scripts/rrdd/rrdd.py b/ocaml/xcp-rrdd/scripts/rrdd/rrdd.py index a5dadf326c8..1132fa92b53 100644 --- a/ocaml/xcp-rrdd/scripts/rrdd/rrdd.py +++ b/ocaml/xcp-rrdd/scripts/rrdd/rrdd.py @@ -283,7 +283,8 @@ def wait_until_next_reading(self, neg_shift=1): self.lazy_complete_init() next_reading = self.register() wait_time = next_reading - neg_shift - if wait_time < 0: wait_time %= self.frequency_in_seconds + if wait_time < 0: + wait_time %= self.frequency_in_seconds time.sleep(wait_time) return except socket.error: @@ -310,13 +311,10 @@ def update(self): metadata_json = json.dumps(metadata, sort_keys=True).encode('utf-8') metadata_checksum = crc32(metadata_json) & 0xffffffff - self.dest.seek(0) - self.dest.write('DATASOURCES'.encode()) - self.dest.write(pack(">LLLQ", - data_checksum, - metadata_checksum, - len(self.datasources), - timestamp)) + # First write the updated data and metadata + encoded_datasource_header = 'DATASOURCES'.encode() + # DATASOURCES + 20 for 32 + 32 + 32 + 64 + self.dest.seek(len(encoded_datasource_header) + 20) for val in data_values: # This is already big endian encoded self.dest.write(val) @@ -324,6 +322,16 @@ def update(self): self.dest.write(pack(">L", len(metadata_json))) self.dest.write(metadata_json) self.dest.flush() + + # Now write the updated header + self.dest.seek(0) + self.dest.write(encoded_datasource_header) + self.dest.write(pack(">LLLQ", + data_checksum, + metadata_checksum, + len(self.datasources), + timestamp)) + self.dest.flush() self.datasources = [] time.sleep( 0.003) # wait a bit to ensure wait_until_next_reading will block