Mercurial > ecos
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 |
