)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"dad0c7e90347e9b855286e5b1b5819407c760944","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"c768aac6_00e9d348","updated":"2025-11-19 06:07:06.000000000","message":"Annoyingly the \u0027_\u0027 ascii value is \u003e then the numbers, so not sure what this does to listings.","commit_id":"326f6f24149b2302a8a95eee610e3428ea37acb5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"61892e34a02e15db8a4594625ec2cbf90dea1f45","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"3742f6b0_86e75131","updated":"2025-11-19 13:16:23.000000000","message":"I wrote a long comment below, so TL;DR:\n\n* this will need more work to handle large floats with nsec resolution.\n* this alone won\u0027t reduce timestamp collisions while there are non-upgraded object servers\n* this would improve timestamp-precision on upgraded nodes\n\nTherefore we should perhaps focus on the random-number-in-offset idea *first* because that will reduce timestamp collisions while there are non-upgraded object servers. And we could add this approach later to further improve \u0027resolution\u0027.\n\nNow the long comment:\n\n1) \n\nTo make time_ns useful we\u0027ll need to do more surgery to the Timestamp class because AFAICT the float won\u0027t support ns resolution when the integer part is O(10^9).\n\n```\ndiff --git a/test/unit/common/utils/test_timestamp.py b/test/unit/common/utils/test_timestamp.py\nindex 91a7d3e99..6b387d0b4 100644\n--- a/test/unit/common/utils/test_timestamp.py\n+++ b/test/unit/common/utils/test_timestamp.py\n@@ -25,6 +25,25 @@ from swift.common.utils import timestamp\n \n class TestTimestamp(unittest.TestCase):\n     \"\"\"Tests for swift.common.utils.timestamp.Timestamp\"\"\"\n+    def test_precision(self):\n+        t1 \u003d timestamp.Timestamp(\u00271234567890.123456\u0027)\n+        t2 \u003d timestamp.Timestamp(\u00271234567890.123455\u0027)\n+        self.assertNotEqual(t1, t2)\n+        # yay? 9 places resolution ?...\n+        t1 \u003d timestamp.Timestamp(\u00271234567.890123456\u0027)\n+        t2 \u003d timestamp.Timestamp(\u00271234567.890123455\u0027)\n+        self.assertNotEqual(t1, t2)\n+        # XXX nay, we don\u0027t get more than 6 decimal places precision once the\n+        # integer part becomes large\n+        t1 \u003d timestamp.Timestamp(\u00271234567890.1234567\u0027)\n+        t2 \u003d timestamp.Timestamp(\u00271234567890.1234566\u0027)\n+        self.assertNotEqual(t1, t2)\n+        t1 \u003d timestamp.Timestamp(\u00271234567890.12345678\u0027)\n+        t2 \u003d timestamp.Timestamp(\u00271234567890.12345677\u0027)\n+        self.assertNotEqual(t1, t2)\n+        t1 \u003d timestamp.Timestamp(\u00271234567890.123456789\u0027)\n+        t2 \u003d timestamp.Timestamp(\u00271234567890.123456788\u0027)\n+        self.assertNotEqual(t1, t2)\n \n     def test_invalid_input(self):\n         with self.assertRaises(ValueError):\n\n```\n\nSo we\u0027d need to look at splitting the \u0027float\u0027 into two ints internal to Timestamp and string formatting them to look like a high precision float.\n\n\n2)\n\nThe \u0027_\u0027 sort order IS annoying:\n\ni.e. what\u0027s not great is when we have the *same* timestamp handled by an old (not upgraded) and a new (upgraded) Timestamp:\n\nt_old \u003d 1234567890.12345\nt_new \u003d 1234567890.123456789\n\nand then the t_old gets an offset and the lexicograhical sort order changes, which offset is not supposed to do:\n\nt_new \u003d 1234567890.123456789\nt_old \u003d 1234567890.12345_0000000001\n\nI think I could convince myself that is ok as long as it happens consistently (this is after all a current timestamp collision). However, even when the two versions are \"normalised\" by parsing both into either a new or an old Timestamp instance, they still sort differently:\n\nAn old-style Timestamp (not upgraded) would parse and represent them as:\nt_new \u003d 1234567890.12345\nt_old \u003d 1234567890.12345_0000000001\n\nWhereas a new style Timestamp (upgraded) would parse and represent them as:\nt_old \u003d 1234567890.123450000_0000000001\nt_new \u003d 1234567890.123456789\n\nThis isn\u0027t an issue if we are *really* careful to not be using lexicographical sorting. But that\u0027s exactly what the current Timestamp implementation does 😞\nhttps://github.com/openstack/swift/blob/master/swift/common/utils/timestamp.py#L247\n\nSo during upgrade we could have two diskfiles making different decisions about which data file to keep!!\n\n*Unless* we make the new-style Timestamp smart enough to preserve old-style format (i.e. don\u0027t add the extra decimal digits if they weren\u0027t in what was parsed). So a smart new style Timestamp (upgraded) would parse and represent them as:\n\nt_new \u003d 1234567890.123456789\nt_old \u003d 1234567890.12345_0000000001\n\n...which sorts the same way as an old-style Timestamp.\n\n3)\n\nBut, if t_old and t_new are in fact different requests in the same deca-micro-second then we can of course still get timestamp collisions on non-upgraded nodes 😞","commit_id":"326f6f24149b2302a8a95eee610e3428ea37acb5"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9f4b4f41a7221546b564edb9e65ea846c3c9a262","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"3de42bbe_4ddbe513","updated":"2026-01-09 06:22:14.000000000","message":"Still fixing tests from mager rebase, but wanted to get something up.","commit_id":"19faa17369894f1cc67d490fb4c35b3a903237ec"}],"swift/common/utils/timestamp.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9e202270c2815fd1cd22db40cf5a7f0b0dac0be7","unresolved":true,"context_lines":[{"line_number":412,"context_line":"        return time.time_ns()"},{"line_number":413,"context_line":"    else:"},{"line_number":414,"context_line":"        # We don\u0027t quite have the resolution, so use monotonic_ns"},{"line_number":415,"context_line":"        # which on a mac has nanosec resolution"},{"line_number":416,"context_line":"        time.time_ns() + time.monotonic_ns() % 1000"}],"source_content_type":"text/x-python","patch_set":1,"id":"9ff8c901_ea72dddd","line":415,"range":{"start_line":415,"start_character":14,"end_line":415,"end_character":47},"updated":"2025-11-19 06:11:07.000000000","message":"I wonder if we should actaully do a mac check.. my linux box doesn\u0027t seem to get monotonic resolution to nanosecs, but is fine because the time.time_ns is","commit_id":"326f6f24149b2302a8a95eee610e3428ea37acb5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"f8e8bc0441f8abfd2aac782c63057b9d8f0bc785","unresolved":true,"context_lines":[{"line_number":412,"context_line":"        return time.time_ns()"},{"line_number":413,"context_line":"    else:"},{"line_number":414,"context_line":"        # We don\u0027t quite have the resolution, so use monotonic_ns"},{"line_number":415,"context_line":"        # which on a mac has nanosec resolution"},{"line_number":416,"context_line":"        time.time_ns() + time.monotonic_ns() % 1000"}],"source_content_type":"text/x-python","patch_set":1,"id":"d5de00f4_c5e38136","line":415,"range":{"start_line":415,"start_character":14,"end_line":415,"end_character":47},"in_reply_to":"9ff8c901_ea72dddd","updated":"2025-11-21 10:11:02.000000000","message":"monotonic isn\u0027t nsecs on my mac:\n```\n(swift-3.8.15) (acoles) ~/0dev/openstack/swift{p-timestamp-collision} % python -c \u0027import time; import platform; platform.platform(); print(time.get_clock_info(\"time\"))\u0027\nnamespace(adjustable\u003dTrue, implementation\u003d\u0027clock_gettime(CLOCK_REALTIME)\u0027, monotonic\u003dFalse, resolution\u003d1.0000000000000002e-06)\n(swift-3.8.15) (acoles) ~/0dev/openstack/swift{p-timestamp-collision} % python -c \u0027import time; import platform; platform.platform(); print(time.get_clock_info(\"monotonic\"))\u0027\nnamespace(adjustable\u003dFalse, implementation\u003d\u0027mach_absolute_time()\u0027, monotonic\u003dTrue, resolution\u003d4.166666666666667e-08)\n```","commit_id":"326f6f24149b2302a8a95eee610e3428ea37acb5"}]}
