Merge lp:~facundo/ubuntuone-client/fix-svfilenew-conflict into lp:ubuntuone-client
- fix-svfilenew-conflict
- Merge into trunk
Proposed by
Facundo Batista
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Facundo Batista | ||||
Approved revision: | 926 | ||||
Merged at revision: | 938 | ||||
Proposed branch: | lp:~facundo/ubuntuone-client/fix-svfilenew-conflict | ||||
Merge into: | lp:ubuntuone-client | ||||
Diff against target: |
293 lines (+136/-43) 4 files modified
contrib/dump_metadata.py (+4/-3) tests/syncdaemon/test_sync.py (+89/-0) ubuntuone/syncdaemon/sync.py (+34/-5) ubuntuone/syncdaemon/u1fsfsm.py (+9/-35) |
||||
To merge this branch: | bzr merge lp:~facundo/ubuntuone-client/fix-svfilenew-conflict | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guillermo Gonzalez | Approve | ||
Lucio Torre (community) | Approve | ||
Review via email: mp+56232@code.launchpad.net |
Commit message
Support SV_FILE_NEW when having a node for that path (LP: #711389)
Description of the change
Support SV_FILE_NEW when having a node for that path
This is because _handle_SV_FILE_NEW is called when there's no match by node_id, but then it searches the node by path, and sometimes there is a node with that path.
Three cases arise:
- if the node still has no node_id: it's just waiting for it, so we go and set it.
- if the node has a node_id but other one: it's a case where the file was overwritten by a move operation; just delete the file and will get the server one.
- if the node has the same node_id: we broke something, because we shouldn't have called _handle_SV_FILE_NEW at all.
Tests included for everything.
To post a comment you must log in.
Revision history for this message
Lucio Torre (lucio.torre) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'contrib/dump_metadata.py' | |||
2 | --- contrib/dump_metadata.py 2011-02-21 17:15:15 +0000 | |||
3 | +++ contrib/dump_metadata.py 2011-04-04 17:52:08 +0000 | |||
4 | @@ -97,10 +97,11 @@ | |||
5 | 97 | 97 | ||
6 | 98 | print "\nShowing trash:" | 98 | print "\nShowing trash:" |
7 | 99 | something = False | 99 | something = False |
9 | 100 | for (vol_id, node_id), (mdid, parent_id, path) in fsm.trash.iteritems(): | 100 | for (vol_id, node_id), (mdid, parent_id, path, is_dir) in \ |
10 | 101 | fsm.trash.iteritems(): | ||
11 | 101 | something = True | 102 | something = True |
14 | 102 | print " mdid=%r volume_id=%r node_id=%r parent_id=%r path=%r" % ( | 103 | print (" mdid=%r volume_id=%r node_id=%r parent_id=%r path=%r " |
15 | 103 | mdid, share_id, node_id, parent_id, path) | 104 | "is_dir=%r" % (mdid, share_id, node_id, parent_id, path, is_dir)) |
16 | 104 | if not something: | 105 | if not something: |
17 | 105 | print " (empty)" | 106 | print " (empty)" |
18 | 106 | 107 | ||
19 | 107 | 108 | ||
20 | === modified file 'tests/syncdaemon/test_sync.py' | |||
21 | --- tests/syncdaemon/test_sync.py 2011-03-31 00:36:23 +0000 | |||
22 | +++ tests/syncdaemon/test_sync.py 2011-04-04 17:52:08 +0000 | |||
23 | @@ -255,6 +255,7 @@ | |||
24 | 255 | BaseSync.setUp(self) | 255 | BaseSync.setUp(self) |
25 | 256 | self.sync = Sync(main=self.main) | 256 | self.sync = Sync(main=self.main) |
26 | 257 | self.fsm = self.main.fs | 257 | self.fsm = self.main.fs |
27 | 258 | self.handler.setLevel(logging.DEBUG) | ||
28 | 258 | 259 | ||
29 | 259 | def test_deleting_open_files_is_no_cause_for_despair(self): | 260 | def test_deleting_open_files_is_no_cause_for_despair(self): |
30 | 260 | """test_deleting_open_files_is_no_cause_for_despair.""" | 261 | """test_deleting_open_files_is_no_cause_for_despair.""" |
31 | @@ -621,6 +622,76 @@ | |||
32 | 621 | 'new_parent_id', 'new_name', 'error') | 622 | 'new_parent_id', 'new_name', 'error') |
33 | 622 | self.assertEqual(called[1:], ['AQ_MOVE_ERROR', {}, '', 'node_id']) | 623 | self.assertEqual(called[1:], ['AQ_MOVE_ERROR', {}, '', 'node_id']) |
34 | 623 | 624 | ||
35 | 625 | def test_SV_FILE_NEW_no_node(self): | ||
36 | 626 | """Handle SV_FILE_NEW not having a node.""" | ||
37 | 627 | # fake method | ||
38 | 628 | called = [] | ||
39 | 629 | orig = SyncStateMachineRunner.new_file | ||
40 | 630 | self.patch(SyncStateMachineRunner, 'new_file', | ||
41 | 631 | lambda *a: called.extend(a) or orig(*a)) | ||
42 | 632 | |||
43 | 633 | # create the parent | ||
44 | 634 | parentpath = os.path.join(self.root, 'somepath') | ||
45 | 635 | self.fsm.create(parentpath, '', node_id='parent_id') | ||
46 | 636 | |||
47 | 637 | # call and check | ||
48 | 638 | r = self.sync._handle_SV_FILE_NEW('', 'node_id', 'parent_id', 'name') | ||
49 | 639 | self.assertEqual(called[1:], ['SV_FILE_NEW', {}, '', 'node_id', | ||
50 | 640 | 'parent_id', 'name']) | ||
51 | 641 | self.assertEqual(r.share_id, '') | ||
52 | 642 | self.assertEqual(r.node_id, 'node_id') | ||
53 | 643 | self.assertEqual(r.path, 'somepath/name') | ||
54 | 644 | |||
55 | 645 | def test_SV_FILE_NEW_node_no_id(self): | ||
56 | 646 | """Handle SV_FILE_NEW having a node without node_id.""" | ||
57 | 647 | # fake method | ||
58 | 648 | called = [] | ||
59 | 649 | orig = SyncStateMachineRunner.new_server_file_having_local | ||
60 | 650 | self.patch(SyncStateMachineRunner, 'new_server_file_having_local', | ||
61 | 651 | lambda *a: called.extend(a) or orig(*a)) | ||
62 | 652 | |||
63 | 653 | # create the node and its parent, to match per path | ||
64 | 654 | parentpath = os.path.join(self.root, 'somepath') | ||
65 | 655 | self.fsm.create(parentpath, '', node_id='parent_id') | ||
66 | 656 | childpath = os.path.join(parentpath, 'name') | ||
67 | 657 | self.fsm.create(childpath, '') | ||
68 | 658 | |||
69 | 659 | # call and check | ||
70 | 660 | self.sync._handle_SV_FILE_NEW('', 'node_id', 'parent_id', 'name') | ||
71 | 661 | self.assertEqual(called[1:], ['SV_FILE_NEW', {}, '', 'node_id', | ||
72 | 662 | 'parent_id', 'name']) | ||
73 | 663 | |||
74 | 664 | def test_SV_FILE_NEW_node_same_id(self): | ||
75 | 665 | """Handle SV_FILE_NEW having a node with the same node_id.""" | ||
76 | 666 | parentpath = os.path.join(self.root, 'somepath') | ||
77 | 667 | self.fsm.create(parentpath, '', node_id='parent_id') | ||
78 | 668 | childpath = os.path.join(parentpath, 'name') | ||
79 | 669 | self.fsm.create(childpath, '', node_id='node_id') | ||
80 | 670 | r = self.assertRaises(ValueError, self.sync._handle_SV_FILE_NEW, | ||
81 | 671 | '', 'node_id', 'parent_id', 'name') | ||
82 | 672 | self.assertTrue("same node_id in handle_SV_FILE_NEW" in str(r)) | ||
83 | 673 | |||
84 | 674 | def test_SV_FILE_NEW_node_different_id(self): | ||
85 | 675 | """Handle SV_FILE_NEW having a node with different node_id.""" | ||
86 | 676 | # create the node and its parent, to match per path | ||
87 | 677 | parentpath = os.path.join(self.root, 'somepath') | ||
88 | 678 | self.fsm.create(parentpath, '', node_id='parent_id') | ||
89 | 679 | childpath = os.path.join(parentpath, 'name') | ||
90 | 680 | self.fsm.create(childpath, '', node_id='other_id') | ||
91 | 681 | |||
92 | 682 | # fake method | ||
93 | 683 | called = [] | ||
94 | 684 | orig = self.fsm.delete_file | ||
95 | 685 | self.patch(self.fsm, 'delete_file', | ||
96 | 686 | lambda path: called.append(path) or orig(path)) | ||
97 | 687 | |||
98 | 688 | # call and check | ||
99 | 689 | self.sync._handle_SV_FILE_NEW('', 'node_id', 'parent_id', 'name') | ||
100 | 690 | self.assertEqual(called, [childpath]) | ||
101 | 691 | self.handler.debug = True | ||
102 | 692 | self.assertTrue(self.handler.check_debug("Wanted to apply SV_FILE_NEW", | ||
103 | 693 | "found it with other id")) | ||
104 | 694 | |||
105 | 624 | 695 | ||
106 | 625 | class SyncStateMachineRunnerTestCase(BaseSync): | 696 | class SyncStateMachineRunnerTestCase(BaseSync): |
107 | 626 | """Tests for the SyncStateMachineRunner.""" | 697 | """Tests for the SyncStateMachineRunner.""" |
108 | @@ -1115,6 +1186,24 @@ | |||
109 | 1115 | # check the create and the make_dir | 1186 | # check the create and the make_dir |
110 | 1116 | self.assertEqual(called, [(new_path, '', 'node_id', True), 'mdid']) | 1187 | self.assertEqual(called, [(new_path, '', 'node_id', True), 'mdid']) |
111 | 1117 | 1188 | ||
112 | 1189 | def test_new_new_server_file_having_local(self): | ||
113 | 1190 | """Set the node_id to the node.""" | ||
114 | 1191 | # create context | ||
115 | 1192 | somepath = os.path.join(self.root, 'foo') | ||
116 | 1193 | self.fsm.create(somepath, '') | ||
117 | 1194 | key = FSKey(self.main.fs, path=somepath) | ||
118 | 1195 | ssmr = SyncStateMachineRunner(fsm=self.fsm, main=self.main, | ||
119 | 1196 | key=key, logger=None) | ||
120 | 1197 | |||
121 | 1198 | # log the call to fsm | ||
122 | 1199 | called = [] | ||
123 | 1200 | self.fsm.set_node_id = lambda *a: called.append(a) | ||
124 | 1201 | |||
125 | 1202 | # call the tested method and check | ||
126 | 1203 | ssmr.new_server_file_having_local('event', {}, '', 'node_id', | ||
127 | 1204 | 'parent_id', 'name') | ||
128 | 1205 | self.assertEqual(called, [(somepath, 'node_id')]) | ||
129 | 1206 | |||
130 | 1118 | 1207 | ||
131 | 1119 | class FakedState(object): | 1208 | class FakedState(object): |
132 | 1120 | """A faked state.""" | 1209 | """A faked state.""" |
133 | 1121 | 1210 | ||
134 | === modified file 'ubuntuone/syncdaemon/sync.py' | |||
135 | --- ubuntuone/syncdaemon/sync.py 2011-03-31 00:36:23 +0000 | |||
136 | +++ ubuntuone/syncdaemon/sync.py 2011-04-04 17:52:08 +0000 | |||
137 | @@ -545,6 +545,11 @@ | |||
138 | 545 | self.m.action_q.uuid_map.set(marker, new_id) | 545 | self.m.action_q.uuid_map.set(marker, new_id) |
139 | 546 | self.m.fs.set_node_id(self.key['path'], new_id) | 546 | self.m.fs.set_node_id(self.key['path'], new_id) |
140 | 547 | 547 | ||
141 | 548 | def new_server_file_having_local(self, event, parms, share_id, node_id, | ||
142 | 549 | parent_id, name): | ||
143 | 550 | """Got new file from server, we have it local but without id yet.""" | ||
144 | 551 | self.m.fs.set_node_id(self.key['path'], node_id) | ||
145 | 552 | |||
146 | 548 | def new_local_dir(self, event, parms, path): | 553 | def new_local_dir(self, event, parms, path): |
147 | 549 | """a new local dir was created""" | 554 | """a new local dir was created""" |
148 | 550 | parent_path = os.path.dirname(path) | 555 | parent_path = os.path.dirname(path) |
149 | @@ -838,9 +843,31 @@ | |||
150 | 838 | key = FSKey(self.m.fs, path=path) | 843 | key = FSKey(self.m.fs, path=path) |
151 | 839 | log = FileLogger(self.logger, key) | 844 | log = FileLogger(self.logger, key) |
152 | 840 | ssmr = SyncStateMachineRunner(self.fsm, self.m, key, log) | 845 | ssmr = SyncStateMachineRunner(self.fsm, self.m, key, log) |
153 | 846 | |||
154 | 847 | # check if the node found by path has other node_id (which will | ||
155 | 848 | # cause a conflict); note that we don't get the node_id from the | ||
156 | 849 | # 'key' as it lies to us with the marker | ||
157 | 850 | try: | ||
158 | 851 | mdid = key.get_mdid() | ||
159 | 852 | except KeyError: | ||
160 | 853 | pass # no md at all, didn't find any node by the path | ||
161 | 854 | else: | ||
162 | 855 | mdobj = self.m.fs.get_by_mdid(mdid) | ||
163 | 856 | if mdobj.node_id is not None: | ||
164 | 857 | if mdobj.node_id == node_id: | ||
165 | 858 | raise ValueError("Found same node_id in handle_SV_FILE_NEW" | ||
166 | 859 | " (node_id=%s path=%r)" % (node_id, path)) | ||
167 | 860 | # have metadata with *other* node_id | ||
168 | 861 | log.debug("Wanted to apply SV_FILE_NEW with node_id %s to node" | ||
169 | 862 | "with path %r, but found it with other id: %s", | ||
170 | 863 | node_id, path, mdobj.node_id) | ||
171 | 864 | key.delete_file() | ||
172 | 865 | return None | ||
173 | 866 | |||
174 | 841 | ssmr.on_event("SV_FILE_NEW", {}, share_id, node_id, parent_id, name) | 867 | ssmr.on_event("SV_FILE_NEW", {}, share_id, node_id, parent_id, name) |
175 | 842 | self.m.event_q.push('SV_FILE_NEW', volume_id=share_id, | 868 | self.m.event_q.push('SV_FILE_NEW', volume_id=share_id, |
176 | 843 | node_id=node_id, parent_id=parent_id, name=name) | 869 | node_id=node_id, parent_id=parent_id, name=name) |
177 | 870 | return self.m.fs.get_by_node_id(share_id, node_id) | ||
178 | 844 | 871 | ||
179 | 845 | def _handle_SV_DIR_NEW(self, share_id, node_id, parent_id, name): | 872 | def _handle_SV_DIR_NEW(self, share_id, node_id, parent_id, name): |
180 | 846 | """on SV_DIR_NEW""" | 873 | """on SV_DIR_NEW""" |
181 | @@ -852,6 +879,7 @@ | |||
182 | 852 | ssmr.on_event("SV_DIR_NEW", {}, share_id, node_id, parent_id, name) | 879 | ssmr.on_event("SV_DIR_NEW", {}, share_id, node_id, parent_id, name) |
183 | 853 | self.m.event_q.push('SV_DIR_NEW', volume_id=share_id, | 880 | self.m.event_q.push('SV_DIR_NEW', volume_id=share_id, |
184 | 854 | node_id=node_id, parent_id=parent_id, name=name) | 881 | node_id=node_id, parent_id=parent_id, name=name) |
185 | 882 | return self.m.fs.get_by_node_id(share_id, node_id) | ||
186 | 855 | 883 | ||
187 | 856 | def _handle_SV_FILE_DELETED(self, share_id, node_id, is_dir): | 884 | def _handle_SV_FILE_DELETED(self, share_id, node_id, is_dir): |
188 | 857 | """on SV_FILE_DELETED. Not called by EQ anymore.""" | 885 | """on SV_FILE_DELETED. Not called by EQ anymore.""" |
189 | @@ -1106,13 +1134,14 @@ | |||
190 | 1106 | continue | 1134 | continue |
191 | 1107 | 1135 | ||
192 | 1108 | # node not there, we must create it | 1136 | # node not there, we must create it |
193 | 1137 | args = (dt.share_id, dt.node_id, dt.parent_id, dt_name) | ||
194 | 1109 | if is_dir: | 1138 | if is_dir: |
197 | 1110 | self._handle_SV_DIR_NEW(dt.share_id, dt.node_id, | 1139 | node = self._handle_SV_DIR_NEW(*args) |
196 | 1111 | dt.parent_id, dt_name) | ||
198 | 1112 | else: | 1140 | else: |
202 | 1113 | self._handle_SV_FILE_NEW(dt.share_id, dt.node_id, | 1141 | node = self._handle_SV_FILE_NEW(*args) |
203 | 1114 | dt.parent_id, dt_name) | 1142 | if node is None: |
204 | 1115 | node = self.m.fs.get_by_node_id(dt.share_id, dt.node_id) | 1143 | # the node was not created! |
205 | 1144 | continue | ||
206 | 1116 | 1145 | ||
207 | 1117 | # if the delta is older than the node, skip! | 1146 | # if the delta is older than the node, skip! |
208 | 1118 | if node.generation > dt.generation: | 1147 | if node.generation > dt.generation: |
209 | 1119 | 1148 | ||
210 | === modified file 'ubuntuone/syncdaemon/u1fsfsm.ods' | |||
211 | 1120 | Binary files ubuntuone/syncdaemon/u1fsfsm.ods 2011-03-08 20:25:00 +0000 and ubuntuone/syncdaemon/u1fsfsm.ods 2011-04-04 17:52:08 +0000 differ | 1149 | Binary files ubuntuone/syncdaemon/u1fsfsm.ods 2011-03-08 20:25:00 +0000 and ubuntuone/syncdaemon/u1fsfsm.ods 2011-04-04 17:52:08 +0000 differ |
212 | === modified file 'ubuntuone/syncdaemon/u1fsfsm.py' | |||
213 | --- ubuntuone/syncdaemon/u1fsfsm.py 2010-09-07 20:49:38 +0000 | |||
214 | +++ ubuntuone/syncdaemon/u1fsfsm.py 2011-04-04 17:52:08 +0000 | |||
215 | @@ -300,32 +300,6 @@ | |||
216 | 300 | 'STATE_OUT': {u'changed': u'=', | 300 | 'STATE_OUT': {u'changed': u'=', |
217 | 301 | u'has_metadata': u'=', | 301 | u'has_metadata': u'=', |
218 | 302 | u'is_directory': u'='}}], | 302 | u'is_directory': u'='}}], |
219 | 303 | u'AQ_DOWNLOAD_CANCELLED': [{'ACTION': u'md.remove_partial(uuid);', | ||
220 | 304 | 'ACTION_FUNC': u'nothing', | ||
221 | 305 | 'COMMENTS': u'Download cancelled, remove the partial file', | ||
222 | 306 | 'PARAMETERS': {u'hash_eq_local_hash': u'*', | ||
223 | 307 | u'hash_eq_server_hash': u'*', | ||
224 | 308 | u'not_authorized': u'NA', | ||
225 | 309 | u'not_available': u'NA'}, | ||
226 | 310 | 'STATE': {u'changed': u'*', | ||
227 | 311 | u'has_metadata': u'T', | ||
228 | 312 | u'is_directory': u'*'}, | ||
229 | 313 | 'STATE_OUT': {u'changed': u'=', | ||
230 | 314 | u'has_metadata': u'=', | ||
231 | 315 | u'is_directory': u'='}}, | ||
232 | 316 | {'ACTION': u'pass', | ||
233 | 317 | 'ACTION_FUNC': u'nothing', | ||
234 | 318 | 'COMMENTS': u'', | ||
235 | 319 | 'PARAMETERS': {u'hash_eq_local_hash': u'*', | ||
236 | 320 | u'hash_eq_server_hash': u'*', | ||
237 | 321 | u'not_authorized': u'NA', | ||
238 | 322 | u'not_available': u'NA'}, | ||
239 | 323 | 'STATE': {u'changed': u'*', | ||
240 | 324 | u'has_metadata': u'F', | ||
241 | 325 | u'is_directory': u'*'}, | ||
242 | 326 | 'STATE_OUT': {u'changed': u'=', | ||
243 | 327 | u'has_metadata': u'=', | ||
244 | 328 | u'is_directory': u'='}}], | ||
245 | 329 | u'AQ_DOWNLOAD_DOES_NOT_EXIST': [{'ACTION': u'', | 303 | u'AQ_DOWNLOAD_DOES_NOT_EXIST': [{'ACTION': u'', |
246 | 330 | 'ACTION_FUNC': u'delete_file', | 304 | 'ACTION_FUNC': u'delete_file', |
247 | 331 | 'COMMENTS': u"Directory doesn't exist anymore, remove it", | 305 | 'COMMENTS': u"Directory doesn't exist anymore, remove it", |
248 | @@ -1015,8 +989,8 @@ | |||
249 | 1015 | 'STATE_OUT': {u'changed': u'=', | 989 | 'STATE_OUT': {u'changed': u'=', |
250 | 1016 | u'has_metadata': u'=', | 990 | u'has_metadata': u'=', |
251 | 1017 | u'is_directory': u'='}}, | 991 | u'is_directory': u'='}}, |
254 | 1018 | {'ACTION': u'md.set(mdid, server_uuid=server_uuid)\nPANIC', | 992 | {'ACTION': u"Node got node_id with a SV_FILE_NEW and now it's uploading something", |
255 | 1019 | 'ACTION_FUNC': u'DESPAIR', | 993 | 'ACTION_FUNC': u'nothing', |
256 | 1020 | 'COMMENTS': u'', | 994 | 'COMMENTS': u'', |
257 | 1021 | 'PARAMETERS': {u'hash_eq_local_hash': u'NA', | 995 | 'PARAMETERS': {u'hash_eq_local_hash': u'NA', |
258 | 1022 | u'hash_eq_server_hash': u'NA', | 996 | u'hash_eq_server_hash': u'NA', |
259 | @@ -1025,8 +999,8 @@ | |||
260 | 1025 | 'STATE': {u'changed': u'SERVER', | 999 | 'STATE': {u'changed': u'SERVER', |
261 | 1026 | u'has_metadata': u'T', | 1000 | u'has_metadata': u'T', |
262 | 1027 | u'is_directory': u'F'}, | 1001 | u'is_directory': u'F'}, |
265 | 1028 | 'STATE_OUT': {u'changed': u'NONE', | 1002 | 'STATE_OUT': {u'changed': u'=', |
266 | 1029 | u'has_metadata': u'T', | 1003 | u'has_metadata': u'=', |
267 | 1030 | u'is_directory': u'='}}, | 1004 | u'is_directory': u'='}}, |
268 | 1031 | {'ACTION': u'aq.uuid_map.set(marker, new_id)', | 1005 | {'ACTION': u'aq.uuid_map.set(marker, new_id)', |
269 | 1032 | 'ACTION_FUNC': u'release_marker_ok', | 1006 | 'ACTION_FUNC': u'release_marker_ok', |
270 | @@ -2211,8 +2185,8 @@ | |||
271 | 2211 | 'STATE_OUT': {u'changed': u'NONE', | 2185 | 'STATE_OUT': {u'changed': u'NONE', |
272 | 2212 | u'has_metadata': u'T', | 2186 | u'has_metadata': u'T', |
273 | 2213 | u'is_directory': u'F'}}, | 2187 | u'is_directory': u'F'}}, |
276 | 2214 | {'ACTION': u'CONFLICT', | 2188 | {'ACTION': u"Didn't find the node by node_id, but found it by path", |
277 | 2215 | 'ACTION_FUNC': u'new_file_on_server_with_local', | 2189 | 'ACTION_FUNC': u'new_server_file_having_local', |
278 | 2216 | 'COMMENTS': u'', | 2190 | 'COMMENTS': u'', |
279 | 2217 | 'PARAMETERS': {u'hash_eq_local_hash': u'NA', | 2191 | 'PARAMETERS': {u'hash_eq_local_hash': u'NA', |
280 | 2218 | u'hash_eq_server_hash': u'NA', | 2192 | u'hash_eq_server_hash': u'NA', |
281 | @@ -2221,9 +2195,9 @@ | |||
282 | 2221 | 'STATE': {u'changed': u'*', | 2195 | 'STATE': {u'changed': u'*', |
283 | 2222 | u'has_metadata': u'T', | 2196 | u'has_metadata': u'T', |
284 | 2223 | u'is_directory': u'*'}, | 2197 | u'is_directory': u'*'}, |
288 | 2224 | 'STATE_OUT': {u'changed': u'NONE', | 2198 | 'STATE_OUT': {u'changed': u'=', |
289 | 2225 | u'has_metadata': u'T', | 2199 | u'has_metadata': u'=', |
290 | 2226 | u'is_directory': u'F'}}], | 2200 | u'is_directory': u'='}}], |
291 | 2227 | u'SV_HASH_NEW': [{'ACTION': u'NA', | 2201 | u'SV_HASH_NEW': [{'ACTION': u'NA', |
292 | 2228 | 'ACTION_FUNC': u'', | 2202 | 'ACTION_FUNC': u'', |
293 | 2229 | 'COMMENTS': u'', | 2203 | 'COMMENTS': u'', |
+1