PDA

View Full Version : Endless loop on shared windowlist databasenode delete



Moon Wizard
February 12th, 2009, 22:38
OK, I think I've narrowed down one of the situations when I see an endless loop occur.

I have an area of the character sheet with multiple nested windowlists (4E_JPG character powers) (nesting = type, power, attacks/effects). When I drop a power onto the power page, I call a library function to add the power to the list. The library function adds the power to the database directly using a createChild() call, then sets the appropriate fields underneath using createChild() and setValue() calls.

After setting the basic fields, I parse the power description to pull out the attacks and place them in the attacks list (a windowlist under the power entry). The attacks list is a special list that always contains a single entry.

At the beginning of the parse function, I delete the attacks list child nodes, parse the attacks, and re-add an attack list child if no attacks were found. I have also tried deleting the whole attack list node, instead of just the children.

When I do this while a client is connected, and subsequently delete the power entry, then I start to see an endless loop of calls to onInit for the power entry class. If I remove the attack list deletion call(s) but otherwise perform the same code, then everything works fine.

Based on debug statements I added, it appears the the onInit function for the power entry is called during the createChild() call to create the power entry node., before the rest of the add power function is executed.

Any ideas why deleting a windowlist node or child nodes of a windowlist would cause an endless loop like this only when a client is connected?

Thanks,
JPG

Foen
February 13th, 2009, 06:30
Are the database nodes held by the client at all? I have seen something like this with shared combat tracker detail, and with shared notes. I think there is some problem with database integrity: perhaps nodes are cached at the client end and recreate themselves at client/host when you try to delete them?

Stuart

Moon Wizard
February 13th, 2009, 09:48
I think they have to be held by the client, because they are part of the charsheet database node. Each charsheet node is assigned the client as a holder whenever the client chooses a character on login.

I make getDatabaseNode().delete() calls all the time to support radial menu deletions. But in this function, I'm using createChild() to create the node and get the reference to the window list, then deleting any children using getChildren() and delete().

Cheers,
JPG

Valarian
February 13th, 2009, 11:09
Is there a cyclical relationship anywhere in the child list?

EugeneZ
February 14th, 2009, 00:08
Is there a cyclical relationship anywhere in the child list?
Ah, reminds me of the good old IE6 circular-link memory leak bug. (DOM element with a javascript object refering to it creates a reverse-link. Try to delete one and boom, memory leak due to circular reference...)

Er, sorry.

Moon Wizard
February 15th, 2009, 08:20
Each child in the attacks list and the effects list is a separate entry. If I look in the db.xml file, everything looks fine, and each entry contains only string and number children. (no links or node references)

I've seen this issue in many different windowlists that are shared across host and clients, but haven't been able to pinpoint the exact statement causing the situation before. I've used lock fields to workaround in most situations, but it's not working this time. Also, this is first time I've been able to consistently reproduce the issue.

Let me see if I can summarize the issue with bullet points:

* Deleting a database node representing a windowlist or an entry in the windowlist, which is itself a child of an entry in a higher level windowlist, will end up causing an infinite loop.

* The infinite loop does not occur until the subsequent higher level windowlist entry is deleted.

* Infinite loop only occurs when node is shared by host and clients, whether window is open only on the host/client making the function call or open on multiple.

* The visual manifestation of the infinite loop is a window in the windowlist which appears and disappears rapidly, or a window in the windowlist which cannot be interacted with.

* Inserting debug statements in the onInit function for the windowlist entry shows that the function is being called constantly, once it enters the infinite loop.

* The database node reference for the windowlist is determined using the databasenode.createChild() function.

* The database node reference for the entries in the windowlist is determined using the databasenode.getChildren()

* The database node for the entries in the windowlist is deleted using the databasenode.delete() function.

* The function call interacting with the database is being called from a library, just like the DesktopManager script in the foundation ruleset.

* Closing all the clients is the only way to stop the infinite loop.

Thanks,
JPG

Foen
February 15th, 2009, 10:50
Thanks JPG, this is a very helpful post. Have you tried using a sourceless windowlist, and adding the child windows manually using createWindow(node)?

Stuart

Moon Wizard
February 15th, 2009, 17:18
Well, the data in the windowlist needs to be stored in the database, because the nested windowlists represent 4E character power types, individual powers, and power attacks/effects.

Since the addition to the data in this situation is potentially triggered from another window (i.e. adding feats that grant powers), then that's why the database is manipulated directly using createChild() and delete(), instead of using the createWindow() and close() functions.

How would I define a sourceless windowlist which has entries that store in the database? If I did that, wouldn't all controls under those entries have to be sourceless, and the windowlist would have to monitor the appropriate powers node to determine whether to create/delete windows? It seems like I'd be trying to recreate the guts of the windowlist control from scratch.

Thanks,
JPG

Foen
February 15th, 2009, 17:26
You can use a sourceless windowlist and add source-ful (yuck!) children. It is handy for managing mixtures of bound and unbound children - such as bound entries, and unbound summary lines.

I'm not saying it will work, but it might narrow down the problem.

Stuart

Moon Wizard
February 16th, 2009, 10:04
OK, I narrowed down another piece by process of elimination. All the lists that were having the problem were checking for an empty list in the onInit function, and adding a window if it was empty.

I might try and see if I can create an extension that recreates the issue.

JPG

Valarian
February 16th, 2009, 11:13
That could be the issue, the list removes all children making the list empty then recognises that it's empty and adds another child ... which is then removed, making the list empty, which then recognises that it's empty and adds another child ... etc.

Moon Wizard
February 17th, 2009, 02:06
The list only checks for empty when a child is deleted via the radial menu, not whenever the underlying database node is updated. This is specifically to prevent that endless loop condition.

How else can you make a list that is never empty?
(The never-empty list is needed in situations where an empty list would collapse to zero height due to layout, which would make the addition of entries via the radial menu inaccessible.)

Just noticed one other thing. I disabled the empty check in the onInit function which prevents the endless loop from occurring. Since the functionality in this one area essentially mimicked the standard windowlist empty entry when initialized, I tried removing the skipempty tag from the windowlist. Unfortunately, removing the skipempty tag is not adding an entry to the list on initialization as expected.

Cheers,
JPG

Foen
February 17th, 2009, 06:01
There are other ways to prevent and empty list collapsing to zero height. Try using setAnchoredHeight in the onListRearranged event. The trick is mentioned in the following thread (post #8):
https://www.fantasygrounds.com/forums/showthread.php?t=9323

Cheers

Stuart

phantomwhale
May 22nd, 2011, 03:43
Horrible case of thread necromancy, but just seen this problem in the DLR extension.

The change I introduced was having two independent window lists both using the same data node. (1) the powers tab in the main screen, known as the "mini-powers" list and (2) the a separate powers list, know as the "main powers" list.

Again, only with a client connected, do I get the error. I have no "when empty, repopulate the list" code, in fact it's the basic savage worlds power list window class (for those with the code).

I have seen the problem with two elements present in the list, and the client deletes one of them, only to see a "blank" entry jump into existence shortly afterwards. Deleting the blank entry then on the GM made another blank entry appear, and trying it again caused everything to crash (infinite loop, I suspect).

Going to try and start digging on this now, but guess I wanted to quickly reopen this thread and see if there was any common wisdom around this I should be aware of, or 4E / BRP / other windows that use locks / controls specifically to avoid this semi-known problem ?

Thanks,
Ben

Moon Wizard
May 22nd, 2011, 08:43
There is a race condition in the database node deletion code that can occur when a host and client both have windowlists open at the same time which point to the same database node.

This has occurred in every ruleset I built since d20_JPG, and way before I was involved on the development of FG. Luckily, I was able to track down the issue a few months ago while working on v2.8.

The race condition actually spans both the networking code , and the windowlist code. So, the fix to address the issue is non-trivial. The fix will be included in the v2.8 release where it can get some extra testing.

In the mean time, I advise GMs from editing the same sheets as players during a game. In most cases, the only way to stop the loop is to have the player log off.

Regards,
JPG

Mooses8D
July 20th, 2011, 08:05
Sorry to resurrect an old thread but is linked to another thread describing the problem I was having tonight when I tried to run a quick session for some friends of mine. It seemed to occur off and on throughout the night. I tried to follow the lis5ed suggestion of not modifying the character sheets while the player was, but the problem would still occur. Has this been fixed for 2.8, and if so can unregistered versions get access to 2.8 as well?

Moon Wizard
July 20th, 2011, 08:55
It is addressed in v2.8. Unfortunately, we do not currently have a way to allow unregistered versions to run v2.8, since the ability to run the beta version is tied to the license key.

The workaround for 2.7 is not to edit the powers page while another person is looking at the character sheet. Either edit while no one is connected, or make sure that only the player or GM has the character sheet open while editing.

I hope to have 2.8 out by August barring any showstoppers.

Cheers,
JPG