comparison host/libcdl/transact.cxx @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children 70190fa0fe10
comparison
equal deleted inserted replaced
75:41bf073c0c32 76:435cced73e2f
1 //{{{ Banner
2
3 //============================================================================
4 //
5 // transaction.cxx
6 //
7 // Implementation of the CdlTransaction class
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000 Red Hat, Inc.
14 //
15 // This file is part of the eCos host tools.
16 //
17 // This program is free software; you can redistribute it and/or modify it
18 // under the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 of the License, or (at your option)
20 // any later version.
21 //
22 // This program is distributed in the hope that it will be useful, but WITHOUT
23 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
25 // more details.
26 //
27 // You should have received a copy of the GNU General Public License along with
28 // this program; if not, write to the Free Software Foundation, Inc.,
29 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 //
31 // ----------------------------------------------------------------------------
32 //
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
36 //
37 // Author(s): bartv
38 // Contact(s): bartv
39 // Date: 1999/07/16
40 // Version: 0.01
41 //
42 //####DESCRIPTIONEND####
43 //============================================================================
44
45 //}}}
46 //{{{ #include's
47
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
50
51 // Get the infrastructure types, assertions, tracing and similar
52 // facilities.
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55
56 // <cdlcore.hxx> defines everything implemented in this module.
57 // It implicitly supplies <string>, <vector> and <map> because
58 // the class definitions rely on these headers.
59 #include <cdlcore.hxx>
60
61 //}}}
62
63 //{{{ CdlTransactionCallback class
64
65 // ----------------------------------------------------------------------------
66 // The callback class is very straightforward. The hard work is done in
67 // the transaction class.
68
69 CdlTransactionCallback::CdlTransactionCallback()
70 {
71 CYG_REPORT_FUNCNAME("CdlTransactionCallback:: constructor");
72 CYG_REPORT_FUNCARG1XV(this);
73
74 // The vectors etc. will take care of themselves.
75 cdltransactioncallback_cookie = CdlTransactionCallback_Magic;
76
77 CYG_POSTCONDITION_THISC();
78 CYG_REPORT_RETURN();
79 }
80
81 CdlTransactionCallback::~CdlTransactionCallback()
82 {
83 CYG_REPORT_FUNCNAME("CdlTransactionCallback:: destructor");
84 CYG_REPORT_FUNCARG1XV(this);
85 CYG_PRECONDITION_THISC();
86
87 cdltransactioncallback_cookie = CdlTransactionCallback_Invalid;
88 value_changes.clear();
89 active_changes.clear();
90 legal_values_changes.clear();
91 value_source_changes.clear();
92 new_conflicts.clear();
93 new_structural_conflicts.clear();
94 nodes_with_resolved_conflicts.clear();
95 nodes_with_resolved_structural_conflicts.clear();
96
97 CYG_REPORT_RETURN();
98 }
99
100 void
101 CdlTransactionCallback::set_callback_fn(void (*fn)(const CdlTransactionCallback&))
102 {
103 CYG_REPORT_FUNCNAME("CdlTransactionCallback::set_callback_fn");
104 CYG_REPORT_FUNCARG1XV(fn);
105
106 CdlTransactionBody::set_callback_fn(fn);
107
108 CYG_REPORT_RETURN();
109 }
110
111 void (*CdlTransactionCallback::get_callback_fn())(const CdlTransactionCallback&)
112 {
113 CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_callback_fn", "result %p");
114
115 void (*result)(const CdlTransactionCallback&) = CdlTransactionBody::get_callback_fn();
116
117 CYG_REPORT_RETVAL(result);
118 return result;
119 }
120
121 bool
122 CdlTransactionCallback::check_this(cyg_assert_class_zeal zeal) const
123 {
124 if (CdlTransactionCallback_Magic != cdltransactioncallback_cookie) {
125 return false;
126 }
127 return true;
128 }
129
130 //}}}
131 //{{{ CdlTransaction statics
132
133 // ----------------------------------------------------------------------------
134 void (*CdlTransactionBody::callback_fn)(const CdlTransactionCallback&) = 0;
135 CdlInferenceCallback CdlTransactionBody::inference_callback = 0;
136 bool CdlTransactionBody::inference_enabled = true;
137 int CdlTransactionBody::inference_recursion_limit = 3;
138 CdlValueSource CdlTransactionBody::inference_override = CdlValueSource_Inferred;
139 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlTransactionBody);
140
141 //}}}
142 //{{{ Transaction creation and destruction
143
144 // ----------------------------------------------------------------------------
145 CdlTransaction
146 CdlTransactionBody::make(CdlToplevel toplevel)
147 {
148 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::make", "result %p");
149 CYG_REPORT_FUNCARG1XV(toplevel);
150 CYG_PRECONDITION_CLASSC(toplevel);
151 CYG_PRECONDITIONC(0 == toplevel->transaction);
152
153 CdlTransaction result = new CdlTransactionBody(toplevel, 0, 0);
154 toplevel->transaction = result;
155
156 CYG_REPORT_RETVAL(result);
157 return result;
158 }
159
160 CdlTransaction
161 CdlTransactionBody::make(CdlConflict conflict)
162 {
163 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::make (sub-transaction)", "result %p");
164 CYG_REPORT_FUNCARG2XV(this, conflict);
165 CYG_PRECONDITION_THISC();
166 CYG_PRECONDITION_ZERO_OR_CLASSC(conflict);
167
168 CdlTransaction result = new CdlTransactionBody(0, this, conflict);
169
170 CYG_REPORT_RETVAL(result);
171 return result;
172 }
173
174 CdlTransactionBody::CdlTransactionBody(CdlToplevel toplevel_arg, CdlTransaction parent_arg, CdlConflict conflict_arg)
175 {
176 CYG_REPORT_FUNCNAME("CdlTransaction:: constructor");
177 CYG_REPORT_FUNCARG4XV(this, toplevel_arg, parent_arg, conflict_arg);
178 CYG_PRECONDITION_ZERO_OR_CLASSC(toplevel_arg);
179 CYG_PRECONDITION_ZERO_OR_CLASSC(parent_arg);
180 CYG_PRECONDITION_ZERO_OR_CLASSC(conflict_arg);
181 CYG_PRECONDITIONC( ((0 == toplevel_arg) && (0 != parent_arg)) || ((0 == parent_arg) && (0 != toplevel_arg)));
182
183 // The containers will take care of themselves, as will all_changes
184 toplevel = toplevel_arg;
185 parent = parent_arg;
186 conflict = conflict_arg;
187 dirty = false;
188 cdltransactionbody_cookie = CdlTransactionBody_Magic;
189 CYGDBG_MEMLEAK_CONSTRUCTOR();
190
191 CYG_POSTCONDITION_THISC();
192 CYG_REPORT_RETURN();
193 }
194
195 // ----------------------------------------------------------------------------
196 CdlTransactionBody::~CdlTransactionBody()
197 {
198 CYG_REPORT_FUNCNAME("CdlTransaction:: destructor");
199 CYG_REPORT_FUNCARG1XV(this);
200 CYG_PRECONDITION_THISC();
201
202 // The transaction must have been either committed or cancelled.
203 // This means that various of the STL containers should be empty
204 CYG_ASSERTC(0 == commit_cancel_ops.size());
205 CYG_ASSERTC(0 == changes.size());
206 CYG_ASSERTC(0 == deleted_conflicts.size());
207 CYG_ASSERTC(0 == deleted_structural_conflicts.size());
208 CYG_ASSERTC(0 == new_conflicts.size());
209 CYG_ASSERTC(0 == new_structural_conflicts.size());
210 CYG_ASSERTC(0 == resolved_conflicts.size());
211 CYG_ASSERTC(0 == global_conflicts_with_solutions.size());
212 CYG_ASSERTC(0 == activated.size());
213 CYG_ASSERTC(0 == deactivated.size());
214 CYG_ASSERTC(0 == legal_values_changes.size());
215 CYG_ASSERTC(0 == value_changes.size());
216 CYG_ASSERTC(0 == active_changes.size());
217
218 // If this was a toplevel transaction, the toplevel knows
219 // about the transaction.
220 if (0 != toplevel) {
221 CYG_ASSERTC(toplevel->transaction == this);
222 toplevel->transaction = 0;
223 }
224 cdltransactionbody_cookie = CdlTransactionBody_Invalid;
225 toplevel = 0;
226 parent = 0;
227 conflict = 0;
228 dirty = false;
229
230 CYGDBG_MEMLEAK_DESTRUCTOR();
231
232 CYG_REPORT_RETURN();
233 }
234
235 //}}}
236 //{{{ check_this()
237
238 // ----------------------------------------------------------------------------
239
240 bool
241 CdlTransactionBody::check_this(cyg_assert_class_zeal zeal) const
242 {
243 if (CdlTransactionBody_Magic != cdltransactionbody_cookie) {
244 return false;
245 }
246 CYGDBG_MEMLEAK_CHECKTHIS();
247
248 //zeal = cyg_extreme;
249 switch(zeal) {
250 case cyg_system_test:
251 case cyg_extreme :
252 {
253 std::map<CdlValuable,CdlValue>::const_iterator map_i;
254 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
255 if (!map_i->first->check_this(cyg_quick) || !map_i->second.check_this(cyg_quick)) {
256 return false;
257 }
258 }
259
260 std::list<CdlConflict>::const_iterator conf_i;
261 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
262 if (!(*conf_i)->check_this(cyg_quick)) {
263 return false;
264 }
265 }
266 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
267 if (!(*conf_i)->check_this(cyg_quick)) {
268 return false;
269 }
270 }
271
272 std::vector<CdlConflict>::const_iterator conf_i2;
273 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
274 if (!(*conf_i2)->check_this(cyg_quick)) {
275 return false;
276 }
277 }
278 for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
279 if (!(*conf_i2)->check_this(cyg_quick)) {
280 return false;
281 }
282 }
283 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
284 if (!(*conf_i2)->check_this(cyg_quick)) {
285 return false;
286 }
287 }
288 for (conf_i = global_conflicts_with_solutions.begin(); conf_i != global_conflicts_with_solutions.end(); conf_i++) {
289 if (!(*conf_i)->check_this(cyg_quick)) {
290 return false;
291 }
292 if (0 != (*conf_i)->transaction) {
293 return false;
294 }
295 }
296
297 // Nodes cannot have been both activated and deactivated in one transaction
298 std::set<CdlNode>::const_iterator node_i;
299 for (node_i = activated.begin(); node_i != activated.end(); node_i++) {
300 if (!(*node_i)->check_this(cyg_quick)) {
301 return false;
302 }
303 if (deactivated.end() != deactivated.find(*node_i)) {
304 return false;
305 }
306 }
307 for (node_i = deactivated.begin(); node_i != deactivated.end(); node_i++) {
308 if (!(*node_i)->check_this(cyg_quick)) {
309 return false;
310 }
311 if (activated.end() != activated.find(*node_i)) {
312 return false;
313 }
314 }
315 std::set<CdlValuable>::const_iterator val_i;
316 for (val_i = legal_values_changes.begin(); val_i != legal_values_changes.end(); val_i++) {
317 if (!(*val_i)->check_this(cyg_quick)) {
318 return false;
319 }
320 }
321
322 std::deque<CdlValuable>::const_iterator val_i2;
323 for (val_i2 = value_changes.begin(); val_i2 != value_changes.end(); val_i2++) {
324 if (!(*val_i2)->check_this(cyg_quick)) {
325 return false;
326 }
327 }
328
329 std::deque<CdlNode>::const_iterator active_i;
330 for (active_i = active_changes.begin(); active_i != active_changes.end(); active_i++) {
331 if (!(*active_i)->check_this(cyg_quick)) {
332 return false;
333 }
334 }
335 }
336 case cyg_thorough:
337 if ((0 != toplevel) && !toplevel->check_this(cyg_quick)) {
338 return false;
339 }
340 if ((0 != parent) && !parent->check_this(cyg_quick)) {
341 return false;
342 }
343 if ((0 != conflict) && !conflict->check_this(cyg_quick)) {
344 return false;
345 }
346
347 case cyg_quick:
348 case cyg_trivial :
349 if ((0 == toplevel) && (0 == parent)) {
350 return false;
351 }
352 if (this == parent) {
353 return false;
354 }
355
356 case cyg_none :
357 break;
358 }
359
360 return true;
361 }
362
363 //}}}
364 //{{{ Misc
365
366 // ----------------------------------------------------------------------------
367 CdlToplevel
368 CdlTransactionBody::get_toplevel() const
369 {
370 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_toplevel", "result %p");
371 CYG_REPORT_FUNCARG1XV(this);
372 CYG_PRECONDITION_THISC();
373
374 CdlToplevel result = toplevel;
375
376 CYG_REPORT_RETVAL(result);
377 return result;
378 }
379
380 CdlTransaction
381 CdlTransactionBody::get_parent() const
382 {
383 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_parent", "result %p");
384 CYG_REPORT_FUNCARG1XV(this);
385 CYG_PRECONDITION_THISC();
386
387 CdlTransaction result = parent;
388
389 CYG_REPORT_RETVAL(result);
390 return result;
391 }
392
393 CdlConflict
394 CdlTransactionBody::get_conflict() const
395 {
396 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
397 CYG_REPORT_FUNCARG1XV(this);
398 CYG_PRECONDITION_THISC();
399
400 CdlConflict result = conflict;
401
402 CYG_REPORT_RETVAL(result);
403 return result;
404 }
405
406
407 // ----------------------------------------------------------------------------
408 void (*CdlTransactionBody::get_callback_fn())(const CdlTransactionCallback&)
409 {
410 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_callback_fn", "result %p");
411
412 void (*result)(const CdlTransactionCallback&) = callback_fn;
413
414 CYG_REPORT_RETVAL(result);
415 return result;
416 }
417
418 void
419 CdlTransactionBody::set_callback_fn(void (*fn)(const CdlTransactionCallback&))
420 {
421 CYG_REPORT_FUNCNAME("CdlTransaction::set_callback_fn");
422 CYG_REPORT_FUNCARG1XV(fn);
423
424 callback_fn = fn;
425
426 CYG_REPORT_RETURN();
427 }
428
429 CdlInferenceCallback
430 CdlTransactionBody::get_inference_callback_fn()
431 {
432 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_callback_fn", "result %p");
433
434 CdlInferenceCallback result = inference_callback;
435
436 CYG_REPORT_RETVAL(result);
437 return result;
438 }
439
440 void
441 CdlTransactionBody::set_inference_callback_fn(CdlInferenceCallback fn)
442 {
443 CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_callback");
444 CYG_REPORT_FUNCARG1XV(fn);
445
446 inference_callback = fn;
447
448 CYG_REPORT_RETURN();
449 }
450
451 void
452 CdlTransactionBody::enable_automatic_inference()
453 {
454 CYG_REPORT_FUNCNAME("CdlTransaction::enable_automatic_inference");
455
456 inference_enabled = true;
457
458 CYG_REPORT_RETURN();
459 }
460
461 void
462 CdlTransactionBody::disable_automatic_inference()
463 {
464 CYG_REPORT_FUNCNAME("CdlTransaction::disable_automatic_inference");
465
466 inference_enabled = false;
467
468 CYG_REPORT_RETURN();
469 }
470
471 bool
472 CdlTransactionBody::is_automatic_inference_enabled()
473 {
474 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_automatic_inference_enabled", "result %d");
475
476 bool result = inference_enabled;
477
478 CYG_REPORT_RETVAL(result);
479 return result;
480 }
481
482 void
483 CdlTransactionBody::set_inference_recursion_limit(int limit)
484 {
485 CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_recursion_limit");
486 CYG_REPORT_FUNCARG1XV(limit);
487 CYG_PRECONDITIONC(0 < limit);
488 CYG_PRECONDITIONC(limit < 16); // arbitrary number
489
490 inference_recursion_limit = limit;
491
492 CYG_REPORT_RETURN();
493 }
494
495 int
496 CdlTransactionBody::get_inference_recursion_limit()
497 {
498 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_recursion_limit", "result %d");
499
500 int result = inference_recursion_limit;
501
502 CYG_REPORT_RETVAL(result);
503 return result;
504 }
505
506 void
507 CdlTransactionBody::set_inference_override(CdlValueSource source)
508 {
509 CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_override");
510 CYG_REPORT_FUNCARG1XV(source);
511 CYG_PRECONDITIONC((CdlValueSource_Invalid == source) || Cdl::is_valid_value_source(source));
512
513 inference_override = source;
514
515 CYG_REPORT_RETURN();
516 }
517
518 CdlValueSource
519 CdlTransactionBody::get_inference_override()
520 {
521 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_override", "result %d");
522
523 CdlValueSource result = inference_override;
524
525 CYG_REPORT_RETVAL((int) result);
526 return result;
527 }
528
529 //}}}
530 //{{{ Value access and updates
531
532 // ----------------------------------------------------------------------------
533 const CdlValue&
534 CdlTransactionBody::get_whole_value(CdlConstValuable valuable_arg) const
535 {
536 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_whole_value", "result %p");
537 CYG_REPORT_FUNCARG2XV(this, valuable_arg);
538 CYG_PRECONDITION_THISC();
539 CYG_PRECONDITION_CLASSC(valuable_arg);
540
541 // Unfortunately I need a valuable rather than a const-valuable when
542 // accessing the STL containers.
543 CdlValuable valuable = const_cast<CdlValuable>(valuable_arg);
544
545 // If we are trying to find a solution, keep track of all valuables
546 // that were accessed.
547 const CdlValue* result = 0;
548 if (0 != conflict) {
549 conflict->solution_references.insert(valuable);
550 }
551
552 std::map<CdlValuable,CdlValue>::const_iterator val_i;
553 val_i = changes.find(valuable);
554 if (val_i != changes.end()) {
555 result = &(val_i->second);
556 } else if (0 != parent) {
557 result = &(parent->get_whole_value(valuable));
558 } else {
559 result = &(valuable->get_whole_value());
560 }
561
562 CYG_REPORT_RETVAL(result);
563 return *result;
564 }
565
566 void
567 CdlTransactionBody::set_whole_value(CdlValuable valuable, const CdlValue& old_value, const CdlValue& new_value)
568 {
569 CYG_REPORT_FUNCNAME("CdlTransaction::set_whole_value");
570 CYG_REPORT_FUNCARG3XV(this, valuable, &new_value);
571 CYG_PRECONDITION_THISC();
572 CYG_PRECONDITION_CLASSC(valuable);
573 CYG_PRECONDITION_CLASSOC(old_value);
574 CYG_PRECONDITION_CLASSOC(new_value);
575 CYG_PRECONDITIONC(&old_value != &new_value);
576
577 CdlValueFlavor flavor = old_value.get_flavor();
578 CYG_ASSERTC(flavor == new_value.get_flavor());
579 CYG_ASSERTC(CdlValueFlavor_None != flavor);
580
581 bool value_changed = false;
582 bool bool_changed = false;
583
584 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
585 if (old_value.is_enabled() != new_value.is_enabled()) {
586 value_changed = true;
587 bool_changed = true;
588 }
589 }
590 if (!value_changed && ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor))) {
591 if (old_value.get_simple_value() != new_value.get_simple_value()) {
592 value_changed = true;
593 }
594 }
595 if (value_changed) {
596 std::deque<CdlValuable>::const_iterator change_i;
597 change_i = std::find(value_changes.begin(), value_changes.end(), valuable);
598 if (change_i == value_changes.end()) {
599 value_changes.push_back(valuable);
600 }
601 }
602
603 // Actually do the update. This may modify old_value, so has to be
604 // left to the end.
605 changes[valuable] = new_value;
606
607 // If there was a change to the boolean part of the value and the valuable
608 // implements an interface, the interface value needs to be recalculated.
609 if (bool_changed && valuable->has_property(CdlPropertyId_Implements)) {
610 std::vector<CdlInterface> interfaces;
611 std::vector<CdlInterface>::const_iterator interface_i;
612 valuable->get_implemented_interfaces(interfaces);
613 for (interface_i = interfaces.begin(); interface_i != interfaces.end(); interface_i++) {
614 (*interface_i)->recalculate(this);
615 }
616 }
617
618 CYG_REPORT_RETURN();
619 }
620
621 const std::map<CdlValuable, CdlValue>&
622 CdlTransactionBody::get_changes() const
623 {
624 CYG_REPORT_FUNCNAME("CdlTransaction::get_changes");
625 CYG_REPORT_FUNCARG1XV(this);
626 CYG_PRECONDITION_THISC();
627
628 CYG_REPORT_RETURN();
629 return changes;
630 }
631
632 //}}}
633 //{{{ Active access and updates
634
635 // ----------------------------------------------------------------------------
636 // Nodes can become active or inactive during transactions, and this affects
637 // propagation and expression evaluation
638
639 bool
640 CdlTransactionBody::is_active(CdlNode node) const
641 {
642 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_active", "result %d");
643 CYG_REPORT_FUNCARG2XV(this, node);
644 CYG_PRECONDITION_THISC();
645 CYG_PRECONDITION_CLASSC(node);
646
647 bool result = false;
648 if (activated.end() != activated.find(node)) {
649 result = true;
650 } else if (deactivated.end() != deactivated.find(node)) {
651 result = false;
652 } else if (0 != parent) {
653 result = parent->is_active(node);
654 } else {
655 result = node->is_active();
656 }
657
658 CYG_REPORT_RETVAL(result);
659 return result;
660 }
661
662 void
663 CdlTransactionBody::set_active(CdlNode node, bool state)
664 {
665 CYG_REPORT_FUNCNAME("CdlTransaction::set_active");
666 CYG_REPORT_FUNCARG3XV(this, node, state);
667 CYG_PRECONDITION_THISC();
668 CYG_PRECONDITION_CLASSC(node);
669
670 if (state) {
671 activated.insert(node);
672 std::set<CdlNode>::iterator node_i = deactivated.find(node);
673 if (deactivated.end() != node_i) {
674 deactivated.erase(node_i);
675 }
676 } else {
677 deactivated.insert(node);
678 std::set<CdlNode>::iterator node_i = activated.find(node);
679 if (activated.end() != node_i) {
680 activated.erase(node_i);
681 }
682 }
683 active_changes.push_back(node);
684
685 CdlValuable valuable = dynamic_cast<CdlValuable>(node);
686 if ((0 != valuable) && valuable->has_property(CdlPropertyId_Implements)) {
687 std::vector<CdlInterface> interfaces;
688 std::vector<CdlInterface>::const_iterator interface_i;
689 valuable->get_implemented_interfaces(interfaces);
690 for (interface_i = interfaces.begin(); interface_i != interfaces.end(); interface_i++) {
691 (*interface_i)->recalculate(this);
692 }
693 }
694
695 CYG_REPORT_RETURN();
696 }
697
698 //}}}
699 //{{{ Conflict access and updates
700
701 //{{{ get_conflict() etc.
702
703 // ----------------------------------------------------------------------------
704 bool
705 CdlTransactionBody::has_conflict(CdlNode node, bool (*pFn)(CdlConflict))
706 {
707 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_conflict", "result %d");
708 CYG_REPORT_FUNCARG3XV(this, node, pFn);
709 CYG_PRECONDITION_THISC();
710 CYG_PRECONDITION_CLASSC(node);
711
712 // Because it is necessary to check whether or not any given
713 // conflict has been cleared in the current transaction or any
714 // parent transaction, recursion into the parent is not
715 // appropriate.
716 bool result = false;
717 std::list<CdlConflict>::const_iterator conf_i;
718 CdlTransaction current_transaction = this;
719 CdlToplevel toplevel = this->toplevel;
720 do {
721 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
722
723 for (conf_i = current_transaction->new_conflicts.begin();
724 conf_i != current_transaction->new_conflicts.end();
725 conf_i++) {
726
727 if ((node == (*conf_i)->get_node()) &&
728 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
729 result = true;
730 break;
731 }
732 }
733
734 toplevel = current_transaction->toplevel;
735 current_transaction = current_transaction->parent;
736 } while (!result && (0 != current_transaction));
737
738 if (!result) {
739 CYG_ASSERT_CLASSC(toplevel);
740 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
741 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
742 result = true;
743 break;
744 }
745 }
746 }
747
748 CYG_REPORT_RETVAL(result);
749 return result;
750 }
751
752 CdlConflict
753 CdlTransactionBody::get_conflict(CdlNode node, bool (*pFn)(CdlConflict))
754 {
755 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
756 CYG_REPORT_FUNCARG3XV(this, node, pFn);
757 CYG_PRECONDITION_THISC();
758 CYG_PRECONDITION_CLASSC(node);
759
760 CdlConflict result = 0;
761 std::list<CdlConflict>::const_iterator conf_i;
762 CdlTransaction current_transaction = this;
763 CdlToplevel toplevel = this->toplevel;
764 do {
765 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
766
767 for (conf_i = current_transaction->new_conflicts.begin();
768 conf_i != current_transaction->new_conflicts.end();
769 conf_i++) {
770
771 if ((node == (*conf_i)->get_node()) &&
772 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
773 result = *conf_i;
774 break;
775 }
776 }
777
778 toplevel = current_transaction->toplevel;
779 current_transaction = current_transaction->parent;
780 } while ((0 == result) && (0 != current_transaction));
781
782 if (0 == result) {
783 CYG_ASSERT_CLASSC(toplevel);
784 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
785 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
786 result = *conf_i;
787 break;
788 }
789 }
790 }
791
792 CYG_REPORT_RETVAL(result);
793 return result;
794 }
795
796 void
797 CdlTransactionBody::get_conflicts(CdlNode node, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
798 {
799 CYG_REPORT_FUNCNAME("CdlTransaction::get_conflicts");
800 CYG_REPORT_FUNCARG3XV(this, node, pFn);
801 CYG_PRECONDITION_THISC();
802 CYG_PRECONDITION_CLASSC(node);
803
804 std::list<CdlConflict>::const_iterator conf_i;
805 CdlTransaction current_transaction = this;
806 CdlToplevel toplevel = this->toplevel;
807 do {
808 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
809
810 for (conf_i = current_transaction->new_conflicts.begin();
811 conf_i != current_transaction->new_conflicts.end();
812 conf_i++) {
813
814 if ((node == (*conf_i)->get_node()) &&
815 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
816 result.push_back(*conf_i);
817 }
818 }
819
820 toplevel = current_transaction->toplevel;
821 current_transaction = current_transaction->parent;
822 } while (0 != current_transaction);
823
824 CYG_ASSERT_CLASSC(toplevel);
825 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
826 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
827 result.push_back(*conf_i);
828 }
829 }
830
831 CYG_REPORT_RETURN();
832 }
833
834 bool
835 CdlTransactionBody::has_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
836 {
837 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_conflict", "result %d");
838 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
839 CYG_PRECONDITION_THISC();
840 CYG_PRECONDITION_CLASSC(node);
841 CYG_PRECONDITION_CLASSC(prop);
842
843 bool result = false;
844 std::list<CdlConflict>::const_iterator conf_i;
845 CdlTransaction current_transaction = this;
846 CdlToplevel toplevel = this->toplevel;
847 do {
848 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
849
850 for (conf_i = current_transaction->new_conflicts.begin();
851 conf_i != current_transaction->new_conflicts.end();
852 conf_i++) {
853
854 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
855 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
856
857 result = true;
858 break;
859 }
860 }
861
862 toplevel = current_transaction->toplevel;
863 current_transaction = current_transaction->parent;
864 } while (!result && (0 != current_transaction));
865
866 if (!result) {
867 CYG_ASSERT_CLASSC(toplevel);
868 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
869 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
870 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
871
872 result = true;
873 break;
874 }
875 }
876 }
877
878 CYG_REPORT_RETVAL(result);
879 return result;
880 }
881
882 CdlConflict
883 CdlTransactionBody::get_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
884 {
885 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
886 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
887 CYG_PRECONDITION_THISC();
888 CYG_PRECONDITION_CLASSC(node);
889 CYG_PRECONDITION_CLASSC(prop);
890
891 CdlConflict result = 0;
892 std::list<CdlConflict>::const_iterator conf_i;
893 CdlTransaction current_transaction = this;
894 CdlToplevel toplevel = this->toplevel;
895 do {
896 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
897
898 for (conf_i = current_transaction->new_conflicts.begin();
899 conf_i != current_transaction->new_conflicts.end();
900 conf_i++) {
901
902 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
903 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
904 result = *conf_i;
905 break;
906 }
907 }
908
909 toplevel = current_transaction->toplevel;
910 current_transaction = current_transaction->parent;
911 } while ((0 == result) && (0 != current_transaction));
912
913 if (0 == result) {
914 CYG_ASSERT_CLASSC(toplevel);
915 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
916 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
917 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
918
919 result = *conf_i;
920 break;
921 }
922 }
923 }
924
925 CYG_REPORT_RETVAL(result);
926 return result;
927 }
928
929 void
930 CdlTransactionBody::get_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
931 {
932 CYG_REPORT_FUNCNAME("CdlTransaction::get_conflict");
933 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
934 CYG_PRECONDITION_THISC();
935 CYG_PRECONDITION_CLASSC(node);
936 CYG_PRECONDITION_CLASSC(prop);
937
938 std::list<CdlConflict>::const_iterator conf_i;
939 CdlTransaction current_transaction = this;
940 CdlToplevel toplevel = this->toplevel;
941 do {
942 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
943
944 for (conf_i = current_transaction->new_conflicts.begin();
945 conf_i != current_transaction->new_conflicts.end();
946 conf_i++) {
947
948 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
949 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
950 result.push_back(*conf_i);
951 }
952 }
953
954 toplevel = current_transaction->toplevel;
955 current_transaction = current_transaction->parent;
956 } while (0 != current_transaction);
957
958 CYG_ASSERT_CLASSC(toplevel);
959 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
960 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
961 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
962
963 result.push_back(*conf_i);
964 }
965 }
966
967 CYG_REPORT_RETURN();
968 }
969
970 //}}}
971 //{{{ get_structural_conflict() etc
972
973 // ----------------------------------------------------------------------------
974 bool
975 CdlTransactionBody::has_structural_conflict(CdlNode node, bool (*pFn)(CdlConflict))
976 {
977 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_structural_conflict", "result %d");
978 CYG_REPORT_FUNCARG3XV(this, node, pFn);
979 CYG_PRECONDITION_THISC();
980 CYG_PRECONDITION_CLASSC(node);
981
982 // Because it is necessary to check whether or not any given
983 // conflict has been cleared in the current transaction or any
984 // parent transaction, recursion into the parent is not
985 // appropriate.
986 bool result = false;
987 std::list<CdlConflict>::const_iterator conf_i;
988 CdlTransaction current_transaction = this;
989 CdlToplevel toplevel = this->toplevel;
990 do {
991 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
992
993 for (conf_i = current_transaction->new_structural_conflicts.begin();
994 conf_i != current_transaction->new_structural_conflicts.end();
995 conf_i++) {
996
997 if ((node == (*conf_i)->get_node()) &&
998 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
999 result = true;
1000 break;
1001 }
1002 }
1003
1004 toplevel = current_transaction->toplevel;
1005 current_transaction = current_transaction->parent;
1006 } while (!result && (0 != current_transaction));
1007
1008 if (!result) {
1009 CYG_ASSERT_CLASSC(toplevel);
1010 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1011 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1012 result = true;
1013 break;
1014 }
1015 }
1016 }
1017
1018 CYG_REPORT_RETVAL(result);
1019 return result;
1020 }
1021
1022 CdlConflict
1023 CdlTransactionBody::get_structural_conflict(CdlNode node, bool (*pFn)(CdlConflict))
1024 {
1025 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_structural_conflict", "result %p");
1026 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1027 CYG_PRECONDITION_THISC();
1028 CYG_PRECONDITION_CLASSC(node);
1029
1030 CdlConflict result = 0;
1031 std::list<CdlConflict>::const_iterator conf_i;
1032 CdlTransaction current_transaction = this;
1033 CdlToplevel toplevel = this->toplevel;
1034 do {
1035 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1036
1037 for (conf_i = current_transaction->new_structural_conflicts.begin();
1038 conf_i != current_transaction->new_structural_conflicts.end();
1039 conf_i++) {
1040
1041 if ((node == (*conf_i)->get_node()) &&
1042 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1043 result = *conf_i;
1044 break;
1045 }
1046 }
1047
1048 toplevel = current_transaction->toplevel;
1049 current_transaction = current_transaction->parent;
1050 } while ((0 == result) && (0 != current_transaction));
1051
1052 if (0 == result) {
1053 CYG_ASSERT_CLASSC(toplevel);
1054 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1055 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1056 result = *conf_i;
1057 break;
1058 }
1059 }
1060 }
1061
1062 CYG_REPORT_RETVAL(result);
1063 return result;
1064 }
1065
1066 void
1067 CdlTransactionBody::get_structural_conflicts(CdlNode node, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
1068 {
1069 CYG_REPORT_FUNCNAME("CdlTransaction::get_structural_conflicts");
1070 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1071 CYG_PRECONDITION_THISC();
1072 CYG_PRECONDITION_CLASSC(node);
1073
1074 std::list<CdlConflict>::const_iterator conf_i;
1075 CdlTransaction current_transaction = this;
1076 CdlToplevel toplevel = this->toplevel;
1077 do {
1078 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1079
1080 for (conf_i = current_transaction->new_structural_conflicts.begin();
1081 conf_i != current_transaction->new_structural_conflicts.end();
1082 conf_i++) {
1083
1084 if ((node == (*conf_i)->get_node()) &&
1085 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1086 result.push_back(*conf_i);
1087 }
1088 }
1089
1090 toplevel = current_transaction->toplevel;
1091 current_transaction = current_transaction->parent;
1092 } while (0 != current_transaction);
1093
1094 CYG_ASSERT_CLASSC(toplevel);
1095 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1096 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1097 result.push_back(*conf_i);
1098 }
1099 }
1100
1101 CYG_REPORT_RETURN();
1102 }
1103
1104 bool
1105 CdlTransactionBody::has_structural_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1106 {
1107 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_structural_conflict", "result %d");
1108 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1109 CYG_PRECONDITION_THISC();
1110 CYG_PRECONDITION_CLASSC(node);
1111 CYG_PRECONDITION_CLASSC(prop);
1112
1113 bool result = false;
1114 std::list<CdlConflict>::const_iterator conf_i;
1115 CdlTransaction current_transaction = this;
1116 CdlToplevel toplevel = this->toplevel;
1117 do {
1118 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1119
1120 for (conf_i = current_transaction->new_structural_conflicts.begin();
1121 conf_i != current_transaction->new_structural_conflicts.end();
1122 conf_i++) {
1123
1124 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1125 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1126
1127 result = true;
1128 break;
1129 }
1130 }
1131
1132 toplevel = current_transaction->toplevel;
1133 current_transaction = current_transaction->parent;
1134 } while (!result && (0 != current_transaction));
1135
1136 if (!result) {
1137 CYG_ASSERT_CLASSC(toplevel);
1138 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1139 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1140 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1141
1142 result = true;
1143 break;
1144 }
1145 }
1146 }
1147
1148 CYG_REPORT_RETVAL(result);
1149 return result;
1150 }
1151
1152 CdlConflict
1153 CdlTransactionBody::get_structural_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1154 {
1155 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_structural_conflict", "result %p");
1156 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1157 CYG_PRECONDITION_THISC();
1158 CYG_PRECONDITION_CLASSC(node);
1159 CYG_PRECONDITION_CLASSC(prop);
1160
1161 CdlConflict result = 0;
1162 std::list<CdlConflict>::const_iterator conf_i;
1163 CdlTransaction current_transaction = this;
1164 CdlToplevel toplevel = this->toplevel;
1165 do {
1166 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1167
1168 for (conf_i = current_transaction->new_structural_conflicts.begin();
1169 conf_i != current_transaction->new_structural_conflicts.end();
1170 conf_i++) {
1171
1172 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1173 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1174 result = *conf_i;
1175 break;
1176 }
1177 }
1178
1179 toplevel = current_transaction->toplevel;
1180 current_transaction = current_transaction->parent;
1181 } while ((0 == result) && (0 != current_transaction));
1182
1183 if (0 == result) {
1184 CYG_ASSERT_CLASSC(toplevel);
1185 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1186 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1187 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1188
1189 result = *conf_i;
1190 break;
1191 }
1192 }
1193 }
1194
1195 CYG_REPORT_RETVAL(result);
1196 return result;
1197 }
1198
1199 void
1200 CdlTransactionBody::get_structural_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict),
1201 std::vector<CdlConflict>& result)
1202 {
1203 CYG_REPORT_FUNCNAME("CdlTransaction::get_structural_conflict");
1204 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1205 CYG_PRECONDITION_THISC();
1206 CYG_PRECONDITION_CLASSC(node);
1207 CYG_PRECONDITION_CLASSC(prop);
1208
1209 std::list<CdlConflict>::const_iterator conf_i;
1210 CdlTransaction current_transaction = this;
1211 CdlToplevel toplevel = this->toplevel;
1212 do {
1213 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1214
1215 for (conf_i = current_transaction->new_structural_conflicts.begin();
1216 conf_i != current_transaction->new_structural_conflicts.end();
1217 conf_i++) {
1218
1219 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1220 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1221 result.push_back(*conf_i);
1222 }
1223 }
1224
1225 toplevel = current_transaction->toplevel;
1226 current_transaction = current_transaction->parent;
1227 } while (0 != current_transaction);
1228
1229 CYG_ASSERT_CLASSC(toplevel);
1230 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1231 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1232 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1233
1234 result.push_back(*conf_i);
1235 }
1236 }
1237
1238 CYG_REPORT_RETURN();
1239 }
1240
1241 //}}}
1242 //{{{ clear_conflicts()
1243
1244 // ----------------------------------------------------------------------------
1245 // Clearing a conflict. This can only happen in the context of a
1246 // transaction.
1247 void
1248 CdlTransactionBody::clear_conflicts(CdlNode node, bool (*pFn)(CdlConflict))
1249 {
1250 CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflicts");
1251 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1252 CYG_PRECONDITION_THISC();
1253 CYG_PRECONDITION_CLASSC(node);
1254
1255 // Recursing into the parent is the wrong thing to do here, it
1256 // would result in the conflict being cleared in the parent rather
1257 // than in the current transaction.
1258 std::list<CdlConflict>::iterator conf_i;
1259 CdlTransaction current_transaction = this;
1260 CdlToplevel toplevel = this->toplevel;
1261 do {
1262 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1263
1264 for (conf_i = current_transaction->new_conflicts.begin(); conf_i != current_transaction->new_conflicts.end(); ) {
1265 CdlConflict conflict = *conf_i++;
1266 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1267 this->clear_conflict(conflict);
1268 }
1269 }
1270 toplevel = current_transaction->toplevel;
1271 current_transaction = current_transaction->parent;
1272 } while (0 != current_transaction);
1273
1274 CYG_ASSERT_CLASSC(toplevel);
1275 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); ) {
1276 CdlConflict conflict = *conf_i++;
1277 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1278 this->clear_conflict(conflict);
1279 }
1280 }
1281
1282 CYG_REPORT_RETURN();
1283 }
1284
1285 void
1286 CdlTransactionBody::clear_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1287 {
1288 CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflicts");
1289 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1290 CYG_PRECONDITION_THISC();
1291 CYG_PRECONDITION_CLASSC(node);
1292
1293 std::list<CdlConflict>::iterator conf_i;
1294 CdlTransaction current_transaction = this;
1295 CdlToplevel toplevel = this->toplevel;
1296 do {
1297 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1298
1299 for (conf_i = current_transaction->new_conflicts.begin(); conf_i != current_transaction->new_conflicts.end(); ) {
1300 CdlConflict conflict = *conf_i++;
1301 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1302 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1303 this->clear_conflict(conflict);
1304 }
1305 }
1306 toplevel = current_transaction->toplevel;
1307 current_transaction = current_transaction->parent;
1308 } while (0 != current_transaction);
1309
1310 CYG_ASSERT_CLASSC(toplevel);
1311 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); ) {
1312 CdlConflict conflict = *conf_i++;
1313 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1314 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1315 this->clear_conflict(conflict);
1316 }
1317 }
1318
1319 CYG_REPORT_RETURN();
1320 }
1321
1322 void
1323 CdlTransactionBody::clear_structural_conflicts(CdlNode node, bool (*pFn)(CdlConflict))
1324 {
1325 CYG_REPORT_FUNCNAME("CdlTransaction::clear_structural_conflicts");
1326 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1327 CYG_PRECONDITION_THISC();
1328 CYG_PRECONDITION_CLASSC(node);
1329
1330 std::list<CdlConflict>::iterator conf_i;
1331 CdlTransaction current_transaction = this;
1332 CdlToplevel toplevel = this->toplevel;
1333 do {
1334 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1335
1336 for (conf_i = current_transaction->new_structural_conflicts.begin();
1337 conf_i != current_transaction->new_structural_conflicts.end();
1338 ) {
1339
1340 CdlConflict conflict = *conf_i++;
1341 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1342 this->clear_conflict(conflict);
1343 }
1344 }
1345 toplevel = current_transaction->toplevel;
1346 current_transaction = current_transaction->parent;
1347 } while (0 != current_transaction);
1348
1349 CYG_ASSERT_CLASSC(toplevel);
1350 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); ) {
1351 CdlConflict conflict = *conf_i++;
1352 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1353 this->clear_conflict(conflict);
1354 }
1355 }
1356
1357 CYG_REPORT_RETURN();
1358 }
1359
1360 void
1361 CdlTransactionBody::clear_structural_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1362 {
1363 CYG_REPORT_FUNCNAME("CdlTransaction::clear_structural_conflicts");
1364 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1365 CYG_PRECONDITION_THISC();
1366 CYG_PRECONDITION_CLASSC(node);
1367
1368 std::list<CdlConflict>::iterator conf_i;
1369 CdlTransaction current_transaction = this;
1370 CdlToplevel toplevel = this->toplevel;
1371 do {
1372 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1373
1374 for (conf_i = current_transaction->new_structural_conflicts.begin();
1375 conf_i != current_transaction->new_structural_conflicts.end();
1376 ) {
1377
1378 CdlConflict conflict = *conf_i++;
1379 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1380 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1381
1382 this->clear_conflict(conflict);
1383 }
1384 }
1385 toplevel = current_transaction->toplevel;
1386 current_transaction = current_transaction->parent;
1387 } while (0 != current_transaction);
1388
1389 CYG_ASSERT_CLASSC(toplevel);
1390 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); ) {
1391 CdlConflict conflict = *conf_i++;
1392 if ((node == conflict->get_node()) && (prop == conflict->get_property()) && (*pFn)(conflict)) {
1393 this->clear_conflict(conflict);
1394 }
1395 }
1396
1397 CYG_REPORT_RETURN();
1398 }
1399
1400 //}}}
1401 //{{{ clear_conflict()
1402
1403 // ----------------------------------------------------------------------------
1404 void
1405 CdlTransactionBody::clear_conflict(CdlConflict conflict)
1406 {
1407 CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflict");
1408 CYG_REPORT_FUNCARG2XV(this, conflict);
1409 CYG_PRECONDITION_THISC();
1410 CYG_PRECONDITION_CLASSC(conflict);
1411
1412 // If this conflict was created during the transaction, it should
1413 // be on the new_conflicts or new_structural_conflicts container
1414 if (this == conflict->transaction) {
1415 // The conflict should be on one of the two new_conflicts deques.
1416 if (conflict->structural) {
1417 std::list<CdlConflict>::iterator conf_i = std::find(new_structural_conflicts.begin(),
1418 new_structural_conflicts.end(), conflict);
1419 CYG_ASSERTC(conf_i != new_structural_conflicts.end());
1420 new_structural_conflicts.erase(conf_i);
1421 } else {
1422 std::list<CdlConflict>::iterator conf_i = std::find(new_conflicts.begin(), new_conflicts.end(), conflict);
1423 CYG_ASSERTC(conf_i != new_conflicts.end());
1424 new_conflicts.erase(conf_i);
1425 }
1426 delete conflict;
1427
1428 } else {
1429 if (conflict->structural) {
1430 deleted_structural_conflicts.push_back(conflict);
1431 } else {
1432 deleted_conflicts.push_back(conflict);
1433 }
1434 }
1435
1436 CYG_REPORT_RETURN();
1437 }
1438
1439 // ----------------------------------------------------------------------------
1440 bool
1441 CdlTransactionBody::has_conflict_been_cleared(CdlConflict conf)
1442 {
1443 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_conflict_been_cleared", "result %d");
1444 CYG_REPORT_FUNCARG2XV(this, conf);
1445 CYG_PRECONDITION_THISC();
1446 CYG_PRECONDITION_CLASSC(conf);
1447
1448 bool result = false;
1449 CdlTransaction current_transaction = this;
1450 do {
1451 if (conf->structural) {
1452 if (std::find(current_transaction->deleted_structural_conflicts.begin(),
1453 current_transaction->deleted_structural_conflicts.end(), conf) !=
1454 current_transaction->deleted_structural_conflicts.end()) {
1455
1456 result = true;
1457 }
1458 } else {
1459 if (std::find(current_transaction->deleted_conflicts.begin(), current_transaction->deleted_conflicts.end(),
1460 conf) != current_transaction->deleted_conflicts.end()) {
1461 result = true;
1462 }
1463 }
1464
1465 current_transaction = current_transaction->parent;
1466 } while (!result && (0 != current_transaction));
1467
1468 CYG_REPORT_RETVAL(result);
1469 return result;
1470 }
1471
1472 //}}}
1473 //{{{ per-transaction data
1474
1475 // ----------------------------------------------------------------------------
1476 // Accessing the per-transaction conflict data.
1477
1478 const std::list<CdlConflict>&
1479 CdlTransactionBody::get_new_conflicts() const
1480 {
1481 CYG_REPORT_FUNCNAME("CdlTransaction::get_new_conflicts");
1482 CYG_REPORT_FUNCARG1XV(this);
1483 CYG_PRECONDITION_THISC();
1484
1485 CYG_REPORT_RETURN();
1486 return new_conflicts;
1487 }
1488
1489 const std::list<CdlConflict>&
1490 CdlTransactionBody::get_new_structural_conflicts() const
1491 {
1492 CYG_REPORT_FUNCNAME("CdlTransaction::get_new_structural_conflicts");
1493 CYG_REPORT_FUNCARG1XV(this);
1494 CYG_PRECONDITION_THISC();
1495
1496 CYG_REPORT_RETURN();
1497 return new_structural_conflicts;
1498 }
1499
1500 const std::vector<CdlConflict>&
1501 CdlTransactionBody::get_deleted_conflicts() const
1502 {
1503 CYG_REPORT_FUNCNAME("CdlTransaction::get_deleted_conflicts");
1504 CYG_REPORT_FUNCARG1XV(this);
1505 CYG_PRECONDITION_THISC();
1506
1507 CYG_REPORT_RETURN();
1508 return deleted_conflicts;
1509 }
1510
1511 const std::vector<CdlConflict>&
1512 CdlTransactionBody::get_deleted_structural_conflicts() const
1513 {
1514 CYG_REPORT_FUNCNAME("CdlTransaction::get_deleted_structural_conflicts");
1515 CYG_REPORT_FUNCARG1XV(this);
1516 CYG_PRECONDITION_THISC();
1517
1518 CYG_REPORT_RETURN();
1519 return deleted_structural_conflicts;
1520 }
1521
1522 const std::vector<CdlConflict>&
1523 CdlTransactionBody::get_resolved_conflicts() const
1524 {
1525 CYG_REPORT_FUNCNAME("CdlTransaction::get_resolved_conflicts");
1526 CYG_REPORT_FUNCARG1XV(this);
1527 CYG_PRECONDITION_THISC();
1528
1529 CYG_REPORT_RETURN();
1530 return resolved_conflicts;
1531 }
1532
1533 const std::list<CdlConflict>&
1534 CdlTransactionBody::get_global_conflicts_with_solutions() const
1535 {
1536 CYG_REPORT_FUNCNAME("CdlTransaction::get_global_conflicts_with_solutions");
1537 CYG_REPORT_FUNCARG1XV(this);
1538 CYG_PRECONDITION_THISC();
1539
1540 CYG_REPORT_RETURN();
1541 return global_conflicts_with_solutions;
1542 }
1543
1544 //}}}
1545
1546 //}}}
1547 //{{{ Commit/cancel operations
1548
1549 // ----------------------------------------------------------------------------
1550 void
1551 CdlTransactionBody::add_commit_cancel_op(CdlTransactionCommitCancelOp* op)
1552 {
1553 CYG_REPORT_FUNCNAME("CdlTransaction::add_commit_cancel_op");
1554 CYG_REPORT_FUNCARG2XV(this, op);
1555 CYG_PRECONDITION_THISC();
1556 CYG_PRECONDITIONC(0 != op);
1557
1558 commit_cancel_ops.push_back(op);
1559
1560 CYG_REPORT_RETURN();
1561 }
1562
1563 void
1564 CdlTransactionBody::cancel_last_commit_cancel_op()
1565 {
1566 CYG_REPORT_FUNCNAME("CdlTransaction::cancel_last_commit_cancel_op");
1567 CYG_REPORT_FUNCARG1XV(this);
1568 CYG_PRECONDITION_THISC();
1569
1570 CdlTransactionCommitCancelOp* op = *(commit_cancel_ops.rbegin());
1571 commit_cancel_ops.pop_back();
1572 op->cancel(this);
1573 delete op;
1574
1575 CYG_REPORT_RETURN();
1576 }
1577
1578 CdlTransactionCommitCancelOp*
1579 CdlTransactionBody::get_last_commit_cancel_op() const
1580 {
1581 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_last_commit_cancel_op", "result %p");
1582 CYG_REPORT_FUNCARG1XV(this);
1583 CYG_PRECONDITION_THISC();
1584
1585 CdlTransactionCommitCancelOp* op = *(commit_cancel_ops.rbegin());
1586
1587 CYG_REPORT_RETVAL(op);
1588 return op;
1589 }
1590
1591 const std::vector<CdlTransactionCommitCancelOp*>&
1592 CdlTransactionBody::get_commit_cancel_ops() const
1593 {
1594 CYG_REPORT_FUNCNAME("CdlTransaction::get_commit_cancel_ops");
1595 CYG_REPORT_FUNCARG1XV(this);
1596 CYG_PRECONDITION_THISC();
1597
1598 CYG_REPORT_RETURN();
1599 return commit_cancel_ops;
1600 }
1601
1602 //}}}
1603 //{{{ Propagation
1604
1605 // ----------------------------------------------------------------------------
1606 // Propagation should happen whenever one or more changes have been applied,
1607 // so that the impact of these changes on other parts of the configuration
1608 // can be fully assessed. The transaction keeps track of all the changes
1609 // to date and invokes appropriate node and property update handlers.
1610
1611 void
1612 CdlTransactionBody::propagate()
1613 {
1614 CYG_REPORT_FUNCNAME("CdlTransaction::propagate");
1615 CYG_REPORT_FUNCARG1XV(this);
1616 CYG_INVARIANT_THISC(CdlTransactionBody);
1617
1618 // Now it is time to worry about value and active changes.
1619 // Propagation may result in new entries, so only the
1620 // front item of one of the vectors is modified.
1621 while ((0 < value_changes.size()) || (0 < active_changes.size())) {
1622
1623 if (0 != value_changes.size()) {
1624
1625 CdlValuable valuable = value_changes.front();
1626 value_changes.pop_front();
1627
1628 // A value change may invalidate one or more solutions.
1629 // This happens during propagation rather than at the time
1630 // that the value is actually changed, so that multiple
1631 // solutions can be applied in one go.
1632 std::list<CdlConflict>::iterator conf_i, conf_j;
1633 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
1634 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1635 (*conf_i)->update_solution_validity(valuable);
1636 }
1637 for (conf_i = global_conflicts_with_solutions.begin();
1638 conf_i != global_conflicts_with_solutions.end();
1639 ) {
1640
1641 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1642 conf_j = conf_i++;
1643
1644 (*conf_j)->update_solution_validity(valuable);
1645 if (!(*conf_j)->has_known_solution()) {
1646 global_conflicts_with_solutions.erase(conf_j);
1647 }
1648 }
1649
1650 // If the valuable is no longer loaded then there is
1651 // no need to worry about propagation
1652 if (0 != valuable->get_toplevel()) {
1653
1654 // Inform the valuable itself about the update, so that
1655 // e.g. the value can be checked against legal_values
1656 valuable->update(this, CdlUpdate_ValueChange);
1657
1658 std::vector<CdlReferrer>& referrers = valuable->referrers;
1659 std::vector<CdlReferrer>::iterator ref_i;
1660 for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
1661 ref_i->update(this, valuable, CdlUpdate_ValueChange);
1662 }
1663 }
1664
1665 } else {
1666
1667 CdlNode node = active_changes.front();
1668 active_changes.pop_front();
1669
1670 if (0 != node->get_toplevel()) {
1671 node->update(this, CdlUpdate_ActiveChange);
1672
1673 std::vector<CdlReferrer>& referrers = node->referrers;
1674 std::vector<CdlReferrer>::iterator ref_i;
1675 for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
1676 ref_i->update(this, node, CdlUpdate_ActiveChange);
1677 }
1678 }
1679 }
1680 }
1681
1682 CYG_REPORT_RETURN();
1683 }
1684
1685 // ----------------------------------------------------------------------------
1686 bool
1687 CdlTransactionBody::is_propagation_required() const
1688 {
1689 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_propagation_required", "result %d");
1690 CYG_REPORT_FUNCARG1XV(this);
1691 CYG_PRECONDITION_THISC();
1692
1693 bool result = false;
1694
1695 if ((0 != value_changes.size()) || (0 != active_changes.size())) {
1696 result = true;
1697 }
1698
1699 CYG_REPORT_RETVAL(result);
1700 return result;
1701 }
1702
1703
1704 // ----------------------------------------------------------------------------
1705 void
1706 CdlTransactionBody::add_legal_values_change(CdlValuable valuable)
1707 {
1708 CYG_REPORT_FUNCNAME("CdlTransaction::add_legal_values_change");
1709 CYG_REPORT_FUNCARG2XV(this, valuable);
1710 CYG_PRECONDITION_THISC();
1711 CYG_PRECONDITION_CLASSC(valuable);
1712
1713 legal_values_changes.insert(valuable);
1714
1715 CYG_REPORT_RETURN();
1716 }
1717
1718 const std::set<CdlValuable>&
1719 CdlTransactionBody::get_legal_values_changes() const
1720 {
1721 CYG_REPORT_FUNCNAME("CdlTransaction::get_legal_values_changes");
1722 CYG_REPORT_FUNCARG1XV(this);
1723 CYG_PRECONDITION_THISC();
1724
1725 CYG_REPORT_RETURN();
1726 return legal_values_changes;
1727 }
1728
1729 //}}}
1730 //{{{ Cancel
1731
1732 // ----------------------------------------------------------------------------
1733 // Cancellation is straightforward, essentially it just involves clearing
1734 // out all of the STL containers. The transaction object can then be-used,
1735 // so fields like parent and toplevel must not change.
1736 void
1737 CdlTransactionBody::cancel()
1738 {
1739 CYG_REPORT_FUNCNAME("CdlTransaction::cancel");
1740 CYG_REPORT_FUNCARG1XV(this);
1741 CYG_INVARIANT_THISC(CdlTransactionBody);
1742
1743 // First take care of the cancel ops, if any, in case a cancel op
1744 // depends on some of the other transaction state.
1745 std::vector<CdlTransactionCommitCancelOp*>::reverse_iterator cancel_i;
1746 for (cancel_i = commit_cancel_ops.rbegin(); cancel_i != commit_cancel_ops.rend(); cancel_i++) {
1747 (*cancel_i)->cancel(this);
1748 delete *cancel_i;
1749 *cancel_i = 0;
1750 }
1751 commit_cancel_ops.clear();
1752
1753 this->changes.clear();
1754 std::list<CdlConflict>::iterator conf_i;
1755 for (conf_i = this->new_conflicts.begin(); conf_i != this->new_conflicts.end(); conf_i++) {
1756 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1757 delete *conf_i;
1758 }
1759 this->new_conflicts.clear();
1760 for (conf_i = this->new_structural_conflicts.begin(); conf_i != this->new_structural_conflicts.end(); conf_i++) {
1761 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1762 delete *conf_i;
1763 }
1764 this->new_structural_conflicts.clear();
1765
1766 this->deleted_structural_conflicts.clear();
1767 this->deleted_conflicts.clear();
1768
1769 // Any conflicts created and resolved during this transaction will
1770 // still be present in resolved_conflicts. Some global conflicts
1771 // may be there as well.
1772 std::vector<CdlConflict>::iterator conf_i2;
1773 for (conf_i2 = this->resolved_conflicts.begin(); conf_i2 != this->resolved_conflicts.end(); conf_i2++) {
1774 if (this == (*conf_i2)->transaction) {
1775 delete (*conf_i2);
1776 }
1777 }
1778 this->resolved_conflicts.clear();
1779
1780 // Any global conflicts which have been updated with a solution need
1781 // to have that solution cleared. Currently no attempt is made to
1782 // keep solutions valid for global conflicts.
1783 for (conf_i = this->global_conflicts_with_solutions.begin();
1784 conf_i != this->global_conflicts_with_solutions.end();
1785 conf_i++) {
1786
1787 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1788 (*conf_i)->clear_solution();
1789 }
1790 this->global_conflicts_with_solutions.clear();
1791
1792 this->activated.clear();
1793 this->deactivated.clear();
1794 this->legal_values_changes.clear();
1795 this->value_changes.clear();
1796 this->active_changes.clear();
1797
1798 CYG_REPORT_RETURN();
1799 }
1800
1801 //}}}
1802 //{{{ Commit
1803
1804 // ----------------------------------------------------------------------------
1805 // The commit operation. There are two main branches for this code. The
1806 // first branch deals with sub-transactions, and basically involves
1807 // transferring changes from the sub-transaction to the parent. It is
1808 // assumed that the sub-transaction has been fully propagated, so
1809 // data can just be transferred from the child to the parent.
1810 //
1811 // The second branch involves committing changes from a transaction to
1812 // the toplevel, invoking the transaction callback if necessary.
1813
1814 void
1815 CdlTransactionBody::commit()
1816 {
1817 CYG_REPORT_FUNCNAME("CdlTransaction::commit");
1818 CYG_REPORT_FUNCARG1XV(this);
1819 CYG_INVARIANT_THISC(CdlTransactionBody);
1820
1821 std::map<CdlValuable, CdlValue>::iterator map_i;
1822 std::list<CdlConflict>::iterator conf_i, conf_j;
1823 std::vector<CdlConflict>::const_iterator conf_i2, conf_j2;
1824 std::set<CdlNode>::iterator set_i, set_j, set_k;
1825 std::set<CdlValuable>::iterator set_i2, set_j2;
1826
1827 if (0 != parent) {
1828 // Any conflicts that were solved by the inference engine further
1829 // down are still resolved.
1830 // Great care has to be taken with conflict ownership. The following
1831 // cases have to be considered.
1832 // 1) the resolved conflict is global, its transaction is zero, this
1833 // conflict must only be destroyed if the toplevel transaction
1834 // is committed - at which time time the conflict should appear
1835 // on the deleted_conflicts lists.
1836 // 2) the conflict belongs to a higher level transaction, we have
1837 // recursed a certain amount trying to resolve it e.g. to explore
1838 // OR branches of the tree. Again the resolved conflict can only
1839 // be destroyed when the appropriate higher-level commit happens,
1840 // and should appear on the deleted conflicts list.
1841 // 3) the conflict was created and resolved further down the tree.
1842 // We are keeping it around for informational purposes only.
1843 // Associating it with this transaction allows the code to
1844 // distinguish this case from (1) and (2).
1845 for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
1846 CdlConflict conf = *conf_i2;
1847 CYG_LOOP_INVARIANT_CLASSC(conf);
1848 CYG_LOOP_INVARIANTC(parent->resolved_conflicts.end() == \
1849 std::find(parent->resolved_conflicts.begin(), \
1850 parent->resolved_conflicts.end(), conf));
1851 parent->resolved_conflicts.push_back(conf);
1852 parent->dirty = true;
1853 if (this == conf->transaction) {
1854 conf->transaction = parent;
1855 }
1856 }
1857 resolved_conflicts.clear();
1858
1859 // Any global conflicts for which solutions were found in the
1860 // sub-transaction still have solutions in the parent.
1861 for (conf_i = global_conflicts_with_solutions.begin(); conf_i != global_conflicts_with_solutions.end(); conf_i++) {
1862
1863 CdlConflict conf = *conf_i;
1864 CYG_LOOP_INVARIANT_CLASSC(conf);
1865
1866 // It is not clear that this search is actually useful, especially
1867 // given that the solution is currently stored with the conflict
1868 // rather than with the transaction.
1869 conf_j = std::find(parent->global_conflicts_with_solutions.begin(),
1870 parent->global_conflicts_with_solutions.end(),
1871 conf);
1872 if (conf_j == parent->global_conflicts_with_solutions.end()) {
1873 parent->global_conflicts_with_solutions.push_back(conf);
1874 parent->dirty = true;
1875 }
1876 }
1877 global_conflicts_with_solutions.clear();
1878
1879 // Now take care of deleted conflicts.
1880 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
1881 CdlConflict conf = *conf_i2;
1882 CYG_LOOP_INVARIANT_CLASSC(conf);
1883 // Possibilities to consider:
1884 // 1) the conflict may have been local to the parent transaction,
1885 // in which case it can be deleted.
1886 // 2) the conflict may have been created in a higher-level
1887 // transaction, in which case it has to be moved to the
1888 // parent's deleted_conflicts vector.
1889 // 3) the conflict may also have been global, again it needs
1890 // to be propagated into the parent's deleted_conflicts vector.
1891 //
1892 // But that is not the whole story. If this sub-transaction was
1893 // created specifically to resolve the conflict then the latter
1894 // should appear on the resolved vector and not be destroyed
1895 // immediately. This is true for both global and per-transaction
1896 // conflicts.
1897 //
1898 // For global conflicts it is also necessary to worry about
1899 // the global_conflicts_with_solutions list, that has to be
1900 // kept in synch with the rest of the world.
1901 conf_i = std::find(parent->new_conflicts.begin(), parent->new_conflicts.end(), conf);
1902 bool can_delete = false;
1903 if (conf_i != parent->new_conflicts.end()) {
1904 parent->new_conflicts.erase(conf_i);
1905 can_delete = true;
1906 } else {
1907 parent->deleted_conflicts.push_back(conf);
1908 }
1909 if (0 == conf->transaction) {
1910 conf_j = std::find(parent->global_conflicts_with_solutions.begin(),
1911 parent->global_conflicts_with_solutions.end(),
1912 conf);
1913 if (conf_j != parent->global_conflicts_with_solutions.end()) {
1914 parent->global_conflicts_with_solutions.erase(conf_j);
1915 }
1916 }
1917 if (conf == this->conflict) {
1918 // The conflict may have been fortuitously resolved lower down,
1919 // in which case it will have appeared in this->resolved_conflicts()
1920 // and copied already.
1921 conf_j2 = std::find(parent->resolved_conflicts.begin(), parent->resolved_conflicts.end(), conf);
1922 if (conf_j2 == parent->resolved_conflicts.end()) {
1923 parent->resolved_conflicts.push_back(conf);
1924 parent->dirty = true;
1925 }
1926 } else if (can_delete) {
1927 delete conf;
1928 }
1929 }
1930 // Unnecessary, but let's keep things clean.
1931 deleted_conflicts.clear();
1932
1933 // Deleted structural conflicts. For now the inference engine can do nothing with
1934 // these so they are a bit simpler.
1935 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
1936
1937 CdlConflict conf = *conf_i2;
1938 CYG_LOOP_INVARIANT_CLASSC(conf);
1939 conf_i = std::find(parent->new_structural_conflicts.begin(), parent->new_structural_conflicts.end(), conf);
1940 if (conf_i != parent->new_structural_conflicts.end()) {
1941 parent->new_structural_conflicts.erase(conf_i);
1942 delete conf;
1943 } else {
1944 parent->deleted_structural_conflicts.push_back(conf);
1945 }
1946 }
1947 deleted_structural_conflicts.clear();
1948
1949 // All value changes need to be propagated from the child to the parent.
1950 // Also, these value changes may invalidate existing solutions.
1951 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
1952 CYG_LOOP_INVARIANT_CLASSC(map_i->first);
1953 CYG_LOOP_INVARIANT_CLASSOC(map_i->second);
1954 parent->changes[map_i->first] = map_i->second;
1955
1956 for (conf_i = parent->new_conflicts.begin(); conf_i != parent->new_conflicts.end(); conf_i++) {
1957 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1958 (*conf_i)->update_solution_validity(map_i->first);
1959 }
1960 for (conf_i = parent->global_conflicts_with_solutions.begin();
1961 conf_i != parent->global_conflicts_with_solutions.end();
1962 ) {
1963
1964 conf_j = conf_i++;
1965 CYG_LOOP_INVARIANT_CLASSC(*conf_j);
1966
1967 (*conf_j)->update_solution_validity(map_i->first);
1968 if (!(*conf_j)->has_known_solution()) {
1969 parent->global_conflicts_with_solutions.erase(conf_j);
1970 }
1971 }
1972 }
1973 changes.clear();
1974
1975 // Continue propagating the conflicts.New conflicts can just
1976 // be added.
1977 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
1978 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1979 parent->new_conflicts.push_back(*conf_i);
1980 parent->dirty = true;
1981 (*conf_i)->transaction = parent;
1982 }
1983 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
1984 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1985 parent->new_structural_conflicts.push_back(*conf_i);
1986 parent->dirty = true;
1987 (*conf_i)->transaction = parent;
1988 }
1989 // The cancel operation at the end will delete new conflicts, so the
1990 // containers had better be cleared here.
1991 new_conflicts.clear();
1992 new_structural_conflicts.clear();
1993
1994
1995 // Also keep track of nodes that have become active or inactive.
1996 set_j = parent->activated.begin();
1997 for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
1998 set_j = parent->activated.insert(set_j, *set_i);
1999 set_k = parent->deactivated.find(*set_i);
2000 if (set_k != parent->deactivated.end()) {
2001 parent->deactivated.erase(set_k);
2002 }
2003 }
2004
2005 set_j = parent->deactivated.begin();
2006 for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2007 set_j = parent->deactivated.insert(set_j, *set_i);
2008 set_k = parent->activated.find(*set_i);
2009 if (set_k != parent->activated.end()) {
2010 parent->activated.erase(set_k);
2011 }
2012 }
2013 activated.clear();
2014 deactivated.clear();
2015
2016 // Keep track of other property changes.
2017 set_j2 = parent->legal_values_changes.begin();
2018 for (set_i2 = legal_values_changes.begin(); set_i2 != legal_values_changes.end(); set_i2++) {
2019 set_j2 = parent->legal_values_changes.insert(set_j2, *set_i2);
2020 }
2021 legal_values_changes.clear();
2022
2023 // Any pending commit/cancel ops needs to be transferred to the parent
2024 parent->commit_cancel_ops.insert(parent->commit_cancel_ops.end(),
2025 this->commit_cancel_ops.begin(), this->commit_cancel_ops.end());
2026 this->commit_cancel_ops.clear();
2027
2028 } else {
2029
2030 CYG_ASSERT_CLASSC(toplevel);
2031
2032 // If there is a registered callback function, it is necessary to fill
2033 // in the remaining fields of the all_changes callback structure. This
2034 // should happen before any conflicts get deleted. The actual callback
2035 // is invoked at the end, once all the changes have been moved to
2036 // the toplevel.
2037 CdlTransactionCallback all_changes;
2038 if (0 != callback_fn) {
2039
2040 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2041
2042 if (0 == map_i->first->get_toplevel()) {
2043 continue;
2044 }
2045 CdlValueFlavor flavor = map_i->second.get_flavor();
2046 const CdlValue& old_value = map_i->first->get_whole_value();
2047 CYG_LOOP_INVARIANTC(flavor == old_value.get_flavor());
2048 bool value_changed = false;
2049
2050 if (old_value.get_source() != map_i->second.get_source()) {
2051 all_changes.value_source_changes.push_back(map_i->first);
2052 }
2053 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2054 if (old_value.is_enabled() != map_i->second.is_enabled()) {
2055 value_changed = true;
2056 }
2057 }
2058 if (!value_changed && ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor))) {
2059 if (old_value.get_simple_value() != map_i->second.get_simple_value()) {
2060 value_changed = true;
2061 }
2062 }
2063 if (value_changed) {
2064 all_changes.value_changes.push_back(map_i->first);
2065 }
2066 }
2067 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2068 all_changes.new_conflicts.push_back(*conf_i);
2069 }
2070 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
2071 all_changes.new_structural_conflicts.push_back(*conf_i);
2072 }
2073 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
2074 CdlNode node = (*conf_i2)->get_node();
2075 CYG_LOOP_INVARIANT_CLASSC(node);
2076
2077 all_changes.nodes_with_resolved_conflicts.push_back(node);
2078 }
2079 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
2080 CdlNode node = (*conf_i2)->get_node();
2081 CYG_LOOP_INVARIANT_CLASSC(node);
2082
2083 all_changes.nodes_with_resolved_structural_conflicts.push_back(node);
2084 }
2085 for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
2086 if (0 != (*set_i)->get_toplevel()) {
2087 all_changes.active_changes.push_back(*set_i);
2088 }
2089 }
2090 for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2091 if (0 != (*set_i)->get_toplevel()) {
2092 all_changes.active_changes.push_back(*set_i);
2093 }
2094 }
2095 for (set_i2 = legal_values_changes.begin(); set_i2 != legal_values_changes.end(); set_i2++) {
2096 if (0 != (*set_i)->get_toplevel()) {
2097 all_changes.legal_values_changes.push_back(*set_i2);
2098 }
2099 }
2100 legal_values_changes.clear();
2101 }
2102
2103 // All new values need to be installed in the appropriate valuable.
2104 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2105 CYG_LOOP_INVARIANT_CLASSC(map_i->first);
2106 CYG_LOOP_INVARIANT_CLASSOC(map_i->second);
2107 map_i->first->value = map_i->second;
2108 }
2109 changes.clear();
2110
2111 // Sort out the conflicts. New conflicts can just be added, although
2112 // care has to be taken to clear state - currently no attempt is
2113 // made to check solution validity for global conflicts.
2114 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2115 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2116 toplevel->conflicts.push_back(*conf_i);
2117 (*conf_i)->transaction = 0;
2118 (*conf_i)->clear_solution();
2119 }
2120 new_conflicts.clear();
2121 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
2122 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2123 toplevel->structural_conflicts.push_back(*conf_i);
2124 (*conf_i)->transaction = 0;
2125 (*conf_i)->clear_solution();
2126 }
2127 new_structural_conflicts.clear();
2128
2129 // Resolved conflicts can be either global or per-transaction
2130 // ones. If the former then the conflict will also be present
2131 // in deleted_conflicts and will get deleted shortly.
2132 for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
2133 CYG_LOOP_INVARIANT_CLASSC(*conf_i2);
2134 if (0 != (*conf_i2)->transaction) {
2135 delete *conf_i2;
2136 }
2137 }
2138 resolved_conflicts.clear();
2139
2140 // Now process conflicts that have gone away. These must actually
2141 // be deleted.
2142 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
2143 CYG_LOOP_INVARIANT_CLASSC(*conf_i2);
2144 std::list<CdlConflict>::iterator tmp;
2145 tmp = std::find(toplevel->conflicts.begin(), toplevel->conflicts.end(), *conf_i2);
2146 CYG_LOOP_INVARIANTC(tmp != toplevel->conflicts.end());
2147 toplevel->conflicts.erase(tmp);
2148 delete *conf_i2;
2149 }
2150 deleted_conflicts.clear();
2151 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
2152 CYG_LOOP_INVARIANT_CLASSC(*conf_i2);
2153 std::list<CdlConflict>::iterator tmp;
2154 tmp = std::find(toplevel->structural_conflicts.begin(), toplevel->structural_conflicts.end(), *conf_i2);
2155 CYG_LOOP_INVARIANTC(tmp != toplevel->structural_conflicts.end());
2156 toplevel->structural_conflicts.erase(tmp);
2157 delete *conf_i2;
2158 }
2159 deleted_structural_conflicts.clear();
2160
2161 // Any global conflicts with solutions need to have their solutions cleared,
2162 // since currently no attempt is made to preserve their accuracy.
2163 for (conf_i = global_conflicts_with_solutions.begin(); conf_i != global_conflicts_with_solutions.end(); conf_i++) {
2164 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2165 (*conf_i)->clear_solution();
2166 }
2167 global_conflicts_with_solutions.clear();
2168
2169 for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
2170 (*set_i)->active = true;
2171 }
2172 for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2173 (*set_i)->active = false;
2174 }
2175 activated.clear();
2176 deactivated.clear();
2177
2178 // Invoke all pending commit operations
2179 std::vector<CdlTransactionCommitCancelOp*>::iterator commit_i;
2180 for (commit_i = commit_cancel_ops.begin(); commit_i != commit_cancel_ops.end(); commit_i++) {
2181 (*commit_i)->commit(this);
2182 delete *commit_i;
2183 *commit_i = 0;
2184 }
2185 commit_cancel_ops.clear();
2186
2187 // Finally take care of the callback.
2188 if (0 != callback_fn) {
2189 (*callback_fn)(all_changes);
2190 }
2191 }
2192
2193 CYG_REPORT_RETURN();
2194 }
2195
2196 //}}}
2197 //{{{ Solution support
2198
2199 // ----------------------------------------------------------------------------
2200 // Saving a solution basically involves remembering what changes took place
2201 // in the corresponding sub-transaction. There is no need to worry about
2202 // other data in the sub-transaction such as conflicts, because there
2203 // are no actual value changes.
2204
2205 void
2206 CdlTransactionBody::save_solution()
2207 {
2208 CYG_REPORT_FUNCNAME("CdlTransaction::save_solution");
2209 CYG_REPORT_FUNCARG1XV(this);
2210 CYG_PRECONDITION_THISC();
2211 // Solutions should only be applicable to sub-transactions immediately
2212 // below the main transaction, since that is the only level at which
2213 // inference callbacks occur
2214 CYG_PRECONDITIONC((0 != parent) && (0 == parent->parent));
2215
2216 CYG_PRECONDITION_CLASSC(conflict);
2217 CYG_PRECONDITIONC(0 == conflict->solution.size());
2218
2219 std::map<CdlValuable, CdlValue>::const_iterator map_i;
2220 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2221 // If the valuable was calculated or is otherwise non-modifiable,
2222 // there is no point in storing it with the solution since the
2223 // information is unlikely to be of interest to the user.
2224 CdlValuable valuable = map_i->first;
2225 if (valuable->is_modifiable()) {
2226 conflict->solution.push_back(*map_i);
2227 }
2228 }
2229
2230 // save_solution() should operate like commit() or cancel(), i.e.
2231 // it leaves an empty sub-transaction. This sub-transaction cannot
2232 // actually be re-used at present because it still references a
2233 // conflict for which a solution is now already in place, but that
2234 // may get cleaned up in future.
2235 this->cancel();
2236 CYG_REPORT_RETURN();
2237 }
2238
2239 // ----------------------------------------------------------------------------
2240 // Can a solution be applied without e.g. overwriting a user value with
2241 // an inferred value. There is a setting inference_override which controls
2242 // this.
2243 bool
2244 CdlTransactionBody::user_confirmation_required() const
2245 {
2246 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::user_confirmation_required", "result %d");
2247 CYG_REPORT_FUNCARG1XV(this);
2248 CYG_PRECONDITION_THISC();
2249 CYG_PRECONDITION_CLASSC(this->parent);
2250
2251 bool result = false;
2252
2253 std::map<CdlValuable, CdlValue>::const_iterator val_i;
2254 for (val_i = changes.begin(); val_i != changes.end(); val_i++) {
2255 const CdlValue& old_value = parent->get_whole_value(val_i->first);
2256 if (old_value.get_source() > CdlTransactionBody::inference_override) {
2257 result = true;
2258 break;
2259 }
2260 }
2261
2262 CYG_REPORT_RETVAL(result);
2263 return result;
2264 }
2265
2266 // ----------------------------------------------------------------------------
2267 // The inference engine is considering modifying a particular valuable. If
2268 // the user has explicitly changed this valuable during the transaction then
2269 // it would be inappropriate to suggest changing it again.
2270 bool
2271 CdlTransactionBody::changed_by_user(CdlValuable valuable) const
2272 {
2273 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::changed_by_user", "result %d");
2274 CYG_REPORT_FUNCARG2XV(this, valuable);
2275 CYG_PRECONDITION_THISC();
2276 CYG_PRECONDITION_CLASSC(valuable);
2277
2278 bool result = false;
2279 std::map<CdlValuable, CdlValue>::const_iterator change_i = changes.find(valuable);
2280 if (change_i != changes.end()) {
2281 CdlValueSource source = change_i->second.get_source();
2282 if (CdlValueSource_User == source) {
2283 result = true;
2284 }
2285 }
2286 if (!result && (0 != parent)) {
2287 result = parent->changed_by_user(valuable);
2288 }
2289
2290 CYG_REPORT_RETVAL(result);
2291 return result;
2292 }
2293
2294 // ----------------------------------------------------------------------------
2295 // A variant which takes into account the hierarchy: disabling a container
2296 // when a sub-node has just been changed by the user is also a no-no.
2297 bool
2298 CdlTransactionBody::subnode_changed_by_user(CdlContainer container) const
2299 {
2300 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::subnode_changed_by_user", "result %d");
2301 CYG_REPORT_FUNCARG2XV(this, container);
2302 CYG_PRECONDITION_THISC();
2303 CYG_PRECONDITION_CLASSC(container);
2304
2305 bool result = false;
2306
2307 const std::vector<CdlNode>& contents = container->get_contents();
2308 std::vector<CdlNode>::const_iterator node_i;
2309 for (node_i = contents.begin(); node_i != contents.end(); node_i++) {
2310 CdlValuable valuable = dynamic_cast<CdlValuable>(*node_i);
2311 if ((0 != valuable) && this->changed_by_user(valuable)) {
2312 result = true;
2313 break;
2314 }
2315 CdlContainer container = dynamic_cast<CdlContainer>(*node_i);
2316 if ((0 != container) && this->subnode_changed_by_user(container)) {
2317 result = true;
2318 break;
2319 }
2320 }
2321
2322 CYG_REPORT_RETVAL(result);
2323 return result;
2324 }
2325
2326 // ----------------------------------------------------------------------------
2327 // Is one solution preferable to another? This code assumes that
2328 // user_confirmation_required() and changed_by_user() have already
2329 // been considered, so the only issue at stake here is the changes
2330 // themselves.
2331 //
2332 // For now a simple metric of the number of changes is used. A more
2333 // intelligent approach would take into account how much of the
2334 // hierarchy is affected, e.g. how many other items would end
2335 // up being disabled. Arguably the calling code should be able to
2336 // supply an additional weighting.
2337
2338 bool
2339 CdlTransactionBody::is_preferable_to(CdlTransaction other) const
2340 {
2341 CYG_REPORT_FUNCNAMETYPE("CdlTransactionBody::preferable_to", "result %d");
2342 CYG_REPORT_FUNCARG2XV(this, other);
2343 CYG_PRECONDITION_THISC();
2344 CYG_PRECONDITION_CLASSC(other);
2345 CYG_PRECONDITIONC(this != other);
2346
2347 bool result = false;
2348 if (this->changes.size() < other->changes.size()) {
2349 result = true;
2350 }
2351
2352 CYG_REPORT_RETVAL(result);
2353 return result;
2354 }
2355
2356 // ----------------------------------------------------------------------------
2357 // Applying solutions. Multiple solutions can be applied in one go. If there
2358 // is any overlap, tough. Propagation needs to happen after solutions are
2359 // applied.
2360
2361 void
2362 CdlTransactionBody::apply_solution(CdlConflict conflict)
2363 {
2364 CYG_REPORT_FUNCNAME("CdlTransaction::apply_solution");
2365 CYG_REPORT_FUNCARG2XV(this, conflict);
2366 CYG_PRECONDITION_THISC();
2367 CYG_PRECONDITION_CLASSC(conflict);
2368
2369 // The solution can be for either a per-transaction conflict
2370 // or a global one. There are two lists to search.
2371 std::list<CdlConflict>::const_iterator conf_i;
2372 conf_i = std::find(this->new_conflicts.begin(), this->new_conflicts.end(), conflict);
2373 if (conf_i == this->new_conflicts.end()) {
2374 conf_i = std::find(this->global_conflicts_with_solutions.begin(),
2375 this->global_conflicts_with_solutions.end(),
2376 conflict);
2377 CYG_ASSERTC(conf_i != this->global_conflicts_with_solutions.end());
2378 }
2379
2380 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2381 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2382 CdlValuable valuable = val_i->first;
2383 CYG_LOOP_INVARIANT_CLASSC(valuable);
2384
2385 const CdlValue& old_value = this->get_whole_value(valuable);
2386 this->set_whole_value(valuable, old_value, val_i->second);
2387 }
2388
2389 CYG_REPORT_RETURN();
2390 }
2391
2392 void
2393 CdlTransactionBody::apply_solutions(const std::vector<CdlConflict>& solutions)
2394 {
2395 CYG_REPORT_FUNCNAME("CdlTransaction::apply_solutions");
2396 CYG_REPORT_FUNCARG1XV(this);
2397 CYG_PRECONDITION_THISC();
2398
2399 std::vector<CdlConflict>::const_iterator conf_i;
2400 for (conf_i = solutions.begin(); conf_i != solutions.end(); conf_i++) {
2401
2402 std::list<CdlConflict>::const_iterator conf_j;
2403 conf_j = std::find(this->new_conflicts.begin(), this->new_conflicts.end(), conflict);
2404 if (conf_j == this->new_conflicts.end()) {
2405 conf_j = std::find(this->global_conflicts_with_solutions.begin(),
2406 this->global_conflicts_with_solutions.end(),
2407 conflict);
2408 CYG_ASSERTC(conf_j != this->global_conflicts_with_solutions.end());
2409 }
2410
2411 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2412 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2413 CdlValuable valuable = val_i->first;
2414 CYG_LOOP_INVARIANT_CLASSC(valuable);
2415 const CdlValue& old_value = this->get_whole_value(valuable);
2416 this->set_whole_value(valuable, old_value, val_i->second);
2417 }
2418 }
2419
2420 CYG_REPORT_RETURN();
2421 }
2422
2423 void
2424 CdlTransactionBody::apply_all_solutions()
2425 {
2426 CYG_REPORT_FUNCNAME("CdlTransaction::apply_all_solutions");
2427 CYG_REPORT_FUNCARG1XV(this);
2428 CYG_PRECONDITION_THISC();
2429
2430 std::list<CdlConflict>::const_iterator conf_i;
2431 for (conf_i = this->new_conflicts.begin(); conf_i != this->new_conflicts.end(); conf_i++) {
2432 if ((*conf_i)->has_known_solution()) {
2433
2434 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2435 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2436 CdlValuable valuable = val_i->first;
2437 CYG_LOOP_INVARIANT_CLASSC(valuable);
2438 const CdlValue& old_value = this->get_whole_value(valuable);
2439 this->set_whole_value(valuable, old_value, val_i->second);
2440 }
2441 }
2442 }
2443 for (conf_i = this->global_conflicts_with_solutions.begin();
2444 conf_i != this->global_conflicts_with_solutions.end();
2445 conf_i++) {
2446
2447 CYG_ASSERTC((*conf_i)->has_known_solution());
2448
2449 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2450 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2451 CdlValuable valuable = val_i->first;
2452 CYG_LOOP_INVARIANT_CLASSC(valuable);
2453 const CdlValue& old_value = this->get_whole_value(valuable);
2454 this->set_whole_value(valuable, old_value, val_i->second);
2455 }
2456 }
2457
2458 CYG_REPORT_RETURN();
2459 }
2460
2461 //}}}
2462 //{{{ Inference
2463
2464 // ----------------------------------------------------------------------------
2465 //{{{ resolve() - all per-transaction conflicts
2466
2467 void
2468 CdlTransactionBody::resolve(int level)
2469 {
2470 CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2471 CYG_REPORT_FUNCARG2XV(this, level);
2472 CYG_PRECONDITION_THISC();
2473
2474 while(1) {
2475 // Resolving one conflict may affect others, so iterating down the list
2476 // is not safe. Instead we need to loop as long as there are conflicts
2477 // to be considered.
2478 std::list<CdlConflict>::iterator conf_i;
2479 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2480 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2481
2482 // Is there any point in attempt to resolve this conflict?
2483 if ((*conf_i)->has_known_solution() ||
2484 (*conf_i)->has_no_solution() ||
2485 !(*conf_i)->resolution_implemented()) {
2486 continue;
2487 }
2488 this->resolve(*conf_i, level);
2489 break;
2490 }
2491 if (conf_i == new_conflicts.end()) {
2492 break;
2493 }
2494 }
2495
2496 CYG_REPORT_RETURN();
2497 }
2498
2499 //}}}
2500 //{{{ resolve() - vector
2501
2502 // ----------------------------------------------------------------------------
2503 void
2504 CdlTransactionBody::resolve(const std::vector<CdlConflict>& conflicts, int level)
2505 {
2506 CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2507 CYG_REPORT_FUNCARG2XV(this, level);
2508 CYG_PRECONDITION_THISC();
2509
2510 std::vector<CdlConflict>::const_iterator conf_i;
2511 for (conf_i = conflicts.begin(); conf_i != conflicts.end(); conf_i++) {
2512 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2513
2514 // Is there any point in attempt to resolve this conflict?
2515 if (!(*conf_i)->has_known_solution() &&
2516 !(*conf_i)->has_no_solution() &&
2517 (*conf_i)->resolution_implemented()) {
2518 this->resolve(*conf_i, level);
2519 }
2520 }
2521
2522 CYG_REPORT_RETURN();
2523 }
2524
2525 //}}}
2526 //{{{ resolve() - single conflict
2527
2528 // ----------------------------------------------------------------------------
2529 // There is a conflict that may have a solution. The resolution
2530 // attempt needs to happen in the context of a sub-transaction
2531 //
2532 // The conflict may have been created during this transaction,
2533 // or it may be a global conflict left over from a previous
2534 // transaction. This can be detected using the conflict's
2535 // transaction field. The commit() code, amongst others, needs
2536 // to handle global and per-transaction conflicts differently.
2537
2538 void
2539 CdlTransactionBody::resolve(CdlConflict conflict, int level)
2540 {
2541 CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2542 CYG_REPORT_FUNCARG3XV(this, conflict, level);
2543 CYG_PRECONDITION_THISC();
2544 CYG_PRECONDITION_CLASSC(conflict);
2545 CYG_PRECONDITIONC(0 == conflict->solution.size());
2546 CYG_PRECONDITIONC((0 <= level) && (level <= inference_recursion_limit));
2547
2548 CdlTransaction sub_transaction = this->make(conflict);
2549 CYG_PRECONDITION_CLASSC(sub_transaction);
2550 if (!conflict->inner_resolve(sub_transaction, level)) {
2551 CYG_ASSERTC(0 == sub_transaction->changes.size());
2552 sub_transaction->cancel();
2553 delete sub_transaction;
2554 conflict->no_solution = true;
2555 CYG_REPORT_RETURN();
2556 return;
2557 }
2558 // Is the inference engine lying? The conflict should be resolved
2559 // in the sub-transaction.
2560 if (conflict->is_structural()) {
2561 if (std::find(sub_transaction->deleted_structural_conflicts.begin(),
2562 sub_transaction->deleted_structural_conflicts.end(),
2563 conflict) == sub_transaction->deleted_structural_conflicts.end()) {
2564
2565 CYG_FAIL("The inference engine has proved too optimistic.");
2566 sub_transaction->cancel();
2567 delete sub_transaction;
2568 conflict->no_solution = true;
2569 CYG_REPORT_RETURN();
2570 return;
2571 }
2572 } else {
2573 if (std::find(sub_transaction->deleted_conflicts.begin(), sub_transaction->deleted_conflicts.end(), conflict)
2574 == sub_transaction->deleted_conflicts.end()) {
2575
2576 CYG_FAIL("The inference engine has proved too optimistic.");
2577 sub_transaction->cancel();
2578 delete sub_transaction;
2579 conflict->no_solution = true;
2580 CYG_REPORT_RETURN();
2581 return;
2582 }
2583 }
2584
2585 // Even if there is a solution it cannot always be applied
2586 // automatically because that would affect existing user
2587 // values. Instead the solution needs to be saved so that
2588 // the user can inspect it later. This should only happen
2589 // at level 0. If we have recursed into the inference
2590 // engine then we should only worry about this right at
2591 // the end, not at every stage (although internally the
2592 // inference code may worry about this when choosing
2593 // between alternatives).
2594 if ((0 == level) && sub_transaction->user_confirmation_required()) {
2595 sub_transaction->save_solution();
2596 sub_transaction->cancel();
2597 delete sub_transaction;
2598 this->dirty = true;
2599
2600 if (0 == conflict->transaction) {
2601 // This is a global conflict, not a per-transaction one.
2602 // There is a separate list of these conflicts.
2603 std::list<CdlConflict>::const_iterator conf_i;
2604 conf_i = std::find(this->global_conflicts_with_solutions.begin(),
2605 this->global_conflicts_with_solutions.end(),
2606 conflict);
2607 if (conf_i == this->global_conflicts_with_solutions.end()) {
2608 this->global_conflicts_with_solutions.push_back(conflict);
2609 }
2610 }
2611 } else {
2612
2613 // This sub-transaction is safe, it can be applied
2614 // immediately. The commit code detects that the
2615 // solution being committed is for a particular
2616 // resolved conflict and will take care of moving that
2617 // conflict to the resolved list.
2618 conflict->solution_references.clear(); // No point in preserving this information
2619 conflict->no_solution = false; // Redundant
2620 std::map<CdlValuable, CdlValue>::const_iterator soln_i;
2621 for (soln_i = sub_transaction->changes.begin(); soln_i != sub_transaction->changes.end(); soln_i++) {
2622 conflict->solution.push_back(*soln_i);
2623 }
2624 sub_transaction->commit();
2625 delete sub_transaction;
2626 }
2627
2628 CYG_REPORT_RETURN();
2629 }
2630
2631 //}}}
2632 //{{{ resolve_recursion()
2633
2634 // ----------------------------------------------------------------------------
2635 // resolve_recursion()
2636 //
2637 // The inference engine has tried one or more changes in the context of
2638 // a sub-transaction. It is now necessary to check whether these changes
2639 // are beneficial, i.e. whether or not any new problems are introduced
2640 // that cannot be resolved.
2641 bool
2642 CdlTransactionBody::resolve_recursion(int level)
2643 {
2644 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::resolve_recursion", "result %d");
2645 CYG_REPORT_FUNCARG2XV(this, level);
2646 CYG_PRECONDITION_THISC();
2647
2648 bool result = false;
2649 this->propagate();
2650 if (0 == new_conflicts.size()) {
2651 result = true;
2652 CYG_REPORT_RETVAL(result);
2653 return result;
2654 }
2655 if (level >= inference_recursion_limit) {
2656 result = false;
2657 CYG_REPORT_RETVAL(result);
2658 return result;
2659 }
2660
2661 // There are new conflicts, but it may be possible to resolve them
2662 // by a recursive invocation of the inference engine.
2663 bool solutions_possible = false;
2664 do {
2665 this->resolve(level + 1);
2666 std::list<CdlConflict>::const_iterator conf_i;
2667 solutions_possible = false;
2668 for (conf_i = this->new_conflicts.begin(); conf_i != this->new_conflicts.end(); conf_i++) {
2669 if (!(*conf_i)->has_no_solution()) {
2670 solutions_possible = true;
2671 }
2672 }
2673 } while(solutions_possible);
2674
2675 result = (0 == new_conflicts.size());
2676 CYG_REPORT_RETVAL(result);
2677 return result;
2678 }
2679
2680 //}}}
2681
2682 //}}}
2683 //{{{ Body
2684
2685 // ----------------------------------------------------------------------------
2686 // The majority of transactions involve the same set of steps. First one
2687 // or more values are modified. Then there has to be propagation, inference,
2688 // an inference callback, ... There may be a number of iterations. It is
2689 // convenient to have a single transaction body function which takes care
2690 // of all of that.
2691 //
2692 // If automatic inference is disabled then life is pretty simple, there
2693 // should be one propagate() operation followed by a commit.
2694 //
2695 // If automatic inference is enabled but there is no inference callback
2696 // then we need a loop consisting of propagation and inference, while
2697 // progress is made. Progress can be detected by value changes.
2698 //
2699 // If there is an inference callback then life gets pretty complicated.
2700 // The problem is figuring out exactly when the inference callback
2701 // should be invoked:
2702 //
2703 // 1) any new conflicts should certainly result in a callback, to give
2704 // the user a chance to cancel the changes.
2705 // 2) any new solutions that have been applied automatically need to
2706 // be shown to the user, again so that it is possible to cancel
2707 // the changes.
2708 // 3) any existing conflicts with a new solution, albeit one that cannot
2709 // be applied automatically, should result in a callback. This is
2710 // somewhat problematical since the new solution may in fact be
2711 // identical to a previous one that the user has already decided
2712 // against committing.
2713 //
2714 // It is not easy to keep track of when new conflicts or solutions get
2715 // added to a transaction. Simply counting the entries in the
2716 // appropriate STL containers is insufficient, as conflicts come and
2717 // go. Instead it is necessary to have a "dirty" flag. Unfortunately
2718 // this too is not fool-proof: a new conflict may have been created,
2719 // resulting in the dirty flag being set, and then the conflict may
2720 // have disappeared.
2721
2722 void
2723 CdlTransactionBody::body()
2724 {
2725 CYG_REPORT_FUNCNAME("CdlTransaction::body");
2726 CYG_REPORT_FUNCARG1XV(this);
2727 CYG_PRECONDITION_THISC();
2728
2729 // The Body() member function can only be applied to a toplevel
2730 // transaction, it does not really make sense to apply it to
2731 // a sub-transaction (at least, not yet);
2732 CYG_PRECONDITIONC((0 == parent) && (0 != toplevel));
2733
2734 if (!inference_enabled) {
2735 this->propagate();
2736 this->commit();
2737 CYG_REPORT_RETURN();
2738 return;
2739 }
2740
2741 if (0 == inference_callback) {
2742 bool progress = false;
2743 do {
2744 progress = false;
2745 this->propagate();
2746 CYG_LOOP_INVARIANTC(0 == value_changes.size());
2747 this->resolve();
2748 if (0 != value_changes.size()) {
2749 progress = true;
2750 }
2751 } while(progress);
2752
2753 this->commit();
2754 CYG_REPORT_RETURN();
2755 return;
2756 }
2757
2758 bool cancel = false;
2759
2760 unsigned int resolved_size = 0;
2761 unsigned int globals_with_solutions_size = 0;
2762
2763 do {
2764 bool progress = false;
2765 do {
2766 progress = false;
2767 this->propagate();
2768 CYG_LOOP_INVARIANTC(0 == value_changes.size());
2769 this->resolve();
2770 if (0 != value_changes.size()) {
2771 progress = true;
2772 }
2773 } while(progress);
2774
2775 // Sanity check: if there are no conflicts and no new entries in
2776 // the resolved vector, then stop here. The user has already seen
2777 // and taken care of everything of interest.
2778 if ((0 == new_conflicts.size()) &&
2779 (resolved_size == resolved_conflicts.size()) &&
2780 (globals_with_solutions_size == global_conflicts_with_solutions.size())) {
2781 cancel = false;
2782 break;
2783 }
2784
2785 // Also, if no conflicts have been added, no new solutions
2786 // have been identified, and no new solutions have been applied,
2787 // then there is no point in asking for user feedback.
2788 if (!this->dirty) {
2789 cancel = false;
2790 break;
2791 }
2792
2793 // Clear state before invoking the callback. If the user does not
2794 // change anything else then we should get out of the loop next
2795 // time around.
2796 this->dirty = false;
2797 resolved_size = resolved_conflicts.size();
2798 globals_with_solutions_size = global_conflicts_with_solutions.size();
2799
2800 // Invoke the callback. If the result is cancel, do so. Otherwise
2801 // we need to spin while things are changing.
2802 if (CdlInferenceCallbackResult_Cancel == (*inference_callback)(this)) {
2803 cancel = true;
2804 }
2805 } while(!cancel);
2806
2807 if (cancel) {
2808 this->cancel();
2809 } else {
2810 this->commit();
2811 }
2812
2813 CYG_REPORT_RETURN();
2814 }
2815
2816 //}}}
2817