| 1 | 1 patch for repository /Users/warner2/stuff/tahoe/t4: |
|---|
| 2 | |
|---|
| 3 | Sun Feb 27 18:10:56 PST 2011 warner@lothar.com |
|---|
| 4 | * test_mutable.py: add test to exercise fencepost bug |
|---|
| 5 | |
|---|
| 6 | New patches: |
|---|
| 7 | |
|---|
| 8 | [test_mutable.py: add test to exercise fencepost bug |
|---|
| 9 | warner@lothar.com**20110228021056 |
|---|
| 10 | Ignore-this: d2f9cf237ce6db42fb250c8ad71a4fc3 |
|---|
| 11 | ] { |
|---|
| 12 | hunk ./src/allmydata/test/test_mutable.py 2 |
|---|
| 13 | |
|---|
| 14 | -import os |
|---|
| 15 | +import os, re |
|---|
| 16 | from cStringIO import StringIO |
|---|
| 17 | from twisted.trial import unittest |
|---|
| 18 | from twisted.internet import defer, reactor |
|---|
| 19 | hunk ./src/allmydata/test/test_mutable.py 2931 |
|---|
| 20 | self.set_up_grid() |
|---|
| 21 | self.c = self.g.clients[0] |
|---|
| 22 | self.nm = self.c.nodemaker |
|---|
| 23 | - self.data = "test data" * 100000 # about 900 KiB; MDMF |
|---|
| 24 | + self.data = "testdata " * 100000 # about 900 KiB; MDMF |
|---|
| 25 | self.small_data = "test data" * 10 # about 90 B; SDMF |
|---|
| 26 | return self.do_upload() |
|---|
| 27 | |
|---|
| 28 | hunk ./src/allmydata/test/test_mutable.py 2981 |
|---|
| 29 | self.failUnlessEqual(results, new_data)) |
|---|
| 30 | return d |
|---|
| 31 | |
|---|
| 32 | + def test_replace_segstart1(self): |
|---|
| 33 | + offset = 128*1024+1 |
|---|
| 34 | + new_data = "NNNN" |
|---|
| 35 | + expected = self.data[:offset]+new_data+self.data[offset+4:] |
|---|
| 36 | + d = self.mdmf_node.get_best_mutable_version() |
|---|
| 37 | + d.addCallback(lambda mv: |
|---|
| 38 | + mv.update(MutableData(new_data), offset)) |
|---|
| 39 | + d.addCallback(lambda ignored: |
|---|
| 40 | + self.mdmf_node.download_best_version()) |
|---|
| 41 | + def _check(results): |
|---|
| 42 | + if results != expected: |
|---|
| 43 | + print |
|---|
| 44 | + print "got: %s ... %s" % (results[:20], results[-20:]) |
|---|
| 45 | + print "exp: %s ... %s" % (expected[:20], expected[-20:]) |
|---|
| 46 | + self.fail("results != expected") |
|---|
| 47 | + d.addCallback(_check) |
|---|
| 48 | + return d |
|---|
| 49 | + |
|---|
| 50 | + def _check_differences(self, got, expected): |
|---|
| 51 | + # displaying arbitrary file corruption is tricky for a |
|---|
| 52 | + # 1MB file of repeating data,, so look for likely places |
|---|
| 53 | + # with problems and display them separately |
|---|
| 54 | + gotmods = [mo.span() for mo in re.finditer('([A-Z]+)', got)] |
|---|
| 55 | + expmods = [mo.span() for mo in re.finditer('([A-Z]+)', expected)] |
|---|
| 56 | + gotspans = ["%d:%d=%s" % (start,end,got[start:end]) |
|---|
| 57 | + for (start,end) in gotmods] |
|---|
| 58 | + expspans = ["%d:%d=%s" % (start,end,expected[start:end]) |
|---|
| 59 | + for (start,end) in expmods] |
|---|
| 60 | + #print "expecting: %s" % expspans |
|---|
| 61 | + |
|---|
| 62 | + SEGSIZE = 128*1024 |
|---|
| 63 | + if got != expected: |
|---|
| 64 | + print "differences:" |
|---|
| 65 | + for segnum in range(len(expected)//SEGSIZE): |
|---|
| 66 | + start = segnum * SEGSIZE |
|---|
| 67 | + end = (segnum+1) * SEGSIZE |
|---|
| 68 | + got_ends = "%s .. %s" % (got[start:start+20], got[end-20:end]) |
|---|
| 69 | + exp_ends = "%s .. %s" % (expected[start:start+20], expected[end-20:end]) |
|---|
| 70 | + if got_ends != exp_ends: |
|---|
| 71 | + print "expected[%d]: %s" % (start, exp_ends) |
|---|
| 72 | + print "got [%d]: %s" % (start, got_ends) |
|---|
| 73 | + if expspans != gotspans: |
|---|
| 74 | + print "expected: %s" % expspans |
|---|
| 75 | + print "got : %s" % gotspans |
|---|
| 76 | + open("EXPECTED","wb").write(expected) |
|---|
| 77 | + open("GOT","wb").write(got) |
|---|
| 78 | + print "wrote data to EXPECTED and GOT" |
|---|
| 79 | + self.fail("didn't get expected data") |
|---|
| 80 | + |
|---|
| 81 | + |
|---|
| 82 | + def test_replace_locations(self): |
|---|
| 83 | + # exercise fencepost conditions |
|---|
| 84 | + expected = self.data |
|---|
| 85 | + SEGSIZE = 128*1024 |
|---|
| 86 | + suspects = range(SEGSIZE-3, SEGSIZE+1)+range(2*SEGSIZE-3, 2*SEGSIZE+1) |
|---|
| 87 | + letters = iter("ABCDEFGHIJKLMNOPQRSTUVWXYZ") |
|---|
| 88 | + d = defer.succeed(None) |
|---|
| 89 | + for offset in suspects: |
|---|
| 90 | + new_data = letters.next()*2 # "AA", then "BB", etc |
|---|
| 91 | + expected = expected[:offset]+new_data+expected[offset+2:] |
|---|
| 92 | + d.addCallback(lambda ign: |
|---|
| 93 | + self.mdmf_node.get_best_mutable_version()) |
|---|
| 94 | + def _modify(mv, offset=offset, new_data=new_data): |
|---|
| 95 | + # close over 'offset','new_data' |
|---|
| 96 | + md = MutableData(new_data) |
|---|
| 97 | + return mv.update(md, offset) |
|---|
| 98 | + d.addCallback(_modify) |
|---|
| 99 | + d.addCallback(lambda ignored: |
|---|
| 100 | + self.mdmf_node.download_best_version()) |
|---|
| 101 | + d.addCallback(self._check_differences, expected) |
|---|
| 102 | + return d |
|---|
| 103 | + |
|---|
| 104 | |
|---|
| 105 | def test_replace_and_extend(self): |
|---|
| 106 | # We should be able to replace data in the middle of a mutable |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | Context: |
|---|
| 110 | |
|---|
| 111 | [web/filenode.py: avoid calling req.finish() on closed HTTP connections. Closes #1366 |
|---|
| 112 | "Brian Warner <warner@lothar.com>"**20110221061544 |
|---|
| 113 | Ignore-this: 799d4de19933f2309b3c0c19a63bb888 |
|---|
| 114 | ] |
|---|
| 115 | [update MDMF code with StorageFarmBroker changes |
|---|
| 116 | "Brian Warner <warner@lothar.com>"**20110221061004 |
|---|
| 117 | Ignore-this: a693b201d31125b391cebe0412ddd027 |
|---|
| 118 | ] |
|---|
| 119 | [resolve more conflicts with current trunk |
|---|
| 120 | "Brian Warner <warner@lothar.com>"**20110221055600 |
|---|
| 121 | Ignore-this: 77ad038a478dbf5d9b34f7a68159a3e0 |
|---|
| 122 | ] |
|---|
| 123 | [Refactor StorageFarmBroker handling of servers |
|---|
| 124 | Brian Warner <warner@lothar.com>**20110221015804 |
|---|
| 125 | Ignore-this: 842144ed92f5717699b8f580eab32a51 |
|---|
| 126 | |
|---|
| 127 | Pass around IServer instance instead of (peerid, rref) tuple. Replace |
|---|
| 128 | "descriptor" with "server". Other replacements: |
|---|
| 129 | |
|---|
| 130 | get_all_servers -> get_connected_servers/get_known_servers |
|---|
| 131 | get_servers_for_index -> get_servers_for_psi (now returns IServers) |
|---|
| 132 | |
|---|
| 133 | This change still needs to be pushed further down: lots of code is now |
|---|
| 134 | getting the IServer and then distributing (peerid, rref) internally. |
|---|
| 135 | Instead, it ought to distribute the IServer internally and delay |
|---|
| 136 | extracting a serverid or rref until the last moment. |
|---|
| 137 | |
|---|
| 138 | no_network.py was updated to retain parallelism. |
|---|
| 139 | ] |
|---|
| 140 | [Add unit tests for cross_check_pkg_resources_versus_import, and a regression test for ref #1355. This requires a little refactoring to make it testable. |
|---|
| 141 | david-sarah@jacaranda.org**20110221015817 |
|---|
| 142 | Ignore-this: 51d181698f8c20d3aca58b057e9c475a |
|---|
| 143 | ] |
|---|
| 144 | [allmydata/__init__.py: .name was used in place of the correct .__name__ when printing an exception. Also, robustify string formatting by using %r instead of %s in some places. fixes #1355. |
|---|
| 145 | david-sarah@jacaranda.org**20110221020125 |
|---|
| 146 | Ignore-this: b0744ed58f161bf188e037bad077fc48 |
|---|
| 147 | ] |
|---|
| 148 | [mutable/filenode.py: fix create_mutable_file('string') |
|---|
| 149 | "Brian Warner <warner@lothar.com>"**20110221014659 |
|---|
| 150 | Ignore-this: dc6bdad761089f0199681eeb784f1001 |
|---|
| 151 | ] |
|---|
| 152 | [resolve conflicts between 393-MDMF patches and trunk as of 1.8.2 |
|---|
| 153 | "Brian Warner <warner@lothar.com>"**20110220230201 |
|---|
| 154 | Ignore-this: 9bbf5d26c994e8069202331dcb4cdd95 |
|---|
| 155 | ] |
|---|
| 156 | [tests: |
|---|
| 157 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003531 |
|---|
| 158 | Ignore-this: 314e8bbcce532ea4d5d2cecc9f31cca0 |
|---|
| 159 | |
|---|
| 160 | - A lot of existing tests relied on aspects of the mutable file |
|---|
| 161 | implementation that were changed. This patch updates those tests |
|---|
| 162 | to work with the changes. |
|---|
| 163 | - This patch also adds tests for new features. |
|---|
| 164 | ] |
|---|
| 165 | [mutable/servermap.py: Alter the servermap updater to work with MDMF files |
|---|
| 166 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003439 |
|---|
| 167 | Ignore-this: 7e408303194834bd59a2f27efab3bdb |
|---|
| 168 | |
|---|
| 169 | These modifications were basically all to the end of having the |
|---|
| 170 | servermap updater use the unified MDMF + SDMF read interface whenever |
|---|
| 171 | possible -- this reduces the complexity of the code, making it easier to |
|---|
| 172 | read and maintain. To do this, I needed to modify the process of |
|---|
| 173 | updating the servermap a little bit. |
|---|
| 174 | |
|---|
| 175 | To support partial-file updates, I also modified the servermap updater |
|---|
| 176 | to fetch the block hash trees and certain segments of files while it |
|---|
| 177 | performed a servermap update (this can be done without adding any new |
|---|
| 178 | roundtrips because of batch-read functionality that the read proxy has). |
|---|
| 179 | |
|---|
| 180 | ] |
|---|
| 181 | [mutable/retrieve.py: Modify the retrieval process to support MDMF |
|---|
| 182 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003409 |
|---|
| 183 | Ignore-this: c03f4e41aaa0366a9bf44847f2caf9db |
|---|
| 184 | |
|---|
| 185 | The logic behind a mutable file download had to be adapted to work with |
|---|
| 186 | segmented mutable files; this patch performs those adaptations. It also |
|---|
| 187 | exposes some decoding and decrypting functionality to make partial-file |
|---|
| 188 | updates a little easier, and supports efficient random-access downloads |
|---|
| 189 | of parts of an MDMF file. |
|---|
| 190 | ] |
|---|
| 191 | [mutable/layout.py and interfaces.py: add MDMF writer and reader |
|---|
| 192 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003304 |
|---|
| 193 | Ignore-this: 44400fec923987b62830da2ed5075fb4 |
|---|
| 194 | |
|---|
| 195 | The MDMF writer is responsible for keeping state as plaintext is |
|---|
| 196 | gradually processed into share data by the upload process. When the |
|---|
| 197 | upload finishes, it will write all of its share data to a remote server, |
|---|
| 198 | reporting its status back to the publisher. |
|---|
| 199 | |
|---|
| 200 | The MDMF reader is responsible for abstracting an MDMF file as it sits |
|---|
| 201 | on the grid from the downloader; specifically, by receiving and |
|---|
| 202 | responding to requests for arbitrary data within the MDMF file. |
|---|
| 203 | |
|---|
| 204 | The interfaces.py file has also been modified to contain an interface |
|---|
| 205 | for the writer. |
|---|
| 206 | ] |
|---|
| 207 | [docs: update docs to mention MDMF |
|---|
| 208 | Kevan Carstensen <kevan@isnotajoke.com>**20100814225644 |
|---|
| 209 | Ignore-this: 1c3caa3cd44831007dcfbef297814308 |
|---|
| 210 | ] |
|---|
| 211 | [nodemaker.py: Make nodemaker expose a way to create MDMF files |
|---|
| 212 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003509 |
|---|
| 213 | Ignore-this: a6701746d6b992fc07bc0556a2b4a61d |
|---|
| 214 | ] |
|---|
| 215 | [mutable/publish.py: Modify the publish process to support MDMF |
|---|
| 216 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003342 |
|---|
| 217 | Ignore-this: 2bb379974927e2e20cff75bae8302d1d |
|---|
| 218 | |
|---|
| 219 | The inner workings of the publishing process needed to be reworked to a |
|---|
| 220 | large extend to cope with segmented mutable files, and to cope with |
|---|
| 221 | partial-file updates of mutable files. This patch does that. It also |
|---|
| 222 | introduces wrappers for uploadable data, allowing the use of |
|---|
| 223 | filehandle-like objects as data sources, in addition to strings. This |
|---|
| 224 | reduces memory inefficiency when dealing with large files through the |
|---|
| 225 | webapi, and clarifies update code there. |
|---|
| 226 | ] |
|---|
| 227 | [mutable/filenode.py: add versions and partial-file updates to the mutable file node |
|---|
| 228 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003231 |
|---|
| 229 | Ignore-this: b7b5434201fdb9b48f902d7ab25ef45c |
|---|
| 230 | |
|---|
| 231 | One of the goals of MDMF as a GSoC project is to lay the groundwork for |
|---|
| 232 | LDMF, a format that will allow Tahoe-LAFS to deal with and encourage |
|---|
| 233 | multiple versions of a single cap on the grid. In line with this, there |
|---|
| 234 | is a now a distinction between an overriding mutable file (which can be |
|---|
| 235 | thought to correspond to the cap/unique identifier for that mutable |
|---|
| 236 | file) and versions of the mutable file (which we can download, update, |
|---|
| 237 | and so on). All download, upload, and modification operations end up |
|---|
| 238 | happening on a particular version of a mutable file, but there are |
|---|
| 239 | shortcut methods on the object representing the overriding mutable file |
|---|
| 240 | that perform these operations on the best version of the mutable file |
|---|
| 241 | (which is what code should be doing until we have LDMF and better |
|---|
| 242 | support for other paradigms). |
|---|
| 243 | |
|---|
| 244 | Another goal of MDMF was to take advantage of segmentation to give |
|---|
| 245 | callers more efficient partial file updates or appends. This patch |
|---|
| 246 | implements methods that do that, too. |
|---|
| 247 | |
|---|
| 248 | ] |
|---|
| 249 | [mutable/checker.py and mutable/repair.py: Modify checker and repairer to work with MDMF |
|---|
| 250 | Kevan Carstensen <kevan@isnotajoke.com>**20100819003216 |
|---|
| 251 | Ignore-this: d3bd3260742be8964877f0a53543b01b |
|---|
| 252 | |
|---|
| 253 | The checker and repairer required minimal changes to work with the MDMF |
|---|
| 254 | modifications made elsewhere. The checker duplicated a lot of the code |
|---|
| 255 | that was already in the downloader, so I modified the downloader |
|---|
| 256 | slightly to expose this functionality to the checker and removed the |
|---|
| 257 | duplicated code. The repairer only required a minor change to deal with |
|---|
| 258 | data representation. |
|---|
| 259 | ] |
|---|
| 260 | [client.py: learn how to create different kinds of mutable files |
|---|
| 261 | Kevan Carstensen <kevan@isnotajoke.com>**20100814225711 |
|---|
| 262 | Ignore-this: 61ff665bc050cba5f58bf2ed779d692b |
|---|
| 263 | ] |
|---|
| 264 | [web: Alter the webapi to get along with and take advantage of the MDMF changes |
|---|
| 265 | Kevan Carstensen <kevan@isnotajoke.com>**20100814081012 |
|---|
| 266 | Ignore-this: 96c2ed4e4a9f450fb84db5d711d10bd6 |
|---|
| 267 | |
|---|
| 268 | The main benefit that the webapi gets from MDMF, at least initially, is |
|---|
| 269 | the ability to do a streaming download of an MDMF mutable file. It also |
|---|
| 270 | exposes a way (through the PUT verb) to append to or otherwise modify |
|---|
| 271 | (in-place) an MDMF mutable file. |
|---|
| 272 | ] |
|---|
| 273 | [scripts: tell 'tahoe put' about MDMF |
|---|
| 274 | Kevan Carstensen <kevan@isnotajoke.com>**20100813234957 |
|---|
| 275 | Ignore-this: c106b3384fc676bd3c0fb466d2a52b1b |
|---|
| 276 | ] |
|---|
| 277 | [immutable/literal.py: implement the same interfaces as other filenodes |
|---|
| 278 | Kevan Carstensen <kevan@isnotajoke.com>**20100810000633 |
|---|
| 279 | Ignore-this: b50dd5df2d34ecd6477b8499a27aef13 |
|---|
| 280 | ] |
|---|
| 281 | [immutable/filenode.py: Make the immutable file node implement the same interfaces as the mutable one |
|---|
| 282 | Kevan Carstensen <kevan@isnotajoke.com>**20100810000619 |
|---|
| 283 | Ignore-this: 93e536c0f8efb705310f13ff64621527 |
|---|
| 284 | ] |
|---|
| 285 | [frontends/sftpd.py: Modify the sftp frontend to work with the MDMF changes |
|---|
| 286 | Kevan Carstensen <kevan@isnotajoke.com>**20100809233535 |
|---|
| 287 | Ignore-this: 2d25e2cfcd0d7bbcbba660c7e1da12f |
|---|
| 288 | ] |
|---|
| 289 | [interfaces.py: Add #993 interfaces |
|---|
| 290 | Kevan Carstensen <kevan@isnotajoke.com>**20100809233244 |
|---|
| 291 | Ignore-this: b58621ac5cc86f1b4b4149f9e6c6a1ce |
|---|
| 292 | ] |
|---|
| 293 | [TAG allmydata-tahoe-1.8.2 |
|---|
| 294 | warner@lothar.com**20110131020101] |
|---|
| 295 | Patch bundle hash: |
|---|
| 296 | 85ba2dfc67d9e255e8b82316f147ac92a2b7896e |
|---|