1 2 3 Previous Next 31 Replies Latest reply on May 18, 2016 12:16 PM by Nicholas Whitehead Go to original post
      • 15. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
        Mark Little Master

        Hmmm, you're right. I thought I'd put all of that logic into the CheckedAction stuff originally but I'm sure there was a good reason originally. I wouldn't suggest changing it.

         

        BTW I thought we had allowed the overriding of the default CA implementation ways back (I may be misremembering again, but I thought I added that)?

        • 16. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
          Mark Little Master

          I would be very careful playing with TAD directly, and still recommend not doing so. That's really an internal implementation detail and it could be changed at any time, breaking your usage.

          • 17. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
            Michael Musgrove Master

            Mark Little wrote:

             

            Hmmm, you're right. I thought I'd put all of that logic into the CheckedAction stuff originally but I'm sure there was a good reason originally. I wouldn't suggest changing it.

             

            BTW I thought we had allowed the overriding of the default CA implementation ways back (I may be misremembering again, but I thought I added that)?

            We do let the user override the default CA via the CoordinatorEnvironmentBean (properties allowCheckedActionFactoryOverride and com.arjuna.ats.arjuna.coordinator.checkedActionFactory). But there is some code not inside the default CA that also emits warnings and that code needs to be moved into the CA (there should be no externally visible difference unless someone overrides the default CA).

            • 18. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
              Mark Little Master

              No, don't move the code. As I said earlier, I'm pretty sure it's in BasicAction for a good reason and moving it doesn't make sense until we/I understand that reason.

              • 19. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                Michael Musgrove Master

                Sure but that implies that both my "fixes" are now on hold, do we have a third option?

                 

                The only reason for having warnings in the code external to the CA are if there are customers who are overriding the default. What's the best way to discover who they are - by putting something on the forums asking for feedback?

                • 20. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                  Mark Little Master

                  "The only reason for having warnings in the code external to the CA are if there are customers who are overriding the default." Really? You can look inside my head and tell me why I wrote that code the way I did back in 1998? Cool

                  • 21. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                    Thomas Jenkinson Master

                    One immediate observation I have is that Nicholas shouldn't code to com.arjuna.ats.internal packages (of which ThreadActionData is one) as these are prone to change at any time.

                     

                    As to moving the warning, although I can't speak to the origin of the code it seems to me that the warning from BasicAction is there to alert you to the fact that the transaction was associated with multiple threads. The CheckedAction override then allows an app to provide bespoke logic to try to clean up this case but IMO the warning is still valid. Ideally what we need to do is make sure that (in collaboration with Nicholas) that its not the case at this point.


                    What I haven't understood clearly with Quasar yet is how come you can't pop the transaction from the thread after your resource manager activity but before you hand back to Quasar:

                    i.e.

                    //db update

                    tm.suspend();

                    I imagine you are saying that a thread could switch at any blocking point (e.g. during the db update) but in that case I don't understand how the TX is automatically associated with the next random thread from the Quasar pool (unless Quasar hands off all the thread locals or something)?

                    • 22. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                      Mark Little Master

                      "Sure but that implies that both my "fixes" are now on hold, do we have a third option?"

                       

                      Which fixes? The approach I mentioned, about overriding CA, should already be possible. Sure it causes a warning to be displayed but unless there's a production need for this I don't think the warning's a real problem at this stage. And yeah, I also suggest someone with Quasar knowledge check to see if there's some way to ensure the fibre-to-thread association can be more thoroughly investigated so that a warning from the new CA implementation is still issues if there's more than one thread present that isn't associated with the "same" fibre, but I again I don't think that's something we can do or should do in the TM code.

                      • 23. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                        Mark Little Master

                        BTW Mike, I'm not suggesting you are wrong only that since I wrote the code and I can't recall at the moment why it's like that when CA is there anyway, there's a good chance there are other reasons why it is the way it is. I need to check my memories and the older code in case there are/were comments, especially in the C++ implementation from where this came originally.

                        • 24. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                          Nicholas Whitehead Newbie

                          Mark, Tom, Michael;

                           

                          Thank you for your attention on this. Much appreciated.

                           

                          If this gets too-much-info, please feel free to say..... I uh.... don't want you to feel put upon.

                           

                          Tom: the reason I can't pop the transaction from the thread is that the fiber can be suspended at any time. This is not under developer control. What happens is that the fiber's continuation is executed by an arbitrary fork-join thread, but at any point, the execution can block at which point it throws a SuspendExecution exception which suspends the fiber. When this happens, repackages the continuation and dis-associates all the threadlocals (and inheritable threadlocals) from the "carrying" fork-join thread. Now the fork-join thread goes off to execute some other fiber's continuation. The earliest point I can insert functionality into the flow is after the thread locals have been cleared. So the sequence is:

                           

                          1. The fiber is running. I can execute TransactionManager.begin() and TransactionManager.getTransaction() and it works fine.
                          2. The fiber is suspended.
                          3. My overriden fiber gets a callback (executing in the associated fork-join thread) in a method onPark(). This would seem to be the perfect place to suspend the transaction and dis-associate it from the fork-join thread, but since the threadlocals have been cleared, calling TransactionManager.suspend() does not work.

                           

                          The other side of this coin is that when a fiber is rescheduled for execution, the threadlocals pulled from whatever thread was carrying the fiber when it was suspended are now surfaced under the new thread selected to continue executing the thread. Apologies if this is completely confusing, but think of this way: To implement lightweight threads (fibers) we pass micro units of execution (continuations) to a fork-join pool. When those continuations block, the task ends and is rescheduled for later execution. The fork-join threads have zero continuous context, they're just dumb workers. All identity must be managed at the Fiber level (they're the new thread). Accordingly, any construct that relies on thread identity needs some modification or work around. The execution looks like this:

                           

                           

                          My proposal to the Quasar devs was to provide a callback to the developer so they can assist with the shuffling of the threadlocals. In this case, my suspend callback would suspend the transaction (disassociate it from the leaving thread) and the resume callback would resume the transaction (associate the transaction with the new thread).  (as an aside, to avoid confusion, I have been referring to Quasar Fiber events as park and unpark to distinguish between transaction resume and suspend.)

                           

                          My proposal looks like this:

                           

                          The Quasar devs are interested in providing support for integration with frameworks that rely on thread-identity ( which I think it is safe to say, JTA in general is ) but they don't particularly care for my proposal.

                          This is a good recap from the ticket I opened:

                           

                          @nickman Problem is, your proposed solution doesn't solve the problem, as you won't be able to use the callbacks. Your solution requires subclassing Fiber, which has two problems:

                          1. It will only work in certain kinds of fibers, which you may not always be able to control.
                          2. It does not compose. What if two different libraries require use of those callbacks? You'll have two different subclasses.

                          The best solution -- and the correct one, especially in light of various asynchronous frameworks -- is for the transaction library not to rely on thread identity. Instead, it should accept a function that returns a current execution context (Object currentExecutionContext()). The default implementation can return Thread.currentThread().getId(), and the Quasar-compatible one would be Strand.currentStrand().getId(). When used in asynchronous libraries (such as RxJava), a different type of execution context would be returned. Instead of comparing the current thread, the library should compare the current execution context.

                          The alternative would be a callback that can be dynamically attached to a fiber (rather than by subclassing), and some mechanism by which any relevant fiber would automatically have this callback registered. I think such a solution is both too excessive and too specific (as it only helps some very specific libraries, that happen to have suspension methods and rely on thread locals in a very specific way).

                           

                          Quasar defines a Strand to be a generic overlap of Threads and Fibers so it looks like a thread and looks like a fiber. That way code does not always have to have different handling for each.

                           

                          That statement is not wrong. I am using a specific construct in Quasar (an actor) where instances are supplied a FiberFactory so I can control the fibers that are used by the actor instances (just like one might define a ThreadFactory to create specific types of threads) but this is not always the case, so my perspective is admittedly, a bit myopic.

                           

                          On the other hand, I am fairly sure that integration with a wide variety of enterprise APIs/Libraries/Services will be incredibly difficult without some sort of support for massaging these context switches which make changes at the thread level that other libraries may be completely unprepared for.

                           

                          I am cleaning up my POC code and will publish it shortly. (it doesn't work, so it is less a Proof of Concept than a Suggestion of Concept)

                           

                          Thanks again for your time.

                           

                          //Nicholas

                          • 25. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                            Mark Little Master

                            "As to moving the warning, although I can't speak to the origin of the code it seems to me that the warning from BasicAction is there to alert you to the fact that the transaction was associated with multiple threads. The CheckedAction override then allows an app to provide bespoke logic to try to clean up this case but IMO the warning is still valid. Ideally what we need to do is make sure that (in collaboration with Nicholas) that its not the case at this point."

                             

                            Yes, that's precisely why the warning is still in BasicAction even if you override the CA implementation. It's a fail-safe in case someone wrote an incorrect CA that resulted in thread-to-transaction association not being correctly handled when the transaction terminates and then being unable to figure out where the problem originated. I wouldn't recommend removing that warning - if someone overrides CA then they should also take responsibility for ensuring users understand they can correctly ignore the warning and if a user says "WTF?" and that reminds the person who has written the new CA about something they didn't do, it's a good thing.

                            • 26. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                              Thomas Jenkinson Master

                              Thanks for the background Nicholas, I do think the Quasar framework sounds rather interesting.

                               

                              I would like to mention that regarding the point that Quasar believes it is possible to address this issue by using their API (Strand association), the actual JTA specification mandates that transactions be associated with Threads and talks at length about thread association. It's not to say something couldn't be done here but its an assumption that exists in multiple places in the library.

                              • 27. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                                Michael Musgrove Master

                                It seems odd having a default CA that duplicates what we already have in the main code.

                                • 28. Re: Using TransactionManager with Quasar Fibers (Lightweight Threads)
                                  Mark Little Master

                                  It's fail-safe. Remember that transaction managers need to be extremely cautious and aware of consistency so you can never really overly warn someone