on master help sign in
project-m36/docs/merge_transactions.markdown
149 lines 10 kB history raw
1# Merge Transactions in Project:M36
3## Introduction
5Common database management systems offer one transaction "stream" whereby multiple database users are simultaneously contending for commits to access or change a single database state. Database management systems implement complex locking and caching in order to simulate concurrent access to this state.
7Project:M36 allows for user-defined named "heads" which represent states (branches) onto which users can tack on additional transactions. This feature enables:
9* experimental changes which may or may not be merged back to the main state of the database
10* reduced contention over a single head
11* genuinely transaction-safe DDL (schema definition changes) without locking, caveats, or abstraction leaks
12* merge transactions according to business logic
13* elimination of "serialization errors"
15Programmers are likely familiar with this workflow since this behavior is analogous to source version control branching and merging. Project:M36 uses terminology from [git version control](https://git-scm.com/).
17## Command Summary
19|Command|Explanation|
20|-------|-----------|
21|:branch <branch name>|Create a new branch.|
22|:jumphead <head name>|Jump to the named head.|
23|:jump <transaction id>|Jump to an arbitrarily-identified transaction. This allows the session's context to travel back in time to a part of the graph which is not a head.|
24|:showgraph|Display the transaction graph as a relation.|
25|:mergetrans <merge strategy> <branchA> <branchB>|Merge one branch onto another. This requires that the current context is on one of the heads. The "merge strategy" is one of "union", "unionpreferbranch <branch name>" , or "selectedbranch".|
27## Merge Strategies
29### Selected Branch Merge
31The naivest merge strategy is to pull in the database context of one branch while discarding the context of a second branch. This merge strategy is useful for marking the end of an experimental branch that is to be considered discarded or a dead end. This merge strategy always succeeds.
33### Union Merge
35The union merge strategy attempts to merge the components of the two branches' database contexts. These components are:
37* inclusion dependencies (constraints)
38* atom functions
39* notifications
40* types
41* relation variables
43If both branches have a atom function, etc. of the same name, then the merge fails with an unresolvable conflict.
45As a special case for relation variables, if both branches have a relation variable of the same name and type (same attributes), then the resultant merged relation variable is a union of both branches' relation variables.
47### Union Prefer Branch Merge
49The union-prefer-branch merge is identical to union merge except that, when encountering a conflict case as described above, the strategy chooses a component from the preferred branch. Thus, this merge strategy always succeeds.
51## Additional Strategies
53Project:M36 will support more complex merge strategies in the future. In particular, business logic will likely dictate that Project:M36 support user-defined strategies, though this is not yet supported.
55## TutorialD Usage
57Branching and merging are built-in to the Project:M36 ```tutd``` client.
59First, let's create a new branch for some new sales data.
60```
61TutorialD (master/main): :branch add_sales_feature
62TutorialD (add_sales_feature):
63```
65Note how the name in parentheses changes as we create and implicitly jump to the new "add_sales_feature" branch.
67Next, we will add the sales data.
69```
70TutorialD (add_sales_feature): sales := relation{tuple{amount 45, product "peanuts"},tuple{amount 20, product "onions"}}
71TutorialD (add_sales_feature): :showexpr sales
72┌───────────┬─────────────┐
73│amount::Int│product::Text│
74├───────────┼─────────────┤
75│45 │"peanuts" │
76│20 │"onions" │
77└───────────┴─────────────┘
78TutorialD (add_sales_feature): :commit
79```
81Now, the relation variable "sales" is available on the "add_sales_feature" branch, but *not* the "master" branch. Let's verify this.
83```
84TutorialD (add_sales_feature): :jumphead master
85TutorialD (master/main): :showexpr sales
86ERR: RelVarNotDefinedError "sales"
87```
89Now that we are on the "master" branch, let's add a relation variables unrelated to sales.
91```
92TutorialD (master/main): employees := relation{tuple{name "Steve"},tuple{name "Cindy"}}
93TutorialD (master/main): :commit
94```
96Note that the "employees" relation variable is only available on the "master" branch and not on the "add_sales_feature" branch.
98Let's look at the transaction graph:
100```
101TutorialD (master/main): :showgraph
102┌─────────────┬───────────────────┬──────────────────────────────────────┬────────────────────────────────────────┐
103│current::Bool│head::Text │id::Text │parents::relation {id::Text} │
104├─────────────┼───────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
105│False │"" │"0d3bf914-1695-4f95-ab93-6c543d7b3dfa"│┌──────────────────────────────────────┐│
106│ │ │ ││id::Text ││
107│ │ │ │├──────────────────────────────────────┤│
108│ │ │ ││"0e51d95b-5578-4190-802b-9ef280a7f386"││
109│ │ │ │└──────────────────────────────────────┘│
110│False │"add_sales_feature"│"8b4d4eaf-31a3-4e48-85d3-bf6e8ac101ea"│┌──────────────────────────────────────┐│
111│ │ │ ││id::Text ││
112│ │ │ │├──────────────────────────────────────┤│
113│ │ │ ││"0d3bf914-1695-4f95-ab93-6c543d7b3dfa"││
114│ │ │ │└──────────────────────────────────────┘│
115│False │"" │"0e51d95b-5578-4190-802b-9ef280a7f386"│┌────────┐ │
116│ │ │ ││id::Text│ │
117│ │ │ │└────────┘ │
118│True │"master" │"e4228cb8-e792-48c9-b987-7d78fb1abe04"│┌──────────────────────────────────────┐│
119│ │ │ ││id::Text ││
120│ │ │ │├──────────────────────────────────────┤│
121│ │ │ ││"0e51d95b-5578-4190-802b-9ef280a7f386"││
122│ │ │ │└──────────────────────────────────────┘│
123└─────────────┴───────────────────┴──────────────────────────────────────┴────────────────────────────────────────┘
125```
127```:showgraph``` shows us which database context is "current" and which parents are linked to each transaction.
129Now, imagine that the work on the "add_sales_merge" branch is complete, so we will merge the "add_sales_feature" branch back into the "master" branch. We say we are merging "back" because both branches share a common ancestor transaction.
131```
132TutorialD (master/main): :mergetrans union add_sales_feature master
133TutorialD (master/main): :showexpr employees
134┌──────────┐
135│name::Text│
136├──────────┤
137│"Steve" │
138│"Cindy" │
139└──────────┘
140TutorialD (master/main): :showexpr sales
141┌───────────┬─────────────┐
142│amount::Int│product::Text│
143├───────────┼─────────────┤
144│45 │"peanuts" │
145│20 │"onions" │
146└───────────┴─────────────┘
147```
149After the merge, both relation variables appear in resultant merged transaction. This is because we used a "union merge strategy" which tries to mash both database contexts together.