)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"535693d48661ddfccc3d33d69a33483e34179ca9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"35774ce3_31705c61","updated":"2026-04-22 14:00:28.000000000","message":"Everpure are in the process of working on a similar feature which we were going to create a spec for. Happy to work with you on this.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"32b0fa2edd6cfef143f23e9d9e5a3b1733ded3c0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"4939647d_ea06e461","updated":"2026-06-09 17:05:50.000000000","message":"Another aspect that we should consider for backup software consuming this API:\n\nIt would be useful to be able to query the list of written blocks initially for the first (full) backup as well, to enable performing a sparse backup there.\n\nMaybe this should be baked into get_cbt_extents() with None provided for the from_snapshot arg, or maybe it needs to take a different shape -- not sure.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"5472fbee389f85d55a6199661e25a16f74788f03","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"07069e74_a953489c","updated":"2026-06-01 19:40:28.000000000","message":"I have put up an implementation of this https://review.opendev.org/c/openstack/cinder/+/990923 with a vendor driver support patch as well: https://review.opendev.org/c/openstack/cinder/+/990982","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"85dd522c226f5a717ca9cfd6033c2a60d324cefa","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"49ee46b0_28a3bd40","updated":"2026-05-12 18:01:16.000000000","message":"I\u0027m biased on this as I am very keen to get this going....LGTM","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"8544adbd_67f6db3c","updated":"2026-06-01 13:15:15.000000000","message":"I\u0027m changing my +1 based on this additional review:\n\nOverall the interface shape here is solid, but it\u0027s quite Ceph-RBD-specific in places (snapshot lifecycle, metadata storage, cleanup). I\u0027ve implemented this against a non-RBD backend (FlashArray get_volumes_diff()) and hit several points where the spec assumes Ceph\u0027s existing snapshot chain. Suggesting changes below to make the contract backend-agnostic and to firm up two correctness/lifecycle details.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"b28f482f_f4ead4a3","updated":"2026-05-01 17:03:51.000000000","message":"Sorry for the late response, and thank you so much for the thorough review!\nYou mentioned similar work underway at Pure Storage — would you like\nto include Pure Storage FlashArray CBT support in this spec as well?\nHappy to collaborate if so.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"c7448666_bc27a24e","updated":"2026-06-21 15:47:09.000000000","message":"Thanks everyone for the thorough review — I\u0027ve updated the spec to address all the comments above. Special thanks to Simon for the implementation work, which informed a lot of these changes. Please take another look when you have a chance.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"a19d79a8_720c45fd","updated":"2026-06-16 14:08:06.000000000","message":"Thanks for the spec. It looks well written. Added some comments.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"670bcf873ea9ca791a7111ef5f963e8bbe8a9f0b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"378fcff6_c50bf2d9","updated":"2026-06-01 14:20:36.000000000","message":"This spec currently targets use of CBT information from a backend by cinder-backup, but if we are going to introduce a get_cbt_extents() driver API, I think we should expose the changed block info as a Cinder API as well.\n\nBackup vendors are interested in being able to query for changed blocks to backup volume data outside of cinder-backup. IMO this would make this feature more complete.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"61e3aba1_2fa13d4b","in_reply_to":"18a336e9_308afa80","updated":"2026-06-21 15:47:09.000000000","message":"Added a new os-list_changed_blocks volume action so external backup tools can query CBT info without going through cinder-backup, modeled on Simon\u0027s existing implementation at https://review.opendev.org/c/openstack/cinder/+/990923. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"83ec60f2435a8660cf4aad7c161a88331e360401","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"18a336e9_308afa80","in_reply_to":"378fcff6_c50bf2d9","updated":"2026-06-01 14:31:13.000000000","message":"That is a fair comment. I agree with this Eric.\nI\u0027ll update my implementation of this spec with your suggestion.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"44b1f3ff0f369a56b3623e1348eb50e0727bc33d","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"c10cfb20_7272efe6","in_reply_to":"4939647d_ea06e461","updated":"2026-06-12 17:11:37.000000000","message":"Agreed, this is worth supporting and I don\u0027t think it needs a new method. Letting from_snapshot\u003dNone mean \"diff against an empty image\" makes get_cbt_extents(volume, None, to_snapshot) return the volume\u0027s allocation map — exactly the written-block list needed for a sparse full backup. It maps cleanly on both reference backends (diff_iterate2(fromsnapname\u003dNULL) on Ceph, and the FlashArray diff API with no prior snapshot), and it fits the \"return only the regions that need to be shipped\" semantics: the full backup is just the from_snapshot\u003dNone case, with never-allocated holes omitted.\n\nI\u0027ve folded this into the two implementation patches I\u0027ve already put up — so the sparse-full path is covered there.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"de6e4238_8d395aa5","in_reply_to":"61e3aba1_2fa13d4b","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"d70b1ddd_b5214b63","in_reply_to":"a5f4c62d_1ca6759f","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":7,"id":"a5f4c62d_1ca6759f","in_reply_to":"c10cfb20_7272efe6","updated":"2026-06-21 15:47:09.000000000","message":"Defined from_snapshot\u003dNone as \"diff against an empty volume\" so a full/bootstrap backup can be sparse too — same mechanism Simon converged on. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"d0b2765ec21fb669551e369345179dec54851ed3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"32247149_2858e613","updated":"2026-06-23 16:25:46.000000000","message":"LGTM","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"9a28efaee5907d96da0e2a38fde5b4baa1098a8b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"d7a439ef_759b27c6","updated":"2026-06-22 13:49:35.000000000","message":"Thanks for the very thorough revision, Inyong — this addresses all of the feedback from Eric, Anoop, and myself, and it lines up cleanly with the reference implementation.\n\nConfirming the key points are resolved:\n\n * The lifecycle is now split into create_cbt_snapshot() / get_cbt_extents() / delete_cbt_snapshot(), with get_cbt_extents() side-effect-free — much cleaner contract.\n * `exists` is inverted to \"True \u003d must back up, False \u003d safe to skip\", and from_snapshot\u003dNone is defined as the allocation-map (sparse full/bootstrap) path.\n * Two distinct fallbacks (non-CBT parent → SHA-diff; lost reference → re-bootstrap), reference point stored transactionally in Backup.metadata, backend-neutral cleanup in the backup manager, and the normative \"Driver Responsibilities\" section.\n * Interface reframed as backend-agnostic with both Ceph RBD and FlashArray sketches, the public os-list_changed_blocks action for external tools, and the RPC 3.21 bump with assert_min_rpc_version.\n\nOne non-blocking note for the implementation phase rather than the spec: with the inverted exists, please make sure the Ceph reference path maps a region that was deallocated since the base snapshot (data → unmap/zero) to exists\u003dTrue so it\u0027s still shipped — RBD\u0027s native exists flag has the opposite polarity (\"allocated in image\"), and we don\u0027t want a discard to be silently skipped on restore. The array-backed path is conservative here since it ships every region the diff returns.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":10,"id":"f47f7b1f_d86df79a","updated":"2026-07-17 13:42:35.000000000","message":"A few final thoughts","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"67833cd4af4909356b0579e04a71d17f5d758dd7","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"931d5470_442a84df","updated":"2026-07-27 14:03:34.000000000","message":"Some additional comments. Thanks for addressing the other comments.","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"b52fe56b_ae78ee26","updated":"2026-08-07 13:16:43.000000000","message":"Thanks for the review. I fixed you mentioned. please check again.","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"88a1b3b9b8f4e78ec7a81f1568897074b43e9c62","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"60eee7cf_deb7c092","in_reply_to":"f47f7b1f_d86df79a","updated":"2026-09-10 13:40:16.000000000","message":"Done","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"7c700f1d8038159235b10963be68582587a3c825","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"26a59ef7_749a706b","updated":"2026-08-26 16:43:57.000000000","message":"Thanks for addressing the comments. LGTM","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":11,"id":"21e117e6_b74415c1","updated":"2026-08-26 17:36:44.000000000","message":"We are beyond the 2026.1 cycle, so move this to 2026.2.\n\nSome final bits that should make it ready for my +@","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"4ae49695_d00a561b","in_reply_to":"21e117e6_b74415c1","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":12,"id":"77f8737d_d6afc38a","updated":"2026-09-17 18:56:23.000000000","message":"@inyong.hong@samsung.com after some deep feedback from NetApp I had to make changes in the implementation code. \nThis means that the spec will need to have a few changes - all below.\nAlso, you should now move this to the 2027.1 directory when #1006031 has merged","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"5e612a13791ec9886e1ec31261b876b5fdae246b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":12,"id":"b86ddfbe_f31beb29","updated":"2026-09-17 13:05:48.000000000","message":"@inyong.hong@samsung.com can you move this to 2027.1 when the directory is ready. I will then re-add my +2","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"1a80f648690935ec2059a0e48c557ab388fc2e22","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":12,"id":"66b40fe8_79149462","updated":"2026-09-10 13:39:58.000000000","message":"I\u0027m happy with this now","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":12,"id":"f8b4886c_3164d116","updated":"2026-08-30 11:10:47.000000000","message":"Thanks Simon. All seven comments are fixed in PS12. Two more things I found while checking the spec against the landed code:\n\n1. The Ceph example passed diff_iterate\u0027s exists through as-is. In an incremental diff exists\u003d0 means the range was discarded and now reads as zeros, so skipping it leaves the parent\u0027s old data on restore. Fixed to match my RBD driver (1002961).\n2. get_cbt_extents() still had the old signature from before paging. Updated to match BaseVD, and it now ends with window_cbt_page().\n\nI also added you as primary assignee and myself as a contributor — I posted the Ceph RBD driver as 1002961.","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"4174f611b115e1f950efae47c8f15d69d465fd35","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":15,"id":"cd40aff8_515a1c0d","updated":"2026-09-19 13:29:05.000000000","message":"Don\u0027t move until #1006031has merged. The Zuul -1 because of that will stop reviewers looking at the spec.","commit_id":"89032a14f3be9504b3a0cca27abc0b5cf6224d82"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"16ab2f179ef10590ff72fb041202ebbc97c5dbc7","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":15,"id":"687f6652_2f2d0cb5","updated":"2026-09-19 07:52:30.000000000","message":"Thanks for the review. \nMoved to specs/2027.1/ and applied all comments.\nAfter this(#1006031) merge I\u0027ll recheck.","commit_id":"89032a14f3be9504b3a0cca27abc0b5cf6224d82"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"4e93c72258f2ac5c4f0b1515b7aa042caea5b303","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"15d80c2d_be161e5d","updated":"2026-09-20 17:37:26.000000000","message":"LGTM. Implementation code is built and working on reference backends and a real backend.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"31bb1980c450021a723399f01815c62626a7b99d","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"2c4a55df_d2568b99","updated":"2026-09-23 15:01:46.000000000","message":"Some additional comments. apologies for pouring in comments one by one.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"ca2aa26bf183f6ab9961818470ae048b33febb37","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"6bda2574_8e209a6b","updated":"2026-09-20 08:48:32.000000000","message":"Understood, reverted to specs/2026.2/. Will move once #1006031 has merged.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"c97cee4cd4d56a91af3f39152641a68ed1c2029f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"89f4a8e6_d2508c78","updated":"2026-09-22 19:19:17.000000000","message":"Yes, that\u0027s the right picture. Each backend tracks change at a fixed granularity (RBD object/stripe, thin-LVM pool chunk, array-specific for FlashArray), a unit touched anywhere is dirty as a whole, and consecutive dirty units are merged -- so offset is the start of the first dirty unit in a run and offset + length the end of the last. A partially modified unit is therefore shipped whole; that\u0027s the inherent granularity cost of CBT and why the coarser the backend\u0027s unit, the more each small write costs. Two nuances: \"block\" here is the backend\u0027s tracking unit, not a sector, and the contract is expressed in bytes on purpose so it stays backend-neutral -- it doesn\u0027t require alignment, consumers just read [offset, offset + length) and would be equally correct with a byte-precise backend. All current drivers happen to be aligned as you describe.\n\nI\u0027ll add a suggestion for changes that @inyong.hong@samsung.com can add to the spec.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"e5c1d3837ad999e2398cb186a883042f1a6c3df6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"0ef2934b_f41a8dbf","updated":"2026-09-23 18:01:17.000000000","message":"please move to 2027.1","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"b334ec4c372c7d0e9152976fccf9065575a59914","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"d8813e3e_7b05aad7","in_reply_to":"0ef2934b_f41a8dbf","updated":"2026-09-28 12:57:06.000000000","message":"Done — moved to specs/2027.1/ and removed the `remove-me.rst`","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"}],"specs/2026.1/incremental-backup-cbt.rst":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":88,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` detects this method on"},{"line_number":89,"context_line":"the volume driver and wraps ``volume_file`` with a lightweight wrapper that"},{"line_number":90,"context_line":"exposes ``get_cbt_extents()`` to the backup driver. ``chunkeddriver.py`` detects"},{"line_number":91,"context_line":"the presence of this method and uses it when available::"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"7520efd6_63759579","line":89,"range":{"start_line":89,"start_character":49,"end_line":89,"end_character":70},"updated":"2026-04-22 13:37:38.000000000","message":"can you create a short pseudocode sketch of the wrapper class:\n* What other methods it exposes?\n* Does it wrap the raw file handle, or sit alongside?\n* How does chunkeddriver.py detect whether the wrapped volume_file has get_cbt_extents available (simple hasattr check? A protocol class?)\n* What is the lifetime of the wrapper — is it created per-backup-operation or per-volume?","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":88,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` detects this method on"},{"line_number":89,"context_line":"the volume driver and wraps ``volume_file`` with a lightweight wrapper that"},{"line_number":90,"context_line":"exposes ``get_cbt_extents()`` to the backup driver. ``chunkeddriver.py`` detects"},{"line_number":91,"context_line":"the presence of this method and uses it when available::"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"bd3d3e91_0cb870fd","line":89,"range":{"start_line":89,"start_character":49,"end_line":89,"end_character":70},"in_reply_to":"7520efd6_63759579","updated":"2026-05-01 17:03:51.000000000","message":"Added detailed pseudocode for CBTVolumeFileWrapper, backup/manager.py\nwrapper creation, and chunkeddriver.py CBT detection. Also clarified\nthat snapshot creation and diff_iterate run in the same RBD session,\nfollowing the same pattern as CephBackupDriver._backup_rbd().","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":88,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` detects this method on"},{"line_number":89,"context_line":"the volume driver and wraps ``volume_file`` with a lightweight wrapper that"},{"line_number":90,"context_line":"exposes ``get_cbt_extents()`` to the backup driver. ``chunkeddriver.py`` detects"},{"line_number":91,"context_line":"the presence of this method and uses it when available::"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"476eec7a_c6dfd0a4","line":89,"range":{"start_line":89,"start_character":49,"end_line":89,"end_character":70},"in_reply_to":"bd3d3e91_0cb870fd","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":107,"context_line":"provides ``offset``, ``length``, and ``exists`` (boolean: ``True`` \u003d data,"},{"line_number":108,"context_line":"``False`` \u003d zero block) for each changed extent."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"**For NetApp ONTAP**:"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"NetApp SnapDiff API provides CBT capabilities, but integration requires"},{"line_number":113,"context_line":"cooperation from the NetApp volume driver to expose capabilities through"},{"line_number":114,"context_line":"``get_cbt_extents()``. The feasibility and scope of NetApp CBT integration will"},{"line_number":115,"context_line":"be evaluated separately."},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"**Reference Point Management**:"},{"line_number":118,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"137903c8_611dc2d7","line":115,"range":{"start_line":110,"start_character":0,"end_line":115,"end_character":24},"updated":"2026-04-22 13:37:38.000000000","message":"Are you going to do this NetApp work? If not, I would not mention NetApp. If you aren\u0027t doing the work and still want to mention NetApp then you should also mention other vendors wit the same capabilities, such as the Everpure FlashArray.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":107,"context_line":"provides ``offset``, ``length``, and ``exists`` (boolean: ``True`` \u003d data,"},{"line_number":108,"context_line":"``False`` \u003d zero block) for each changed extent."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"**For NetApp ONTAP**:"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"NetApp SnapDiff API provides CBT capabilities, but integration requires"},{"line_number":113,"context_line":"cooperation from the NetApp volume driver to expose capabilities through"},{"line_number":114,"context_line":"``get_cbt_extents()``. The feasibility and scope of NetApp CBT integration will"},{"line_number":115,"context_line":"be evaluated separately."},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"**Reference Point Management**:"},{"line_number":118,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"2486bc1a_6ae93cd8","line":115,"range":{"start_line":110,"start_character":0,"end_line":115,"end_character":24},"in_reply_to":"137903c8_611dc2d7","updated":"2026-05-01 17:03:51.000000000","message":"Removed. checked that NetApp SnapDiff API only works with SnapMirror,\nnot general snapshot-based CBT. NetApp section has been dropped.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":107,"context_line":"provides ``offset``, ``length``, and ``exists`` (boolean: ``True`` \u003d data,"},{"line_number":108,"context_line":"``False`` \u003d zero block) for each changed extent."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"**For NetApp ONTAP**:"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"NetApp SnapDiff API provides CBT capabilities, but integration requires"},{"line_number":113,"context_line":"cooperation from the NetApp volume driver to expose capabilities through"},{"line_number":114,"context_line":"``get_cbt_extents()``. The feasibility and scope of NetApp CBT integration will"},{"line_number":115,"context_line":"be evaluated separately."},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"**Reference Point Management**:"},{"line_number":118,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"46d89f9c_9c52e798","line":115,"range":{"start_line":110,"start_character":0,"end_line":115,"end_character":24},"in_reply_to":"2486bc1a_6ae93cd8","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":160,"context_line":"        \"version\": \"1.0\","},{"line_number":161,"context_line":"        \"cbt_method\": \"\","},{"line_number":162,"context_line":"        \"cbt_backend\": \"ceph\","},{"line_number":163,"context_line":"        \"reference_point\": {"},{"line_number":164,"context_line":"            \"type\": \"rbd_snapshot\","},{"line_number":165,"context_line":"            \"snapshot_id\": \"backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\""},{"line_number":166,"context_line":"        },"}],"source_content_type":"text/x-rst","patch_set":6,"id":"7b9ba4be_8eb070bf","line":163,"range":{"start_line":163,"start_character":9,"end_line":163,"end_character":24},"updated":"2026-04-22 13:37:38.000000000","message":"what is the lifecycle of this reference_point? who creates it and when, who deletes it and when, what happens is a snapshot deletion fails, what happens if the backup fails after the snapshot is created but before the metadata is written?\nYou should specify:\n* The reference point snapshot is created at the start of a backup operation and recorded in metadata on success\n* On the next incremental backup, after the new reference point is successfully recorded, the previous reference point snapshot is deleted\n* If backup fails after snapshot creation, the snapshot is cleaned up as part of the backup failure path\n* A periodic audit/cleanup mechanism should be noted as a follow-on work item for orphaned reference snapshots","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":160,"context_line":"        \"version\": \"1.0\","},{"line_number":161,"context_line":"        \"cbt_method\": \"\","},{"line_number":162,"context_line":"        \"cbt_backend\": \"ceph\","},{"line_number":163,"context_line":"        \"reference_point\": {"},{"line_number":164,"context_line":"            \"type\": \"rbd_snapshot\","},{"line_number":165,"context_line":"            \"snapshot_id\": \"backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\""},{"line_number":166,"context_line":"        },"}],"source_content_type":"text/x-rst","patch_set":6,"id":"ed4912af_d13b2220","line":163,"range":{"start_line":163,"start_character":9,"end_line":163,"end_character":24},"in_reply_to":"276ba4a3_dad4724d","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":160,"context_line":"        \"version\": \"1.0\","},{"line_number":161,"context_line":"        \"cbt_method\": \"\","},{"line_number":162,"context_line":"        \"cbt_backend\": \"ceph\","},{"line_number":163,"context_line":"        \"reference_point\": {"},{"line_number":164,"context_line":"            \"type\": \"rbd_snapshot\","},{"line_number":165,"context_line":"            \"snapshot_id\": \"backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\""},{"line_number":166,"context_line":"        },"}],"source_content_type":"text/x-rst","patch_set":6,"id":"276ba4a3_dad4724d","line":163,"range":{"start_line":163,"start_character":9,"end_line":163,"end_character":24},"in_reply_to":"7b9ba4be_8eb070bf","updated":"2026-05-01 17:03:51.000000000","message":"Added full snapshot lifecycle documentation: creation inside\nget_cbt_extents(), retention via backup_ceph_max_snapshots (recommended\nvalue: 1), failure cleanup in except block, and crash recovery via\n_cleanup_temp_volumes_snapshots_for_one_backup(). Naming follows existing\nCeph-to-Ceph convention using _get_new_snap_name().","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":184,"context_line":"* CBT API call fails"},{"line_number":185,"context_line":"* Inconsistent reference chain detected"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"In all cases, log the reason and proceed with standard full scan without user"},{"line_number":188,"context_line":"impact."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"97513bce_f8ceffdb","line":188,"range":{"start_line":187,"start_character":0,"end_line":188,"end_character":7},"updated":"2026-04-22 13:37:38.000000000","message":"what log level and what message content should be supplied here?","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":184,"context_line":"* CBT API call fails"},{"line_number":185,"context_line":"* Inconsistent reference chain detected"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"In all cases, log the reason and proceed with standard full scan without user"},{"line_number":188,"context_line":"impact."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"d02c3bef_9536e140","line":188,"range":{"start_line":187,"start_character":0,"end_line":188,"end_character":7},"in_reply_to":"97513bce_f8ceffdb","updated":"2026-05-01 17:03:51.000000000","message":"Added explicit log levels: LOG.info for CBT usage with extent stats,\nLOG.info for fallback cases with reason.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":184,"context_line":"* CBT API call fails"},{"line_number":185,"context_line":"* Inconsistent reference chain detected"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"In all cases, log the reason and proceed with standard full scan without user"},{"line_number":188,"context_line":"impact."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"b62c3775_a092861e","line":188,"range":{"start_line":187,"start_character":0,"end_line":188,"end_character":7},"in_reply_to":"d02c3bef_9536e140","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"Restore operations work with both CBT-optimized and traditional backups."},{"line_number":193,"context_line":"Layer incremental changes on top of full backups regardless of whether CBT"},{"line_number":194,"context_line":"was used. CBT metadata is informational for performance analysis only."},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"Data model impact"}],"source_content_type":"text/x-rst","patch_set":6,"id":"c074bf05_cda03465","line":194,"range":{"start_line":192,"start_character":0,"end_line":194,"end_character":70},"updated":"2026-04-22 13:37:38.000000000","message":"The changed_blocks array stored in cbt_metadata is not purely informational — it is the only record of which byte ranges were written during a CBT incremental backup. Without it, a restore of a CBT incremental has no way to know which extents to apply to the target volume or in what order.\nYou should add a Restore Path section covering chain reconstruction, extent ordering and integrity and cross-backend restore","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"Restore operations work with both CBT-optimized and traditional backups."},{"line_number":193,"context_line":"Layer incremental changes on top of full backups regardless of whether CBT"},{"line_number":194,"context_line":"was used. CBT metadata is informational for performance analysis only."},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"Data model impact"}],"source_content_type":"text/x-rst","patch_set":6,"id":"e070b114_5b0952c4","line":194,"range":{"start_line":192,"start_character":0,"end_line":194,"end_character":70},"in_reply_to":"c074bf05_cda03465","updated":"2026-05-01 17:03:51.000000000","message":"Added Restore Path section. CBT does not affect restore — the existing\nChunkedBackupDriver.restore() handles chain reconstruction via parent_id,\nordered application, MD5 integrity, and cross-backend restore using\nchunk offsets stored in backup storage. See inline comment for details.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":189,"context_line":""},{"line_number":190,"context_line":"**Restore Compatibility**:"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"Restore operations work with both CBT-optimized and traditional backups."},{"line_number":193,"context_line":"Layer incremental changes on top of full backups regardless of whether CBT"},{"line_number":194,"context_line":"was used. CBT metadata is informational for performance analysis only."},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"Data model impact"}],"source_content_type":"text/x-rst","patch_set":6,"id":"212464f1_9cbffed4","line":194,"range":{"start_line":192,"start_character":0,"end_line":194,"end_character":70},"in_reply_to":"e070b114_5b0952c4","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":235,"context_line":"  ``false`` if known zero block"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"**Storage Location**:"},{"line_number":238,"context_line":"* Metadata is stored in the backup object\u0027s metadata field"},{"line_number":239,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":240,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":241,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":6,"id":"44b8d014_919a3212","line":238,"range":{"start_line":238,"start_character":2,"end_line":238,"end_character":58},"updated":"2026-04-22 13:37:38.000000000","message":"this is convenient, but can create a scale problem. For example, a 10 TB volume with 4 KB block granularity and 10% change rate, the changed block list could contain on the order of 250,000 entries. At approximately 80 bytes per JSON entry (offset, length, exists, plus a checksum if added), that is ~20 MB of JSON in a single backup metadata field. Most database backends have practical limits on field size well below this.\nSpecify either a maximum extent map size and define what happens when it is exceeded or note that the changed_blocks array should store consolidated extents — merging adjacent or near-adjacent changed regions into single entries — rather than raw block-level granularity from the backend API.\nI would add a note to the Data Model section specifying that adjacent extents should be consolidated by the driver before being stored, and document a recommended maximum for the changed_blocks array size (suggest 10,000 entries as a soft limit, with fallback to full scan if exceeded).","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":235,"context_line":"  ``false`` if known zero block"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"**Storage Location**:"},{"line_number":238,"context_line":"* Metadata is stored in the backup object\u0027s metadata field"},{"line_number":239,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":240,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":241,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9a219ce1_b8673c50","line":238,"range":{"start_line":238,"start_character":2,"end_line":238,"end_character":58},"in_reply_to":"44b8d014_919a3212","updated":"2026-05-01 17:03:51.000000000","message":"Resolved by removing changed_blocks from backup metadata entirely.\nThe list is used only in memory during backup and discarded afterward.\nChunk objects already store offset/length, so no persistent storage needed.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":235,"context_line":"  ``false`` if known zero block"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"**Storage Location**:"},{"line_number":238,"context_line":"* Metadata is stored in the backup object\u0027s metadata field"},{"line_number":239,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":240,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":241,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":6,"id":"d602e733_48561f4d","line":238,"range":{"start_line":238,"start_character":2,"end_line":238,"end_character":58},"in_reply_to":"9a219ce1_b8673c50","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":241,"context_line":"* Not required for restore operations"},{"line_number":242,"context_line":""},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"Performance Impact"},{"line_number":245,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":246,"context_line":""},{"line_number":247,"context_line":"**Positive Impact**:"}],"source_content_type":"text/x-rst","patch_set":6,"id":"d7dc1c67_5c6bdb7c","line":244,"range":{"start_line":244,"start_character":0,"end_line":244,"end_character":18},"updated":"2026-04-22 13:37:38.000000000","message":"This whole section is pitched entirely at software-defined storage, eg. Ceph, but array-backed volumes may have near zero CBT query overhead, so mentioning this will add weight to this spec as a generic interface.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"77e2cbd71b9ddef570b472f3c699ddc054337c90","unresolved":true,"context_lines":[{"line_number":241,"context_line":"* Not required for restore operations"},{"line_number":242,"context_line":""},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"Performance Impact"},{"line_number":245,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":246,"context_line":""},{"line_number":247,"context_line":"**Positive Impact**:"}],"source_content_type":"text/x-rst","patch_set":6,"id":"ebcf7de0_9305c756","line":244,"range":{"start_line":244,"start_character":0,"end_line":244,"end_character":18},"in_reply_to":"d7dc1c67_5c6bdb7c","updated":"2026-05-01 17:03:51.000000000","message":"Added note to Performance Impact: hardware storage arrays implement CBT\nin hardware, resulting in near-zero overhead compared to software-defined\nbackends.","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":241,"context_line":"* Not required for restore operations"},{"line_number":242,"context_line":""},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"Performance Impact"},{"line_number":245,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":246,"context_line":""},{"line_number":247,"context_line":"**Positive Impact**:"}],"source_content_type":"text/x-rst","patch_set":6,"id":"7b69c408_a3b013d4","line":244,"range":{"start_line":244,"start_character":0,"end_line":244,"end_character":18},"in_reply_to":"ebcf7de0_9305c756","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ba1ee18041c53db830025303deb7e3531d48d22","unresolved":true,"context_lines":[{"line_number":365,"context_line":"  volume driver and wrap ``volume_file`` with a lightweight CBT-aware wrapper"},{"line_number":366,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":367,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":368,"context_line":"* Evaluate NetApp CBT integration feasibility with volume driver"},{"line_number":369,"context_line":"  cooperation (NetApp SnapDiff API may provide CBT capabilities but requires"},{"line_number":370,"context_line":"  volume driver cooperation)"},{"line_number":371,"context_line":"* Implement automatic fallback behavior"},{"line_number":372,"context_line":"* Unit tests for CBT detection and fallback"},{"line_number":373,"context_line":"* Unit tests for CBT API integration (mocked backends)"}],"source_content_type":"text/x-rst","patch_set":6,"id":"fa69d174_9e0ba80c","line":370,"range":{"start_line":368,"start_character":2,"end_line":370,"end_character":28},"updated":"2026-04-22 13:37:38.000000000","message":"see previous comment","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":365,"context_line":"  volume driver and wrap ``volume_file`` with a lightweight CBT-aware wrapper"},{"line_number":366,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":367,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":368,"context_line":"* Evaluate NetApp CBT integration feasibility with volume driver"},{"line_number":369,"context_line":"  cooperation (NetApp SnapDiff API may provide CBT capabilities but requires"},{"line_number":370,"context_line":"  volume driver cooperation)"},{"line_number":371,"context_line":"* Implement automatic fallback behavior"},{"line_number":372,"context_line":"* Unit tests for CBT detection and fallback"},{"line_number":373,"context_line":"* Unit tests for CBT API integration (mocked backends)"}],"source_content_type":"text/x-rst","patch_set":6,"id":"5182a6e8_8d1c5e84","line":370,"range":{"start_line":368,"start_character":2,"end_line":370,"end_character":28},"in_reply_to":"fa69d174_9e0ba80c","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"166d8e420662bf818b141f8f743f81792ba05617"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":22,"context_line":"the storage system\u0027s native CBT API to identify specific changed ranges."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Note that the existing ``CephBackupDriver`` implements CBT optimization for"},{"line_number":25,"context_line":"Ceph→Ceph backups using ``rbd export-diff/import-diff``, but this is tightly"},{"line_number":26,"context_line":"coupled to both Ceph source and Ceph target. This specification focuses on enabling"},{"line_number":27,"context_line":"CBT optimization for backups to general backup targets (Swift, S3, etc.)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"426d43c8_9bdfe949","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":9},"updated":"2026-06-16 14:08:06.000000000","message":"Since this is an upstream spec, can we keep it driver neutral and use Ceph as an example in places where explanation needs to be provided?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":22,"context_line":"the storage system\u0027s native CBT API to identify specific changed ranges."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Note that the existing ``CephBackupDriver`` implements CBT optimization for"},{"line_number":25,"context_line":"Ceph→Ceph backups using ``rbd export-diff/import-diff``, but this is tightly"},{"line_number":26,"context_line":"coupled to both Ceph source and Ceph target. This specification focuses on enabling"},{"line_number":27,"context_line":"CBT optimization for backups to general backup targets (Swift, S3, etc.)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"a1cc40e4_ce6d8ecb","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":9},"in_reply_to":"2f3e153a_ae819e62","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":22,"context_line":"the storage system\u0027s native CBT API to identify specific changed ranges."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Note that the existing ``CephBackupDriver`` implements CBT optimization for"},{"line_number":25,"context_line":"Ceph→Ceph backups using ``rbd export-diff/import-diff``, but this is tightly"},{"line_number":26,"context_line":"coupled to both Ceph source and Ceph target. This specification focuses on enabling"},{"line_number":27,"context_line":"CBT optimization for backups to general backup targets (Swift, S3, etc.)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"2f3e153a_ae819e62","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":9},"in_reply_to":"426d43c8_9bdfe949","updated":"2026-06-21 15:47:09.000000000","message":"Reframed the intro to state the interface is backend-agnostic, with Ceph as the running example. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":78,"context_line":"* **chunkeddriver extension**: CBT detection and coordination logic is"},{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"}],"source_content_type":"text/x-rst","patch_set":7,"id":"4ce4f939_f971d61d","line":81,"range":{"start_line":81,"start_character":2,"end_line":81,"end_character":80},"updated":"2026-06-01 13:15:15.000000000","message":"Recommend distinguishing two fallback cases, because a blanket \"full scan\" permanently degrades a CBT chain:\n\n* Parent is a non-CBT backup (has a SHA256 file) → fall back to the existing SHA-diff incremental (efficient, no full read needed).\n* Parent is a CBT backup but the diff can\u0027t run (reference snapshot deleted on the array, decode error, API failure) → re-bootstrap: create a fresh reference point and do a one-off full scan, so the next backup is a CBT incremental again. \n\nWithout this, a single lost reference snapshot drops the chain to full-scan/SHA forever until an operator manually runs a new full backup.\nThis self-healing behavior matters a lot operationally when reference snapshots can disappear out-of-band.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":78,"context_line":"* **chunkeddriver extension**: CBT detection and coordination logic is"},{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"}],"source_content_type":"text/x-rst","patch_set":7,"id":"d9d60e89_0ce4610b","line":81,"range":{"start_line":81,"start_character":2,"end_line":81,"end_character":80},"in_reply_to":"149ee4e9_117ebbe8","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":78,"context_line":"* **chunkeddriver extension**: CBT detection and coordination logic is"},{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"}],"source_content_type":"text/x-rst","patch_set":7,"id":"149ee4e9_117ebbe8","line":81,"range":{"start_line":81,"start_character":2,"end_line":81,"end_character":80},"in_reply_to":"4ce4f939_f971d61d","updated":"2026-06-21 15:47:09.000000000","message":"Split into two fallback cases as suggested: no-reference-point uses the existing SHA-diff path, lost-reference re-bootstraps with a fresh snapshot. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"},{"line_number":85,"context_line":"* **Initial backend support**: Ceph RBD only. Other backends may add CBT"},{"line_number":86,"context_line":"  support by implementing ``get_cbt_extents()`` in their volume driver."},{"line_number":87,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"998e5bd6_8d86eb3d","line":84,"range":{"start_line":82,"start_character":2,"end_line":84,"end_character":72},"updated":"2026-06-01 13:15:15.000000000","message":"This needs tightening, and I\u0027d suggest inverting it. Define the diff as returning only the regions that need to be shipped, and make exists an explicit skip signal:\n\n`exists\u003dTrue` — region changed and must be backed up. A block that changed to zero is still exists\u003dTrue (read from the device, which returns zeros). This preserves restore correctness for data→zero transitions.\n`exists\u003dFalse` — region is unallocated/sparse and can be skipped, inheriting from the parent chain on restore.\n\nAs written (\"read and store all exists\u003dFalse\"), the flag carries no benefit — you store zeros either way. With the skip semantics it becomes a real I/O/space optimization for sparse volumes, while data→zero correctness is handled by reporting those as exists\u003dTrue. Worth stating the data→zero rule explicitly, because the obvious reading of \"exists\u003dFalse \u003d zeroed → skip it\" would silently corrupt incrementals.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"},{"line_number":85,"context_line":"* **Initial backend support**: Ceph RBD only. Other backends may add CBT"},{"line_number":86,"context_line":"  support by implementing ``get_cbt_extents()`` in their volume driver."},{"line_number":87,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"1834d34b_38261226","line":84,"range":{"start_line":82,"start_character":2,"end_line":84,"end_character":72},"in_reply_to":"2ab8a620_3605f5a7","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":79,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":80,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":81,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":82,"context_line":"* **Zero block handling**: ``exists\u003dFalse`` extents (zeroed blocks) are read"},{"line_number":83,"context_line":"  from the device (returns zeros) and stored as normal backup objects, ensuring"},{"line_number":84,"context_line":"  correct restore behavior without requiring separate zero-fill metadata"},{"line_number":85,"context_line":"* **Initial backend support**: Ceph RBD only. Other backends may add CBT"},{"line_number":86,"context_line":"  support by implementing ``get_cbt_extents()`` in their volume driver."},{"line_number":87,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"2ab8a620_3605f5a7","line":84,"range":{"start_line":82,"start_character":2,"end_line":84,"end_character":72},"in_reply_to":"998e5bd6_8d86eb3d","updated":"2026-06-21 15:47:09.000000000","message":"Inverted as suggested — exists\u003dTrue now means \"must back up\" (including data→zero), exists\u003dFalse means \"safe to skip\". Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"**CBT Interface**:"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"}],"source_content_type":"text/x-rst","patch_set":7,"id":"10b91dcb_bc11cfcf","line":90,"range":{"start_line":90,"start_character":66,"end_line":90,"end_character":77},"updated":"2026-06-16 14:08:06.000000000","message":"What would be passed in to_snapshot? Since the snapshot is yet to be taken?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"**CBT Interface**:"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"}],"source_content_type":"text/x-rst","patch_set":7,"id":"d61ea30a_499f0561","line":90,"range":{"start_line":90,"start_character":66,"end_line":90,"end_character":77},"in_reply_to":"10b91dcb_bc11cfcf","updated":"2026-06-21 15:47:09.000000000","message":"Resolved structurally — create_cbt_snapshot() now creates it before get_cbt_extents() is ever called, so to_snapshot always exists by then. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"**CBT Interface**:"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"Volume drivers implement ``get_cbt_extents(volume, from_snapshot, to_snapshot)``"},{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"}],"source_content_type":"text/x-rst","patch_set":7,"id":"91c30ada_012efa6d","line":90,"range":{"start_line":90,"start_character":66,"end_line":90,"end_character":77},"in_reply_to":"d61ea30a_499f0561","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"},{"line_number":94,"context_line":"which detects the presence of ``get_cbt_extents()`` and uses it when available."},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"**For Ceph RBD** (``cinder/volume/drivers/rbd.py``)::"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"9a9c2bfd_5f360278","line":94,"range":{"start_line":94,"start_character":64,"end_line":94,"end_character":79},"updated":"2026-06-16 14:08:06.000000000","message":"What is the expectation from driver response if the diff cannot be evaluated and driver cannot respond to get_cbt_extents() API?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"},{"line_number":94,"context_line":"which detects the presence of ``get_cbt_extents()`` and uses it when available."},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"**For Ceph RBD** (``cinder/volume/drivers/rbd.py``)::"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"ffbca324_c82f857b","line":94,"range":{"start_line":94,"start_character":64,"end_line":94,"end_character":79},"in_reply_to":"9a9c2bfd_5f360278","updated":"2026-06-21 15:47:09.000000000","message":"get_cbt_extents() must return None on any failure (no partial/guessed diff) — stated at its definition and in the new Driver Responsibilities section. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":91,"context_line":"using backend-native APIs. ``cinder/backup/manager.py`` calls this via RPC to"},{"line_number":92,"context_line":"``cinder/volume/manager.py``, which delegates to the volume driver. The result"},{"line_number":93,"context_line":"is wrapped in a ``CBTVolumeFileWrapper`` and passed to ``chunkeddriver.py``,"},{"line_number":94,"context_line":"which detects the presence of ``get_cbt_extents()`` and uses it when available."},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"**For Ceph RBD** (``cinder/volume/drivers/rbd.py``)::"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"45df9a5a_340ecd60","line":94,"range":{"start_line":94,"start_character":64,"end_line":94,"end_character":79},"in_reply_to":"ffbca324_c82f857b","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"Snapshot lifecycle:"},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"* **Creation**: snapshot creation and diff calculation are handled together"},{"line_number":253,"context_line":"  inside ``get_cbt_extents()``, following the same pattern as the existing"},{"line_number":254,"context_line":"  Ceph-to-Ceph backup driver (``CephBackupDriver._backup_rbd()``), where"},{"line_number":255,"context_line":"  ``create_snap()`` and ``_rbd_diff_transfer()`` run in the same RBD session."},{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"}],"source_content_type":"text/x-rst","patch_set":7,"id":"f846ba85_0bff42ae","line":257,"range":{"start_line":252,"start_character":2,"end_line":257,"end_character":44},"updated":"2026-06-01 13:15:15.000000000","message":"Recommend splitting the snapshot lifecycle out of get_cbt_extents() into two additional optional driver methods:\n\ncreate_cbt_snapshot(volume, snapshot)   # establish a reference point\ndelete_cbt_snapshot(volume, snapshot)   # idempotent, best-effort\n\nFolding creation into get_cbt_extents() works for Ceph because the RBD backup driver already maintains a snapshot chain, but backends without that machinery (e.g. FlashArray) have no way to establish the first reference point for the initial incremental. Explicit create/delete lets the backup manager bootstrap a reference point on the full backup, so CBT is available from the very first incremental rather than only after a second CBT-aware backup has run. It also gives the manager a defined hook to reclaim superseded snapshots instead of relying on a Ceph-only retention mechanism (see comment on _remove_last_snapshots). Keep all three as no-op base stubs returning None","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"Snapshot lifecycle:"},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"* **Creation**: snapshot creation and diff calculation are handled together"},{"line_number":253,"context_line":"  inside ``get_cbt_extents()``, following the same pattern as the existing"},{"line_number":254,"context_line":"  Ceph-to-Ceph backup driver (``CephBackupDriver._backup_rbd()``), where"},{"line_number":255,"context_line":"  ``create_snap()`` and ``_rbd_diff_transfer()`` run in the same RBD session."},{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"}],"source_content_type":"text/x-rst","patch_set":7,"id":"3460c81e_e3627764","line":257,"range":{"start_line":252,"start_character":2,"end_line":257,"end_character":44},"in_reply_to":"cf073182_5f67c4c9","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"Snapshot lifecycle:"},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"* **Creation**: snapshot creation and diff calculation are handled together"},{"line_number":253,"context_line":"  inside ``get_cbt_extents()``, following the same pattern as the existing"},{"line_number":254,"context_line":"  Ceph-to-Ceph backup driver (``CephBackupDriver._backup_rbd()``), where"},{"line_number":255,"context_line":"  ``create_snap()`` and ``_rbd_diff_transfer()`` run in the same RBD session."},{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"}],"source_content_type":"text/x-rst","patch_set":7,"id":"cf073182_5f67c4c9","line":257,"range":{"start_line":252,"start_character":2,"end_line":257,"end_character":44},"in_reply_to":"f846ba85_0bff42ae","updated":"2026-06-21 15:47:09.000000000","message":"Split into create_cbt_snapshot() / get_cbt_extents() / delete_cbt_snapshot() as you proposed — get_cbt_extents() is now side-effect-free. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"a3a36e20_464a4902","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"updated":"2026-06-01 13:15:15.000000000","message":"This is Ceph-RBD-specific and won\u0027t generalize. Suggest defining cleanup in backend-neutral terms in the backup manager:\n\n* On a successful incremental, drop the now-superseded parent reference snapshot via delete_cbt_snapshot() (Cinder incremental chains are linear, so it has no other consumer).\n* On cancel/error, drop the freshly created (now orphaned) reference snapshot.\n* Require delete_cbt_snapshot() to be idempotent for an already-absent snapshot.\n\nThe Ceph driver can still map these onto its existing retention internally, but the contract shouldn\u0027t bake backup_ceph_max_snapshots into the framework.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"093c0324_bc7ed907","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"in_reply_to":"1a3bb66d_59a26fc2","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"1a3bb66d_59a26fc2","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"in_reply_to":"2c1ed8e7_0786592d","updated":"2026-06-21 15:47:09.000000000","message":"Moved cleanup into the backup manager in backend-neutral terms (delete superseded on success, delete orphan on error/cancel), dropped backup_ceph_max_snapshots. Also made delete_cbt_snapshot() explicitly idempotent, and the framework doesn\u0027t require synchronous deletion — a driver may soft-delete and reclaim later as long as the call itself doesn\u0027t block the backup. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":256,"context_line":"  This is intentional: Ceph requires the same RBD image context for both"},{"line_number":257,"context_line":"  operations, making separation impractical."},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"* **Retention**: after a successful backup, ``_remove_last_snapshots()``"},{"line_number":260,"context_line":"  deletes snapshots exceeding ``backup_ceph_max_snapshots``. The default"},{"line_number":261,"context_line":"  value of ``0`` means unlimited retention (no snapshots are deleted)."},{"line_number":262,"context_line":"  Setting ``backup_ceph_max_snapshots\u003d1`` is recommended for CBT use,"},{"line_number":263,"context_line":"  as only the most recent snapshot is needed for the next incremental backup."}],"source_content_type":"text/x-rst","patch_set":7,"id":"2c1ed8e7_0786592d","line":260,"range":{"start_line":259,"start_character":17,"end_line":260,"end_character":60},"in_reply_to":"a3a36e20_464a4902","updated":"2026-06-16 14:08:06.000000000","message":"Agreed that delete should be idempotent and driver should handle the deletion if not possible from backend by either soft deleting and later on deleting the snapshot in a looped call if possible (best effort).","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"671e23ab09266683f8cecabb8dc0b09a1e1de040","unresolved":true,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"1. **Chain reconstruction**: walks ``parent_id`` links from the requested"},{"line_number":304,"context_line":"   backup back to the full backup, building an ordered list."},{"line_number":305,"context_line":"2. **Ordered application**: applies each backup in order (full first, then"},{"line_number":306,"context_line":"   incrementals) by writing each chunk to ``obj[\u0027offset\u0027]`` in the volume."},{"line_number":307,"context_line":"3. **Integrity**: each chunk has an MD5 checksum stored at backup time and"},{"line_number":308,"context_line":"   verified on restore."}],"source_content_type":"text/x-rst","patch_set":7,"id":"b74f525c_492a80ac","line":305,"range":{"start_line":305,"start_character":28,"end_line":305,"end_character":56},"updated":"2026-06-16 14:08:06.000000000","message":"Any failure scenarios to be covered if restoring one of the snapshots fails?","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"1. **Chain reconstruction**: walks ``parent_id`` links from the requested"},{"line_number":304,"context_line":"   backup back to the full backup, building an ordered list."},{"line_number":305,"context_line":"2. **Ordered application**: applies each backup in order (full first, then"},{"line_number":306,"context_line":"   incrementals) by writing each chunk to ``obj[\u0027offset\u0027]`` in the volume."},{"line_number":307,"context_line":"3. **Integrity**: each chunk has an MD5 checksum stored at backup time and"},{"line_number":308,"context_line":"   verified on restore."}],"source_content_type":"text/x-rst","patch_set":7,"id":"2e07c3e0_0e3ac620","line":305,"range":{"start_line":305,"start_character":28,"end_line":305,"end_character":56},"in_reply_to":"9cc42bd2_875f0ead","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"1. **Chain reconstruction**: walks ``parent_id`` links from the requested"},{"line_number":304,"context_line":"   backup back to the full backup, building an ordered list."},{"line_number":305,"context_line":"2. **Ordered application**: applies each backup in order (full first, then"},{"line_number":306,"context_line":"   incrementals) by writing each chunk to ``obj[\u0027offset\u0027]`` in the volume."},{"line_number":307,"context_line":"3. **Integrity**: each chunk has an MD5 checksum stored at backup time and"},{"line_number":308,"context_line":"   verified on restore."}],"source_content_type":"text/x-rst","patch_set":7,"id":"9cc42bd2_875f0ead","line":305,"range":{"start_line":305,"start_character":28,"end_line":305,"end_character":56},"in_reply_to":"b74f525c_492a80ac","updated":"2026-06-21 15:47:09.000000000","message":"Restore failure handling for the incremental chain (e.g. a checksum mismatch or missing chunk while applying one of the backups) is existing ChunkedBackupDriver.restore() behavior, completely unchanged by CBT — CBT only affects how data is read during backup, not how it\u0027s applied during restore. So this is out of scope for this spec.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":344,"context_line":""},{"line_number":345,"context_line":"**Storage Location**:"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"* Metadata is stored as a JSON file in the backup storage (S3, Swift, NFS,"},{"line_number":348,"context_line":"  etc.) alongside the backup chunk objects, not in the Cinder database."},{"line_number":349,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":350,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":351,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":7,"id":"9fe112ce_348895d6","line":348,"range":{"start_line":347,"start_character":2,"end_line":348,"end_character":71},"updated":"2026-06-01 13:15:15.000000000","message":"Suggest storing the reference-point metadata in the Backup.metadata field (a DictOfStringsField) instead of a side object in the backup store. Rationale:\n\n* The backup manager needs the parent\u0027s reference point to plan the next incremental; reading it from the DB avoids an extra object-store round-trip (and credentials/availability dependency on the target) before the backup even starts.\n* It\u0027s written transactionally with the backup record via the existing object, rather than as a separate object that can be orphaned or partially written.\n* It\u0027s queryable and travels with the backup record through normal Cinder mechanisms.\n\nConcretely: \n\nbackup.metadata[\u0027cbt_metadata\u0027] \u003d json.dumps(\n    {\u0027reference_snapshot\u0027: ...,\n     \u0027cbt_backend\u0027: ...}\n) \n\nIf object-store storage is kept for a reason I\u0027m missing, please spell out why DB storage was rejected in the Alternatives section.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":344,"context_line":""},{"line_number":345,"context_line":"**Storage Location**:"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"* Metadata is stored as a JSON file in the backup storage (S3, Swift, NFS,"},{"line_number":348,"context_line":"  etc.) alongside the backup chunk objects, not in the Cinder database."},{"line_number":349,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":350,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":351,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":7,"id":"499dd2a3_4793acfb","line":348,"range":{"start_line":347,"start_character":2,"end_line":348,"end_character":71},"in_reply_to":"54520f73_accac167","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":344,"context_line":""},{"line_number":345,"context_line":"**Storage Location**:"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"* Metadata is stored as a JSON file in the backup storage (S3, Swift, NFS,"},{"line_number":348,"context_line":"  etc.) alongside the backup chunk objects, not in the Cinder database."},{"line_number":349,"context_line":"* Generated and stored by the backup driver during backup operations"},{"line_number":350,"context_line":"* Used by subsequent incremental backups to locate the reference point"},{"line_number":351,"context_line":"* Not required for restore operations"}],"source_content_type":"text/x-rst","patch_set":7,"id":"54520f73_accac167","line":348,"range":{"start_line":347,"start_character":2,"end_line":348,"end_character":71},"in_reply_to":"9fe112ce_348895d6","updated":"2026-06-21 15:47:09.000000000","message":"Moved cbt_metadata into Backup.metadata (DB field) instead of an object-store file, per your rationale. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":430,"context_line":"  The default value of ``0`` (unlimited) means snapshots are never deleted,"},{"line_number":431,"context_line":"  which may consume significant space over time."},{"line_number":432,"context_line":""},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"Upgrade impact"},{"line_number":435,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":436,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"c8cd80d1_b423bec8","line":433,"updated":"2026-06-01 13:15:15.000000000","message":"Recommend adding a short normative subsection \"Driver responsibilities\" so vendor drivers have a single source of truth:\n\n* All CBT methods must return None/no-op on failure rather than raise.\nReference snapshots must persist until the framework deletes them (no array-side auto-expiry), since a lost reference forces a re-bootstrap.\n* On a missing baseline in get_cbt_extents(), return None (never a partial/guessed diff — that\u0027s the one path to silent corruption) and roll back any to_snapshot the driver created in that call.\n* Drivers should consolidate adjacent same-type extents before returning, to bound the RPC payload.\n\n(I wrote exactly this up as a contributor guide while implementing — happy to fold it into the spec.)","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":430,"context_line":"  The default value of ``0`` (unlimited) means snapshots are never deleted,"},{"line_number":431,"context_line":"  which may consume significant space over time."},{"line_number":432,"context_line":""},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"Upgrade impact"},{"line_number":435,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":436,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"f095260a_b0dff202","line":433,"in_reply_to":"c8cd80d1_b423bec8","updated":"2026-06-21 15:47:09.000000000","message":"Added a \"Driver Responsibilities\" subsection covering all the points you listed. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":430,"context_line":"  The default value of ``0`` (unlimited) means snapshots are never deleted,"},{"line_number":431,"context_line":"  which may consume significant space over time."},{"line_number":432,"context_line":""},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"Upgrade impact"},{"line_number":435,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":436,"context_line":""}],"source_content_type":"text/x-rst","patch_set":7,"id":"dc9c822e_f9785444","line":433,"in_reply_to":"f095260a_b0dff202","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":479,"context_line":""},{"line_number":480,"context_line":"* Add ``get_cbt_extents(volume, from_snapshot, to_snapshot)`` stub to"},{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"}],"source_content_type":"text/x-rst","patch_set":7,"id":"bb300cb1_b4c7360d","line":483,"range":{"start_line":482,"start_character":41,"end_line":483,"end_character":71},"updated":"2026-06-01 13:15:15.000000000","message":"Suggest framing the interface as explicitly backend-agnostic and listing a second reference implementation to prove that: FlashArray via the volumes/diff REST API (get_volumes_diff(base_name\u003d…, names\u003d[…], block_size\u003d…, segment_length\u003d…)), which returns changed (offset, length) extents. This also surfaces a consistency caveat worth adding to the spec: the diff is computed against a backend snapshot, while the backup reads the attached device — so the source must be static for the backup duration (Cinder\u0027s snapshot-based backup of in-use volumes satisfies this). RBD\u0027s diff_iterate against a snapshot has the same requirement; stating it once in the spec helps every future driver author.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":479,"context_line":""},{"line_number":480,"context_line":"* Add ``get_cbt_extents(volume, from_snapshot, to_snapshot)`` stub to"},{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"}],"source_content_type":"text/x-rst","patch_set":7,"id":"69e9d039_b39d744d","line":483,"range":{"start_line":482,"start_character":41,"end_line":483,"end_character":71},"in_reply_to":"4fba89c2_e0a977a3","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":479,"context_line":""},{"line_number":480,"context_line":"* Add ``get_cbt_extents(volume, from_snapshot, to_snapshot)`` stub to"},{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"}],"source_content_type":"text/x-rst","patch_set":7,"id":"4fba89c2_e0a977a3","line":483,"range":{"start_line":482,"start_character":41,"end_line":483,"end_character":71},"in_reply_to":"bb300cb1_b4c7360d","updated":"2026-06-21 15:47:09.000000000","message":"Reframed the interface as backend-agnostic and added a storage-array (FlashArray) implementation sketch alongside Ceph RBD, plus the static-source consistency requirement. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"471037b5655923a6f587961efae7eb5524254f92","unresolved":true,"context_lines":[{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"},{"line_number":487,"context_line":"  and wrap ``volume_file`` with ``CBTVolumeFileWrapper`` when supported"}],"source_content_type":"text/x-rst","patch_set":7,"id":"58ad6f78_6dc65329","line":484,"range":{"start_line":484,"start_character":2,"end_line":484,"end_character":62},"updated":"2026-06-01 13:15:15.000000000","message":"Two additions:\n\n* Include create_cbt_snapshot() and delete_cbt_snapshot() in the RPC list.\n* Call out the cinder-volume RPC API version bump explicitly (we\u0027re using 3.21 as the next availble) and the upgrade ordering (volume before backup). The methods should be guarded with assert_min_rpc_version so a not-yet-upgraded volume service degrades gracefully to full scan rather than erroring. Also worth specifying that supports_cbt() returns True only when the driver actually overrides BaseVD.get_cbt_extents (a class-identity check), so the stub doesn\u0027t falsely advertise support.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"faaa0d7764aee6b4ba45ab1a894d86ab1e22fed6","unresolved":true,"context_lines":[{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"},{"line_number":487,"context_line":"  and wrap ``volume_file`` with ``CBTVolumeFileWrapper`` when supported"}],"source_content_type":"text/x-rst","patch_set":7,"id":"ef0510ef_8735b73d","line":484,"range":{"start_line":484,"start_character":2,"end_line":484,"end_character":62},"in_reply_to":"58ad6f78_6dc65329","updated":"2026-06-21 15:47:09.000000000","message":"Added all four RPC methods, bumped to RPC version 3.21 with assert_min_rpc_version, documented upgrade ordering, and made supports_cbt() a class-identity check. Done in PS8.","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"3ea537253598b06a771bb282d0c42e92caf70964","unresolved":false,"context_lines":[{"line_number":481,"context_line":"  ``cinder/volume/driver.py`` base class (returns ``None`` by default)"},{"line_number":482,"context_line":"* Implement ``get_cbt_extents()`` in the Ceph RBD volume driver"},{"line_number":483,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.diff_iterate()``"},{"line_number":484,"context_line":"* Add ``supports_cbt()`` and ``get_cbt_extents()`` RPC methods to"},{"line_number":485,"context_line":"  ``cinder/volume/manager.py`` and ``cinder/volume/rpcapi.py``"},{"line_number":486,"context_line":"* Extend ``cinder/backup/manager.py`` to call ``volume_rpcapi.supports_cbt()``"},{"line_number":487,"context_line":"  and wrap ``volume_file`` with ``CBTVolumeFileWrapper`` when supported"}],"source_content_type":"text/x-rst","patch_set":7,"id":"b80891aa_e50c21fd","line":484,"range":{"start_line":484,"start_character":2,"end_line":484,"end_character":62},"in_reply_to":"ef0510ef_8735b73d","updated":"2026-06-22 13:50:44.000000000","message":"Done","commit_id":"ec7e8e6c0a859b6cbbbd7ae6745a947c34ff932e"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"6adb5604bcb060038cfb22c0f7afc8d4c1cea5aa","unresolved":true,"context_lines":[{"line_number":113,"context_line":"* ``create_cbt_snapshot(volume, snapshot)``: create a backend reference"},{"line_number":114,"context_line":"  snapshot identified by ``snapshot``. Returns the reference identifier on"},{"line_number":115,"context_line":"  success, or ``None`` if it could not be established."},{"line_number":116,"context_line":"* ``get_cbt_extents(volume, from_snapshot, to_snapshot)``: return the list"},{"line_number":117,"context_line":"  of changed extents between two *already existing* reference snapshots."},{"line_number":118,"context_line":"  This call is **side-effect-free** — it only diffs, it never creates or"},{"line_number":119,"context_line":"  deletes a snapshot — so the same contract can be reused by other callers"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6aebfa1a_1b5fe882","line":116,"range":{"start_line":116,"start_character":2,"end_line":116,"end_character":55},"updated":"2026-07-01 20:53:06.000000000","message":"define from_snapshot/to_snapshot as backend snapshot identifiers consistent with provider_id, and require CBT drivers to set provider_id on snapshots","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":113,"context_line":"* ``create_cbt_snapshot(volume, snapshot)``: create a backend reference"},{"line_number":114,"context_line":"  snapshot identified by ``snapshot``. Returns the reference identifier on"},{"line_number":115,"context_line":"  success, or ``None`` if it could not be established."},{"line_number":116,"context_line":"* ``get_cbt_extents(volume, from_snapshot, to_snapshot)``: return the list"},{"line_number":117,"context_line":"  of changed extents between two *already existing* reference snapshots."},{"line_number":118,"context_line":"  This call is **side-effect-free** — it only diffs, it never creates or"},{"line_number":119,"context_line":"  deletes a snapshot — so the same contract can be reused by other callers"}],"source_content_type":"text/x-rst","patch_set":8,"id":"0599e3cc_0414c6a3","line":116,"range":{"start_line":116,"start_character":2,"end_line":116,"end_character":55},"in_reply_to":"3dd48963_4b3d8ffe","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"dfe3e2e1525ffd0911aecc709ed720b634bee8d4","unresolved":true,"context_lines":[{"line_number":113,"context_line":"* ``create_cbt_snapshot(volume, snapshot)``: create a backend reference"},{"line_number":114,"context_line":"  snapshot identified by ``snapshot``. Returns the reference identifier on"},{"line_number":115,"context_line":"  success, or ``None`` if it could not be established."},{"line_number":116,"context_line":"* ``get_cbt_extents(volume, from_snapshot, to_snapshot)``: return the list"},{"line_number":117,"context_line":"  of changed extents between two *already existing* reference snapshots."},{"line_number":118,"context_line":"  This call is **side-effect-free** — it only diffs, it never creates or"},{"line_number":119,"context_line":"  deletes a snapshot — so the same contract can be reused by other callers"}],"source_content_type":"text/x-rst","patch_set":8,"id":"3dd48963_4b3d8ffe","line":116,"range":{"start_line":116,"start_character":2,"end_line":116,"end_character":55},"in_reply_to":"6aebfa1a_1b5fe882","updated":"2026-07-02 15:04:51.000000000","message":"Done. I clarified that from_snapshot and to_snapshot are backend snapshot identifiers, not Cinder snapshot UUIDs, and that they must be consistent with the corresponding snapshot.provider_id values.\n\nI also added this to the Driver Responsibilities section: create_cbt_snapshot() must set snapshot.provider_id to the backend snapshot identifier, and get_cbt_extents()/delete_cbt_snapshot() consume those provider identifiers.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"71a9ea49e5831db809b955ddcef8d54e614d5b59","unresolved":true,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6bb3a6c1_5fb5a926","line":773,"updated":"2026-07-01 14:26:02.000000000","message":"Has anyone looked at doing this in the LVM driver? I think that may be important for backup vendors etc wanting to implement support for this Cinder API.  A fake driver implementation might also be useful.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"916114157506774ae486017bb4997f57ea1daac1","unresolved":true,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6d999b9f_c1a06093","line":773,"in_reply_to":"6bb3a6c1_5fb5a926","updated":"2026-07-01 19:06:43.000000000","message":"I\u0027ve cretaed a fake driver - https://review.opendev.org/c/openstack/cinder/+/995703\nI\u0027ll look at the LVM driver next","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"88a1b3b9b8f4e78ec7a81f1568897074b43e9c62","unresolved":false,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"39d6b13b_fdfe49b4","line":773,"in_reply_to":"6ce9c54f_b21189fb","updated":"2026-09-10 13:40:16.000000000","message":"Done","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"dfe3e2e1525ffd0911aecc709ed720b634bee8d4","unresolved":true,"context_lines":[{"line_number":770,"context_line":"  ``delete_cbt_snapshot(volume, snapshot)`` stubs to"},{"line_number":771,"context_line":"  ``cinder/volume/driver.py`` base class (returning ``None``/no-op by"},{"line_number":772,"context_line":"  default)"},{"line_number":773,"context_line":"* Implement all three in the Ceph RBD volume driver"},{"line_number":774,"context_line":"  (``cinder/volume/drivers/rbd.py``) using ``rbd_image.create_snap()``,"},{"line_number":775,"context_line":"  ``rbd_image.diff_iterate()``, and ``rbd_image.remove_snap()``"},{"line_number":776,"context_line":"* (Optional, not required for this spec\u0027s merge) implement the same"}],"source_content_type":"text/x-rst","patch_set":8,"id":"6ce9c54f_b21189fb","line":773,"in_reply_to":"6d999b9f_c1a06093","updated":"2026-07-02 15:04:51.000000000","message":"Thanks Simon!","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":4523,"name":"Eric Harney","email":"eharney@redhat.com","username":"eharney"},"change_message_id":"71a9ea49e5831db809b955ddcef8d54e614d5b59","unresolved":true,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"7eef3713_a701c7d4","line":844,"updated":"2026-07-01 14:26:02.000000000","message":"I think this is the first Cinder API that will return megabytes of data over RPC and the HTTP API. We should build a cinder-tempest-plugin test that generates a worst-case scenario for changes in a volume (i.e. many writes with gaps between them) and ensure that we don\u0027t run into issues at the amqp/http layers.","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"48642604_49f9d858","line":844,"in_reply_to":"08a4f229_2beceb0a","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"dfe3e2e1525ffd0911aecc709ed720b634bee8d4","unresolved":true,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"08a4f229_2beceb0a","line":844,"in_reply_to":"3b32eaa2_1663582a","updated":"2026-07-02 15:04:51.000000000","message":"Thanks Simon!","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"916114157506774ae486017bb4997f57ea1daac1","unresolved":true,"context_lines":[{"line_number":841,"context_line":"**Performance Tests**:"},{"line_number":842,"context_line":""},{"line_number":843,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":844,"context_line":""},{"line_number":845,"context_line":""},{"line_number":846,"context_line":"Documentation Impact"},{"line_number":847,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"3b32eaa2_1663582a","line":844,"in_reply_to":"7eef3713_a701c7d4","updated":"2026-07-01 19:06:43.000000000","message":"Agreed - I\u0027ll work on both an LVM driver for this and a tempest scenario","commit_id":"a9c03996ba50a59668d6a933b604efed1d17afd9"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":214,"context_line":""},{"line_number":215,"context_line":"        return extents"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"**A second backend, to confirm the interface generalizes**: a storage"},{"line_number":218,"context_line":"array driver (e.g. Pure Storage FlashArray) can implement the same three"},{"line_number":219,"context_line":"methods on top of its own native APIs instead of RBD\u0027s. ``create_cbt_snapshot()``"},{"line_number":220,"context_line":"and ``delete_cbt_snapshot()`` map to the array\u0027s snapshot create/delete"},{"line_number":221,"context_line":"calls, and ``get_cbt_extents()`` maps to the array\u0027s own diff API (for"},{"line_number":222,"context_line":"FlashArray, ``volumes/diff``, called with the two reference snapshot"},{"line_number":223,"context_line":"names and a block size), which likewise returns a list of changed"},{"line_number":224,"context_line":"``(offset, length)`` extents that the driver converts into the same"},{"line_number":225,"context_line":"``{offset, length, exists}`` shape. No part of the interface assumes RBD."},{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"}],"source_content_type":"text/x-rst","patch_set":9,"id":"14632276_fe7ca6ad","line":225,"range":{"start_line":217,"start_character":0,"end_line":225,"end_character":73},"updated":"2026-07-03 18:05:40.000000000","message":"The spec says two reference implementations (Ceph RBD + an array driver) were built to prove the interface generalises. In practice the landed set is LVM-thin (995738) and Pure FlashArray (990982), plus a backend-agnostic fake reference driver (995703) intended as vendor-facing worked example. Worth updating the spec\u0027s wording to name the actual references (and the fake driver), since Ceph RBD is used as the narrative example but isn\u0027t the landed second implementation.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":214,"context_line":""},{"line_number":215,"context_line":"        return extents"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"**A second backend, to confirm the interface generalizes**: a storage"},{"line_number":218,"context_line":"array driver (e.g. Pure Storage FlashArray) can implement the same three"},{"line_number":219,"context_line":"methods on top of its own native APIs instead of RBD\u0027s. ``create_cbt_snapshot()``"},{"line_number":220,"context_line":"and ``delete_cbt_snapshot()`` map to the array\u0027s snapshot create/delete"},{"line_number":221,"context_line":"calls, and ``get_cbt_extents()`` maps to the array\u0027s own diff API (for"},{"line_number":222,"context_line":"FlashArray, ``volumes/diff``, called with the two reference snapshot"},{"line_number":223,"context_line":"names and a block size), which likewise returns a list of changed"},{"line_number":224,"context_line":"``(offset, length)`` extents that the driver converts into the same"},{"line_number":225,"context_line":"``{offset, length, exists}`` shape. No part of the interface assumes RBD."},{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"}],"source_content_type":"text/x-rst","patch_set":9,"id":"482e98d6_741363ec","line":225,"range":{"start_line":217,"start_character":0,"end_line":225,"end_character":73},"in_reply_to":"14632276_fe7ca6ad","updated":"2026-07-05 14:23:57.000000000","message":"Done — the spec now names the actual references (LVM-thin, FlashArray, and the fake driver) and keeps Ceph RBD as the narrative example only; I\u0027m planning to implement the Ceph RBD driver as a follow-up.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":214,"context_line":""},{"line_number":215,"context_line":"        return extents"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"**A second backend, to confirm the interface generalizes**: a storage"},{"line_number":218,"context_line":"array driver (e.g. Pure Storage FlashArray) can implement the same three"},{"line_number":219,"context_line":"methods on top of its own native APIs instead of RBD\u0027s. ``create_cbt_snapshot()``"},{"line_number":220,"context_line":"and ``delete_cbt_snapshot()`` map to the array\u0027s snapshot create/delete"},{"line_number":221,"context_line":"calls, and ``get_cbt_extents()`` maps to the array\u0027s own diff API (for"},{"line_number":222,"context_line":"FlashArray, ``volumes/diff``, called with the two reference snapshot"},{"line_number":223,"context_line":"names and a block size), which likewise returns a list of changed"},{"line_number":224,"context_line":"``(offset, length)`` extents that the driver converts into the same"},{"line_number":225,"context_line":"``{offset, length, exists}`` shape. No part of the interface assumes RBD."},{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"}],"source_content_type":"text/x-rst","patch_set":9,"id":"436b040f_f8dad083","line":225,"range":{"start_line":217,"start_character":0,"end_line":225,"end_character":73},"in_reply_to":"482e98d6_741363ec","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"},{"line_number":229,"context_line":"*attached device*. This is only correct if the source does not change"},{"line_number":230,"context_line":"between when the reference snapshots are taken and when the backup"},{"line_number":231,"context_line":"finishes reading — which Cinder\u0027s snapshot-based backup of in-use volumes"},{"line_number":232,"context_line":"already guarantees. Any future driver implementing these methods must"},{"line_number":233,"context_line":"preserve this property."},{"line_number":234,"context_line":""}],"source_content_type":"text/x-rst","patch_set":9,"id":"41266a87_24dd62c1","line":231,"range":{"start_line":229,"start_character":19,"end_line":231,"end_character":16},"updated":"2026-07-17 13:42:35.000000000","message":"The lifecycle assumes create_cbt_snapshot() always makes a fresh reference on the volume. For an in-use volume, cinder-backup already freezes a temp snapshot to read a consistent image; the framework adopts that temp snapshot as the CBT reference (uses its provider_id, records its Cinder id, clears temp_snapshot_id on success so temp cleanup doesn\u0027t delete it) rather than creating a second snapshot on the live volume. Cleanup is then identifier-aware: adopted references delete via the snapshot API, driver-created ones via delete_cbt_snapshot(). This also means a single get_cbt_extents() call can legitimately mix a create_cbt_snapshot return (from) with an adopted snapshot\u0027s provider_id (to), which drivers must resolve identically. Worth adding to the lifecycle/Driver-Responsibilities sections. (Implemented in 990923.)","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"},{"line_number":229,"context_line":"*attached device*. This is only correct if the source does not change"},{"line_number":230,"context_line":"between when the reference snapshots are taken and when the backup"},{"line_number":231,"context_line":"finishes reading — which Cinder\u0027s snapshot-based backup of in-use volumes"},{"line_number":232,"context_line":"already guarantees. Any future driver implementing these methods must"},{"line_number":233,"context_line":"preserve this property."},{"line_number":234,"context_line":""}],"source_content_type":"text/x-rst","patch_set":9,"id":"94f3e999_b2c4144c","line":231,"range":{"start_line":229,"start_character":19,"end_line":231,"end_character":16},"in_reply_to":"41266a87_24dd62c1","updated":"2026-08-07 13:16:43.000000000","message":"Done — Snapshot lifecycle now covers temp-snapshot adoption for in-use volumes and provenance-aware cleanup.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"88a1b3b9b8f4e78ec7a81f1568897074b43e9c62","unresolved":false,"context_lines":[{"line_number":226,"context_line":""},{"line_number":227,"context_line":"**Consistency requirement**: both reference implementations compute their"},{"line_number":228,"context_line":"diff against backend *snapshots*, while the backup itself reads the"},{"line_number":229,"context_line":"*attached device*. This is only correct if the source does not change"},{"line_number":230,"context_line":"between when the reference snapshots are taken and when the backup"},{"line_number":231,"context_line":"finishes reading — which Cinder\u0027s snapshot-based backup of in-use volumes"},{"line_number":232,"context_line":"already guarantees. Any future driver implementing these methods must"},{"line_number":233,"context_line":"preserve this property."},{"line_number":234,"context_line":""}],"source_content_type":"text/x-rst","patch_set":9,"id":"676f194c_650bd8e0","line":231,"range":{"start_line":229,"start_character":19,"end_line":231,"end_character":16},"in_reply_to":"94f3e999_b2c4144c","updated":"2026-09-10 13:40:16.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[{"line_number":275,"context_line":"    from_snapshot \u003d None"},{"line_number":276,"context_line":"    with open(device_path, \u0027rb\u0027) as device_file:"},{"line_number":277,"context_line":"        # Use CBT if parent backup exists and volume driver supports it"},{"line_number":278,"context_line":"        if backup.parent_id and volume_rpcapi.supports_cbt(context, volume):"},{"line_number":279,"context_line":"            parent_cbt_meta \u003d json.loads(parent_backup.metadata[\u0027cbt_metadata\u0027])"},{"line_number":280,"context_line":"            from_snapshot \u003d parent_cbt_meta[\u0027reference_snapshot\u0027]"},{"line_number":281,"context_line":"            to_snapshot \u003d \u0027backup.%s.snap.%s\u0027 % (backup.id, timestamp)"}],"source_content_type":"text/x-rst","patch_set":9,"id":"d388c350_fff1b4f6","line":278,"updated":"2026-07-17 13:42:35.000000000","message":"The manager only checks backup.parent_id and supports_cbt(volume) before creating a reference snapshot. It should also gate on the configured backup driver being a ChunkedBackupDriver. CBT is only consumed by the chunked drivers; with a non-chunked backup driver the reference (and, for in-use volumes, the adopted temp snapshot) is never recorded or cleaned up and leaks on every backup. Worth calling out explicitly since Ceph — the spec\u0027s running example as a volume backend — is a non-chunked backup driver, so the distinction (volume-backend-that-does-CBT vs backup-driver-that-consumes-it) is easy to conflate. (Fixed in 990923.)","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":275,"context_line":"    from_snapshot \u003d None"},{"line_number":276,"context_line":"    with open(device_path, \u0027rb\u0027) as device_file:"},{"line_number":277,"context_line":"        # Use CBT if parent backup exists and volume driver supports it"},{"line_number":278,"context_line":"        if backup.parent_id and volume_rpcapi.supports_cbt(context, volume):"},{"line_number":279,"context_line":"            parent_cbt_meta \u003d json.loads(parent_backup.metadata[\u0027cbt_metadata\u0027])"},{"line_number":280,"context_line":"            from_snapshot \u003d parent_cbt_meta[\u0027reference_snapshot\u0027]"},{"line_number":281,"context_line":"            to_snapshot \u003d \u0027backup.%s.snap.%s\u0027 % (backup.id, timestamp)"}],"source_content_type":"text/x-rst","patch_set":9,"id":"b1b0ec2e_55207373","line":278,"in_reply_to":"a02991da_b283bd46","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":275,"context_line":"    from_snapshot \u003d None"},{"line_number":276,"context_line":"    with open(device_path, \u0027rb\u0027) as device_file:"},{"line_number":277,"context_line":"        # Use CBT if parent backup exists and volume driver supports it"},{"line_number":278,"context_line":"        if backup.parent_id and volume_rpcapi.supports_cbt(context, volume):"},{"line_number":279,"context_line":"            parent_cbt_meta \u003d json.loads(parent_backup.metadata[\u0027cbt_metadata\u0027])"},{"line_number":280,"context_line":"            from_snapshot \u003d parent_cbt_meta[\u0027reference_snapshot\u0027]"},{"line_number":281,"context_line":"            to_snapshot \u003d \u0027backup.%s.snap.%s\u0027 % (backup.id, timestamp)"}],"source_content_type":"text/x-rst","patch_set":9,"id":"a02991da_b283bd46","line":278,"in_reply_to":"d388c350_fff1b4f6","updated":"2026-08-07 13:16:43.000000000","message":"Done — the gate now also requires a ChunkedBackupDriver, and Fallback Behavior lists the non-chunked case.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"1db1cd50875d25b1ae07f8997f9410f3a36b9730","unresolved":true,"context_lines":[{"line_number":461,"context_line":"* **Parent backup has no reference point** (predates CBT, or CBT was"},{"line_number":462,"context_line":"  never enabled for that chain): use the existing SHA-diff incremental"},{"line_number":463,"context_line":"  approach. No CBT API call is attempted."},{"line_number":464,"context_line":"* **Parent backup has a reference point, but the CBT diff cannot be"},{"line_number":465,"context_line":"  computed against it** (reference snapshot removed out-of-band, decode"},{"line_number":466,"context_line":"  error, or backend API failure): re-bootstrap — create a fresh reference"},{"line_number":467,"context_line":"  snapshot and, as with a true first backup, attempt"},{"line_number":468,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` for a sparse full backup"},{"line_number":469,"context_line":"  before falling back to a dense full scan. Either way, record the fresh"},{"line_number":470,"context_line":"  reference snapshot as this backup\u0027s reference point so the next backup"},{"line_number":471,"context_line":"  can resume CBT."},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"In every case (including the two above and the normal CBT path), a new"},{"line_number":474,"context_line":"reference snapshot is created at the end of the backup and recorded in"}],"source_content_type":"text/x-rst","patch_set":9,"id":"2b3e72a2_2f1844fc","line":471,"range":{"start_line":464,"start_character":0,"end_line":471,"end_character":17},"updated":"2026-07-17 13:42:35.000000000","message":"The re-bootstrap bullet prescribes a sparse full backup (get_cbt_extents(volume, None, to_snapshot)) before falling back to dense. That\u0027s unsafe: a re-bootstrapped backup still has parent_id, so on restore it\u0027s layered on the parent chain. A sparse (allocation-map) backup omits regions that were deallocated since the parent (guest fstrim/discard), so restore leaves the parent\u0027s stale data there → silent corruption. A re-bootstrap must be a dense full scan (ship every block so restore overwrites the whole volume), not a sparse allocation map. The sparse optimization is only safe for a true first backup (no parent). (Fixed in 990923; recommend the spec say re-bootstrap is always dense.)","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":461,"context_line":"* **Parent backup has no reference point** (predates CBT, or CBT was"},{"line_number":462,"context_line":"  never enabled for that chain): use the existing SHA-diff incremental"},{"line_number":463,"context_line":"  approach. No CBT API call is attempted."},{"line_number":464,"context_line":"* **Parent backup has a reference point, but the CBT diff cannot be"},{"line_number":465,"context_line":"  computed against it** (reference snapshot removed out-of-band, decode"},{"line_number":466,"context_line":"  error, or backend API failure): re-bootstrap — create a fresh reference"},{"line_number":467,"context_line":"  snapshot and, as with a true first backup, attempt"},{"line_number":468,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` for a sparse full backup"},{"line_number":469,"context_line":"  before falling back to a dense full scan. Either way, record the fresh"},{"line_number":470,"context_line":"  reference snapshot as this backup\u0027s reference point so the next backup"},{"line_number":471,"context_line":"  can resume CBT."},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"In every case (including the two above and the normal CBT path), a new"},{"line_number":474,"context_line":"reference snapshot is created at the end of the backup and recorded in"}],"source_content_type":"text/x-rst","patch_set":9,"id":"c91b534a_822e69bf","line":471,"range":{"start_line":464,"start_character":0,"end_line":471,"end_character":17},"in_reply_to":"2b3e72a2_2f1844fc","updated":"2026-08-07 13:16:43.000000000","message":"Agreed — re-bootstrap is now always dense; sparse is only permitted when the backup has no parent_id.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":461,"context_line":"* **Parent backup has no reference point** (predates CBT, or CBT was"},{"line_number":462,"context_line":"  never enabled for that chain): use the existing SHA-diff incremental"},{"line_number":463,"context_line":"  approach. No CBT API call is attempted."},{"line_number":464,"context_line":"* **Parent backup has a reference point, but the CBT diff cannot be"},{"line_number":465,"context_line":"  computed against it** (reference snapshot removed out-of-band, decode"},{"line_number":466,"context_line":"  error, or backend API failure): re-bootstrap — create a fresh reference"},{"line_number":467,"context_line":"  snapshot and, as with a true first backup, attempt"},{"line_number":468,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` for a sparse full backup"},{"line_number":469,"context_line":"  before falling back to a dense full scan. Either way, record the fresh"},{"line_number":470,"context_line":"  reference snapshot as this backup\u0027s reference point so the next backup"},{"line_number":471,"context_line":"  can resume CBT."},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"In every case (including the two above and the normal CBT path), a new"},{"line_number":474,"context_line":"reference snapshot is created at the end of the backup and recorded in"}],"source_content_type":"text/x-rst","patch_set":9,"id":"2402d5fe_30b4d940","line":471,"range":{"start_line":464,"start_character":0,"end_line":471,"end_character":17},"in_reply_to":"c91b534a_822e69bf","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":654,"context_line":"``os-list_changed_blocks``, gated by a new microversion, so any Cinder API"},{"line_number":655,"context_line":"consumer (not just ``cinder-backup``) can query CBT information directly:"},{"line_number":656,"context_line":""},{"line_number":657,"context_line":"* **Request**: ``target_snapshot_id`` (required), ``base_snapshot_id``"},{"line_number":658,"context_line":"  (optional — omitted or ``null`` requests the volume\u0027s full allocation"},{"line_number":659,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":660,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"}],"source_content_type":"text/x-rst","patch_set":9,"id":"bec54a56_e56fcfe9","line":661,"range":{"start_line":657,"start_character":0,"end_line":661,"end_character":22},"updated":"2026-07-03 18:05:40.000000000","message":"The changed-blocks action is implemented with full pagination/windowing, which the spec should capture: the request accepts offset/length (a byte window) and marker/limit, and the response returns changed_blocks_next_marker alongside changed_blocks; the microversion is 3.72. Importantly, the window is threaded all the way down to the driver\u0027s get_cbt_extents (via a shared volume_utils.window_cbt_page helper that over-fetches one extent past limit so the API can detect further pages) — so it bounds the extent list held in memory and crossing Oslo RPC, not just the HTTP response. Implemented in cinder 990923; documented in api-ref/admin guide 995964; reference driver 995703 shows the one-line driver pattern.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":654,"context_line":"``os-list_changed_blocks``, gated by a new microversion, so any Cinder API"},{"line_number":655,"context_line":"consumer (not just ``cinder-backup``) can query CBT information directly:"},{"line_number":656,"context_line":""},{"line_number":657,"context_line":"* **Request**: ``target_snapshot_id`` (required), ``base_snapshot_id``"},{"line_number":658,"context_line":"  (optional — omitted or ``null`` requests the volume\u0027s full allocation"},{"line_number":659,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":660,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"}],"source_content_type":"text/x-rst","patch_set":9,"id":"7651b7f9_551fa2c8","line":661,"range":{"start_line":657,"start_character":0,"end_line":661,"end_character":22},"in_reply_to":"1397f2bc_cb1b44ab","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":654,"context_line":"``os-list_changed_blocks``, gated by a new microversion, so any Cinder API"},{"line_number":655,"context_line":"consumer (not just ``cinder-backup``) can query CBT information directly:"},{"line_number":656,"context_line":""},{"line_number":657,"context_line":"* **Request**: ``target_snapshot_id`` (required), ``base_snapshot_id``"},{"line_number":658,"context_line":"  (optional — omitted or ``null`` requests the volume\u0027s full allocation"},{"line_number":659,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":660,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"}],"source_content_type":"text/x-rst","patch_set":9,"id":"1397f2bc_cb1b44ab","line":661,"range":{"start_line":657,"start_character":0,"end_line":661,"end_character":22},"in_reply_to":"bec54a56_e56fcfe9","updated":"2026-07-05 14:23:57.000000000","message":"Done — documented offset/length, marker/limit, changed_blocks_next_marker and microversion 3.72, including the window being threaded down to get_cbt_extents via window_cbt_page.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"9b9d7168_746511e4","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"updated":"2026-07-03 18:05:40.000000000","message":"Still open: a consumer only learns a backend lacks CBT by calling and getting a 409; there\u0027s no advertised capability. We documented the 409-probe approach but did not implement discovery (volume-type capability / extension flag). The spec should either accept 409-on-use as the contract or list capability advertisement as a work item. This is the one substantive gap remaining.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"aef3533c_af9f6e5f","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"4b8bbdc3_2e4d6191","updated":"2026-08-26 17:36:44.000000000","message":"We should add 413 in here as well as it is used in #1001037","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"67833cd4af4909356b0579e04a71d17f5d758dd7","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"8da85939_3932e4aa","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"4c15d946_17f35cb9","updated":"2026-07-27 14:03:34.000000000","message":"Shouldnt this be done via backend capability? A driver could mark the support as true if it truly supports CBT. Using that, the volume manager knows if a call would succeed or fail and return from volume manager itself.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"7c700f1d8038159235b10963be68582587a3c825","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"4b8bbdc3_2e4d6191","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"80526a90_51529106","updated":"2026-08-26 16:43:57.000000000","message":"Acknowledged","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"80526a90_51529106","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"8da85939_3932e4aa","updated":"2026-08-07 13:16:43.000000000","message":"Same as my reply on the supports_cbt() comment","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"4c15d946_17f35cb9","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"9b9d7168_746511e4","updated":"2026-07-05 14:23:57.000000000","message":"Agreed — the spec now explicitly adopts 409-on-use as the contract and lists capability advertisement as future work.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":661,"context_line":"  sparse full backup)."},{"line_number":662,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":663,"context_line":"  extents, using the same shape as the driver interface."},{"line_number":664,"context_line":"* **Errors**: ``409 Conflict`` if the volume\u0027s backend does not support"},{"line_number":665,"context_line":"  CBT or the requested snapshots cannot be compared (``get_cbt_extents()``"},{"line_number":666,"context_line":"  returned ``None``)."},{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."}],"source_content_type":"text/x-rst","patch_set":9,"id":"1f344eb5_c5818946","line":666,"range":{"start_line":664,"start_character":0,"end_line":666,"end_character":21},"in_reply_to":"aef3533c_af9f6e5f","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":""},{"line_number":672,"context_line":"Security impact"},{"line_number":673,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"b5421f61_47f601bd","line":670,"updated":"2026-07-03 18:05:40.000000000","message":"Recommend the spec state explicitly that the action returns only the changed-block map, not the data; reading the changed bytes stays on the normal Cinder data path (create-volume-from-snapshot → attach → read). We\u0027ve locked this as the design (documented in 995964) and deliberately scoped a first-class \"read snapshot region\" data API out. Please confirm that scoping in the spec.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":""},{"line_number":672,"context_line":"Security impact"},{"line_number":673,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"759e6210_0aa438f9","line":670,"in_reply_to":"31fc6f48_6d393dcf","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":667,"context_line":""},{"line_number":668,"context_line":"This reuses the same driver methods and ``exists`` semantics defined for"},{"line_number":669,"context_line":"the backup path; no new driver interface is introduced."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":""},{"line_number":672,"context_line":"Security impact"},{"line_number":673,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"31fc6f48_6d393dcf","line":670,"in_reply_to":"b5421f61_47f601bd","updated":"2026-07-05 14:23:57.000000000","message":"Done — added a Scope note: the action returns only the changed-block map, reads stay on the normal Cinder data path, and a \"read snapshot region\" data API is deliberately out of scope.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":802,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":803,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":804,"context_line":"* Implement automatic fallback behavior"},{"line_number":805,"context_line":"* Handle large extent lists that may exceed Oslo RPC default message size"},{"line_number":806,"context_line":"  limits (~128MB) — evaluate pagination or streaming approach"},{"line_number":807,"context_line":"* Evaluate compact extent representation (e.g. tuples instead of dicts) to"},{"line_number":808,"context_line":"  reduce RPC message size for large volumes"},{"line_number":809,"context_line":"* Add the ``os-list_changed_blocks`` volume action (new microversion,"}],"source_content_type":"text/x-rst","patch_set":9,"id":"3d7ebe5c_e56f858d","line":806,"range":{"start_line":805,"start_character":0,"end_line":806,"end_character":61},"updated":"2026-07-03 18:05:40.000000000","message":"This work item (\"evaluate pagination or streaming\") is resolved: pagination is pushed down to the driver, so no call materialises or transfers more than one page. The neighbouring item (line ~807, \"evaluate compact extent representation, tuples instead of dicts\") is therefore optional — windowing plus the existing adjacent-extent consolidation bound the payload; a compact/packed encoding remains a possible future optimisation but is no longer needed for correctness at scale. Suggest marking one done and the other optional.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":802,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":803,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":804,"context_line":"* Implement automatic fallback behavior"},{"line_number":805,"context_line":"* Handle large extent lists that may exceed Oslo RPC default message size"},{"line_number":806,"context_line":"  limits (~128MB) — evaluate pagination or streaming approach"},{"line_number":807,"context_line":"* Evaluate compact extent representation (e.g. tuples instead of dicts) to"},{"line_number":808,"context_line":"  reduce RPC message size for large volumes"},{"line_number":809,"context_line":"* Add the ``os-list_changed_blocks`` volume action (new microversion,"}],"source_content_type":"text/x-rst","patch_set":9,"id":"851e53c5_8412b026","line":806,"range":{"start_line":805,"start_character":0,"end_line":806,"end_character":61},"in_reply_to":"3d7ebe5c_e56f858d","updated":"2026-07-05 14:23:57.000000000","message":"Done — marked the pagination item as done and the compact extent representation as an optional future optimization.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":802,"context_line":"* Extend ``chunkeddriver.py`` with CBT support: ``_backup_with_cbt()``,"},{"line_number":803,"context_line":"  ``_get_cbt_reference_point()``, ``_save_cbt_metadata()``"},{"line_number":804,"context_line":"* Implement automatic fallback behavior"},{"line_number":805,"context_line":"* Handle large extent lists that may exceed Oslo RPC default message size"},{"line_number":806,"context_line":"  limits (~128MB) — evaluate pagination or streaming approach"},{"line_number":807,"context_line":"* Evaluate compact extent representation (e.g. tuples instead of dicts) to"},{"line_number":808,"context_line":"  reduce RPC message size for large volumes"},{"line_number":809,"context_line":"* Add the ``os-list_changed_blocks`` volume action (new microversion,"}],"source_content_type":"text/x-rst","patch_set":9,"id":"131c2973_a17fd7a9","line":806,"range":{"start_line":805,"start_character":0,"end_line":806,"end_character":61},"in_reply_to":"851e53c5_8412b026","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"a4adb2e2ef4b12a0da1296a45dd4a3a3e11a974d","unresolved":true,"context_lines":[{"line_number":852,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":853,"context_line":""},{"line_number":854,"context_line":""},{"line_number":855,"context_line":"Documentation Impact"},{"line_number":856,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":857,"context_line":""},{"line_number":858,"context_line":"Admin guide:"},{"line_number":859,"context_line":""},{"line_number":860,"context_line":"* Explanation of CBT optimization and benefits"},{"line_number":861,"context_line":"* Configuration options for enabling/disabling CBT"},{"line_number":862,"context_line":"* Prerequisites for Ceph RBD"},{"line_number":863,"context_line":"* Troubleshooting guide for CBT-related issues"},{"line_number":864,"context_line":""},{"line_number":865,"context_line":"Release notes:"},{"line_number":866,"context_line":""},{"line_number":867,"context_line":"* New feature announcement"},{"line_number":868,"context_line":"* Performance improvements"},{"line_number":869,"context_line":"* Configuration requirements"},{"line_number":870,"context_line":""},{"line_number":871,"context_line":""},{"line_number":872,"context_line":"References"},{"line_number":873,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"a058d248_03a0b4c1","line":870,"range":{"start_line":855,"start_character":0,"end_line":870,"end_character":0},"updated":"2026-07-03 18:05:40.000000000","message":"api-ref for os-list_changed_blocks (request/response, exists semantics, pagination, 409) and an admin \"consuming CBT from the REST API\" guide now exist in 995964; recommend listing api-ref as an explicit deliverable here so the spec\u0027s doc plan matches what shipped.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":false,"context_lines":[{"line_number":852,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":853,"context_line":""},{"line_number":854,"context_line":""},{"line_number":855,"context_line":"Documentation Impact"},{"line_number":856,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":857,"context_line":""},{"line_number":858,"context_line":"Admin guide:"},{"line_number":859,"context_line":""},{"line_number":860,"context_line":"* Explanation of CBT optimization and benefits"},{"line_number":861,"context_line":"* Configuration options for enabling/disabling CBT"},{"line_number":862,"context_line":"* Prerequisites for Ceph RBD"},{"line_number":863,"context_line":"* Troubleshooting guide for CBT-related issues"},{"line_number":864,"context_line":""},{"line_number":865,"context_line":"Release notes:"},{"line_number":866,"context_line":""},{"line_number":867,"context_line":"* New feature announcement"},{"line_number":868,"context_line":"* Performance improvements"},{"line_number":869,"context_line":"* Configuration requirements"},{"line_number":870,"context_line":""},{"line_number":871,"context_line":""},{"line_number":872,"context_line":"References"},{"line_number":873,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"730b29c5_01caa092","line":870,"range":{"start_line":855,"start_character":0,"end_line":870,"end_character":0},"in_reply_to":"882da38e_84d1accb","updated":"2026-08-30 11:10:47.000000000","message":"Done","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"7ee6ea8372e71a0b3d8ab7703d1aae5ad0f02a3d","unresolved":true,"context_lines":[{"line_number":852,"context_line":"* Measure read range reduction vs full scan for various scenarios"},{"line_number":853,"context_line":""},{"line_number":854,"context_line":""},{"line_number":855,"context_line":"Documentation Impact"},{"line_number":856,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":857,"context_line":""},{"line_number":858,"context_line":"Admin guide:"},{"line_number":859,"context_line":""},{"line_number":860,"context_line":"* Explanation of CBT optimization and benefits"},{"line_number":861,"context_line":"* Configuration options for enabling/disabling CBT"},{"line_number":862,"context_line":"* Prerequisites for Ceph RBD"},{"line_number":863,"context_line":"* Troubleshooting guide for CBT-related issues"},{"line_number":864,"context_line":""},{"line_number":865,"context_line":"Release notes:"},{"line_number":866,"context_line":""},{"line_number":867,"context_line":"* New feature announcement"},{"line_number":868,"context_line":"* Performance improvements"},{"line_number":869,"context_line":"* Configuration requirements"},{"line_number":870,"context_line":""},{"line_number":871,"context_line":""},{"line_number":872,"context_line":"References"},{"line_number":873,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":9,"id":"882da38e_84d1accb","line":870,"range":{"start_line":855,"start_character":0,"end_line":870,"end_character":0},"in_reply_to":"a058d248_03a0b4c1","updated":"2026-07-05 14:23:57.000000000","message":"Done — listed the api-ref (request/response, exists, pagination, 409) and the \"Consuming CBT from the REST API\" admin guide as explicit deliverables, with 995964 linked in References.","commit_id":"138d684e896e43a86443b5736f919fa556466ffb"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"67833cd4af4909356b0579e04a71d17f5d758dd7","unresolved":true,"context_lines":[{"line_number":91,"context_line":"  reads as zero with no need to back it up — on restore, any byte range"},{"line_number":92,"context_line":"  not covered by a backed-up extent is left as-is (zero), which is"},{"line_number":93,"context_line":"  already correct since it was never written"},{"line_number":94,"context_line":"* **Backend-agnostic interface**: the three CBT driver methods are not"},{"line_number":95,"context_line":"  Ceph-specific. Reference implementations were developed alongside the"},{"line_number":96,"context_line":"  framework to confirm this: the LVM driver (thin-provisioned volumes),"},{"line_number":97,"context_line":"  a storage array backend (Pure Storage FlashArray, via its"},{"line_number":98,"context_line":"  ``volumes/diff`` REST API), and a backend-agnostic fake reference"},{"line_number":99,"context_line":"  driver intended as a worked example for vendors (see References)."},{"line_number":100,"context_line":"  Ceph RBD is used only as the narrative example throughout this"},{"line_number":101,"context_line":"  document; it is not one of those reference implementations, and its"}],"source_content_type":"text/x-rst","patch_set":10,"id":"c001b609_7f700c69","line":98,"range":{"start_line":94,"start_character":0,"end_line":98,"end_character":67},"updated":"2026-07-27 14:03:34.000000000","message":"Is this logic expected to work similarly for files as blocks? Some drivers expose files (NFS) as block (eg. NetApp driver). Do we know if this would work for NFS? Also, in case of NFS, the expectation is to again return the same values i.e. offset, length and exists?","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"7c700f1d8038159235b10963be68582587a3c825","unresolved":false,"context_lines":[{"line_number":91,"context_line":"  reads as zero with no need to back it up — on restore, any byte range"},{"line_number":92,"context_line":"  not covered by a backed-up extent is left as-is (zero), which is"},{"line_number":93,"context_line":"  already correct since it was never written"},{"line_number":94,"context_line":"* **Backend-agnostic interface**: the three CBT driver methods are not"},{"line_number":95,"context_line":"  Ceph-specific. Reference implementations were developed alongside the"},{"line_number":96,"context_line":"  framework to confirm this: the LVM driver (thin-provisioned volumes),"},{"line_number":97,"context_line":"  a storage array backend (Pure Storage FlashArray, via its"},{"line_number":98,"context_line":"  ``volumes/diff`` REST API), and a backend-agnostic fake reference"},{"line_number":99,"context_line":"  driver intended as a worked example for vendors (see References)."},{"line_number":100,"context_line":"  Ceph RBD is used only as the narrative example throughout this"},{"line_number":101,"context_line":"  document; it is not one of those reference implementations, and its"}],"source_content_type":"text/x-rst","patch_set":10,"id":"7e7133bc_e690f5ff","line":98,"range":{"start_line":94,"start_character":0,"end_line":98,"end_character":67},"in_reply_to":"6e771973_009301a1","updated":"2026-08-26 16:43:57.000000000","message":"Done","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":91,"context_line":"  reads as zero with no need to back it up — on restore, any byte range"},{"line_number":92,"context_line":"  not covered by a backed-up extent is left as-is (zero), which is"},{"line_number":93,"context_line":"  already correct since it was never written"},{"line_number":94,"context_line":"* **Backend-agnostic interface**: the three CBT driver methods are not"},{"line_number":95,"context_line":"  Ceph-specific. Reference implementations were developed alongside the"},{"line_number":96,"context_line":"  framework to confirm this: the LVM driver (thin-provisioned volumes),"},{"line_number":97,"context_line":"  a storage array backend (Pure Storage FlashArray, via its"},{"line_number":98,"context_line":"  ``volumes/diff`` REST API), and a backend-agnostic fake reference"},{"line_number":99,"context_line":"  driver intended as a worked example for vendors (see References)."},{"line_number":100,"context_line":"  Ceph RBD is used only as the narrative example throughout this"},{"line_number":101,"context_line":"  document; it is not one of those reference implementations, and its"}],"source_content_type":"text/x-rst","patch_set":10,"id":"6e771973_009301a1","line":98,"range":{"start_line":94,"start_character":0,"end_line":98,"end_character":67},"in_reply_to":"c001b609_7f700c69","updated":"2026-08-07 13:16:43.000000000","message":"Yes, same values — offsets are in the volume\u0027s address space, not the backing file\u0027s; added a short note.","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"67833cd4af4909356b0579e04a71d17f5d758dd7","unresolved":true,"context_lines":[{"line_number":108,"context_line":"optional — a driver that implements none of them is simply not CBT-capable,"},{"line_number":109,"context_line":"and the base class in ``cinder/volume/driver.py`` stubs each method to a"},{"line_number":110,"context_line":"no-op returning ``None`` so that an unmodified driver behaves exactly as it"},{"line_number":111,"context_line":"does today. However, the three are not independently optional: a driver"},{"line_number":112,"context_line":"that supports CBT must implement all three together. Overriding only"},{"line_number":113,"context_line":"``get_cbt_extents()`` without ``create_cbt_snapshot()``, for example, would"},{"line_number":114,"context_line":"make ``supports_cbt()`` falsely report CBT as available (see below) while"},{"line_number":115,"context_line":"every backup attempt fails to establish a reference point and silently"}],"source_content_type":"text/x-rst","patch_set":10,"id":"f2f6f1d8_fd500ff2","line":112,"range":{"start_line":111,"start_character":63,"end_line":112,"end_character":51},"updated":"2026-07-27 14:03:34.000000000","message":"Do we have any implications to Volume Group snapshots? If a volume is part of volume group - Cinder allows the snapshots to be taken. So backups can be taken of individual volumes. But since this feature does not expect consistent snapshot diffs, may be we can call it out as not supported/not compatible with Volume Group Snapshots?","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"7c700f1d8038159235b10963be68582587a3c825","unresolved":false,"context_lines":[{"line_number":108,"context_line":"optional — a driver that implements none of them is simply not CBT-capable,"},{"line_number":109,"context_line":"and the base class in ``cinder/volume/driver.py`` stubs each method to a"},{"line_number":110,"context_line":"no-op returning ``None`` so that an unmodified driver behaves exactly as it"},{"line_number":111,"context_line":"does today. However, the three are not independently optional: a driver"},{"line_number":112,"context_line":"that supports CBT must implement all three together. Overriding only"},{"line_number":113,"context_line":"``get_cbt_extents()`` without ``create_cbt_snapshot()``, for example, would"},{"line_number":114,"context_line":"make ``supports_cbt()`` falsely report CBT as available (see below) while"},{"line_number":115,"context_line":"every backup attempt fails to establish a reference point and silently"}],"source_content_type":"text/x-rst","patch_set":10,"id":"0b82afa9_80f2ec58","line":112,"range":{"start_line":111,"start_character":63,"end_line":112,"end_character":51},"in_reply_to":"74d3e07e_636fec31","updated":"2026-08-26 16:43:57.000000000","message":"Done","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":108,"context_line":"optional — a driver that implements none of them is simply not CBT-capable,"},{"line_number":109,"context_line":"and the base class in ``cinder/volume/driver.py`` stubs each method to a"},{"line_number":110,"context_line":"no-op returning ``None`` so that an unmodified driver behaves exactly as it"},{"line_number":111,"context_line":"does today. However, the three are not independently optional: a driver"},{"line_number":112,"context_line":"that supports CBT must implement all three together. Overriding only"},{"line_number":113,"context_line":"``get_cbt_extents()`` without ``create_cbt_snapshot()``, for example, would"},{"line_number":114,"context_line":"make ``supports_cbt()`` falsely report CBT as available (see below) while"},{"line_number":115,"context_line":"every backup attempt fails to establish a reference point and silently"}],"source_content_type":"text/x-rst","patch_set":10,"id":"74d3e07e_636fec31","line":112,"range":{"start_line":111,"start_character":63,"end_line":112,"end_character":51},"in_reply_to":"f2f6f1d8_fd500ff2","updated":"2026-08-07 13:16:43.000000000","message":"Group members are unaffected, not unsupported — backup create is per-volume; added a short note.","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"67833cd4af4909356b0579e04a71d17f5d758dd7","unresolved":true,"context_lines":[{"line_number":143,"context_line":""},{"line_number":144,"context_line":"``cinder/backup/manager.py`` drives all three, plus a fourth method"},{"line_number":145,"context_line":"``supports_cbt(volume)``, via RPC through ``cinder/volume/manager.py``,"},{"line_number":146,"context_line":"which delegates to the volume driver. ``supports_cbt()`` returns ``True``"},{"line_number":147,"context_line":"only when the running driver class actually overrides **all three**"},{"line_number":148,"context_line":"methods — ``get_cbt_extents``, ``create_cbt_snapshot``, and"},{"line_number":149,"context_line":"``delete_cbt_snapshot`` — each checked against ``BaseVD`` by class"},{"line_number":150,"context_line":"identity, not merely whether the attribute is callable (the base class"},{"line_number":151,"context_line":"stubs are always callable, and checking only one method would let a"},{"line_number":152,"context_line":"partial override falsely advertise CBT support). The diff result is"}],"source_content_type":"text/x-rst","patch_set":10,"id":"afe43bb1_295b248a","line":149,"range":{"start_line":146,"start_character":0,"end_line":149,"end_character":21},"updated":"2026-07-27 14:03:34.000000000","message":"Should this be handled via capabilities instead? A driver can return a capability driver_supports_cbt\u003dtrue if it has the capability to handle the workflows?","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"7c700f1d8038159235b10963be68582587a3c825","unresolved":false,"context_lines":[{"line_number":143,"context_line":""},{"line_number":144,"context_line":"``cinder/backup/manager.py`` drives all three, plus a fourth method"},{"line_number":145,"context_line":"``supports_cbt(volume)``, via RPC through ``cinder/volume/manager.py``,"},{"line_number":146,"context_line":"which delegates to the volume driver. ``supports_cbt()`` returns ``True``"},{"line_number":147,"context_line":"only when the running driver class actually overrides **all three**"},{"line_number":148,"context_line":"methods — ``get_cbt_extents``, ``create_cbt_snapshot``, and"},{"line_number":149,"context_line":"``delete_cbt_snapshot`` — each checked against ``BaseVD`` by class"},{"line_number":150,"context_line":"identity, not merely whether the attribute is callable (the base class"},{"line_number":151,"context_line":"stubs are always callable, and checking only one method would let a"},{"line_number":152,"context_line":"partial override falsely advertise CBT support). The diff result is"}],"source_content_type":"text/x-rst","patch_set":10,"id":"5fd90465_de7242eb","line":149,"range":{"start_line":146,"start_character":0,"end_line":149,"end_character":21},"in_reply_to":"35ae93ab_ca03422b","updated":"2026-08-26 16:43:57.000000000","message":"Acknowledged","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"12e9fabc493c5383ab9688d1c7316449cfb0efea","unresolved":true,"context_lines":[{"line_number":143,"context_line":""},{"line_number":144,"context_line":"``cinder/backup/manager.py`` drives all three, plus a fourth method"},{"line_number":145,"context_line":"``supports_cbt(volume)``, via RPC through ``cinder/volume/manager.py``,"},{"line_number":146,"context_line":"which delegates to the volume driver. ``supports_cbt()`` returns ``True``"},{"line_number":147,"context_line":"only when the running driver class actually overrides **all three**"},{"line_number":148,"context_line":"methods — ``get_cbt_extents``, ``create_cbt_snapshot``, and"},{"line_number":149,"context_line":"``delete_cbt_snapshot`` — each checked against ``BaseVD`` by class"},{"line_number":150,"context_line":"identity, not merely whether the attribute is callable (the base class"},{"line_number":151,"context_line":"stubs are always callable, and checking only one method would let a"},{"line_number":152,"context_line":"partial override falsely advertise CBT support). The diff result is"}],"source_content_type":"text/x-rst","patch_set":10,"id":"35ae93ab_ca03422b","line":149,"range":{"start_line":146,"start_character":0,"end_line":149,"end_character":21},"in_reply_to":"afe43bb1_295b248a","updated":"2026-08-07 13:16:43.000000000","message":"You\u0027re right that introspection can\u0027t express \"implemented but unavailable\" — recorded public capability advertisement as an explicit follow-up spec change.","commit_id":"2570508b4914fd35bd2c910417f1d93c31258b92"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":94,"context_line":"  written value happens to be zero) and must be read and backed up;"},{"line_number":95,"context_line":"  skipping it would silently corrupt the restore for a data-to-zero"},{"line_number":96,"context_line":"  overwrite. ``exists\u003dFalse`` means the extent was never allocated, so it"},{"line_number":97,"context_line":"  reads as zero with no need to back it up — on restore, any byte range"},{"line_number":98,"context_line":"  not covered by a backed-up extent is left as-is (zero), which is"},{"line_number":99,"context_line":"  already correct since it was never written"},{"line_number":100,"context_line":"* **Backend-agnostic interface**: the three CBT driver methods are not"},{"line_number":101,"context_line":"  Ceph-specific. Reference implementations were developed alongside the"},{"line_number":102,"context_line":"  framework to confirm this: the LVM driver (thin-provisioned volumes),"}],"source_content_type":"text/x-rst","patch_set":11,"id":"deeb0dda_29bc6529","line":99,"range":{"start_line":97,"start_character":57,"end_line":99,"end_character":44},"updated":"2026-08-26 17:36:44.000000000","message":"That only holds for a fresh target. Restoring a sparse full backup onto a pre-existing volume needs the uncovered ranges zero-filled, which the implementation does (`_zero_fill_uncovered`, gated on sparse and not `volume_is_new`). The spec\u0027s `sparse-only-when-no-parent_id` invariant is excellent; this is the missing other half.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"b30acb530b2579145cbdd057681243fd4d8358dc","unresolved":false,"context_lines":[{"line_number":94,"context_line":"  written value happens to be zero) and must be read and backed up;"},{"line_number":95,"context_line":"  skipping it would silently corrupt the restore for a data-to-zero"},{"line_number":96,"context_line":"  overwrite. ``exists\u003dFalse`` means the extent was never allocated, so it"},{"line_number":97,"context_line":"  reads as zero with no need to back it up — on restore, any byte range"},{"line_number":98,"context_line":"  not covered by a backed-up extent is left as-is (zero), which is"},{"line_number":99,"context_line":"  already correct since it was never written"},{"line_number":100,"context_line":"* **Backend-agnostic interface**: the three CBT driver methods are not"},{"line_number":101,"context_line":"  Ceph-specific. Reference implementations were developed alongside the"},{"line_number":102,"context_line":"  framework to confirm this: the LVM driver (thin-provisioned volumes),"}],"source_content_type":"text/x-rst","patch_set":11,"id":"11c7c044_9e83dd38","line":99,"range":{"start_line":97,"start_character":57,"end_line":99,"end_character":44},"in_reply_to":"adcd5ae0_07422c6f","updated":"2026-09-08 04:37:31.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":true,"context_lines":[{"line_number":94,"context_line":"  written value happens to be zero) and must be read and backed up;"},{"line_number":95,"context_line":"  skipping it would silently corrupt the restore for a data-to-zero"},{"line_number":96,"context_line":"  overwrite. ``exists\u003dFalse`` means the extent was never allocated, so it"},{"line_number":97,"context_line":"  reads as zero with no need to back it up — on restore, any byte range"},{"line_number":98,"context_line":"  not covered by a backed-up extent is left as-is (zero), which is"},{"line_number":99,"context_line":"  already correct since it was never written"},{"line_number":100,"context_line":"* **Backend-agnostic interface**: the three CBT driver methods are not"},{"line_number":101,"context_line":"  Ceph-specific. Reference implementations were developed alongside the"},{"line_number":102,"context_line":"  framework to confirm this: the LVM driver (thin-provisioned volumes),"}],"source_content_type":"text/x-rst","patch_set":11,"id":"adcd5ae0_07422c6f","line":99,"range":{"start_line":97,"start_character":57,"end_line":99,"end_character":44},"in_reply_to":"deeb0dda_29bc6529","updated":"2026-08-30 11:10:47.000000000","message":"Done — uncovered ranges are only safe to leave on a new target; _zero_fill_uncovered handles a pre-existing one. Also fixed \"Restore operations are unchanged\" and the same claim in the backup comment.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":616,"context_line":"* Drivers should consolidate adjacent extents that share the same"},{"line_number":617,"context_line":"  ``exists`` value before returning, to bound the size of the extent list"},{"line_number":618,"context_line":"  serialized over RPC."},{"line_number":619,"context_line":""},{"line_number":620,"context_line":""},{"line_number":621,"context_line":"Data model impact"},{"line_number":622,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":11,"id":"49c5a579_1ffb2551","line":619,"updated":"2026-08-26 17:36:44.000000000","message":"Need to add in here the \"never silently truncate\" rule. This is the correctness-critical one: `next_marker` is only computed when a limit is applied, so a driver that truncates its own result reports a partial list as complete → corrupt incremental. It\u0027s now an explicit contract rule in `BaseVD` and the contributor guide.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":true,"context_lines":[{"line_number":616,"context_line":"* Drivers should consolidate adjacent extents that share the same"},{"line_number":617,"context_line":"  ``exists`` value before returning, to bound the size of the extent list"},{"line_number":618,"context_line":"  serialized over RPC."},{"line_number":619,"context_line":""},{"line_number":620,"context_line":""},{"line_number":621,"context_line":"Data model impact"},{"line_number":622,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":11,"id":"7fa08344_51a46092","line":619,"in_reply_to":"49c5a579_1ffb2551","updated":"2026-08-30 11:10:47.000000000","message":"Done — added to Driver Responsibilities with CBTPagingRequired, and 413 to Capability discovery, the api-ref item and the Errors list.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"b30acb530b2579145cbdd057681243fd4d8358dc","unresolved":false,"context_lines":[{"line_number":616,"context_line":"* Drivers should consolidate adjacent extents that share the same"},{"line_number":617,"context_line":"  ``exists`` value before returning, to bound the size of the extent list"},{"line_number":618,"context_line":"  serialized over RPC."},{"line_number":619,"context_line":""},{"line_number":620,"context_line":""},{"line_number":621,"context_line":"Data model impact"},{"line_number":622,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":11,"id":"0b978a1b_6383bd43","line":619,"in_reply_to":"7fa08344_51a46092","updated":"2026-09-08 04:37:31.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":728,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":729,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":730,"context_line":"  sparse full backup). Optional ``offset`` and ``length`` restrict the"},{"line_number":731,"context_line":"  query to a byte window, and ``marker``/``limit`` paginate the result."},{"line_number":732,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":733,"context_line":"  extents, using the same shape as the driver interface, plus"},{"line_number":734,"context_line":"  ``changed_blocks_next_marker`` when more extents remain beyond"}],"source_content_type":"text/x-rst","patch_set":11,"id":"8a54e490_49791446","line":731,"range":{"start_line":731,"start_character":51,"end_line":731,"end_character":70},"updated":"2026-08-26 17:36:44.000000000","message":"limit now defaults to, and is capped at, a new `changed_blocks_max_limit`\n   option (default 1000), so omitting limit no longer returns the whole\n   list -- callers page via `changed_blocks_next_marker`. That belongs here, and the option in **Other deployer impact**.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"b30acb530b2579145cbdd057681243fd4d8358dc","unresolved":false,"context_lines":[{"line_number":728,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":729,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":730,"context_line":"  sparse full backup). Optional ``offset`` and ``length`` restrict the"},{"line_number":731,"context_line":"  query to a byte window, and ``marker``/``limit`` paginate the result."},{"line_number":732,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":733,"context_line":"  extents, using the same shape as the driver interface, plus"},{"line_number":734,"context_line":"  ``changed_blocks_next_marker`` when more extents remain beyond"}],"source_content_type":"text/x-rst","patch_set":11,"id":"e05f46d3_db23af56","line":731,"range":{"start_line":731,"start_character":51,"end_line":731,"end_character":70},"in_reply_to":"1f4d5d40_2f1d748c","updated":"2026-09-08 04:37:31.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":true,"context_lines":[{"line_number":728,"context_line":"  map, i.e. a diff against an empty baseline, the same semantics"},{"line_number":729,"context_line":"  ``get_cbt_extents(volume, None, to_snapshot)`` uses internally for a"},{"line_number":730,"context_line":"  sparse full backup). Optional ``offset`` and ``length`` restrict the"},{"line_number":731,"context_line":"  query to a byte window, and ``marker``/``limit`` paginate the result."},{"line_number":732,"context_line":"* **Response**: ``changed_blocks``, a list of ``{offset, length, exists}``"},{"line_number":733,"context_line":"  extents, using the same shape as the driver interface, plus"},{"line_number":734,"context_line":"  ``changed_blocks_next_marker`` when more extents remain beyond"}],"source_content_type":"text/x-rst","patch_set":11,"id":"1f4d5d40_2f1d748c","line":731,"range":{"start_line":731,"start_character":51,"end_line":731,"end_character":70},"in_reply_to":"8a54e490_49791446","updated":"2026-08-30 11:10:47.000000000","message":"Done. Also fixed the Response bullet — changed_blocks_next_marker is always returned, null on the last page.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":809,"context_line":"Other deployer impact"},{"line_number":810,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":811,"context_line":""},{"line_number":812,"context_line":"None. Reference snapshot cleanup is handled automatically by the backup"},{"line_number":813,"context_line":"manager (see Cleanup under Snapshot lifecycle) — at most two reference"},{"line_number":814,"context_line":"snapshots per backup chain exist at once (the parent\u0027s, and the one just"},{"line_number":815,"context_line":"created for the backup in progress), and the older of the two is removed"}],"source_content_type":"text/x-rst","patch_set":11,"id":"45c47369_c7714d78","line":812,"range":{"start_line":812,"start_character":0,"end_line":812,"end_character":4},"updated":"2026-08-26 17:36:44.000000000","message":"Not true now - needs to add `changed_blocks_max_limit` and `changed_blocks_rpc_timeout`","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":true,"context_lines":[{"line_number":809,"context_line":"Other deployer impact"},{"line_number":810,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":811,"context_line":""},{"line_number":812,"context_line":"None. Reference snapshot cleanup is handled automatically by the backup"},{"line_number":813,"context_line":"manager (see Cleanup under Snapshot lifecycle) — at most two reference"},{"line_number":814,"context_line":"snapshots per backup chain exist at once (the parent\u0027s, and the one just"},{"line_number":815,"context_line":"created for the backup in progress), and the older of the two is removed"}],"source_content_type":"text/x-rst","patch_set":11,"id":"ac1d9c12_fa59debd","line":812,"range":{"start_line":812,"start_character":0,"end_line":812,"end_character":4},"in_reply_to":"45c47369_c7714d78","updated":"2026-08-30 11:10:47.000000000","message":"Done — both options with their defaults and when to change them.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"b30acb530b2579145cbdd057681243fd4d8358dc","unresolved":false,"context_lines":[{"line_number":809,"context_line":"Other deployer impact"},{"line_number":810,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":811,"context_line":""},{"line_number":812,"context_line":"None. Reference snapshot cleanup is handled automatically by the backup"},{"line_number":813,"context_line":"manager (see Cleanup under Snapshot lifecycle) — at most two reference"},{"line_number":814,"context_line":"snapshots per backup chain exist at once (the parent\u0027s, and the one just"},{"line_number":815,"context_line":"created for the backup in progress), and the older of the two is removed"}],"source_content_type":"text/x-rst","patch_set":11,"id":"632c9eaa_26b66901","line":812,"range":{"start_line":812,"start_character":0,"end_line":812,"end_character":4},"in_reply_to":"ac1d9c12_fa59debd","updated":"2026-09-08 04:37:31.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":878,"context_line":"-----------"},{"line_number":879,"context_line":""},{"line_number":880,"context_line":"Primary assignee:"},{"line_number":881,"context_line":"  TBD"},{"line_number":882,"context_line":""},{"line_number":883,"context_line":"Work Items"},{"line_number":884,"context_line":"----------"}],"source_content_type":"text/x-rst","patch_set":11,"id":"5e5e7827_aae084d6","line":881,"range":{"start_line":881,"start_character":2,"end_line":881,"end_character":5},"updated":"2026-08-26 17:36:44.000000000","message":"add simondodsley - given I\u0027ve already written the implementation","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":true,"context_lines":[{"line_number":878,"context_line":"-----------"},{"line_number":879,"context_line":""},{"line_number":880,"context_line":"Primary assignee:"},{"line_number":881,"context_line":"  TBD"},{"line_number":882,"context_line":""},{"line_number":883,"context_line":"Work Items"},{"line_number":884,"context_line":"----------"}],"source_content_type":"text/x-rst","patch_set":11,"id":"defcca7a_7d6d7c0d","line":881,"range":{"start_line":881,"start_character":2,"end_line":881,"end_character":5},"in_reply_to":"5e5e7827_aae084d6","updated":"2026-08-30 11:10:47.000000000","message":"Done — you as primary, me as a contributor for the RBD driver (1002961).","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"b30acb530b2579145cbdd057681243fd4d8358dc","unresolved":false,"context_lines":[{"line_number":878,"context_line":"-----------"},{"line_number":879,"context_line":""},{"line_number":880,"context_line":"Primary assignee:"},{"line_number":881,"context_line":"  TBD"},{"line_number":882,"context_line":""},{"line_number":883,"context_line":"Work Items"},{"line_number":884,"context_line":"----------"}],"source_content_type":"text/x-rst","patch_set":11,"id":"3bbc1e3c_26bf8285","line":881,"range":{"start_line":881,"start_character":2,"end_line":881,"end_character":5},"in_reply_to":"defcca7a_7d6d7c0d","updated":"2026-09-08 04:37:31.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"bf5f69eafb0b802ffb8ba3afc476c53f367c00eb","unresolved":true,"context_lines":[{"line_number":1012,"context_line":""},{"line_number":1013,"context_line":".. _Ceph RBD diff_iterate API: https://docs.ceph.com/en/latest/man/8/rbd/#differential-io"},{"line_number":1014,"context_line":""},{"line_number":1015,"context_line":"* `Ceph RBD diff_iterate API`_"},{"line_number":1016,"context_line":"* CBT backup framework and changed-blocks API:"},{"line_number":1017,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/990923"},{"line_number":1018,"context_line":"* Reference CBT volume driver for vendors:"},{"line_number":1019,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995703"},{"line_number":1020,"context_line":"* LVM CBT support for thin-provisioned volumes:"},{"line_number":1021,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995738"},{"line_number":1022,"context_line":"* Pure Storage FlashArray CBT support:"},{"line_number":1023,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/990982"},{"line_number":1024,"context_line":"* api-ref and admin guide for ``os-list_changed_blocks``:"},{"line_number":1025,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995964"}],"source_content_type":"text/x-rst","patch_set":11,"id":"cf842c22_f89d219b","line":1025,"range":{"start_line":1015,"start_character":0,"end_line":1025,"end_character":56},"updated":"2026-08-26 17:36:44.000000000","message":"References are stale. 990923 is listed as \"framework and changed-blocks API\", but it was split: 990923 is now contract+API, 1000747 is the backup-consumption half. Missing entirely: 1000747, 1001037, 999911 (the data→zero restore bugfix this depends on), and 995741 (the worst-case tempest test).","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"b30acb530b2579145cbdd057681243fd4d8358dc","unresolved":false,"context_lines":[{"line_number":1012,"context_line":""},{"line_number":1013,"context_line":".. _Ceph RBD diff_iterate API: https://docs.ceph.com/en/latest/man/8/rbd/#differential-io"},{"line_number":1014,"context_line":""},{"line_number":1015,"context_line":"* `Ceph RBD diff_iterate API`_"},{"line_number":1016,"context_line":"* CBT backup framework and changed-blocks API:"},{"line_number":1017,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/990923"},{"line_number":1018,"context_line":"* Reference CBT volume driver for vendors:"},{"line_number":1019,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995703"},{"line_number":1020,"context_line":"* LVM CBT support for thin-provisioned volumes:"},{"line_number":1021,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995738"},{"line_number":1022,"context_line":"* Pure Storage FlashArray CBT support:"},{"line_number":1023,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/990982"},{"line_number":1024,"context_line":"* api-ref and admin guide for ``os-list_changed_blocks``:"},{"line_number":1025,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995964"}],"source_content_type":"text/x-rst","patch_set":11,"id":"8a20de4b_752b4988","line":1025,"range":{"start_line":1015,"start_character":0,"end_line":1025,"end_character":56},"in_reply_to":"11a49c59_a38c6cee","updated":"2026-09-08 04:37:31.000000000","message":"Done","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"17d0db3dda286de159be4259fdd83e00eb469541","unresolved":true,"context_lines":[{"line_number":1012,"context_line":""},{"line_number":1013,"context_line":".. _Ceph RBD diff_iterate API: https://docs.ceph.com/en/latest/man/8/rbd/#differential-io"},{"line_number":1014,"context_line":""},{"line_number":1015,"context_line":"* `Ceph RBD diff_iterate API`_"},{"line_number":1016,"context_line":"* CBT backup framework and changed-blocks API:"},{"line_number":1017,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/990923"},{"line_number":1018,"context_line":"* Reference CBT volume driver for vendors:"},{"line_number":1019,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995703"},{"line_number":1020,"context_line":"* LVM CBT support for thin-provisioned volumes:"},{"line_number":1021,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995738"},{"line_number":1022,"context_line":"* Pure Storage FlashArray CBT support:"},{"line_number":1023,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/990982"},{"line_number":1024,"context_line":"* api-ref and admin guide for ``os-list_changed_blocks``:"},{"line_number":1025,"context_line":"  https://review.opendev.org/c/openstack/cinder/+/995964"}],"source_content_type":"text/x-rst","patch_set":11,"id":"11a49c59_a38c6cee","line":1025,"range":{"start_line":1015,"start_character":0,"end_line":1025,"end_character":56},"in_reply_to":"cf842c22_f89d219b","updated":"2026-08-30 11:10:47.000000000","message":"Done — 990923 relabelled contract+API; added 1000747, 1001037, 999911 (prerequisite), 995741, 1002961.","commit_id":"a95d8ac7e0191d23818447840427ed1d7072672a"}],"specs/2026.2/incremental-backup-cbt.rst":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":true,"context_lines":[{"line_number":330,"context_line":"        if (backup.parent_id and"},{"line_number":331,"context_line":"                isinstance(backup_service, ChunkedBackupDriver) and"},{"line_number":332,"context_line":"                volume_rpcapi.supports_cbt(context, volume)):"},{"line_number":333,"context_line":"            parent_cbt_meta \u003d json.loads(parent_backup.metadata[\u0027cbt_metadata\u0027])"},{"line_number":334,"context_line":"            from_snapshot \u003d parent_cbt_meta[\u0027reference_snapshot\u0027]"},{"line_number":335,"context_line":"            to_snapshot \u003d \u0027backup.%s.snap.%s\u0027 % (backup.id, timestamp)"},{"line_number":336,"context_line":"            # Establish this backup\u0027s reference point first; get_cbt_extents"},{"line_number":337,"context_line":"            # is side-effect-free and only diffs snapshots that already exist."}],"source_content_type":"text/x-rst","patch_set":12,"id":"93e102c9_c319bb57","line":334,"range":{"start_line":333,"start_character":1,"end_line":334,"end_character":65},"updated":"2026-09-17 18:56:23.000000000","message":"change to:\n```\nparent_cbt_meta \u003d (parent_backup.metadata or {}).get(\u0027cbt_metadata\u0027)\nif parent_cbt_meta:\n    from_snapshot \u003d json.loads(parent_cbt_meta)[\u0027reference_snapshot\u0027]\n```","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"16ab2f179ef10590ff72fb041202ebbc97c5dbc7","unresolved":false,"context_lines":[{"line_number":330,"context_line":"        if (backup.parent_id and"},{"line_number":331,"context_line":"                isinstance(backup_service, ChunkedBackupDriver) and"},{"line_number":332,"context_line":"                volume_rpcapi.supports_cbt(context, volume)):"},{"line_number":333,"context_line":"            parent_cbt_meta \u003d json.loads(parent_backup.metadata[\u0027cbt_metadata\u0027])"},{"line_number":334,"context_line":"            from_snapshot \u003d parent_cbt_meta[\u0027reference_snapshot\u0027]"},{"line_number":335,"context_line":"            to_snapshot \u003d \u0027backup.%s.snap.%s\u0027 % (backup.id, timestamp)"},{"line_number":336,"context_line":"            # Establish this backup\u0027s reference point first; get_cbt_extents"},{"line_number":337,"context_line":"            # is side-effect-free and only diffs snapshots that already exist."}],"source_content_type":"text/x-rst","patch_set":12,"id":"1334fc24_065abf73","line":334,"range":{"start_line":333,"start_character":1,"end_line":334,"end_character":65},"in_reply_to":"93e102c9_c319bb57","updated":"2026-09-19 07:52:30.000000000","message":"Done","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":true,"context_lines":[{"line_number":347,"context_line":"        backup_service.backup(backup, volume_file)"},{"line_number":348,"context_line":"    # End of with block: CBTVolumeFileWrapper is destroyed"},{"line_number":349,"context_line":""},{"line_number":350,"context_line":"    if ref:"},{"line_number":351,"context_line":"        # Record this backup\u0027s reference point so the next incremental"},{"line_number":352,"context_line":"        # backup can use it as from_snapshot."},{"line_number":353,"context_line":"        meta \u003d dict(backup.metadata) if backup.metadata else {}"},{"line_number":354,"context_line":"        meta[\u0027cbt_metadata\u0027] \u003d json.dumps({\u0027reference_snapshot\u0027: ref,"},{"line_number":355,"context_line":"                                           \u0027cbt_backend\u0027: cbt_backend})"},{"line_number":356,"context_line":"        backup.metadata \u003d meta"},{"line_number":357,"context_line":"        backup.save()"},{"line_number":358,"context_line":"        # Cleanup: the parent\u0027s reference snapshot is now superseded."},{"line_number":359,"context_line":"        # delete_cbt_snapshot() is best-effort and idempotent."},{"line_number":360,"context_line":"        if from_snapshot:"},{"line_number":361,"context_line":"            volume_rpcapi.delete_cbt_snapshot(context, volume, from_snapshot)"},{"line_number":362,"context_line":""},{"line_number":363,"context_line":"**chunkeddriver.py** — CBT detection and usage in ``backup()``::"},{"line_number":364,"context_line":""}],"source_content_type":"text/x-rst","patch_set":12,"id":"63ff93cb_2069dcfd","line":361,"range":{"start_line":350,"start_character":0,"end_line":361,"end_character":77},"updated":"2026-09-17 18:56:23.000000000","message":"change to:\n```\n    if ref:\n        # The chunked driver has recorded ``ref`` under cbt_metadata as part\n        # of backup() (see _save_cbt_metadata below); the manager only has\n        # to retire the parent\u0027s now-superseded reference snapshot.\n        # delete_cbt_snapshot() is best-effort and idempotent.\n        if from_snapshot:\n            volume_rpcapi.delete_cbt_snapshot(context, volume, from_snapshot)\n```","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"16ab2f179ef10590ff72fb041202ebbc97c5dbc7","unresolved":false,"context_lines":[{"line_number":347,"context_line":"        backup_service.backup(backup, volume_file)"},{"line_number":348,"context_line":"    # End of with block: CBTVolumeFileWrapper is destroyed"},{"line_number":349,"context_line":""},{"line_number":350,"context_line":"    if ref:"},{"line_number":351,"context_line":"        # Record this backup\u0027s reference point so the next incremental"},{"line_number":352,"context_line":"        # backup can use it as from_snapshot."},{"line_number":353,"context_line":"        meta \u003d dict(backup.metadata) if backup.metadata else {}"},{"line_number":354,"context_line":"        meta[\u0027cbt_metadata\u0027] \u003d json.dumps({\u0027reference_snapshot\u0027: ref,"},{"line_number":355,"context_line":"                                           \u0027cbt_backend\u0027: cbt_backend})"},{"line_number":356,"context_line":"        backup.metadata \u003d meta"},{"line_number":357,"context_line":"        backup.save()"},{"line_number":358,"context_line":"        # Cleanup: the parent\u0027s reference snapshot is now superseded."},{"line_number":359,"context_line":"        # delete_cbt_snapshot() is best-effort and idempotent."},{"line_number":360,"context_line":"        if from_snapshot:"},{"line_number":361,"context_line":"            volume_rpcapi.delete_cbt_snapshot(context, volume, from_snapshot)"},{"line_number":362,"context_line":""},{"line_number":363,"context_line":"**chunkeddriver.py** — CBT detection and usage in ``backup()``::"},{"line_number":364,"context_line":""}],"source_content_type":"text/x-rst","patch_set":12,"id":"a77eb4fc_59af202d","line":361,"range":{"start_line":350,"start_character":0,"end_line":361,"end_character":77},"in_reply_to":"63ff93cb_2069dcfd","updated":"2026-09-19 07:52:30.000000000","message":"Done","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":true,"context_lines":[{"line_number":672,"context_line":"  Cinder mechanisms."},{"line_number":673,"context_line":""},{"line_number":674,"context_line":"**CBT Metadata Schema**:"},{"line_number":675,"context_line":""},{"line_number":676,"context_line":"When CBT is enabled for a backup, ``cbt_metadata`` holds::"},{"line_number":677,"context_line":""},{"line_number":678,"context_line":"    backup.metadata[\u0027cbt_metadata\u0027] \u003d json.dumps({"},{"line_number":679,"context_line":"        \u0027reference_snapshot\u0027: \u0027backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\u0027,"},{"line_number":680,"context_line":"        \u0027cbt_backend\u0027: \u0027ceph\u0027,"},{"line_number":681,"context_line":"    })"},{"line_number":682,"context_line":""},{"line_number":683,"context_line":"**Field Descriptions**:"},{"line_number":684,"context_line":""}],"source_content_type":"text/x-rst","patch_set":12,"id":"ba671326_5b85af4c","line":681,"range":{"start_line":675,"start_character":0,"end_line":681,"end_character":6},"updated":"2026-09-17 18:56:23.000000000","message":"change to:\n```\nWhen CBT is enabled for a backup, ``cbt_metadata`` (the key is defined once\nas ``cinder.common.constants.CBT_METADATA_KEY``) holds::\n\n    backup.metadata[\u0027cbt_metadata\u0027] \u003d json.dumps({\n        \u0027reference_snapshot\u0027: \u0027backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\u0027,\n        \u0027cbt_backend\u0027: \u0027ceph\u0027,\n        \u0027reference_snapshot_cinder_id\u0027: \u0027\u003csnapshot uuid\u003e\u0027,   # in-use volumes only\n    })\n```","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"16ab2f179ef10590ff72fb041202ebbc97c5dbc7","unresolved":false,"context_lines":[{"line_number":672,"context_line":"  Cinder mechanisms."},{"line_number":673,"context_line":""},{"line_number":674,"context_line":"**CBT Metadata Schema**:"},{"line_number":675,"context_line":""},{"line_number":676,"context_line":"When CBT is enabled for a backup, ``cbt_metadata`` holds::"},{"line_number":677,"context_line":""},{"line_number":678,"context_line":"    backup.metadata[\u0027cbt_metadata\u0027] \u003d json.dumps({"},{"line_number":679,"context_line":"        \u0027reference_snapshot\u0027: \u0027backup.\u003cbackup_id\u003e.snap.\u003ctimestamp\u003e\u0027,"},{"line_number":680,"context_line":"        \u0027cbt_backend\u0027: \u0027ceph\u0027,"},{"line_number":681,"context_line":"    })"},{"line_number":682,"context_line":""},{"line_number":683,"context_line":"**Field Descriptions**:"},{"line_number":684,"context_line":""}],"source_content_type":"text/x-rst","patch_set":12,"id":"88bc391b_23d12047","line":681,"range":{"start_line":675,"start_character":0,"end_line":681,"end_character":6},"in_reply_to":"ba671326_5b85af4c","updated":"2026-09-19 07:52:30.000000000","message":"Done","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":true,"context_lines":[{"line_number":688,"context_line":"  ``get_cbt_extents()`` call"},{"line_number":689,"context_line":"* ``cbt_backend``: storage backend name (``\"ceph\"``, etc.) that produced"},{"line_number":690,"context_line":"  the reference snapshot"},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"**Storage Location**:"},{"line_number":693,"context_line":""},{"line_number":694,"context_line":"* Stored in ``Backup.metadata`` (Cinder database)."}],"source_content_type":"text/x-rst","patch_set":12,"id":"defe838a_eb3328d6","line":691,"updated":"2026-09-17 18:56:23.000000000","message":"insert:\n```\n* ``reference_snapshot_cinder_id``: present only when the reference point is\n  an adopted Cinder snapshot (the temporary snapshot of an in-use volume);\n  the framework deletes it through the snapshot API rather than\n  ``delete_cbt_snapshot()``\n```","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"16ab2f179ef10590ff72fb041202ebbc97c5dbc7","unresolved":false,"context_lines":[{"line_number":688,"context_line":"  ``get_cbt_extents()`` call"},{"line_number":689,"context_line":"* ``cbt_backend``: storage backend name (``\"ceph\"``, etc.) that produced"},{"line_number":690,"context_line":"  the reference snapshot"},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"**Storage Location**:"},{"line_number":693,"context_line":""},{"line_number":694,"context_line":"* Stored in ``Backup.metadata`` (Cinder database)."}],"source_content_type":"text/x-rst","patch_set":12,"id":"3ca4168c_eb6dff44","line":691,"in_reply_to":"defe838a_eb3328d6","updated":"2026-09-19 07:52:30.000000000","message":"Done","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":true,"context_lines":[{"line_number":699,"context_line":"      meta[\u0027cbt_metadata\u0027] \u003d json.dumps(...)"},{"line_number":700,"context_line":"      backup.metadata \u003d meta"},{"line_number":701,"context_line":"      backup.save()"},{"line_number":702,"context_line":""},{"line_number":703,"context_line":"* Read by the backup manager from the parent backup\u0027s record before"},{"line_number":704,"context_line":"  planning the next incremental backup."},{"line_number":705,"context_line":"* Not required for restore operations."}],"source_content_type":"text/x-rst","patch_set":12,"id":"915aaf54_4bb9c314","line":702,"updated":"2026-09-17 18:56:23.000000000","message":"Add in here:\n```\n* Reserved key. ``Backup.metadata`` is user-writable through the backup\n  update API (microversion 3.43+), and the backup record saves metadata with\n  delete-on-omit semantics, so a user replacing their own keys would\n  otherwise drop ``cbt_metadata`` and break the chain. The backup API\n  therefore treats ``cbt_metadata`` as reserved: an update preserves the\n  stored value and ignores any value supplied for the key. The key remains\n  visible in reads. As defence in depth, the chunked driver promotes an\n  incremental to a full backup if the parent\u0027s SHA256 file turns out to be\n  unreadable, rather than failing the backup.\n```","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"4174f611b115e1f950efae47c8f15d69d465fd35","unresolved":false,"context_lines":[{"line_number":699,"context_line":"      meta[\u0027cbt_metadata\u0027] \u003d json.dumps(...)"},{"line_number":700,"context_line":"      backup.metadata \u003d meta"},{"line_number":701,"context_line":"      backup.save()"},{"line_number":702,"context_line":""},{"line_number":703,"context_line":"* Read by the backup manager from the parent backup\u0027s record before"},{"line_number":704,"context_line":"  planning the next incremental backup."},{"line_number":705,"context_line":"* Not required for restore operations."}],"source_content_type":"text/x-rst","patch_set":12,"id":"9fb3f3a8_08bc0952","line":702,"in_reply_to":"915aaf54_4bb9c314","updated":"2026-09-19 13:29:05.000000000","message":"Done","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"18120062064d9a69f51fb2007388790be93e7eb9","unresolved":true,"context_lines":[{"line_number":916,"context_line":"**Backup driver side** (``cinder/backup/chunkeddriver.py``):"},{"line_number":917,"context_line":""},{"line_number":918,"context_line":"* Detect ``get_cbt_extents`` on ``volume_file`` and branch into CBT path"},{"line_number":919,"context_line":"* Implement ``_backup_with_cbt()``, ``_get_cbt_reference_point()``,"},{"line_number":920,"context_line":"  and ``_save_cbt_metadata()``"},{"line_number":921,"context_line":"* Implement fallback to full scan for all failure scenarios"},{"line_number":922,"context_line":"* Store and retrieve CBT metadata in backup object metadata"},{"line_number":923,"context_line":""}],"source_content_type":"text/x-rst","patch_set":12,"id":"639b34fd_0afe00b8","line":920,"range":{"start_line":919,"start_character":0,"end_line":920,"end_character":30},"updated":"2026-09-17 18:56:23.000000000","message":"change to:\n```\n* Implement ``_backup_cbt()`` (ships only the reported extents, validating\n  each lies within the volume) and ``_save_cbt_metadata()`` (records the\n  reference point the wrapper exposes via ``get_cbt_reference_point()``)\n```","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"4174f611b115e1f950efae47c8f15d69d465fd35","unresolved":false,"context_lines":[{"line_number":916,"context_line":"**Backup driver side** (``cinder/backup/chunkeddriver.py``):"},{"line_number":917,"context_line":""},{"line_number":918,"context_line":"* Detect ``get_cbt_extents`` on ``volume_file`` and branch into CBT path"},{"line_number":919,"context_line":"* Implement ``_backup_with_cbt()``, ``_get_cbt_reference_point()``,"},{"line_number":920,"context_line":"  and ``_save_cbt_metadata()``"},{"line_number":921,"context_line":"* Implement fallback to full scan for all failure scenarios"},{"line_number":922,"context_line":"* Store and retrieve CBT metadata in backup object metadata"},{"line_number":923,"context_line":""}],"source_content_type":"text/x-rst","patch_set":12,"id":"81bbd78f_d3daed45","line":920,"range":{"start_line":919,"start_character":0,"end_line":920,"end_character":30},"in_reply_to":"639b34fd_0afe00b8","updated":"2026-09-19 13:29:05.000000000","message":"Done","commit_id":"6745111578a40d9cada26de348ad388e803319c2"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"5cf6a1e9fd5fbd7c138f44047abdd09a05612c97","unresolved":true,"context_lines":[{"line_number":88,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":89,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":90,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":91,"context_line":"* **Sparse extent handling**: ``exists`` distinguishes allocated extents"},{"line_number":92,"context_line":"  that must be backed up from unallocated (sparse) extents that can be"},{"line_number":93,"context_line":"  skipped. ``exists\u003dTrue`` means the extent was written to (even if the"},{"line_number":94,"context_line":"  written value happens to be zero) and must be read and backed up;"},{"line_number":95,"context_line":"  skipping it would silently corrupt the restore for a data-to-zero"},{"line_number":96,"context_line":"  overwrite. ``exists\u003dFalse`` means the extent was never allocated, so it"},{"line_number":97,"context_line":"  reads as zero with no need to back it up. Any byte range not covered by"},{"line_number":98,"context_line":"  a backed-up extent may be left untouched when restoring to a newly"},{"line_number":99,"context_line":"  created target volume, because a new volume is initialized to zero."},{"line_number":100,"context_line":"  When restoring a sparse full backup onto a pre-existing volume, the"}],"source_content_type":"text/x-rst","patch_set":16,"id":"56362235_ac888e55","line":97,"range":{"start_line":91,"start_character":2,"end_line":97,"end_character":43},"updated":"2026-09-23 15:14:17.000000000","message":"replace with:\n* **Sparse extent handling**: every reported extent is a contiguous run of\n  changed units and must be shipped; drivers never report unchanged\n  regions. ``exists`` is ``True`` for all such extents, including a change\n  from data to zero. A driver *may* additionally report never-written holes\n  as ``exists\u003dFalse`` (they read as zero and the consumer skips them), but\n  omitting them is equivalent and is what all reference drivers do.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"b334ec4c372c7d0e9152976fccf9065575a59914","unresolved":false,"context_lines":[{"line_number":88,"context_line":"  implemented in ``chunkeddriver.py``, enabling all backup drivers"},{"line_number":89,"context_line":"  (Swift, S3, GCS, NFS, etc.) to benefit without per-driver changes"},{"line_number":90,"context_line":"* **Automatic fallback**: If CBT is unavailable or fails, fall back to full scan"},{"line_number":91,"context_line":"* **Sparse extent handling**: ``exists`` distinguishes allocated extents"},{"line_number":92,"context_line":"  that must be backed up from unallocated (sparse) extents that can be"},{"line_number":93,"context_line":"  skipped. ``exists\u003dTrue`` means the extent was written to (even if the"},{"line_number":94,"context_line":"  written value happens to be zero) and must be read and backed up;"},{"line_number":95,"context_line":"  skipping it would silently corrupt the restore for a data-to-zero"},{"line_number":96,"context_line":"  overwrite. ``exists\u003dFalse`` means the extent was never allocated, so it"},{"line_number":97,"context_line":"  reads as zero with no need to back it up. Any byte range not covered by"},{"line_number":98,"context_line":"  a backed-up extent may be left untouched when restoring to a newly"},{"line_number":99,"context_line":"  created target volume, because a new volume is initialized to zero."},{"line_number":100,"context_line":"  When restoring a sparse full backup onto a pre-existing volume, the"}],"source_content_type":"text/x-rst","patch_set":16,"id":"4e2e1b57_537ff9d8","line":97,"range":{"start_line":91,"start_character":2,"end_line":97,"end_character":43},"in_reply_to":"56362235_ac888e55","updated":"2026-09-28 12:57:06.000000000","message":"Done","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"9a932618679cafc733aba2f2f091395bfd0edbc3","unresolved":true,"context_lines":[{"line_number":206,"context_line":""},{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"}],"source_content_type":"text/x-rst","patch_set":16,"id":"3f8f8bb5_03ffceac","line":209,"range":{"start_line":209,"start_character":0,"end_line":209,"end_character":41},"updated":"2026-09-22 13:12:35.000000000","message":"The length in this case would always be block size? Since a data block that got modified would need to be read from its offset to the length (which would mean the end of block?)","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"c97cee4cd4d56a91af3f39152641a68ed1c2029f","unresolved":true,"context_lines":[{"line_number":206,"context_line":""},{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"}],"source_content_type":"text/x-rst","patch_set":16,"id":"f2a23324_14cb3bc7","line":209,"updated":"2026-09-22 19:19:17.000000000","message":"Update to say:\n  - length (int): length in bytes.  Not tied to any block size: a backend\n    reports at its own native granularity and adjacent changed ranges are\n    merged, so one extent may span many blocks.  Consumers read\n    [offset, offset + length) in slices of their own choosing.\n    In practice a backend reports at its own tracking granularity, a unit\n    modified anywhere is reported whole, and consecutive dirty units are\n    merged into one extent.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"bf0fa6562213452078d5544e1409e41f771ab651","unresolved":false,"context_lines":[{"line_number":206,"context_line":""},{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"}],"source_content_type":"text/x-rst","patch_set":16,"id":"60a8fc2b_365087db","line":209,"range":{"start_line":209,"start_character":0,"end_line":209,"end_character":41},"in_reply_to":"058b98c0_4a04fd1b","updated":"2026-09-28 13:02:05.000000000","message":"Done","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"ca78e090c056767aa3139474422b631d8ebc1587","unresolved":true,"context_lines":[{"line_number":206,"context_line":""},{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"}],"source_content_type":"text/x-rst","patch_set":16,"id":"058b98c0_4a04fd1b","line":209,"range":{"start_line":209,"start_character":0,"end_line":209,"end_character":41},"in_reply_to":"06c348da_929c1711","updated":"2026-09-22 19:12:43.000000000","message":"Thanks for the reply Simon. The reading of these \"dirty\" blocks would be at the granularity of blocks right? A block cannot be read from middle. Which would mean an extent would be a list of blocks that have been modified no matter completely or partially. so the offset would be start of the contagious dirty block and length would be the end of the last block that has been modified in in succession?","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"9569f0e7826e9e44b7f70d4da3af2b8b167b1c77","unresolved":true,"context_lines":[{"line_number":206,"context_line":""},{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"}],"source_content_type":"text/x-rst","patch_set":16,"id":"06c348da_929c1711","line":209,"range":{"start_line":209,"start_character":0,"end_line":209,"end_character":41},"in_reply_to":"3f8f8bb5_03ffceac","updated":"2026-09-22 13:22:11.000000000","message":"- length (int): length in bytes.  Not tied to any block size: a backend\n    reports at its own native granularity and adjacent changed ranges are\n    merged, so one extent may span many blocks.  Consumers read\n    [offset, offset + length) in slices of their own choosing.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"bf0fa6562213452078d5544e1409e41f771ab651","unresolved":false,"context_lines":[{"line_number":206,"context_line":""},{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"}],"source_content_type":"text/x-rst","patch_set":16,"id":"a617b257_bb54fdde","line":209,"in_reply_to":"f2a23324_14cb3bc7","updated":"2026-09-28 13:02:05.000000000","message":"Done","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":38059,"name":"Anoop Kumar Shukla","display_name":"Anoop Shukla","email":"anoop.shukla@netapp.com","username":"anoop2","status":"NetApp"},"change_message_id":"31bb1980c450021a723399f01815c62626a7b99d","unresolved":true,"context_lines":[{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"},{"line_number":213,"context_line":"            it exists\u003dFalse. Anything a diff reports is a change and"},{"line_number":214,"context_line":"            must be shipped, including a change from data to zero -- an"},{"line_number":215,"context_line":"            overwrite with zeros, or a deallocation by guest"},{"line_number":216,"context_line":"            fstrim/discard."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        incremental \u003d from_snapshot is not None"},{"line_number":219,"context_line":"        extents \u003d []"}],"source_content_type":"text/x-rst","patch_set":16,"id":"76850dfc_bae486b1","line":216,"range":{"start_line":210,"start_character":12,"end_line":216,"end_character":27},"updated":"2026-09-23 15:01:46.000000000","message":"I dont get the point of this bool value. If we are only reporting the extents which have the diffs, why do we need to return exists? It confuses implementors thinking exists\u003dFalse will need to be responded for any blocks which do not have changes. Which can end up scanning and reporting all blocks? OR, is it for the datablocks which are not modified but are part of the extent (length)?\n\nFor eg: if I have 4 blocks and b1, b2 and b4 are modified not b3, is the offset of the extent starting with start of b1 and length till b4 where b3 is shown as exists\u003dFalse?","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"5cf6a1e9fd5fbd7c138f44047abdd09a05612c97","unresolved":true,"context_lines":[{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"},{"line_number":213,"context_line":"            it exists\u003dFalse. Anything a diff reports is a change and"},{"line_number":214,"context_line":"            must be shipped, including a change from data to zero -- an"},{"line_number":215,"context_line":"            overwrite with zeros, or a deallocation by guest"},{"line_number":216,"context_line":"            fstrim/discard."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        incremental \u003d from_snapshot is not None"},{"line_number":219,"context_line":"        extents \u003d []"}],"source_content_type":"text/x-rst","patch_set":16,"id":"6950a86c_e698d36b","line":216,"range":{"start_line":210,"start_character":10,"end_line":216,"end_character":27},"updated":"2026-09-23 15:14:17.000000000","message":"replace with:\n          - exists (bool): True for every changed extent (always, in\n            practice).  False is optional and means a never-written hole\n            that reads as zero; the consumer skips it, and omitting it\n            is equivalent.  Extents never contain unchanged units, and a\n            driver must never enumerate unchanged regions to report them.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"b334ec4c372c7d0e9152976fccf9065575a59914","unresolved":false,"context_lines":[{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"},{"line_number":213,"context_line":"            it exists\u003dFalse. Anything a diff reports is a change and"},{"line_number":214,"context_line":"            must be shipped, including a change from data to zero -- an"},{"line_number":215,"context_line":"            overwrite with zeros, or a deallocation by guest"},{"line_number":216,"context_line":"            fstrim/discard."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        incremental \u003d from_snapshot is not None"},{"line_number":219,"context_line":"        extents \u003d []"}],"source_content_type":"text/x-rst","patch_set":16,"id":"895764d6_9ccaeaf2","line":216,"range":{"start_line":210,"start_character":12,"end_line":216,"end_character":27},"in_reply_to":"3489a9be_d0cc84ba","updated":"2026-09-28 12:57:06.000000000","message":"You\u0027re right, and the inconsistency is mine — the extent contract was first written against RBD\u0027s diff_iterate, where exists means \"allocated in the newer image\", and when the design moved to a backend-neutral interface some of that wording stayed behind while the contract had already become \"changed runs that must be shipped\". PS17 aligns L91-96, L216 and L637 on Simon\u0027s wording.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"b334ec4c372c7d0e9152976fccf9065575a59914","unresolved":false,"context_lines":[{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"},{"line_number":213,"context_line":"            it exists\u003dFalse. Anything a diff reports is a change and"},{"line_number":214,"context_line":"            must be shipped, including a change from data to zero -- an"},{"line_number":215,"context_line":"            overwrite with zeros, or a deallocation by guest"},{"line_number":216,"context_line":"            fstrim/discard."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        incremental \u003d from_snapshot is not None"},{"line_number":219,"context_line":"        extents \u003d []"}],"source_content_type":"text/x-rst","patch_set":16,"id":"eddc7eac_cbe47de4","line":216,"range":{"start_line":210,"start_character":10,"end_line":216,"end_character":27},"in_reply_to":"6950a86c_e698d36b","updated":"2026-09-28 12:57:06.000000000","message":"Done","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"5cf6a1e9fd5fbd7c138f44047abdd09a05612c97","unresolved":true,"context_lines":[{"line_number":207,"context_line":"        Each extent is a dict with:"},{"line_number":208,"context_line":"          - offset (int): byte offset within the volume"},{"line_number":209,"context_line":"          - length (int): length in bytes"},{"line_number":210,"context_line":"          - exists (bool): True if the extent must be backed up."},{"line_number":211,"context_line":"            Report only the regions that must be shipped, always with"},{"line_number":212,"context_line":"            exists\u003dTrue, and omit everything else rather than reporting"},{"line_number":213,"context_line":"            it exists\u003dFalse. Anything a diff reports is a change and"},{"line_number":214,"context_line":"            must be shipped, including a change from data to zero -- an"},{"line_number":215,"context_line":"            overwrite with zeros, or a deallocation by guest"},{"line_number":216,"context_line":"            fstrim/discard."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        incremental \u003d from_snapshot is not None"},{"line_number":219,"context_line":"        extents \u003d []"}],"source_content_type":"text/x-rst","patch_set":16,"id":"3489a9be_d0cc84ba","line":216,"range":{"start_line":210,"start_character":12,"end_line":216,"end_character":27},"in_reply_to":"76850dfc_bae486b1","updated":"2026-09-23 15:14:17.000000000","message":"Fair point -- the spec is inconsistent about this and your reading of L91-96 is the natural one. To your example: no, an extent never contains an unchanged unit. Extents are contiguous runs of changed units only, so b1+b2 is one extent, b4 is another, and b3 is not reported at all. exists\u003dFalse is optional: it means \"known-unallocated hole, reads as zero\", the consumer skips it, and omitting it is equivalent -- every current driver omits it. Drivers must never scan or report unchanged regions. The field is there because it mirrors the diff APIs drivers wrap (RBD diff_iterate reports (offset, length, exists), QEMU/NBD block status has zero/hole flags), so a driver can pass its backend\u0027s answer through, and it leaves room for a future hole-punch optimisation without changing the response shape. I\u0027ll suggest wording so L91-96, L216 and L637 all say the same thing.","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@everpuredata.com","username":"sdodsley"},"change_message_id":"5cf6a1e9fd5fbd7c138f44047abdd09a05612c97","unresolved":true,"context_lines":[{"line_number":634,"context_line":"  ``from_snapshot`` (e.g. it no longer exists on the backend), return"},{"line_number":635,"context_line":"  ``None``. Never return a partial or guessed diff — that is the one path"},{"line_number":636,"context_line":"  that leads to silent data corruption on restore."},{"line_number":637,"context_line":"* Drivers should consolidate adjacent extents that share the same"},{"line_number":638,"context_line":"  ``exists`` value before returning, to bound the size of the extent list"},{"line_number":639,"context_line":"  serialized over RPC."},{"line_number":640,"context_line":"* A driver must **never silently truncate** its result. A short list is"},{"line_number":641,"context_line":"  indistinguishable from a complete one — ``changed_blocks_next_marker``"}],"source_content_type":"text/x-rst","patch_set":16,"id":"fec793ed_d31a5490","line":638,"range":{"start_line":637,"start_character":46,"end_line":638,"end_character":18},"updated":"2026-09-23 15:14:17.000000000","message":"remove this part of the sentence","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"},{"author":{"_account_id":36686,"name":"Inyong Hong","display_name":"hongp","email":"inyong.hong@samsung.com","username":"hong-p"},"change_message_id":"b334ec4c372c7d0e9152976fccf9065575a59914","unresolved":false,"context_lines":[{"line_number":634,"context_line":"  ``from_snapshot`` (e.g. it no longer exists on the backend), return"},{"line_number":635,"context_line":"  ``None``. Never return a partial or guessed diff — that is the one path"},{"line_number":636,"context_line":"  that leads to silent data corruption on restore."},{"line_number":637,"context_line":"* Drivers should consolidate adjacent extents that share the same"},{"line_number":638,"context_line":"  ``exists`` value before returning, to bound the size of the extent list"},{"line_number":639,"context_line":"  serialized over RPC."},{"line_number":640,"context_line":"* A driver must **never silently truncate** its result. A short list is"},{"line_number":641,"context_line":"  indistinguishable from a complete one — ``changed_blocks_next_marker``"}],"source_content_type":"text/x-rst","patch_set":16,"id":"28d6c8a6_86efbb84","line":638,"range":{"start_line":637,"start_character":46,"end_line":638,"end_character":18},"in_reply_to":"fec793ed_d31a5490","updated":"2026-09-28 12:57:06.000000000","message":"Done","commit_id":"0fcfebe81f0faeaaf5e54d7ce07d6f672dce0112"}]}
