{"action":"created","comment":{"url":"https://api.github.com/repos/raiden-network/raiden/pulls/comments/116290557","pull_request_review_id":37899772,"id":116290557,"diff_hunk":"@@ -0,0 +1,238 @@\n+# -*- coding: utf-8 -*-\n+import pickle\n+import sqlite3\n+from abc import ABCMeta, abstractmethod\n+\n+from raiden.utils import create_file_iff_not_existing\n+\n+\n+# TODO:\n+# - snapshots should be used to reduce the log file size\n+\n+class TransactionLogSerializer(object):\n+    \"\"\" TransactionLogSerializer\n+\n+        An abstract class defining the serialization interface for the\n+        Transaction log. Allows for pluggable serializer backends.\n+    \"\"\"\n+    __metaclass__ = ABCMeta\n+\n+    @abstractmethod\n+    def serialize(self, transaction):\n+        pass\n+\n+    @abstractmethod\n+    def deserialize(self, data):\n+        pass\n+\n+\n+class PickleTransactionSerializer(TransactionLogSerializer):\n+    \"\"\" PickleTransactionSerializer\n+\n+        A simple transaction serializer using pickle\n+    \"\"\"\n+    def serialize(self, transaction):\n+        # Some of our StateChange classes have __slots__ without having a __getstate__\n+        # As seen in the SO question below:\n+        # http://stackoverflow.com/questions/2204155/why-am-i-getting-an-error-about-my-class-defining-slots-when-trying-to-pickl#2204702\n+        # We can either add a __getstate__ to all of them or use the `-1` protocol and be\n+        # incompatible with ancient python version. Here I opt for the latter.\n+        return pickle.dumps(transaction, -1)\n+\n+    def deserialize(self, data):\n+        return pickle.loads(data)\n+\n+\n+class TransactionLogStorageBackend(object):\n+    \"\"\" TransactionLogStorageBackend\n+\n+        An abstract class defining the storage backend for the transaction log.\n+        Allows for pluggable storage backends.\n+    \"\"\"\n+    __metaclass__ = ABCMeta\n+\n+    @abstractmethod\n+    def write_transaction(self, identifier, data):\n+        pass\n+\n+    @abstractmethod\n+    def write_state_snapshot(self, identifier, data):\n+        pass\n+\n+    @abstractmethod\n+    def read(self):\n+        pass\n+\n+    @abstractmethod\n+    def last_identifier(self):\n+        pass\n+\n+\n+class TransactionLogSQLiteBackend(TransactionLogStorageBackend):\n+\n+    def __init__(self, database_path):\n+        self.conn = sqlite3.connect(database_path)\n+        self.conn.text_factory = str\n+        cursor = self.conn.cursor()\n+        cursor.execute(\n+            'CREATE TABLE IF NOT EXISTS transactions ('\n+            '    id integer primary key autoincrement, data binary'\n+            ')'\n+        )\n+        cursor.execute(\n+            'CREATE TABLE IF NOT EXISTS state_snapshot (id integer primary key, data binary)'\n+        )\n+        self.conn.commit()\n+\n+    def write_transaction(self, data):\n+        cursor = self.conn.cursor()\n+        cursor.execute(\n+            'INSERT INTO transactions(id, data) VALUES(null,?)',\n+            (data,)\n+        )\n+        self.conn.commit()\n+\n+    def write_state_snapshot(self, identifier, data):\n+        cursor = self.conn.cursor()\n+        result = cursor.execute(\n+            'SELECT * from state_snapshot',\n+            (identifier, data)\n+        )\n+        result = result.fetchone()\n+        if result is None:\n+            cursor.execute(\n+                'INSERT INTO state_snapshot(id, data) VALUES(?,?)',\n+                (identifier, data)\n+            )\n+        else:\n+            cursor.execute(\n+                'UPDATE state_snapshot SET id=?, data=? WHERE id=?',\n+                (identifier, data, result[0])\n+            )\n+        self.conn.commit()\n+\n+    def get_transaction_by_id(self, identifier):\n+        cursor = self.conn.cursor()\n+        result = cursor.execute(\n+            'SELECT data from transactions where id=?', (identifier,)\n+        )\n+        result = result.fetchall()\n+        if result != list():\n+            assert len(result) == 1\n+            result = result[0][0]\n+        return result\n+\n+    def get_all_transactions(self):\n+        cursor = self.conn.cursor()\n+        result = cursor.execute(\n+            'SELECT * from transactions'\n+        )\n+        return result.fetchall()\n+\n+    def read(self):\n+        pass\n+\n+    def last_identifier(self):\n+        cursor = self.conn.cursor()\n+        result = cursor.execute(\n+            'SELECT seq FROM sqlite_sequence WHERE name=\"transactions\"'\n+        )\n+        result = result.fetchall()\n+        if result != list():\n+            assert len(result) == 1\n+            result = result[0][0]\n+        else:\n+            result = 0\n+        return result\n+\n+    def __del__(self):\n+        self.conn.close()\n+\n+\n+class TransactionLogFileBackend(TransactionLogStorageBackend):\n+    \"\"\"This is just an example for having a file backend. Not actually implemented\"\"\"\n+\n+    def __init__(self, filepath):\n+        self.filepath = filepath\n+        self.file = create_file_iff_not_existing(\n+            self.filepath,\n+            return_it=True,\n+            mode='r+',\n+            buffering=False\n+        )\n+        self._synced = False  #: True when the existing log is read to the end\n+\n+    def write_transaction(self, data):\n+        pass\n+\n+    def write_state_snapshot(self, identifier, data):\n+        pass\n+\n+    def read(self):\n+        pass\n+\n+    def last_identifier(self):\n+        pass\n+\n+    def __del__(self):\n+        self.file.flush()\n+        self.file.close()\n+\n+\n+class TransactionLog(object):","path":"raiden/transfer/log.py","position":182,"original_position":182,"commit_id":"412b3245e08aab139bf816d17c4fa15a050e638b","original_commit_id":"412b3245e08aab139bf816d17c4fa15a050e638b","user":{"login":"hackaugusto","id":310139,"avatar_url":"https://avatars3.githubusercontent.com/u/310139?v=3","gravatar_id":"","url":"https://api.github.com/users/hackaugusto","html_url":"https://github.com/hackaugusto","followers_url":"https://api.github.com/users/hackaugusto/followers","following_url":"https://api.github.com/users/hackaugusto/following{/other_user}","gists_url":"https://api.github.com/users/hackaugusto/gists{/gist_id}","starred_url":"https://api.github.com/users/hackaugusto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hackaugusto/subscriptions","organizations_url":"https://api.github.com/users/hackaugusto/orgs","repos_url":"https://api.github.com/users/hackaugusto/repos","events_url":"https://api.github.com/users/hackaugusto/events{/privacy}","received_events_url":"https://api.github.com/users/hackaugusto/received_events","type":"User","site_admin":false},"body":"IMO this class can have it's interface simplified, instead of exposing the storage details (identifiers, saved state changes, etc.) the interface could be simply `log`, `snapshot`, and `restore`","created_at":"2017-05-12T18:04:07Z","updated_at":"2017-05-12T18:08:28Z","html_url":"https://github.com/raiden-network/raiden/pull/584#discussion_r116290557","pull_request_url":"https://api.github.com/repos/raiden-network/raiden/pulls/584","_links":{"self":{"href":"https://api.github.com/repos/raiden-network/raiden/pulls/comments/116290557"},"html":{"href":"https://github.com/raiden-network/raiden/pull/584#discussion_r116290557"},"pull_request":{"href":"https://api.github.com/repos/raiden-network/raiden/pulls/584"}}},"pull_request":{"url":"https://api.github.com/repos/raiden-network/raiden/pulls/584","id":119450889,"html_url":"https://github.com/raiden-network/raiden/pull/584","diff_url":"https://github.com/raiden-network/raiden/pull/584.diff","patch_url":"https://github.com/raiden-network/raiden/pull/584.patch","issue_url":"https://api.github.com/repos/raiden-network/raiden/issues/584","number":584,"state":"open","locked":false,"title":"Writing on the Write-Ahead-Log","user":{"login":"LefterisJP","id":1658405,"avatar_url":"https://avatars2.githubusercontent.com/u/1658405?v=3","gravatar_id":"","url":"https://api.github.com/users/LefterisJP","html_url":"https://github.com/LefterisJP","followers_url":"https://api.github.com/users/LefterisJP/followers","following_url":"https://api.github.com/users/LefterisJP/following{/other_user}","gists_url":"https://api.github.com/users/LefterisJP/gists{/gist_id}","starred_url":"https://api.github.com/users/LefterisJP/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LefterisJP/subscriptions","organizations_url":"https://api.github.com/users/LefterisJP/orgs","repos_url":"https://api.github.com/users/LefterisJP/repos","events_url":"https://api.github.com/users/LefterisJP/events{/privacy}","received_events_url":"https://api.github.com/users/LefterisJP/received_events","type":"User","site_admin":false},"body":"Fix https://github.com/raiden-network/raiden/issues/298","created_at":"2017-05-08T13:44:34Z","updated_at":"2017-05-12T18:08:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f7d31e25a1dc2573f957ec41a62e87932e8517e0","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/raiden-network/raiden/pulls/584/commits","review_comments_url":"https://api.github.com/repos/raiden-network/raiden/pulls/584/comments","review_comment_url":"https://api.github.com/repos/raiden-network/raiden/pulls/comments{/number}","comments_url":"https://api.github.com/repos/raiden-network/raiden/issues/584/comments","statuses_url":"https://api.github.com/repos/raiden-network/raiden/statuses/412b3245e08aab139bf816d17c4fa15a050e638b","head":{"label":"LefterisJP:write_ahead_logging","ref":"write_ahead_logging","sha":"412b3245e08aab139bf816d17c4fa15a050e638b","user":{"login":"LefterisJP","id":1658405,"avatar_url":"https://avatars2.githubusercontent.com/u/1658405?v=3","gravatar_id":"","url":"https://api.github.com/users/LefterisJP","html_url":"https://github.com/LefterisJP","followers_url":"https://api.github.com/users/LefterisJP/followers","following_url":"https://api.github.com/users/LefterisJP/following{/other_user}","gists_url":"https://api.github.com/users/LefterisJP/gists{/gist_id}","starred_url":"https://api.github.com/users/LefterisJP/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LefterisJP/subscriptions","organizations_url":"https://api.github.com/users/LefterisJP/orgs","repos_url":"https://api.github.com/users/LefterisJP/repos","events_url":"https://api.github.com/users/LefterisJP/events{/privacy}","received_events_url":"https://api.github.com/users/LefterisJP/received_events","type":"User","site_admin":false},"repo":{"id":69238217,"name":"raiden","full_name":"LefterisJP/raiden","owner":{"login":"LefterisJP","id":1658405,"avatar_url":"https://avatars2.githubusercontent.com/u/1658405?v=3","gravatar_id":"","url":"https://api.github.com/users/LefterisJP","html_url":"https://github.com/LefterisJP","followers_url":"https://api.github.com/users/LefterisJP/followers","following_url":"https://api.github.com/users/LefterisJP/following{/other_user}","gists_url":"https://api.github.com/users/LefterisJP/gists{/gist_id}","starred_url":"https://api.github.com/users/LefterisJP/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LefterisJP/subscriptions","organizations_url":"https://api.github.com/users/LefterisJP/orgs","repos_url":"https://api.github.com/users/LefterisJP/repos","events_url":"https://api.github.com/users/LefterisJP/events{/privacy}","received_events_url":"https://api.github.com/users/LefterisJP/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/LefterisJP/raiden","description":"Raiden Network","fork":true,"url":"https://api.github.com/repos/LefterisJP/raiden","forks_url":"https://api.github.com/repos/LefterisJP/raiden/forks","keys_url":"https://api.github.com/repos/LefterisJP/raiden/keys{/key_id}","collaborators_url":"https://api.github.com/repos/LefterisJP/raiden/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/LefterisJP/raiden/teams","hooks_url":"https://api.github.com/repos/LefterisJP/raiden/hooks","issue_events_url":"https://api.github.com/repos/LefterisJP/raiden/issues/events{/number}","events_url":"https://api.github.com/repos/LefterisJP/raiden/events","assignees_url":"https://api.github.com/repos/LefterisJP/raiden/assignees{/user}","branches_url":"https://api.github.com/repos/LefterisJP/raiden/branches{/branch}","tags_url":"https://api.github.com/repos/LefterisJP/raiden/tags","blobs_url":"https://api.github.com/repos/LefterisJP/raiden/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/LefterisJP/raiden/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/LefterisJP/raiden/git/refs{/sha}","trees_url":"https://api.github.com/repos/LefterisJP/raiden/git/trees{/sha}","statuses_url":"https://api.github.com/repos/LefterisJP/raiden/statuses/{sha}","languages_url":"https://api.github.com/repos/LefterisJP/raiden/languages","stargazers_url":"https://api.github.com/repos/LefterisJP/raiden/stargazers","contributors_url":"https://api.github.com/repos/LefterisJP/raiden/contributors","subscribers_url":"https://api.github.com/repos/LefterisJP/raiden/subscribers","subscription_url":"https://api.github.com/repos/LefterisJP/raiden/subscription","commits_url":"https://api.github.com/repos/LefterisJP/raiden/commits{/sha}","git_commits_url":"https://api.github.com/repos/LefterisJP/raiden/git/commits{/sha}","comments_url":"https://api.github.com/repos/LefterisJP/raiden/comments{/number}","issue_comment_url":"https://api.github.com/repos/LefterisJP/raiden/issues/comments{/number}","contents_url":"https://api.github.com/repos/LefterisJP/raiden/contents/{+path}","compare_url":"https://api.github.com/repos/LefterisJP/raiden/compare/{base}...{head}","merges_url":"https://api.github.com/repos/LefterisJP/raiden/merges","archive_url":"https://api.github.com/repos/LefterisJP/raiden/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/LefterisJP/raiden/downloads","issues_url":"https://api.github.com/repos/LefterisJP/raiden/issues{/number}","pulls_url":"https://api.github.com/repos/LefterisJP/raiden/pulls{/number}","milestones_url":"https://api.github.com/repos/LefterisJP/raiden/milestones{/number}","notifications_url":"https://api.github.com/repos/LefterisJP/raiden/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/LefterisJP/raiden/labels{/name}","releases_url":"https://api.github.com/repos/LefterisJP/raiden/releases{/id}","deployments_url":"https://api.github.com/repos/LefterisJP/raiden/deployments","created_at":"2016-09-26T10:14:16Z","updated_at":"2016-09-26T10:14:18Z","pushed_at":"2017-05-12T13:18:20Z","git_url":"git://github.com/LefterisJP/raiden.git","ssh_url":"git@github.com:LefterisJP/raiden.git","clone_url":"https://github.com/LefterisJP/raiden.git","svn_url":"https://github.com/LefterisJP/raiden","homepage":null,"size":3141,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"raiden-network:master","ref":"master","sha":"1f75898b2d7bf64e998f1d253e792d6d18f759ea","user":{"login":"raiden-network","id":19666847,"avatar_url":"https://avatars2.githubusercontent.com/u/19666847?v=3","gravatar_id":"","url":"https://api.github.com/users/raiden-network","html_url":"https://github.com/raiden-network","followers_url":"https://api.github.com/users/raiden-network/followers","following_url":"https://api.github.com/users/raiden-network/following{/other_user}","gists_url":"https://api.github.com/users/raiden-network/gists{/gist_id}","starred_url":"https://api.github.com/users/raiden-network/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raiden-network/subscriptions","organizations_url":"https://api.github.com/users/raiden-network/orgs","repos_url":"https://api.github.com/users/raiden-network/repos","events_url":"https://api.github.com/users/raiden-network/events{/privacy}","received_events_url":"https://api.github.com/users/raiden-network/received_events","type":"Organization","site_admin":false},"repo":{"id":50646767,"name":"raiden","full_name":"raiden-network/raiden","owner":{"login":"raiden-network","id":19666847,"avatar_url":"https://avatars2.githubusercontent.com/u/19666847?v=3","gravatar_id":"","url":"https://api.github.com/users/raiden-network","html_url":"https://github.com/raiden-network","followers_url":"https://api.github.com/users/raiden-network/followers","following_url":"https://api.github.com/users/raiden-network/following{/other_user}","gists_url":"https://api.github.com/users/raiden-network/gists{/gist_id}","starred_url":"https://api.github.com/users/raiden-network/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raiden-network/subscriptions","organizations_url":"https://api.github.com/users/raiden-network/orgs","repos_url":"https://api.github.com/users/raiden-network/repos","events_url":"https://api.github.com/users/raiden-network/events{/privacy}","received_events_url":"https://api.github.com/users/raiden-network/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/raiden-network/raiden","description":"Raiden Network","fork":false,"url":"https://api.github.com/repos/raiden-network/raiden","forks_url":"https://api.github.com/repos/raiden-network/raiden/forks","keys_url":"https://api.github.com/repos/raiden-network/raiden/keys{/key_id}","collaborators_url":"https://api.github.com/repos/raiden-network/raiden/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/raiden-network/raiden/teams","hooks_url":"https://api.github.com/repos/raiden-network/raiden/hooks","issue_events_url":"https://api.github.com/repos/raiden-network/raiden/issues/events{/number}","events_url":"https://api.github.com/repos/raiden-network/raiden/events","assignees_url":"https://api.github.com/repos/raiden-network/raiden/assignees{/user}","branches_url":"https://api.github.com/repos/raiden-network/raiden/branches{/branch}","tags_url":"https://api.github.com/repos/raiden-network/raiden/tags","blobs_url":"https://api.github.com/repos/raiden-network/raiden/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/raiden-network/raiden/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/raiden-network/raiden/git/refs{/sha}","trees_url":"https://api.github.com/repos/raiden-network/raiden/git/trees{/sha}","statuses_url":"https://api.github.com/repos/raiden-network/raiden/statuses/{sha}","languages_url":"https://api.github.com/repos/raiden-network/raiden/languages","stargazers_url":"https://api.github.com/repos/raiden-network/raiden/stargazers","contributors_url":"https://api.github.com/repos/raiden-network/raiden/contributors","subscribers_url":"https://api.github.com/repos/raiden-network/raiden/subscribers","subscription_url":"https://api.github.com/repos/raiden-network/raiden/subscription","commits_url":"https://api.github.com/repos/raiden-network/raiden/commits{/sha}","git_commits_url":"https://api.github.com/repos/raiden-network/raiden/git/commits{/sha}","comments_url":"https://api.github.com/repos/raiden-network/raiden/comments{/number}","issue_comment_url":"https://api.github.com/repos/raiden-network/raiden/issues/comments{/number}","contents_url":"https://api.github.com/repos/raiden-network/raiden/contents/{+path}","compare_url":"https://api.github.com/repos/raiden-network/raiden/compare/{base}...{head}","merges_url":"https://api.github.com/repos/raiden-network/raiden/merges","archive_url":"https://api.github.com/repos/raiden-network/raiden/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/raiden-network/raiden/downloads","issues_url":"https://api.github.com/repos/raiden-network/raiden/issues{/number}","pulls_url":"https://api.github.com/repos/raiden-network/raiden/pulls{/number}","milestones_url":"https://api.github.com/repos/raiden-network/raiden/milestones{/number}","notifications_url":"https://api.github.com/repos/raiden-network/raiden/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/raiden-network/raiden/labels{/name}","releases_url":"https://api.github.com/repos/raiden-network/raiden/releases{/id}","deployments_url":"https://api.github.com/repos/raiden-network/raiden/deployments","created_at":"2016-01-29T07:40:47Z","updated_at":"2017-05-11T18:11:05Z","pushed_at":"2017-05-12T10:48:17Z","git_url":"git://github.com/raiden-network/raiden.git","ssh_url":"git@github.com:raiden-network/raiden.git","clone_url":"https://github.com/raiden-network/raiden.git","svn_url":"https://github.com/raiden-network/raiden","homepage":null,"size":3121,"stargazers_count":317,"watchers_count":317,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":66,"mirror_url":null,"open_issues_count":126,"forks":66,"open_issues":126,"watchers":317,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/raiden-network/raiden/pulls/584"},"html":{"href":"https://github.com/raiden-network/raiden/pull/584"},"issue":{"href":"https://api.github.com/repos/raiden-network/raiden/issues/584"},"comments":{"href":"https://api.github.com/repos/raiden-network/raiden/issues/584/comments"},"review_comments":{"href":"https://api.github.com/repos/raiden-network/raiden/pulls/584/comments"},"review_comment":{"href":"https://api.github.com/repos/raiden-network/raiden/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/raiden-network/raiden/pulls/584/commits"},"statuses":{"href":"https://api.github.com/repos/raiden-network/raiden/statuses/412b3245e08aab139bf816d17c4fa15a050e638b"}}}}
{"actor":{"display_login":"hackaugusto"}}