Changes between Version 1 and Version 2 of TracDev/Proposals/Journaling
- Timestamp:
- Nov 23, 2006, 4:36:20 PM (17 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
TracDev/Proposals/Journaling
v1 v2 36 36 == A solution == 37 37 38 Every ''change'' event could be journal led.39 A `journal` table could record alltransactions and serve as40 a basis for redispatching changes happening in one process38 Every ''change'' event could be journaled. 39 Several `journal` tables (one per resource) could record all the transactions and serve as 40 a basis for dispatching changes happening in one process 41 41 to other processes, in a generic way. 42 42 43 After all, this journaling is already done in some cases. 43 After all, such a kind of journaling is already done for tickets. 44 45 === Current Situation === 44 46 For example, all the ticket changes are journaled, in the `ticket_change` table: 45 47 {{{ … … 60 62 who did what (see #1890 for details). 61 63 62 This would lead to even more duplication of data than what we have now.63 Granted, currently this duplication (of the ticket/time/author values)64 are used to group related changes. 64 But adding those to the above table would lead to even more duplication of data than what we currently have. 65 Currently this duplication (of the ticket/time/author values) 66 is even used to group together related changes! 65 67 68 === Step in the Right Direction === 66 69 A cleaner approach, for #1890, would be: 67 70 {{{ … … 84 87 }}} 85 88 89 90 === The `_journal` and `_history` tables === 86 91 Now, with this proposal, this could be extended to: 87 92 {{{ 88 93 #!sql 89 CREATE TABLE ticket_ change(94 CREATE TABLE ticket_history ( 90 95 tid integer, 96 id int, 91 97 field text, 92 oldvalue text, 93 newvalue text, 98 value text 94 99 ); 95 100 96 CREATE TABLE journal (101 CREATE TABLE ticket_journal ( 97 102 tid integer PRIMARY KEY, 98 type text, 99 id text, 103 id int, 100 104 change text, 101 105 time integer, … … 106 110 }}} 107 111 108 And `ticket_change` could even be generalized to `property_change` 109 and go in the direction of a generalization of properties to 110 all Trac objects (remember the TracObjectModelProposal?) 112 `ticket_history` could eventually be spread in multiple, type-specialized tables (`ticket_int_property`, ...). 111 113 112 The `change` column in `journal` could contain some keyword about 114 See also TracDev/Proposals/DataModel#ResourceChangeHistory. 115 116 The `change` column in `<resource>_journal` could contain some keyword about 113 117 the nature of the change: `CREATE`, `DELETE`, `MODIFICATION`, etc. 114 118 119 Each process would write into the `<resource>_journal` table during the same 120 transaction that modifies the object model tables themselves. 121 122 This could be something along the lines of the following API: 123 {{{ 124 #!python 125 class WikiModule(): 126 def _do_create(self, pagename): 127 ... 128 # Getting a new transaction for creating a Wiki page 129 tnx = Transaction(self.env.get_db_cnx()) 130 tnx.prepare(req, 'CREATE') 131 tnx.save('wiki', id=pagename, readonly=readonly, content=content) 132 tnx.commit() # flush all changes to disk 133 self.notify(tnx) # dispatch change information to listeners 134 135 class TicketModule(): 136 def _do_save(self, ticket): 137 tnx = Transaction(self.env.get_db_cnx()) 138 tnx.prepare(req, 'MODIFY') 139 tnx.save('ticket', ticket) 140 tnx.commit() # flush all changes to disk 141 self.notify(tnx) # dispatch change information to listeners 142 }}} 143 The actual `Transaction` object would know how to modify the underlying (generic) data model. 144 145 146 === Notifying changes === 115 147 Now, how to use this information? 116 148 117 Each process would write into the `journal` table during the same 118 transaction that modifies the object model tables themselves. 119 This will mostly be something along the lines of: 120 {{{ 121 #!python 122 tid = record_in_journal(req, db, 'wiki', page, 'CREATE') 123 }}} 124 and: 125 {{{ 126 #!python 127 tid = record_in_journal(req, db, 'ticket', id, 'MODIFY') 128 }}} 149 Each module's `notify(tnx)` method would have to propagate the appropriate change information to registered listeners (the IWikiChangeListener, ITicketChangeListener, etc. interfaces). 129 150 130 Each process will also have to keep track of the last `tid` known. 151 Each module would also have to keep track of the last `tid` it has dispatched. 152 In `notify(tnx)`, we would check for all existing `tid` inserted since the last dispatched `tid` (or the one we had at system startup). If there are more than one `tid`, those are coming from changes created by ''other'' processes. 131 153 132 If this happens to have changed (details to be finalized: 133 the detection could be done either during `record_in_journal` itself, 134 or before request dispatching, or ...), there could be a ''replay'' 135 of those events, triggering the appropriate change listeners. 136 137 The change listeners would anyway gain to be refactored in a more 138 generic way (merging the IWikiChangeListener, ITicketChangeListener 139 giving IMilestoneChangeListener, IChangesetChangeListener etc. for free, 140 the usual TracObjectModelProposal blurb ;) ). 141 142 Last but not least, there would be a need to differentiate between 143 '''primary''' change and '''secondary''' change. 144 primary change:: the change originated from the same process; 145 there's only one process which ever sees a change as being a primary change 146 secondary change:: the change originated from another process. 154 This way, we could easily differentiate between '''primary''' changes and '''secondary''' changes. 155 primary change:: `tid == tnx.tid`; the change originated from the same process. 156 There's only one process which ever sees a change as being a primary change, it's the one which just created that change. 157 secondary change:: `tid != tnx.tid`; the change originated from another process. 147 158 148 159 This distinction is quite important w.r.t. to side-effects. … … 156 167 for refreshing all sorts of internal caches (the use cases listed 157 168 [TracDev/Proposals/Journaling#Someexamples above]). 158 169 170 Finally note that this Transaction class could make good use of the [http://www.sqlalchemy.org/docs/unitofwork.myt Unit Of Work] concept of SQLAlchemy, should we use that in a future version.