Merge lp:~facundo/magicicada-server/temp-file-renamed-on-commit into lp:magicicada-server

Proposed by Facundo Batista
Status: Merged
Approved by: Natalia Bidart
Approved revision: 40
Merged at revision: 42
Proposed branch: lp:~facundo/magicicada-server/temp-file-renamed-on-commit
Merge into: lp:magicicada-server
Diff against target: 186 lines (+61/-11)
5 files modified
src/server/content.py (+2/-1)
src/server/diskstorage.py (+23/-6)
src/server/tests/test_diskstorage.py (+29/-2)
src/server/tests/test_upload.py (+3/-1)
src/server/upload.py (+4/-1)
To merge this branch: bzr merge lp:~facundo/magicicada-server/temp-file-renamed-on-commit
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Review via email: mp+281507@code.launchpad.net

Commit message

In an Upload, move the file in DiskStorage to final name only on commit.

Description of the change

In an Upload, move the file in DiskStorage to final name only on commit.

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) :
Revision history for this message
Facundo Batista (facundo) wrote :

Comments replied, if all is ok let's land this.

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Thanks for the responses.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/content.py'
2--- src/server/content.py 2015-12-05 15:25:06 +0000
3+++ src/server/content.py 2016-01-04 11:44:03 +0000
4@@ -1,5 +1,5 @@
5 # Copyright 2008-2015 Canonical
6-# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)
7+# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU Affero General Public License as
11@@ -399,6 +399,7 @@
12 def _commit(self):
13 """Make this upload the current content for the node."""
14 self.producer.stopProducing()
15+ self.consumer.commit()
16 yield self.producer.flush_decompressor()
17
18 # size matches hint
19
20=== modified file 'src/server/diskstorage.py'
21--- src/server/diskstorage.py 2015-09-25 12:09:50 +0000
22+++ src/server/diskstorage.py 2016-01-04 11:44:03 +0000
23@@ -1,4 +1,4 @@
24-# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)
25+# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
26 #
27 # This program is free software: you can redistribute it and/or modify
28 # it under the terms of the GNU Affero General Public License as
29@@ -18,7 +18,6 @@
30 import os
31
32 from twisted.internet import defer, reactor
33-from twisted.protocols.ftp import FileConsumer
34
35 # the levels of directories for the tree where will store all nodes
36 DIRS_LEVELS = 3
37@@ -91,17 +90,35 @@
38 self.resumeProducing()
39
40
41-class FileWriterConsumer(FileConsumer):
42+class FileWriterConsumer(object):
43 """A file consumer (writes to disk) starting from a filepath."""
44
45 def __init__(self, filepath, offset):
46 self.filepath = filepath
47+ self.temppath = temppath = filepath + ".temp"
48+
49 if offset:
50- fh = open(filepath, 'ab')
51+ fh = open(temppath, 'ab')
52 fh.seek(offset)
53 else:
54- fh = open(filepath, 'wb')
55- super(FileWriterConsumer, self).__init__(fh)
56+ fh = open(temppath, 'wb')
57+ self.fh = fh
58+
59+ def registerProducer(self, producer, streaming):
60+ self.producer = producer
61+ assert streaming
62+
63+ def unregisterProducer(self):
64+ self.producer = None
65+ self.fh.close()
66+
67+ def write(self, data):
68+ self.fh.write(data)
69+
70+ def commit(self):
71+ """Commit the file."""
72+ self.fh.close()
73+ os.rename(self.temppath, self.filepath)
74
75
76 class DiskStorage(object):
77
78=== modified file 'src/server/tests/test_diskstorage.py'
79--- src/server/tests/test_diskstorage.py 2015-09-17 19:15:50 +0000
80+++ src/server/tests/test_diskstorage.py 2016-01-04 11:44:03 +0000
81@@ -1,6 +1,6 @@
82 # -*- coding: utf-8 -*-
83
84-# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)
85+# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
86 #
87 # This program is free software: you can redistribute it and/or modify
88 # it under the terms of the GNU Affero General Public License as
89@@ -83,6 +83,7 @@
90 consumer = ds.put(node_id)
91 consumer.write(data)
92 consumer.unregisterProducer()
93+ consumer.commit()
94
95 # check the file
96 path = ds._get_treepath(node_id)
97@@ -106,14 +107,40 @@
98 consumer.write(data1)
99 consumer.unregisterProducer()
100
101- # write more
102+ # write more and finish
103 data2 = b' and part 2'
104 consumer = ds.put(node_id, len(data1))
105 consumer.write(data2)
106 consumer.unregisterProducer()
107+ consumer.commit()
108
109 # check the file
110 path = ds._get_treepath(node_id)
111 with open(os.path.join(path, node_id), 'rb') as fh:
112 written = fh.read()
113 self.assertEqual(written, data1 + data2)
114+
115+ def test_put_node_rename_on_commit(self):
116+ # write it
117+ node_id = "dinw78cdync8"
118+ ds = DiskStorage(self.tmpdir)
119+ data = 'test content to write'
120+ consumer = ds.put(node_id)
121+ consumer.write(data)
122+ path = ds._get_treepath(node_id)
123+
124+ # at this point, it's all written in a temp file, check it (however,
125+ # manually flush as we still didn't close it)
126+ consumer.fh.flush()
127+ with open(consumer.temppath, 'rb') as fh:
128+ written = fh.read()
129+ self.assertEqual(written, data)
130+
131+ # now let it know it's all done
132+ consumer.commit()
133+
134+ # check the final file is there and the temp is gone
135+ with open(os.path.join(path, node_id), 'rb') as fh:
136+ written = fh.read()
137+ self.assertEqual(written, data)
138+ self.assertFalse(os.path.exists(consumer.temppath))
139
140=== modified file 'src/server/tests/test_upload.py'
141--- src/server/tests/test_upload.py 2015-09-26 13:02:01 +0000
142+++ src/server/tests/test_upload.py 2016-01-04 11:44:03 +0000
143@@ -1,5 +1,5 @@
144 # Copyright 2008-2015 Canonical
145-# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)
146+# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
147 #
148 # This program is free software: you can redistribute it and/or modify
149 # it under the terms of the GNU Affero General Public License as
150@@ -76,6 +76,7 @@
151 yield producer.dataReceived(message[part:part + chunk_sz])
152 producer.stopProducing()
153 yield producer.flush_decompressor()
154+ consumer.commit()
155
156 with open(consumer.filepath, "rb") as fh:
157 self.assertEqual(fh.read(), message)
158@@ -109,6 +110,7 @@
159
160 # stop and re-check
161 producer.stopProducing()
162+ consumer.commit()
163 yield producer.flush_decompressor()
164 with open(consumer.filepath, "rb") as fh:
165 self.assertEqual(fh.read(), message)
166
167=== modified file 'src/server/upload.py'
168--- src/server/upload.py 2015-09-18 23:36:43 +0000
169+++ src/server/upload.py 2016-01-04 11:44:03 +0000
170@@ -1,5 +1,5 @@
171 # Copyright 2008-2015 Canonical
172-# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)
173+# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
174 #
175 # This program is free software: you can redistribute it and/or modify
176 # it under the terms of the GNU Affero General Public License as
177@@ -138,6 +138,9 @@
178 if self.producer is not None:
179 self.producer.consumer = self.producer = None
180
181+ def commit(self):
182+ """Nothing to do in a null consumer."""
183+
184 def cancel(self):
185 """Cancel this consumer."""
186 self.producer = None

Subscribers

People subscribed via source and target branches

to all changes: