blob: 92e1fe9336cf76b830630ec6ce8b750a5b39a4d7 [file] [log] [blame]
% defer/updates.tex
% mainfile: ../perfbook.tex
% SPDX-License-Identifier: CC-BY-SA-3.0
\section{What About Updates?}
\label{sec:defer:What About Updates?}
%
\epigraph{The only thing constant in life is change.}
{Fran\c{c}ois de la Rochefoucauld}
The deferred-processing techniques called out in this chapter are most
directly applicable to read-mostly situations, which begs the question
``But what about updates?''
After all, increasing the performance and scalability of readers is all
well and good, but it is only natural to also want great performance and
scalability for writers.
We have already seen one situation featuring high performance and
scalability for writers, namely the counting algorithms surveyed in
\cref{chp:Counting}.
These algorithms featured partially partitioned data structures so
that updates can operate locally, while the more-expensive reads
must sum across the entire data structure.
Silas Boyd-Wickhizer has generalized this notion to produce
OpLog, which he has applied to
Linux-kernel pathname lookup, VM reverse mappings, and the \co{stat()} system
call~\cite{SilasBoydWickizerPhD}.
Another approach, called ``Disruptor'', is designed for applications
that process high-volume streams of input data.
The approach is to rely on single-producer-single-consumer FIFO queues,
minimizing the need for synchronization~\cite{AdrianSutton2013LCA:Disruptor}.
For Java applications, Disruptor also has the virtue of minimizing use
of the garbage collector.
And of course, where feasible, fully partitioned or ``sharded'' systems
provide excellent performance and scalability, as noted in
\cref{chp:Partitioning and Synchronization Design}.
The next chapter will look at updates in the context of several types
of data structures.