Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
tar
Level 7

Scene Graph m.global is not reliable under moderate load (returns invalid sometimes)

So here is a major problem: 
1. The app heavily relies on m.global and accesses it's fields from Task nodes
2. Recently I've discovered that sometimes m.global fields are invalid (however returns valid objects when stopped in debugger)
3. As I have a solid programming background, I've guessed it is due to some threading issues and found this topic in docs https://sdkdocs.roku.com/display/sdkdoc/Scene+Graph+Threads#SceneGraphThreads-TaskNodeThreadRendezvousTimeout


Does it mean that m.global fields are not reliable to access from TaskNode at all???

In my tests it could be as strange as follows:

myVar1 = m.global.someField ' myVar1 is invalid
myVar2 = m.global.someField ' myVar2 is ok


docs say: "During application development, you should check for these timeouts to increase the performance of your published application."But I'd rather want it to lag, but be consistent.

Is there a way to avoid invalid responses when accessing m.global fields?
Is there any global storage (accessible from any thread) that does not rely on render thread as m.global?

I know, I can pass m.global state to GetGlobalAA() of task thread before running any TaskNode and add some business logic to get data from there, but I'm really tired of workarounds in my Scene Graph app.
And it is not an ideal solution, because each thread has it's own global AA and will require syncing it with m.global when it changes, which is not that easy to implement if even possible to make it work properly at all.
Is it the one possible solution or am I missing something simple and obvious?
0 Kudos
5 Replies
tar
Level 7

Re: Scene Graph m.global is not reliable under moderate load (returns invalid sometimes)

temporary solved it next way

myVar = m.global.someImportantField
while myVar = invalid
   ' do not spam render thread (m.global owner) with requests, but try at least 10 times per second '
    sleep(100)
   ' usually works from the first try '
    myVar = m.global.someImportantField
end while
0 Kudos
Highlighted
EnTerr
Level 8

Re: Scene Graph m.global is not reliable under moderate load (returns invalid sometimes)

"tar" wrote:
So here is a major problem: 
1. The app heavily relies on m.global and accesses it's fields from Task nodes
2. Recently I've discovered that sometimes m.global fields are invalid (however returns valid objects when stopped in debugger)
3. As I have a solid programming background, I've guessed it is due to some threading issues and found this topic in docs https://sdkdocs.roku.com/display/sdkdoc/Scene+Graph+Threads#SceneGraphThreads-TaskNodeThreadRendezvo...

Does it mean that m.global fields are not reliable to access from TaskNode at all???
...
Is there a way to avoid invalid responses when accessing m.global fields?
Is there any global storage (accessible from any thread) that does not rely on render thread as m.global?

Yes. No. And mostly no.

It's not only `m.global` fields that are unreliable - rather, any and all fields of a RSG node are unreliable to access between threads! 
I put it in red because think is very important issue to grasp. Regardless if you set or get the field - or if you do it explicitly with .getField()/.setField() - or with "."-access. Beware there will be no error though - if you are setting a field, it just won't get set - and if you are getting it, it will return `invalid`. 

Yes, i know - that is horrible. In my not-so-humble opinion, this (d)effect is the 2nd worst, the 2nd most crippling mistake of RSG. The good news is, seems there is something in the works to patch this in future release - but it has its own issues. See BUG-0025 "Debug rendezvous with Godot" for details if you are part of the developer beta.
0 Kudos
EnTerr
Level 8

Re: Scene Graph m.global is not reliable under moderate load (returns invalid sometimes)

"tar" wrote:
temporary solved it next way
myVar = m.global.someImportantField
while myVar = invalid
   ' do not spam render thread (m.global owner) with requests, but try at least 10 times per second '
    sleep(100)
   ' usually works from the first try '
    myVar = m.global.someImportantField
end while


You can generalize it a little, like so (typing this on the fly, not tested):
function get_node_field(node as Object, fieldName as String):
 ' sample use: get_node_field(m.global, "someImportantField") '
 res = invalid
 while res = invalid:
   res = node.getField(fieldName)
 end while
 return res
end function

Beware that there is no way to account for a field that actually has its value set to invalid. If that's the case, the function gets infinitely loopy. I thought for a moment i can use .hasField() to check - but nope, that one would also fail on a "dreadlock" and return False (in other words it returning False means either there is no such field or... there is such field but a timeout occured). Congrats @RokuCo - that was some sleight-of-hand throw into the halting problem  :mrgreen:

PS. don't forget to write also write_node_field() counterpart, since setting a field may also fail silently due to lock timeout
PPS. i see no need to sleep() since the rendezvous in my understanding already takes care of that, presumably it does not spin in a tight loop.
0 Kudos
tar
Level 7

Re: Scene Graph m.global is not reliable under moderate load (returns invalid sometimes)

Thanks @EnTerr, I appreciate your detailed answer.
So it is like building on a sand then. Wait... 2nd worst mistake? Which one is the 1st?
I am not a part of a developer beta, just don't have a time for that.
0 Kudos
EnTerr
Level 8

Re: Scene Graph m.global is not reliable under moderate load (returns invalid sometimes)

"tar" wrote:
So it is like building on a sand then.

Interesting metaphor. Perhaps. Thus instead of a house - one has to build a houseboat, to make sure it won't sink?

Wait... 2nd worst mistake? Which one is the 1st?

The first most damaging to the developers at large i think is the choice of giving access to the fields with "." (dot-access is a shortcut to getField/setField). I am sure in theory it sounded cool - in practice though that sets a quicksand trap. Most people don't realize that on usage `node.field` does a deep-copy. You have probably discovered that but just in case, see viewtopic.php?f=34&t=95416 for a refresher. 

And even after you know the dangers of dot-ing in RSG, it's un-intuitive which dot in the access chain A.B.C.D.E is the dangerous one. In your case `m.global.someImportantField`, the 1st dot is safe (since m is a regular dictionary). The 2nd dot may (or may not) be tricky, since that's a node (mine)field. If that field is another Node, it's safe - no copy. If it's an array or dictionary though, that gets copied first - with the side effect that if you do `m.global.myRoAssocArray.foo = "bar": ? m.global.myRoAssocArray.foo` - there will be no error but `m.global.myRoAssocArray` remains un-changed... mindfreak?
0 Kudos