Serializability is a well-understood concurrency
control mechanism that eases reasoning about
highly-concurrent database
programs. Unfortunately, enforcing
serializability has a high performance cost,
especially on geographically distributed
database clusters. Consequently, many databases
allow programmers to choose when a
transaction must be executed under
serializability, with the expectation that
transactions would only be so marked when
necessary to avoid serious concurrency bugs.
However, this is a significant burden to impose
on developers, requiring them to (a) reason
about subtle concurrent interactions among
potentially interfering transactions, (b)
determine when such interactions would violate
desired invariants, and (c) then identify the
minimum number of transactions whose executions
should be serialized to prevent these
violations. To mitigate this burden, this paper
presents a sound and fully automated schema
refactoring procedure that transforms a
program's data layout -- rather than its
concurrency control logic -- to eliminate
statically identified concurrency bugs, allowing
more transactions to be safely executed under
weaker and more performant database guarantees.
Experimental results over a range of realistic
database benchmarks indicate that our approach
is highly effective in eliminating concurrency
bugs, with safe refactored programs showing an
average of 120% higher throughput and 45%
lower latency compared to a serialized baseline.