{"id":1447,"date":"2017-03-12T14:25:34","date_gmt":"2017-03-12T21:25:34","guid":{"rendered":"https:\/\/www.ussherpress.com\/blog\/?p=1447"},"modified":"2017-03-12T14:33:08","modified_gmt":"2017-03-12T21:33:08","slug":"foreverlist-update-starting-to-implement-transaction-log-as-storage","status":"publish","type":"post","link":"https:\/\/www.ussherpress.com\/blog\/?p=1447","title":{"rendered":"ForeverList update: Starting to implement transaction log as storage"},"content":{"rendered":"<p>Quick update on the <a href=\"https:\/\/www.ussherpress.com\/blog\/?tag=foreverlist\">ForeverList project<\/a>: Today I\u00a0spent two hours and implemented basic loading and storing of the ForeverList document as a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transaction_log\">transaction log<\/a>.<\/p>\n<p>First of all,\u00a0its worth noting what &#8220;document&#8221; in ForeverList will be. ForeverList lets you create lists of notes,\u00a0where each note\u00a0is made up of text and possibly more child notes. This way, you can organize your notes hierarchically.<\/p>\n<p>Now onto the transaction log: When you edit a\u00a0ForeverList document, ForeverList will store individual changes as transactions in a log. A transaction is simply a description of a change to the document. For instance, if you create a new\u00a0note, the app will store an entry in the\u00a0log that says &#8220;user created a new note\u00a0and here is the text they entered&#8221;. If you go and change the text in\u00a0that note later, it will create a log entry that says &#8220;user changed the text for this note to &#8216;blah blah blah'&#8221;.<\/p>\n<p>When the user saves the document, which is made up of many notes, the app will simply store this log of changes\u00a0and not the notes themselves. If you close the app and later re-open the document, the app will load this log of changes and play it back from start to finish to re-create the document and its notes.<\/p>\n<p>Why do it this way instead of storing the document&#8217;s\u00a0list of notes verbatim? Well, using\u00a0transaction logs will allow a document to be edited by multiple devices. That is, it will let you open up the document on multiple Macs or iPhones (once I write that version of the app) because each device\u00a0will get its own transaction log. When you save from that device, it will<strong>\u00a0only<\/strong> write the changes that were made from that device. However, when you open a file, we&#8217;ll take all the changes made from all devices\u00a0and merge them into a mega log file and play back all the changes in chronological order. <a href=\"https:\/\/www.ussherpress.com\/blog\/?p=1262\">This is basically how I implemented the storage for\u00a0Lil Todo.<\/a><\/p>\n<p>Sharing a single file across multiple devices requires a lot of coordination. If your Mac\u00a0and iPhone are editing at the same time, how do you let them save different copies of the same file? How do you resolve conflicts if one of them saves first and the other one notices? By breaking down the changes into a log with timestamps, we avoid coordination by forcing each device to write to its own file (nobody else is allowed to write to it!) and we avoid conflicts by letting the latest change &#8220;win&#8221;.<\/p>\n<p>One important\u00a0bit about how the document is stored:\u00a0the document is actually going to be a directory that contains multiple files, i.e. all the transaction logs from all devices. (In the future, when you drag and drop images\u00a0into the app, I&#8217;ll also store the images in this folder as well!) The way I&#8217;m handling this is via <a href=\"https:\/\/developer.apple.com\/library\/content\/documentation\/CoreFoundation\/Conceptual\/CFBundles\/DocumentPackages\/DocumentPackages.html\">Document Packages<\/a> on the Mac. Cocoa on the Mac\u00a0allows you to write a <a href=\"https:\/\/developer.apple.com\/reference\/appkit\/nsdocument\">Document<\/a>-based app where instead of saving to a specific file, you provide a &#8220;document package&#8221; object which describes a list of files that will be written to disk instead of a single one.<\/p>\n<p>At this point,\u00a0I don&#8217;t have cross-device syncing support yet.\u00a0In the future, you&#8217;ll be able to use a\u00a0cloud storage provider like Dropbox or OneDrive. For now, what you <em>will<\/em> be able to do is save a ForeverList document to something like Dropbox and you&#8217;ll still be able to open and edit that document from multiple clients because each client will only save to its own transaction logs. If they all shared the same file, however, we would have to worry about different file versions and synchronizing access to the file and potential conflicts in the changes. Dropbox will take care of syncing the individual transaction log contents for you.<\/p>\n<p>In summary:<\/p>\n<ul>\n<li>Each device\u00a0will record each change that is made to a document and save\u00a0those changes to its\u00a0own transaction log.<\/li>\n<li>The ForeverList &#8220;document&#8221; will simply be a folder that contains multiple transaction logs, one from each device.<\/li>\n<li>When ForeverList opens a document, it will open up the folder, collect all the transaction logs from all\u00a0devices and then merge them into a single transaction log, which it will then &#8220;play&#8221; from start to finish to reconstruct the document.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Quick update on the ForeverList project: Today I\u00a0spent two hours and implemented basic loading and storing of the ForeverList document as a transaction log. First of all,\u00a0its worth noting what &#8220;document&#8221; in ForeverList will be. ForeverList lets you create lists of notes,\u00a0where each note\u00a0is made up of text and possibly more child notes. This way, &hellip; <a href=\"https:\/\/www.ussherpress.com\/blog\/?p=1447\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">ForeverList update: Starting to implement transaction log as storage<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[131,120],"tags":[126],"_links":{"self":[{"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1447"}],"collection":[{"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1447"}],"version-history":[{"count":6,"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1447\/revisions"}],"predecessor-version":[{"id":1453,"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1447\/revisions\/1453"}],"wp:attachment":[{"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1447"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1447"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ussherpress.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1447"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}