title: How to achieve an insert across multiple tables in Cassandra, uniquely and atomically?
body: <p>I have a data model where the domain object has two fields that must both be unique and the object must be gettable via both independently.
  One of them is randomly generated, so we can assume no possible collisions.
  The other is user-selected. Here's what I've come up with:</p>
  
  <pre><code>CREATE TABLE object_primary (
      generated_value text PRIMARY KEY,
      data blob
  );
  
  CREATE TABLE object_unique_index (
      user_value text PRIMARY KEY,
      generated_value text
  );
  </code></pre>
  
  <p>Here I'm using object_unique_index as both an index into the primary table and a resource lock, where the resource is the user-chosen globally unique value.</p>
  
  <p>First thoughts:</p>
  
  <ul>
  <li>Inserting into object_unique_index must use <code>IF NOT EXISTS</code>. Therefore I cannot use a batch.</li>
  <li>Inserting into object_primary doesn't as uniqueness is already guaranteed by the generator. This then lets me use custom <code>TIMESTAMP</code>s, avoiding a read-back on creation.</li>
  <li>If the first insert fails, I shouldn't continue with the second insert.</li>
  <li>If the second insert fails, I should rollback the first insert.</li>
  <li>The system should not be left in a state where a row exists in either column without the other.</li>
  <li>I'm willing to ignore errors during rollback, and will delegate clean-up to an external (possibly manual) process.</li>
  </ul>
  
  <p>It seems clear how to proceeded, but I am struggling with interpreting certain error cases for a <strong>non-conditional</strong> update. All existing descriptions assume you don't care what the end result is, and will just try the write again later.</p>
  
  <p><code>UnavailableException</code>: There weren't enough nodes up for a quorum, but when they come back on-line the saved hint will re-run the write. Does this mean that the eventual state will be that the write succeeded? If so, what read consistency level allows me to see it? If not, how do I know what the eventual state will be?</p>
  
  <p><code>CassandraWriteTimeoutException</code>: There were enough nodes for a quorum, but some of them didn't reply in time. As far as I can tell this is just a more ambiguous version of <code>UnavailableException</code>. Are there any differences in how it should be handled?</p>
  
  <p>A lot of my confusion is coming from the conflicting statements <a href="http://www.datastax.com/dev/blog/how-cassandra-deals-with-replica-failure" rel="noreferrer">here</a>:</p>
  
  <blockquote>
    <p>The coordinator can force the results towards either the pre-update or post-update state.</p>
    
    <p>[...]</p>
    
    <p>the coordinator stores the update locally, and will re-send it to the failed replica when it recovers, thus forcing it to the post-update state that the client wanted originally</p>
  </blockquote>
  
  <p>So when does it force it to the pre-update state? How can I tell whether it ends up in post-update (so I ignore it) or pre-update (so I rollback the first insert)?</p>
  
  <p>Is there a way to solve this without requiring all inserts to be conditional, and thus adding more performance penalties and losing the ability to set the writetime?</p>