| NODE_DATA Design (Sheffield 2010-08-18) |
| ======================================= |
| |
| Essentially it replaces BASE_NODE and WORKING_NODE by combining all |
| the existing columns with a new op_depth column where op_depth == 0 is |
| the old BASE_NODE and op_depth != 0 is the old WORKING_NODE. |
| |
| Category Columns |
| |
| indexing: wc_id, local_relpath, parent_relpath, op_depth |
| status: presence |
| node-rev: repos_id, repos_relpath, revnum |
| content: kind, properties, depth, target, checksum |
| last-change: changed_rev, changed_date, changed_author |
| wc-cache: translated_size, last_mod_time |
| misc: dav_cache, file_external |
| |
| When op_depth == 0 the node-rev columns represent the checked-out |
| repository node, otherwise they represent the copyfrom node. |
| |
| Presence has the same six values as BASE_NODE/WORKING_NODE: normal, |
| incomplete, absent, excluded, not-present, base-deleted. There are |
| some presence/op_depth constraints, e.g. base-deleted is not valid for |
| op_depth 0 and absent is not valid for op_depth != 0. |
| |
| The wc-cache values are only valid for the greatest op_depth for any |
| local_relpath. This is acceptable partly because the overhead of |
| having them in a separate table (which would need to include wc_id and |
| local_relpath) offsets the redundancy of having them at all op_depth. |
| |
| Basic Delete/Copy |
| ----------------- |
| |
| Key: |
| n normal |
| b base-deleted |
| p not-present |
| + operation root (op_depth == number of components in local_relpath) |
| ~ operation pseudo-root (revnum != revnum of parent) |
| * not expected on disk |
| |
| Checkout/update: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| f1 n |
| f2 n |
| A1/ n |
| f1 n |
| g1 n |
| A2/ n |
| B1/ n |
| f1 n |
| h1 n |
| |
| |
| Delete f1, add f3, delete A2/B1: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| f1* n b+ |
| f2 n |
| f3 n+ |
| A1/ n |
| f1 n |
| g1 n |
| A2/ n |
| B1/* n b+ |
| f1* n b |
| h1* n b |
| |
| Copy A1 to A2/B1 (a replace): |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| f1* n b+ |
| f2 n |
| f3 n+ |
| A1/ n |
| f1 n |
| g1 n |
| A2/ n |
| B1/ n n+ |
| f1 n n |
| h1* n b |
| g1 n n |
| |
| |
| Delete A2/B1/f1, add A2/B1/C1, A2/B1/C1/f1: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| f1* n b+ |
| f2 n |
| f3 n+ |
| A1/ n |
| f1 n |
| g1 n |
| A2/ n |
| B1/ n n+ |
| f1* n n b+ |
| h1* n b |
| g1 n n |
| C1/ n+ |
| f1 n+ |
| |
| Copy f2 to A2/B1/f1 (a replace): |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| f1* n b+ |
| f2 n |
| f3 n+ |
| A1/ n |
| f1 n |
| g1 n |
| A2/ n |
| B1/ n n+ |
| f1 n n n+ |
| h1* n b |
| g1 n n |
| C1/ n+ |
| f1 n+ |
| |
| |
| Copy A1 to A2/C1/D1: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| f1* n b+ |
| f2 n |
| f3 n+ |
| A1/ n |
| f1 n |
| g1 n |
| A2/ n |
| B1/ n n+ |
| f1 n n n+ |
| h1* n b |
| g1 n n |
| C1/ n+ |
| f1 n+ |
| D1/ n+ |
| f1 n |
| g1 n |
| |
| |
| Handling Mixed Revisions |
| ======================== |
| |
| Checkout/update/edit/delete/commit: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n 3 |
| A1/ n 3 |
| f1 n 3 |
| f2* n 3 b |
| f3* p |
| B1/ n 5 |
| f1 n 5 |
| h1 n 7 |
| |
| Copy A1 to A2: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n 3 |
| A1/ n 3 |
| f1 n 3 |
| f2* n 3 b |
| f3* p |
| B1/ n 5 |
| f1 n 5 |
| h1 n 7 |
| A2/ n+3 |
| f1 n 3 |
| f2* p |
| f3* p |
| B1/ n~5 |
| f1 n 5 |
| h1 n~7 |
| |
| Where revnum != revnum of parent the node is pseudo-root and must be |
| added during commit (the FS layer converts to a replace if required, |
| see issue 3314). |
| |
| Delete Storage Optimisation |
| --------------------------- |
| |
| Rather than store deletes as a layer with a new op_depth we could |
| store them in the nearest existing layer, using a delete flag. This |
| is because delete doesn't need to store anything other than the fact |
| of the delete. This would make each op_depth layer correspond to an |
| add/copy onto a deleted node or as a new node. This would remove the |
| base-deleted presence value. |
| |
| Checkout/update/copy A1 to A3/A1: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| A1/ n |
| B1/ n |
| f1 n |
| A2/ n |
| A3/ n |
| A1/ n+ |
| B1/ n |
| f1 n |
| |
| Delete A2/B2/B1: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| A1/ n |
| B1/ n |
| f1 n |
| A2/ n |
| A3/ n |
| A1/ n+ |
| B1/* nd |
| f1* nd |
| |
| Copy A2 to A3/A1/A2: |
| |
| Local_Relpath NODE_DATA |
| 0 1 2 3 4 |
| ------------------------------------------------ |
| / n |
| A1/ n |
| B1/ n |
| f1 n |
| A2/ n |
| A3/ n |
| A1/ n+ |
| B1/ nd n |
| f1* nd |