Feeders & Thread-Safety

Hi,

my impression is that feeders are shared between actors, and thus threads (can be easily observed by printing current thread names/IDs in next() on any non-trivial simulation/scenario), whilst the contract of Iterators is inherently mutable and not thread-safe without external synchronization. I couldn’t find such synchronization happening. Am I missing something obvious on the design of feeders?

Thanks a lot.

  • Roman

Hi Roman,

You’re right, the Feeder API doesn’t enforce synchronisation, because in most use cases, you don’t need it. :wink:

What you have to understand is how Akka actors work with the JMM:
http://doc.akka.io/docs/akka/snapshot/general/jmm.html

Basically, one actor only handles one message at a time and ensure memory sync, so you don’t need sync as long as:

  • you only pop from a given feeder at one and only one place in your scenario
  • or, you don’t really care about sync in your use case (ex: do you really really need sync on a random feeder?)
    If you’re not in this situation, you can for example use the concurrentQueue, that I realize I forgot to document:

https://github.com/excilys/gatling/wiki/Feeders#wiki-concurrentQueue

Cheers,

Stéphane

Hi Stéphane,

thanks for your answer, unfortunately I think I’m still not fully getting it though so I’m counting on your patience to help me understand it better :slight_smile: One actor only handles one message at a time, that’s true. Do you mean that as long as I pass the feeder only to a single feed() call, there is only 1 actor who is ever going to access the feeder, no matter the number of users etc. that I configure?

I do see next() on the same feeder being called from different threads, which might be fine as long as its still the same actor (as mentioned in your link to the Akka docs, “you don’t get any guarantee that the same thread will be executing the same actor for different messages”).

If, however, different actors get access to the same feeder (Iterator), I don’t see how that cannot be a problem, e.g. two different actors checking hasNext on the same feeder roughly at the same time, both getting “true”, yet only one of them will actually succeed on the subsequent call to next(), or different actors invoking next() on the same feeder at roughly the same time and that feeder accesses some local mutable state (like a local index var as in the iterator you get from Array(…).iterator) or other non-thread-safe objects (like a JDBC ResultSet in the JDBC feeder).

Thanks a lot.

  • Roman

2012/11/16 Stéphane Landelle <slandelle@excilys.com>

thanks for your answer, unfortunately I think I'm still not fully getting
it though so I'm counting on your patience to help me understand it better
:slight_smile:

No pro :wink:

One actor only handles one message at a time, that's true. Do you mean
that as long as I pass the feeder only to a single feed() call, there is
only 1 actor who is ever going to access the feeder, no matter the number
of users etc. that I configure?

Exactly

I do see next() on the same feeder being called from different threads,
which might be fine as long as its still the same actor (as mentioned in
your link to the Akka docs, "you don't get any guarantee that the same
thread will be executing the same actor for different messages").

If, however, different actors get access to the same feeder (Iterator), I
don't see how that cannot be a problem, e.g. two different actors checking
hasNext on the same feeder roughly at the same time, both getting "true",
yet only one of them will actually succeed on the subsequent call to
next(), or different actors invoking next() on the same feeder at roughly
the same time and that feeder accesses some local mutable state (like a
local index var as in the iterator you get from Array(...).iterator) or
other non-thread-safe objects (like a JDBC ResultSet in the JDBC feeder).

It depends on your Feeder implementation/use case. For example, with a
random or circular feeder, hasNext will always return true and you don't
really care about the exact record being polled as long as you get one. If
you have multiple actors polling from the same queue feeder, you might
probably want to use the concurrentQueue instead of the regular one.

OK?

Hi,

2012/11/16 Stéphane Landelle <slandelle@excilys.com>

Ok, that sheds some light on it, the mapping from scenarios to actors wasn’t clear for me. If one scenario is handled by one and the same actor for all users, that makes sense.

Right, as long as the implementation is thread-safe (e.g. even java.util.Random can’t be relied upon to be thread-safe). When sharing the same feeder in multiple scenarios and thus actors, I’d rather go the concurrentQueue route that you mention.

Maybe it would be good to document a bit how the scenarios map to actors and that you better shouldn’t share feeders other than the concurrentQueue ones between scenarios.

I think I get it now, thanks!

  • Roman

Right, as long as the implementation is thread-safe (e.g. even

java.util.Random can't be relied upon to be thread-safe<java - Is Random class thread safe? - Stack Overflow;
).

Yep, but it should cause any real problem, just maybe your distribution not
being uniform.
The main problem with Random is that it uses an AtomicLong, so, even if it
doesn't block, it loops and consumes CPU.
If you're running on JDK7, you might consider using ThreadLocalRandom
(Gatling is still built on JDK6, so we don't use it yet).

When sharing the same feeder in multiple scenarios and thus actors, I'd

rather go the concurrentQueue route that you mention.

Maybe it would be good to document a bit how the scenarios map to actors
and that you better shouldn't share feeders other than the concurrentQueue
ones between scenarios.

That's what I tried to explain here:

Maybe we should add a new page explaining Gatling internals.

I think I get it now, thanks!

You're welcome.

Cheers,

Stéphane