March 2, 2012 Short Description: Fixed crash creating an Exchange in large-series models Bug Number: 5168 Release notes (y/n): Yes (6.1.4) For Release Nums: 6.2 and 6.1.4 Gnats 5168: Crash creating an Exchange: recursion stack overflow. When an Exchange receives a "slot changed" notification for either its source balance or destination balance slots, the subsequent timesteps in that slot are now recomputed (solved) using ITERATION rather than RECURSION. When this occurs at a time when the SeriesSlot::setAllValues method is active on that slot, the "iteration" over the subsequent timesteps is limited to just one timestep. The Exchange's 'apply_edit' method's use of SeriesSlot::setAllValues (for the source balance and destination balance slots) is now made to iterate FORWARD rather than BACKWARDS through the slot's time series. Modified Files: Accounting/Exchange.hpp Accounting/Exchange.cpp Accounting/PassThroughAccount.cpp (**) Sim/SeriesSlot.hpp Sim/SeriesSlot.cpp Sim/SeriesSlot.DMI.cpp Q3GUI/SlotQtDlg.cpp (**) (**)-NOTE: Only these two files have diverged from 6.1 in 6.2 development. ----------------------- Accounting/Exchange.hpp Accounting/Exchange.cpp ----------------------- Method Exchange::slotChanged (const Date_Time*, const Slot* ...) invokes various "solve" methods, depending on which role the specified slot plays within the Exchange. Calls to these two methods: (1) solve_next_source_balance (const Date_Time*) (2) solve_next_dest_balance (const Date_Time*) ... have been replaced with calls to these two new methods: (1) solve_subsequent_source_balances (const Date_Time *when); (2) solve_subsequent_dest_balances (const Date_Time *when); ... These new methods iterate over the remaining timesteps within the relevant series to call the original methods. When these two new "solve_subsequent_" are active, recursive calls into them abort immediately (to allow the iteration which is already in progress to do the required processing). Also: removed some unused Slot* parameters from several "solve" methods. ---------------------- Sim/SeriesSlot.hpp Sim/SeriesSlot.cpp ---------------------- The SeriesSlot::setAllValues() method iterates through all the values in the SeriesSlot's series, and re-assigns existing values -- only to force the side-effects of that operation. It's called only in a handful of places (see below). It had previously, internally determined whether the iteration should proceed forwards or backwards through the series -- somewhat arbitrarily iterating backwards for (and only for) Accounting slots. This has been changed. The direction of the iteration is now specified as a parameter: void setAllValues (bool forward); This method now called from, with the indicated 'forward' parameter: (1) void Exchange::apply_edit(Exchange *copy) _sourceBalance.setAllValues (true); // forward _destBalance.setAllValues (true); // forward (2) void PassThroughAccount::storageAllowed(bool allowed) _storage.setAllValues (false); // not forward (3) void SlotQtDlg::importSlot (bool doResizeSlot, bool onlySelected) const bool forward = !impSerSlot->hasAttribute (Slot::AccountingSlotBits); impSerSlot->setAllValues (forward); (4) bool SeriesSlot::dmiImport(slotControl *s_ctl) // Set all the values so they propagate. const bool forward = !hasAttribute(AccountingSlotBits); setAllValues (forward); ALSO, in SeriesSlot::setAllValues(), a publicly readable flag is set on the SeriesSlot indicating that this method is running: bool _setAllValues_inProgress; bool setAllValues_inProgress() const { return _setAllValues_inProgress; } --------------------------------- Accounting/PassThroughAccount.cpp Q3GUI/SlotQtDlg.cpp Sim/SeriesSlot.DMI.cpp --------------------------------- Added "forward" parameter value in calls to SeriesSlot::setAllValues(). See above. ---