[ https://issues.apache.org/jira/browse/CASSANDRA-8963?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14629517#comment-14629517 ]
Sylvain Lebresne commented on CASSANDRA-8963: --------------------------------------------- Without getting into the naming debate above, I'd want to say that imo the current {{OpOrder}} implementation/API is largely ok and I'm not a huge fan of changing for changing. Based on my own experience with that class (which thus could be off for other people), my suspicion is that the 2 main things that makes {{OpOrder}} hard to approach initially are that: # the class javadoc does a poor job at explaining clearly/simply what the class is about. The discussions around 'consumer and producer processing contiguous batches' and other 'position the work is at' are, I think, too abstract. And while the example could help, it references methods that are either non-existent ('seal()') or barely used in the codebase ('isAfter()'), making it less than ideal for getting an initial grasps of the class and its usage in the code. # the actual usages of the class are barely documented. I suspect that's the biggest problem btw. If you look at the {{readOrdering.start()}} we do at the beginning of a read, you have no clue why we're doing it. You then scroll to the definition of {{readOrdering}}, but that give you no real clue on what this is about because the small comment there is both pretty vague and outdated ({{readOrdering}} is now used for much more than protecting off-heap storage). Your third inclination is then to go to the {{OpOrder}} class javadoc, hoping the understanding of the class will bring you enough enlightenment to figure out why {{readOrdering}} exists on your own. But then the first point kicks in, at which point you'll probably give up, considering all this unintuitive. So I would submit that just fixing those 2 things would be good enough. Now, for the sake of not just criticising without offering anything, I could propose as a starting point for the class javadoc something like: {noformat} /** * A synchronization primitive that allows a specific operation X to wait until all other operations started before X are completed. * * There is 2 sides to using this class. Given a particular {@code OpOrder order}: * 1) each operation for which we might want to wait the completion of should call {@code order.start()} when they start, which assign them a group * ({@code OpOrder.Group}), and should close that group once completed (it's crucial for any group assigned through {@code start()} be closed, * so an {@code OpOrder.Group} should preferably be protected by a try-with-ressources). * 2) an operation that wants to wait on the completion of operations protected though 1) should issue a barrier {@code order.newBarrier()}, issue it * {@code order.issue()} and then wait on that barrier ({@code OpOrder.Barrier.await()}). The guarantee is then that {@code await()} will only return * once all the operations protected through 1) that started before the barrier has been issued have completed (where completed means "have closed * their assigned group object"). * * In practice, an example use case of this is the {{readOrdering}} of {{ColumnFamilyStore}}. It is used to protect every read operation, from * before we start reading the memtables and sstables, to when the result is fully read. Which then allows us to protect other operation from * racing with reads. For instance, to drop a table, we first mark the table dropped (guaranteeing no new read on that table can start), but * then issue a new barrier on {{readOrdering}} and wait on it before discarding the memtables/sstables. This guarantees us that any read that * may be in-flight when we mark the table dropped is completed before we delete the memtables/sstables. */ {noformat} Then I'd also add a bigger comment on {{readOrdering}} declaration that sums all the reasons it is used for, and would do the same for all other OpOrder. API-wise, the only change I'd maybe suggest is around {{issue()}}. Ideally, I'd remove {{issue()}} altogether, making the creation of a barrier issuing it implicitly, because that's a bit simpler. There is only one case where we don't issue right away and maybe we can slightly refactor the code to not need this? But if that's not possible (or too contrived), then I'd make {{newBarrier()}} issue implicitly, remove the references to {{issue()}} in the javadoc above, and add a {{newUnissuedBarrier()}} method for the rare cases where we need it. If the class is easier to apprehend then it's ok if you have to go read the fine-prints for more advanced usages. Anyway, even if you hate the suggestions above and want to debate naming to death (which is cool, I'm all for naming death-match), I'd humbly suggest delaying it post-3.0 because I really think this can wait. > Make OpOrder more intuitive > --------------------------- > > Key: CASSANDRA-8963 > URL: https://issues.apache.org/jira/browse/CASSANDRA-8963 > Project: Cassandra > Issue Type: Improvement > Components: Core > Reporter: Benedict > Assignee: Benedict > Priority: Minor > Fix For: 3.x > > > There has been plenty of feedback about OpOrder being unintuitive. As well as > revisiting the naming, I propose to introduce an Action object with RAII > (AutoCloseable) protection that should be more obvious to users of the API. > We can also then protect this by a Ref instance for use cases where the > action lifetime is illdefined, and perhaps also introduce some checks for > actions whose lifetimes extend beyond a sensible limit to report those where > the object reference is retained. -- This message was sent by Atlassian JIRA (v6.3.4#6332)