)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":3,"context_line":"AuthorDate: 2026-07-22 18:00:48 -0500"},{"line_number":4,"context_line":"Commit:     Clay Gerrard \u003cclay.gerrard@gmail.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-09-22 18:59:12 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"WIP: container-sync: preserve jittered timestamps"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Container sync compares a source\u0027s public X-Timestamp to the row"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"55b49706_8cfdfac0","line":6,"updated":"2026-09-23 10:32:02.000000000","message":"I struggled to understand this commit message so ended up re-writing it to help myself see the whole scope of the patch. This is unlikely to be perfect but offering as an alternative:\n\n\"\nWIP: container-sync: adapt to v2 timestamps with jitter\n\nThis patch makes several changes to container sync to make it compatible with v2 timestamps that have a jitter component.\n\nContainer sync decides if a local source object needs to be sync\u0027d to a remote container by comparing the timestamps of the two objects. The remote object HEAD response only provides the normalised x-timestamp value, making it impossible to distinguish source and remote timestamps that are within the same deca-microsecond but have different jitter values.\n\nWith this patch, when the remote\u0027s normalised x-timestamp is equal to the local source normalised timestamp, a further comparison is made of the remote and source etags. If the etags are also equal then the remote is considered to be in sync. There remains a possibility that the remote and source do in fact have different timestamps within the same deca-microseond and different metadata. This patch does not address that case.\n\nContainer sync also checks that an on-disk source object is up to date with the local container DB row before sending its content to the remote container. Previously this comparison used normalised forms of the timestamps. With this patch the more precise internal form is used so that on-disk object and container DB rows with different timestamps in the same deca-microsecond will be differentiated.\n\nFinally, this patch changes the x-timestamp header that container sync sends with a PUT to use the internal form of the source x-backend-timestamp (when available) i.e. it now sends the full precision source timestamp including jitter. This ensures that the object created in the remote container has exactly the same timestamp as the source.\n\"","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":4,"context_line":"Commit:     Clay Gerrard \u003cclay.gerrard@gmail.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-09-22 18:59:12 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"WIP: container-sync: preserve jittered timestamps"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Container sync compares a source\u0027s public X-Timestamp to the row"},{"line_number":10,"context_line":"timestamp, losing offset information. A jittered source object can"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"0b62e09f_63035f1c","line":7,"updated":"2026-09-23 10:32:02.000000000","message":"the headline claim disguises the fact that we cannot discover the remote timestamp jitter","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"WIP: container-sync: preserve jittered timestamps"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Container sync compares a source\u0027s public X-Timestamp to the row"},{"line_number":10,"context_line":"timestamp, losing offset information. A jittered source object can"},{"line_number":11,"context_line":"therefore appear current and be skipped. A public timestamp can also"},{"line_number":12,"context_line":"be forwarded instead of a backend timestamp."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"35795cfa_02417c0a","line":9,"range":{"start_line":9,"start_character":26,"end_line":9,"end_character":34},"updated":"2026-09-23 10:32:02.000000000","message":"am I mis-understanding or is there a confusion of source vs remote? my reading is that the source (aka local) is conditionally PUT to the remote. The use of \"row timestamp\" in the commit message is vague w.r.t. the code using local or source.\n\nThe *remote* only provides a normal x-timestamp.","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":7,"context_line":"WIP: container-sync: preserve jittered timestamps"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Container sync compares a source\u0027s public X-Timestamp to the row"},{"line_number":10,"context_line":"timestamp, losing offset information. A jittered source object can"},{"line_number":11,"context_line":"therefore appear current and be skipped. A public timestamp can also"},{"line_number":12,"context_line":"be forwarded instead of a backend timestamp."},{"line_number":13,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"e4dce7ba_756a1a80","line":10,"range":{"start_line":10,"start_character":18,"end_line":10,"end_character":24},"updated":"2026-09-23 10:32:02.000000000","message":"offset is not jitter; in fact we want to lose offset information when comparing source and remote","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Container sync compares a source\u0027s public X-Timestamp to the row"},{"line_number":10,"context_line":"timestamp, losing offset information. A jittered source object can"},{"line_number":11,"context_line":"therefore appear current and be skipped. A public timestamp can also"},{"line_number":12,"context_line":"be forwarded instead of a backend timestamp."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Use the source X-Backend-Timestamp for comparisons and forwarding"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"028ae6f0_8e9aba33","line":11,"range":{"start_line":11,"start_character":43,"end_line":11,"end_character":59},"updated":"2026-09-23 10:32:02.000000000","message":"\u0027can\u0027 implies not always - but IIUC on master the PUT *always* sends a normalised x-timestamp value, which is no longer sufficient. I\u0027m finding it unhelpful to have the introduction of \"public timestamp\" as another way of saying \"normalised\".","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"c8e311d8_04a7ad3c","updated":"2026-09-21 15:08:38.000000000","message":"I think this is the right direction","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"8d7feed5_ccf49c25","updated":"2026-09-23 10:32:02.000000000","message":"I realise this is marked WIP but I\u0027ll be AFK for a few days so wanted to leave feedback.\n\nApart from the inline comments, I\u0027m also voting -1 because I think they may be a reason why container sync previously explicitly used the normal timestamp format: local and remote objects would be considered to be in sync if they had different *offsets*.\n\nThe internal timestamp format of a v2 timestamp includes the offset as well as jitter. We need to compare timestamps *with jitter* but *without offset*. \n\nWe may need a third format that masks out the offset from the hex part. I think when I previously suggested this I may have advocated that we call it something like \u0027variant-id\u0027 because it identifies the unique variant of an object 🤷\n\nAlternatively, we add comparison methods to Timestamp that compare only the relevant components (``Timestamp.equal_variant(other)`` 🤷)","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"}],"swift/container/sync.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":606,"context_line":""},{"line_number":607,"context_line":"                timestamp \u003d Timestamp("},{"line_number":608,"context_line":"                    headers.get(\u0027x-timestamp\u0027, Timestamp.zero()))"},{"line_number":609,"context_line":"                if timestamp.normal \u003c ts_meta.normal:"},{"line_number":610,"context_line":"                    if exc:"},{"line_number":611,"context_line":"                        raise exc"},{"line_number":612,"context_line":"                    raise Exception("}],"source_content_type":"text/x-python","patch_set":1,"id":"86cb95ac_9ea04c02","side":"PARENT","line":609,"range":{"start_line":609,"start_character":19,"end_line":609,"end_character":52},"updated":"2026-09-21 15:08:38.000000000","message":"+1 this is no longer sufficient","commit_id":"91120e58800875c79ff8493cd5acc6ab0bae04de"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":507,"context_line":"                                      retries\u003d0)"},{"line_number":508,"context_line":"            remote_ts \u003d Timestamp("},{"line_number":509,"context_line":"                metadata.get(\u0027x-timestamp\u0027, Timestamp.zero()))"},{"line_number":510,"context_line":"            self.logger.debug(\"remote obj timestamp %s local obj %s\" %"},{"line_number":511,"context_line":"                              (timestamp.internal, remote_ts.internal))"},{"line_number":512,"context_line":"            if timestamp \u003c\u003d remote_ts:"},{"line_number":513,"context_line":"                return True"},{"line_number":514,"context_line":"            # Object in remote should be updated"}],"source_content_type":"text/x-python","patch_set":1,"id":"9f826fc3_c65ac7ac","line":511,"range":{"start_line":510,"start_character":12,"end_line":511,"end_character":71},"updated":"2026-09-21 15:08:38.000000000","message":"this debug is wrong?? w.r.t. order of the substitutions","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":509,"context_line":"                metadata.get(\u0027x-timestamp\u0027, Timestamp.zero()))"},{"line_number":510,"context_line":"            self.logger.debug(\"remote obj timestamp %s local obj %s\" %"},{"line_number":511,"context_line":"                              (timestamp.internal, remote_ts.internal))"},{"line_number":512,"context_line":"            if timestamp \u003c\u003d remote_ts:"},{"line_number":513,"context_line":"                return True"},{"line_number":514,"context_line":"            # Object in remote should be updated"},{"line_number":515,"context_line":"            return False"}],"source_content_type":"text/x-python","patch_set":1,"id":"acdd81af_3c52cd28","line":512,"updated":"2026-09-21 15:08:38.000000000","message":"ok, so when we have\n\nremote_ts.internal \u003d t1_2000000001000000\nsource_ts.internal \u003d t1_2000000002000000\n\nwe compare\n\nt1_2000000002000000 \u003c\u003d t1\n\nwhich is False and so we sync - right outcome! 🙂\n\nAnd when we have\n\nremote_ts.internal \u003d t1_2000000002000000\nsource_ts.internal \u003d t1_2000000002000000\n\nor \n\nremote_ts.internal \u003d t1_2000000003000000\nsource_ts.internal \u003d t1_2000000002000000\n\nwe compare\n\nt1_2000000002000000 \u003c\u003d t1\n\nwhich is False and so we sync - unnecessary sync, but right outcome (409)! 🙂","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":510,"context_line":"            self.logger.debug(\"remote obj timestamp %s local obj %s\" %"},{"line_number":511,"context_line":"                              (timestamp.internal, remote_ts.internal))"},{"line_number":512,"context_line":"            if timestamp \u003c\u003d remote_ts:"},{"line_number":513,"context_line":"                return True"},{"line_number":514,"context_line":"            # Object in remote should be updated"},{"line_number":515,"context_line":"            return False"},{"line_number":516,"context_line":"        except ClientException as http_err:"}],"source_content_type":"text/x-python","patch_set":1,"id":"06f9a573_06cf81c4","line":513,"updated":"2026-09-21 15:08:38.000000000","message":"future me would love a comment to acknowledge the approximated comparison w.r.t the outcome","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":609,"context_line":"                    timestamp \u003d Timestamp(headers[\u0027x-backend-timestamp\u0027])"},{"line_number":610,"context_line":"                    is_stale \u003d timestamp \u003c ts_meta"},{"line_number":611,"context_line":"                else:"},{"line_number":612,"context_line":"                    # A public source timestamp cannot distinguish jittered"},{"line_number":613,"context_line":"                    # versions. The container row is authoritative when its"},{"line_number":614,"context_line":"                    # normal form matches the source response."},{"line_number":615,"context_line":"                    is_stale \u003d source_timestamp.normal \u003c ts_meta.normal"},{"line_number":616,"context_line":"                    timestamp \u003d (ts_meta if source_timestamp.normal \u003d\u003d"}],"source_content_type":"text/x-python","patch_set":1,"id":"dcd73abc_1c115f25","line":613,"range":{"start_line":612,"start_character":22,"end_line":613,"end_character":32},"updated":"2026-09-21 15:08:38.000000000","message":"I don\u0027t understand this comment. The headers, and therefore source_timestamp, are from an internal client GET. What\u0027s \"public\" referring to?\n\nVery old objects might not have x-backend-timestamp","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":627,"context_line":"                for key in (\u0027date\u0027, \u0027last-modified\u0027):"},{"line_number":628,"context_line":"                    if key in headers:"},{"line_number":629,"context_line":"                        del headers[key]"},{"line_number":630,"context_line":"                headers.pop(\u0027x-backend-timestamp\u0027, None)"},{"line_number":631,"context_line":"                headers[\u0027x-timestamp\u0027] \u003d timestamp.internal"},{"line_number":632,"context_line":"                if \u0027etag\u0027 in headers:"},{"line_number":633,"context_line":"                    headers[\u0027etag\u0027] \u003d normalize_etag(headers[\u0027etag\u0027])"}],"source_content_type":"text/x-python","patch_set":1,"id":"9b04baaa_046423a5","line":630,"updated":"2026-09-21 15:08:38.000000000","message":"😬","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":627,"context_line":"                for key in (\u0027date\u0027, \u0027last-modified\u0027):"},{"line_number":628,"context_line":"                    if key in headers:"},{"line_number":629,"context_line":"                        del headers[key]"},{"line_number":630,"context_line":"                headers.pop(\u0027x-backend-timestamp\u0027, None)"},{"line_number":631,"context_line":"                headers[\u0027x-timestamp\u0027] \u003d timestamp.internal"},{"line_number":632,"context_line":"                if \u0027etag\u0027 in headers:"},{"line_number":633,"context_line":"                    headers[\u0027etag\u0027] \u003d normalize_etag(headers[\u0027etag\u0027])"}],"source_content_type":"text/x-python","patch_set":1,"id":"093ca552_1fbbae69","line":630,"in_reply_to":"9b04baaa_046423a5","updated":"2026-09-23 10:32:02.000000000","message":"my agent has same anxiety as me:\n\n```\n 3. Header stripping is narrow — sync.py:660 pops only x-backend-timestamp. The internal client pipeline at sync.py:53-74 has no gatekeeper, which is\n  precisely why x-backend-timestamp is visible at all. So other x-backend-* headers plausibly also leak through and get forwarded verbatim to what may be a\n  foreign cluster. Stripping the whole prefix would be safer and is the same line count.\n```","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":628,"context_line":"                    if key in headers:"},{"line_number":629,"context_line":"                        del headers[key]"},{"line_number":630,"context_line":"                headers.pop(\u0027x-backend-timestamp\u0027, None)"},{"line_number":631,"context_line":"                headers[\u0027x-timestamp\u0027] \u003d timestamp.internal"},{"line_number":632,"context_line":"                if \u0027etag\u0027 in headers:"},{"line_number":633,"context_line":"                    headers[\u0027etag\u0027] \u003d normalize_etag(headers[\u0027etag\u0027])"},{"line_number":634,"context_line":"                if \u0027content-type\u0027 in headers:"}],"source_content_type":"text/x-python","patch_set":1,"id":"0d736838_66ad2b8a","line":631,"updated":"2026-09-21 15:08:38.000000000","message":"this is the cunning part: apparently the remote proxy WILL admit x-timestamp with jitter 😀 very forwards thinking of past-us","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cb6181076336a8f389a2c9f9c239318214b52962","unresolved":true,"context_lines":[{"line_number":643,"context_line":"                               logger\u003dself.logger, timeout\u003dself.conn_timeout)"},{"line_number":644,"context_line":"                except ClientException as err:"},{"line_number":645,"context_line":"                    if err.http_status !\u003d HTTP_CONFLICT:"},{"line_number":646,"context_line":"                        raise"},{"line_number":647,"context_line":"                self.container_puts +\u003d 1"},{"line_number":648,"context_line":"                self.container_stats[\u0027puts\u0027] +\u003d 1"},{"line_number":649,"context_line":"                self.container_stats[\u0027bytes\u0027] +\u003d row[\u0027size\u0027]"}],"source_content_type":"text/x-python","patch_set":1,"id":"a7a7ae59_a3bb8a12","line":646,"updated":"2026-09-21 15:08:38.000000000","message":"was it ever appropriate to treat a 409 as an error? could it mean anything other than \"the remote is now newer, no need for sync but thanks for trying\"?","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":607,"context_line":"                timestamp \u003d Timestamp("},{"line_number":608,"context_line":"                    headers.get(\u0027x-timestamp\u0027, Timestamp.zero()))"},{"line_number":609,"context_line":"                if timestamp.normal \u003c ts_meta.normal:"},{"line_number":610,"context_line":"                    if exc:"},{"line_number":611,"context_line":"                        raise exc"},{"line_number":612,"context_line":"                    raise Exception("},{"line_number":613,"context_line":"                        \u0027Unknown exception trying to GET: \u0027"}],"source_content_type":"text/x-python","patch_set":2,"id":"faeba40e_6670fd54","side":"PARENT","line":610,"updated":"2026-09-23 10:32:02.000000000","message":"I think this was allowing for NOT raising the exc in the case when the source GET failed but the row timestamps was zero??? IDK, very confusing","commit_id":"91120e58800875c79ff8493cd5acc6ab0bae04de"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":609,"context_line":"                if timestamp.normal \u003c ts_meta.normal:"},{"line_number":610,"context_line":"                    if exc:"},{"line_number":611,"context_line":"                        raise exc"},{"line_number":612,"context_line":"                    raise Exception("},{"line_number":613,"context_line":"                        \u0027Unknown exception trying to GET: \u0027"},{"line_number":614,"context_line":"                        \u0027%(account)r %(container)r %(object)r\u0027 %"},{"line_number":615,"context_line":"                        {\u0027account\u0027: info[\u0027account\u0027],"}],"source_content_type":"text/x-python","patch_set":2,"id":"9493dff9_b17f363b","side":"PARENT","line":612,"updated":"2026-09-23 10:32:02.000000000","message":"IIUC on master we get here if the source GET returns a 404","commit_id":"91120e58800875c79ff8493cd5acc6ab0bae04de"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":499,"context_line":"        :param realm_key: The realm key from self.realms_conf, if there"},{"line_number":500,"context_line":"            is one. If None, fallback to using the older"},{"line_number":501,"context_line":"            allowed_sync_hosts way of syncing."},{"line_number":502,"context_line":"        :param timestamp: last modified date of local object"},{"line_number":503,"context_line":"        :param local_etag: etag recorded in the local container row"},{"line_number":504,"context_line":"        :returns: True if object already exists in remote"},{"line_number":505,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":2,"id":"7e7bbb5f_835a9255","line":502,"range":{"start_line":502,"start_character":26,"end_line":502,"end_character":60},"updated":"2026-09-23 10:32:02.000000000","message":"can we change this to ``metadata Timestamp of local object``\n\n``last modified date`` does not imply a Timestamp instance to me","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":523,"context_line":"                if _matching_etags(local_etag, remote_etag):"},{"line_number":524,"context_line":"                    # Optimistically treat matching entity tags as proof that"},{"line_number":525,"context_line":"                    # the remote has this jittered update. This may miss a"},{"line_number":526,"context_line":"                    # metadata-only update made within the same normal tick."},{"line_number":527,"context_line":"                    return True"},{"line_number":528,"context_line":"            # Object in remote should be updated"},{"line_number":529,"context_line":"            return False"}],"source_content_type":"text/x-python","patch_set":2,"id":"45b32643_9c34c67b","line":526,"updated":"2026-09-23 10:32:02.000000000","message":"docs should be updated to note that sync is not 100% guaranteed\nhttps://docs.openstack.org/swift/latest/overview_container_sync.html","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":523,"context_line":"                if _matching_etags(local_etag, remote_etag):"},{"line_number":524,"context_line":"                    # Optimistically treat matching entity tags as proof that"},{"line_number":525,"context_line":"                    # the remote has this jittered update. This may miss a"},{"line_number":526,"context_line":"                    # metadata-only update made within the same normal tick."},{"line_number":527,"context_line":"                    return True"},{"line_number":528,"context_line":"            # Object in remote should be updated"},{"line_number":529,"context_line":"            return False"}],"source_content_type":"text/x-python","patch_set":2,"id":"7bbcad33_777e5888","line":526,"range":{"start_line":526,"start_character":64,"end_line":526,"end_character":75},"updated":"2026-09-23 10:32:02.000000000","message":"let\u0027s call it what it is, a deca-microsecond; no need to introduce a new vernacular","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":610,"context_line":"                    exc \u003d err"},{"line_number":611,"context_line":""},{"line_number":612,"context_line":"                if exc:"},{"line_number":613,"context_line":"                    raise exc"},{"line_number":614,"context_line":"                if source_obj_status // 100 !\u003d 2:"},{"line_number":615,"context_line":"                    raise Exception("},{"line_number":616,"context_line":"                        \u0027Unexpected status %(status)s trying to GET: \u0027"}],"source_content_type":"text/x-python","patch_set":2,"id":"c1e556d1_1cb3b2d9","line":613,"updated":"2026-09-23 10:32:02.000000000","message":"why wasn\u0027t this raised at line 610?\n\nin fact, why is there a try/except lines 599-607","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":618,"context_line":"                        {\u0027status\u0027: source_obj_status,"},{"line_number":619,"context_line":"                         \u0027account\u0027: info[\u0027account\u0027],"},{"line_number":620,"context_line":"                         \u0027container\u0027: info[\u0027container\u0027],"},{"line_number":621,"context_line":"                         \u0027object\u0027: row[\u0027name\u0027]})"},{"line_number":622,"context_line":""},{"line_number":623,"context_line":"                # skip object_versioning links; this is in case the container"},{"line_number":624,"context_line":"                # metadata is out of date"}],"source_content_type":"text/x-python","patch_set":2,"id":"79e4ec44_6a4a976a","line":621,"updated":"2026-09-23 10:32:02.000000000","message":"IIUC this is necessary because we now compare x-backend-timestamp from the GET response, and a 404 may have an x-backend-timestamp (but would not have an x-timestamp)\n\nbut why not just change line 604 to make 4xx an unacceptable status? The UnexpectedResponse will reach the same handler at line 698","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":630,"context_line":"                    return True"},{"line_number":631,"context_line":""},{"line_number":632,"context_line":"                source_timestamp \u003d Timestamp("},{"line_number":633,"context_line":"                    headers.get(\u0027x-timestamp\u0027, Timestamp.zero()))"},{"line_number":634,"context_line":"                if \u0027x-backend-timestamp\u0027 in headers:"},{"line_number":635,"context_line":"                    timestamp \u003d Timestamp(headers[\u0027x-backend-timestamp\u0027])"},{"line_number":636,"context_line":"                    is_stale \u003d timestamp \u003c ts_meta"}],"source_content_type":"text/x-python","patch_set":2,"id":"70da64e6_5c1783a7","line":633,"updated":"2026-09-23 10:32:02.000000000","message":"this assignment could/should go inside the else clause; sat here it feels like this is the definitive source timestamp used for the PUT (whereas it is still ``timestamp``)","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":642,"context_line":"                    if source_timestamp.normal \u003d\u003d ts_meta.normal:"},{"line_number":643,"context_line":"                        if not _matching_etags("},{"line_number":644,"context_line":"                                row.get(\u0027etag\u0027), headers.get(\u0027etag\u0027)):"},{"line_number":645,"context_line":"                            is_stale \u003d True"},{"line_number":646,"context_line":"                        timestamp \u003d ts_meta"},{"line_number":647,"context_line":"                    else:"},{"line_number":648,"context_line":"                        timestamp \u003d source_timestamp"}],"source_content_type":"text/x-python","patch_set":2,"id":"645ebbb2_d851a813","line":645,"updated":"2026-09-23 10:32:02.000000000","message":"I\u0027m not sure why we are comparing etags here? if the source 200 response does not have x-backend-timestamp then the source is really old and therefore does not have jitter? so comparing row timestamp with source timestamp should be sufficient","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"39ca65f3b61d1c52a06a85a4945623aaefb41ec0","unresolved":true,"context_lines":[{"line_number":648,"context_line":"                        timestamp \u003d source_timestamp"},{"line_number":649,"context_line":"                if is_stale:"},{"line_number":650,"context_line":"                    raise Exception("},{"line_number":651,"context_line":"                        \u0027Unknown exception trying to GET: \u0027"},{"line_number":652,"context_line":"                        \u0027%(account)r %(container)r %(object)r\u0027 %"},{"line_number":653,"context_line":"                        {\u0027account\u0027: info[\u0027account\u0027],"},{"line_number":654,"context_line":"                         \u0027container\u0027: info[\u0027container\u0027],"}],"source_content_type":"text/x-python","patch_set":2,"id":"a998e5b9_d4f7a13c","line":651,"range":{"start_line":651,"start_character":25,"end_line":651,"end_character":42},"updated":"2026-09-23 10:32:02.000000000","message":"do we still think this is the most useful error message? the condition is now very clear: stale source object w.r.t. container db row","commit_id":"a6faad06929ac58625f4683d4d9792baeb236c41"}],"test/unit/container/test_sync.py":[{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"7cab797c7c8c4eeb26c44d84d7d23efaa26b00dc","unresolved":false,"context_lines":[{"line_number":1075,"context_line":"            200, {\u0027x-backend-timestamp\u0027: timestamp.internal},"},{"line_number":1076,"context_line":"            iter([b\u0027contents\u0027])))"},{"line_number":1077,"context_line":""},{"line_number":1078,"context_line":"        with mock.patch(\u0027swift.container.sync.put_object\u0027, side_effect\u003d"},{"line_number":1079,"context_line":"                        ClientException(\u0027conflict\u0027, http_status\u003d409)):"},{"line_number":1080,"context_line":"            self.assertTrue(cs.container_sync_row("},{"line_number":1081,"context_line":"                {\u0027deleted\u0027: False, \u0027name\u0027: \u0027object\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"0c865ee3_3164dfa1","line":1078,"updated":"2026-07-23 01:46:58.000000000","message":"pep8: E251 unexpected spaces around keyword / parameter equals","commit_id":"3f15ac5c78c96fe7d2db9313254b35e66bf713a0"}]}
