tests: retry os.rename on PermissionError failure in lttng_live_server.py
[babeltrace.git] / tests / data / plugins / src.ctf.lttng-live / lttng_live_server.py
index 4c3c9ff45c0088d23f67e197fbcc6b6a4e925764..573c47e31914bb38557cd56f816ed7d5c47128ef 100644 (file)
@@ -26,6 +26,7 @@ import logging
 import os
 import os.path
 import re
+import time
 import socket
 import struct
 import sys
@@ -457,7 +458,7 @@ class _LttngLiveViewerProtocolCodec:
                 version, tracing_session_id, offset, seek_type
             )
         elif cmd_type == 4:
-            stream_id, = self._unpack_payload('Q', data)
+            (stream_id,) = self._unpack_payload('Q', data)
             return _LttngLiveViewerGetNextDataStreamIndexEntryCommand(
                 version, stream_id
             )
@@ -467,15 +468,15 @@ class _LttngLiveViewerProtocolCodec:
                 version, stream_id, offset, req_length
             )
         elif cmd_type == 6:
-            stream_id, = self._unpack_payload('Q', data)
+            (stream_id,) = self._unpack_payload('Q', data)
             return _LttngLiveViewerGetMetadataStreamDataCommand(version, stream_id)
         elif cmd_type == 7:
-            tracing_session_id, = self._unpack_payload('Q', data)
+            (tracing_session_id,) = self._unpack_payload('Q', data)
             return _LttngLiveViewerGetNewStreamInfosCommand(version, tracing_session_id)
         elif cmd_type == 8:
             return _LttngLiveViewerCreateViewerSessionCommand(version)
         elif cmd_type == 9:
-            tracing_session_id, = self._unpack_payload('Q', data)
+            (tracing_session_id,) = self._unpack_payload('Q', data)
             return _LttngLiveViewerDetachFromTracingSessionCommand(
                 version, tracing_session_id
             )
@@ -674,9 +675,15 @@ class _LttngDataStreamIndex(collections.abc.Sequence):
                     break
 
                 assert len(data) == size
-                offset_bytes, total_size_bits, content_size_bits, timestamp_begin, timestamp_end, events_discarded, stream_class_id = struct.unpack(
-                    fmt, data
-                )
+                (
+                    offset_bytes,
+                    total_size_bits,
+                    content_size_bits,
+                    timestamp_begin,
+                    timestamp_end,
+                    events_discarded,
+                    stream_class_id,
+                ) = struct.unpack(fmt, data)
 
                 self._entries.append(
                     _LttngDataStreamIndexEntry(
@@ -1320,7 +1327,9 @@ class LttngLiveServer:
 
     def _listen(self):
         logging.info('Listening: port={}'.format(self._server_port))
-        self._sock.listen()
+        # Backlog must be present for Python version < 3.5.
+        # 128 is an arbitrary number since we expect only 1 connection anyway.
+        self._sock.listen(128)
         self._conn, viewer_addr = self._sock.accept()
         logging.info(
             'Accepted viewer: addr={}:{}'.format(viewer_addr[0], viewer_addr[1])
@@ -1336,13 +1345,41 @@ class LttngLiveServer:
         with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_port_file:
             print(self._server_port, end='', file=tmp_port_file)
 
-        # Rename temporary file to real file
-        os.rename(tmp_port_file.name, port_filename)
-        logging.info(
-            'Renamed port file: src-path="{}", dst-path="{}"'.format(
-                tmp_port_file.name, port_filename
-            )
-        )
+        # Rename temporary file to real file.
+        #
+        # For unknown reasons, on Windows, moving the port file from its
+        # temporary location to its final location (where the user of
+        # the server expects it to appear) may raise a `PermissionError`
+        # exception.
+        #
+        # We suppose it's possible that something in the Windows kernel
+        # hasn't completely finished using the file when we try to move
+        # it.
+        #
+        # Use a wait-and-retry scheme as a (bad) workaround.
+        num_attempts = 5
+        retry_delay_s = 1
+
+        for attempt in reversed(range(num_attempts)):
+            try:
+                os.replace(tmp_port_file.name, port_filename)
+                logging.info(
+                    'Renamed port file: src-path="{}", dst-path="{}"'.format(
+                        tmp_port_file.name, port_filename
+                    )
+                )
+                return
+            except PermissionError:
+                logging.info(
+                    'Permission error while attempting to rename port file; retrying in {} second: src-path="{}", dst-path="{}"'.format(
+                        retry_delay_s, tmp_port_file.name, port_filename
+                    )
+                )
+
+                if attempt == 0:
+                    raise
+
+                time.sleep(retry_delay_s)
 
 
 # A tracing session descriptor.
This page took 0.030522 seconds and 4 git commands to generate.