Delta States


One or more bulletin boards are grouped to allow the user to move back and forth through modeler changes in larger moves than from bulletin board to bulletin board.

When the application calls api_note_state, all bulletin boards made since the previous call to api_note_state (or since logging was first turned on) are returned in a delta state as shown in the following figure.

Figure. Delta State Structure

The current delta state is the delta state that is being built. This delta state is open. When api_note_state is called, the current delta state is closed and becomes the active delta state.

The active delta state is the most recently closed delta state made by calling api_note_state. Also, rolling to a particular delta state makes that state the active delta state. This state is active in the sense that it represents the state of the model directly after roll or calling api_note_state (before construction of a new delta state begins).

The delta state contains a pointer to the first in a list of singly-linked bulletin boards. Each bulletin board contains a pointer to the next bulletin board in the chain only.

The delta state holds two state identifiers that refer to the current (Prev DS) state and to the next (Next DS) state. State identifiers are internal modeler state names that are created when a state is noted. Each modeler state is expressed as a unique integer.

To permit the user to move between modeler states, the application must remember the delta states returned to it.

Note: The "next" state pointer in the model is with respect to roll back, as in "the state obtained when rolling the model back one step." Likewise, the "previous" state references "the last state obtained before rolling the model back."

Rolling to Delta States

Moving to a state means "make the model data structure the same as it was when the state was noted." To move to any state, call api_change_to_state with the desired state as an argument. To move to modeler state 1, you can call api_change_to_state with delta state 1 as an argument. api_change_to_state is a read/write function that changes the model; it does not create bulletins or a bulletin board because they already exist in the delta state.

    

Figure. Rolling to Delta States

In a nonlinear or branching case, a delta state can have an additional partner delta state pointer. The partner pointer is part of circular linked list of states branching from the same state. The partner pointer is always set; if there is no other branch, the pointer points to itself.

The only way to reliably get backward or forward to a given state is to give it a name and remember that name, or to remember its pointer. This is then used as the argument in the roll function.

Rolling the model backward presents no problems or additional overhead to the application developer. However, because branching is permitted in the delta states, roll forward could present an ambiguous situation. How does ACIS know which state is referenced when a roll forward is requested? It does not. If the state is important, either the pointer or the name of a given state has to be remembered (For example, api_note_state).

The delete_if_empty argument in api_note_state allows the caller to remove a delta state that contains no bulletins. So if this argument is set TRUE, some code may need to be modified to account for deleted empty states, for example, code that relies on a particular number of states on a stream.

Use the partner delta state pointer to branch to the various delta states. The partner list is a circular linked list of delta states all having the same previous state. Traversing into the various branch delta states uses this circular partner list, not just the next delta state pointer. When a branch of the history is pruned, the partner delta state pointers are also updated.

When experimenting with roll backward S-steps and roll forward S+n-steps with a state having branches, you may experience unwanted side effects. Specifically, there may be a difference between what happens when rolling backward to a branch state and then "blindly rolling forward," and what happens when rolling backward past the branch state and then blindly rolling forward. It is the "blindly rolling forward" and the ambiguities in the branch state which have the potential for difficulties. The solution is to not blindly roll forward, but rather to note the delta states of importance beforehand and then to explicitly roll to those states.

Integer identifiers, unique to a given history stream, can be requested for each entity. These IDs remain constant through roll, save and restore (with APIs api_save_history and api_restore_history). An entity can be returned from a given ID when the entity is alive in the active state of the history stream. NULL is returned when the entity is not alive.

The format of ENTITY and HISTORY_STREAM records accommodates the addition of entity IDs. An integer field in the entity record holds the entity's ID. A value of -1 indicates that an ID has not yet been requested for the ENTITY. This is field #2 in any entity record, where the entity type is field #0. An integer field in history stream records (part of the history data section) holds the next available entity ID in that stream. This is field #3 in the history stream record, where "history_stream" is the first field.

Keeping the Part and Display in Sync with the Model

Call the PART::update method when an entity has been updated. The part itself does not really care, but this triggers the entity_callback mechanism with a pm_Update_Entity so that observers know that something interesting has occurred. During a later rollback, the entity_callback mechanism is triggered with a pm_Roll_Update_Entity.

PART::update does change the model and therefore starts a new DELTA_STATE if one is not already open. The reason for the model change is to create a change bulletin on the ID_ATTRIB (and the DISPLAY_ATTRIB if using the GI tool). This change bulletin is noticed during rollback and is used keep the PART (and display) in sync with the active state of the model.

PART::update should be called after each change to the model. Call PART::update and then api_note_state inside the delta state where the changes occurred. There is no need to call PART::update after roll.

Deleting Delta States and Freeing Memory

When delta states are no longer required, delete them by calling to api_delete_ds or api_prune_history. This call releases their space to free store, making it available for use in subsequent modeling. The delta state, bulletin boards, and bulletins are returned to free store, and entity records referred to in the bulletins are also released.

A DELTA_STATE will be automatically deleted if it is empty and was noted by api_note_state or api_pm_note_state. The criterion for empty is no BULLETINs. There may be one or more BULLETIN_BOARDs, but if none have any BULLETINs, then the DELTA_STATE is empty.

Other API calls are available to prune preceding states, following states, and all states, depending upon the roll back or roll forward information needed.

api_delete_ds is a procedural version of the DELTA_STATE class destructor. It releases memory associated with the DELTA_STATE including some BULLETIN_BOARDs, BULLETINs and backup copies of various ENTITYs.

So to release memory used by rollback, call api_delete_ds. To minimize the memory used by rollback, call api_logging(FALSE), which causes the system to automatically delete the DELTA_STATEs as often as possible, while still retaining rollback's role in error handling.

api_stop_modeller properly shuts down the modeler and frees all the memory used by ACIS. api_stop_modeller relies on the fact that if no DELTA_STATEs have been deleted, then the rollback history contains pointers to all the live ENTITYs as well as the backups. The key phrase here is "if no DELTA_STATEs have been deleted."

api_prune_history also deletes delta states, but first saves the information needed by api_stop_modeller.

There are three ways to clean up on exit:

api_stop_modeller can make up for lax programming, but only if no DELTA_STATEs have been deleted. This includes explicit deletes, deletes through api_delete_ds, and implicit deletes due to api_logging(FALSE).

The developer concerned with memory should use one of these methods:

Any of these can be used with the compress#_bb option, which merges multiple BULLETIN_BOARDs into one (on by default). This means that each delta state will have a single bulletin board, which saves a significant amount of memory, improves performance of roll and API_TRIAL_BEGIN/END blocks.

[Top]