diff options
Diffstat (limited to 'chapters')
| -rw-r--r-- | chapters/beyond-dsp.tex | 10 | ||||
| -rw-r--r-- | chapters/design-space.tex | 31 | ||||
| -rw-r--r-- | chapters/dynamization.tex | 41 | ||||
| -rw-r--r-- | chapters/introduction.tex | 28 | ||||
| -rw-r--r-- | chapters/sigmod23/background.tex | 6 | ||||
| -rw-r--r-- | chapters/sigmod23/framework.tex | 8 | ||||
| -rw-r--r-- | chapters/tail-latency.tex | 32 |
7 files changed, 79 insertions, 77 deletions
diff --git a/chapters/beyond-dsp.tex b/chapters/beyond-dsp.tex index 7a0df37..a2e7abf 100644 --- a/chapters/beyond-dsp.tex +++ b/chapters/beyond-dsp.tex @@ -251,7 +251,7 @@ O \left( \log_2 n \cdot P(n) + D(n) + \log_2 n \cdot \mathscr{Q}_\ell(n) + C_e(n \end{equation} As an example, we'll express IRS using the above interface and -analyze its complexity to show that the resulting solution as the +analyze its complexity to show that the resulting solution is the same $\Theta(log^2 n + k)$ cost as the specialized solution from Chapter~\ref{chap:sampling}. We use $\mathbftt{local\_preproc}$ to determine the number of records on each block falling on the @@ -904,7 +904,7 @@ previous section, as well as versions of $\mathbftt{local\_preproc}$ and $\mathbftt{local\_query}$ for pre-processing and querying an unsorted set of records, which is necessary to allow the mutable buffer to be used as part of the query process.\footnote{ - In the worst case, these routines could construct temporary shard + In the worst case, these routines could construct a temporary shard over the mutable buffer, and use this to answer queries. } The $\mathbftt{repeat}$ function is necessary even for normal eDSP problems, and should just return \texttt{false} with no other @@ -1023,7 +1023,7 @@ face of deleted records. \item \textbf{Leveling.}\\ Our leveling policy is identical to the one discussed in Chapter~\ref{chap:sampling}. The capacity of level $i$ is $N_b \cdot -s^i+1$ records. The first level ($i$) with available capacity to hold +s^{i+1}$ records. The first level ($i$) with available capacity to hold all the records from the level above it ($i-1$ or the buffer, if $i = 0$) is found. Then, for all levels $j < i$, the records in $j$ are merged with the records in $j+1$ and the resulting shard placed in level @@ -1778,7 +1778,7 @@ number of records on it, rather than returning the set of records, to overcome differences in the query interfaces in our baselines, some of which make extra copies of the records. We consider traversing the range and counting to be a more fair comparison. Range counts are true -invertible search problems, and so we use tombstone-deletes. The query +invertible search problems, and so we use tombstone deletes. The query process itself performs no preprocessing. Local queries use the index to identify the first record in the query range and then traverses the range, counting the number of records and tombstones encountered. These counts @@ -1891,7 +1891,7 @@ $N_B = 1200$, $s = 8$, the tiering layout policy, and tombstone deletes, with a standard Bentley-Saxe dynamization (\textbf{BSM-FST}), as well as a single static instance of the structure (\textbf{FST}). -The results are show in Figure~\ref{fig:fst-eval}. As with range scans, +The results are shown in Figure~\ref{fig:fst-eval}. As with range scans, the Bentley-Saxe method shows horrible insertion performance relative to our framework in Figure~\ref{fig:fst-insert}. Note that the significant observed difference in update throughput for the two data sets is diff --git a/chapters/design-space.tex b/chapters/design-space.tex index cfea75e..f788a7a 100644 --- a/chapters/design-space.tex +++ b/chapters/design-space.tex @@ -53,7 +53,7 @@ of metric indices~\cite{naidan14,bkdtree}, a class of data structure and search problem for which we saw very good performance from standard Bentley-Saxe in Section~\ref{ssec:dyn-knn-exp}. The other experiments in Chapter~\ref{chap:framework} show that, for other types of problem, -the technique does not fair quite so well. +the technique does not fare quite so well. \section{Asymptotic Analysis} \label{sec:design-asymp} @@ -61,7 +61,7 @@ the technique does not fair quite so well. Before beginning with derivations for the cost functions of dynamized structures within the context of our proposed design space, we should make a few comments about the assumptions -and techniques that we will us in our analysis. As this design space +and techniques that we will use in our analysis. As this design space involves adjusting constants, we will leave the design-space related constants within our asymptotic expressions. Additionally, we will perform the analysis for a simple decomposable search problem. Deletes @@ -89,9 +89,9 @@ decided to maintain the core concept of binary decomposition. One interesting mathematical property of a Bentley-Saxe dynamization is that the internal layout of levels exactly matches the binary representation of the record count contained within the index. For example, a dynamization containing -$n=20$ records will have 4 records in the third level, and 16 in the fourth, +$n=20$ records will have 4 records in the third level, and 16 in the fifth, with all other levels being empty. If we represent a full level with a 1 -and an empty level with a 0, then we'd have $1100$, which is $20$ in +and an empty level with a 0, then we'd have $10100$, which is $20$ in base 2. \begin{algorithm} @@ -129,7 +129,7 @@ $\mathscr{I}_{target} \gets \text{build}(\text{unbuild}(\mathscr{I}_0) \cup \ld Our generalization, then, is to represent the data as an $s$-ary decomposition, where the scale factor represents the base of the representation. To accomplish this, we set of capacity of level $i$ to -be $N_B (s - 1) \cdot s^i$, where $N_b$ is the size of the buffer. The +be $N_B (s - 1) \cdot s^i$, where $N_B$ is the size of the buffer. The resulting structure will have at most $\log_s n$ shards. The resulting policy is described in Algorithm~\ref{alg:design-bsm}. @@ -192,7 +192,7 @@ analysis. The worst-case cost of a reconstruction is $B(n)$, and there are $\log_s(n)$ total levels, so the total reconstruction costs associated with a record can be upper-bounded by, $B(n) \cdot \frac{W(\log_s(n))}{n}$, and then this cost amortized over the $n$ -insertions necessary to get the record into the last level. We'lll also +insertions necessary to get the record into the last level. We'll also condense the multiplicative constants and drop the additive ones to more clearly represent the relationship we're looking to show. This results in an amortized insertion cost of, @@ -306,12 +306,13 @@ $\mathscr{I}_0 \gets \text{build}(r)$ \; \end{algorithm} Our leveling layout policy is described in -Algorithm~\ref{alg:design-leveling}. Each level contains a single structure -with a capacity of $N_B\cdot s^{i+1}$ records. When a reconstruction occurs, -the first level $i$ that has enough space to have the records in the -level $i-1$ stored inside of it is selected as the target, and then a new -structure is built at level $i$ containing the records in it and level -$i-1$. Then, all levels $j < (i - 1)$ are shifted by one level to level +Algorithm~\ref{alg:design-leveling}. Each level contains a single +structure with a capacity of $N_B\cdot s^{i+1}$ records. When a +reconstruction occurs, the smallest level, $i$, with space to contain the +records from level $i-1$, in addition to the records currently within +it, is located. Then, a new structure is built at level $i$ containing +all of the records in levels $i$ and $i-1$, and the structure at level +$i-1$ is deleted. Finally, all levels $j < (i - 1)$ are shifted to level $j+1$. This process clears space in level $0$ to contain the buffer flush. \begin{theorem} @@ -634,7 +635,7 @@ to minimize its influence on the results (we've seen before in Sections~\ref{ssec:ds-exp} and \ref{ssec:dyn-ds-exp} that scale factor affects leveling and tiering in opposite ways) and isolate the influence of the layout policy alone to as great a degree as possible. We used a -buffer size of $N_b=12000$ for the ISAM tree structure, and $N_B=1000$ +buffer size of $N_B=12000$ for the ISAM tree structure, and $N_B=1000$ for the VPTree. We generated this distribution by inserting $30\%$ of the records from @@ -750,7 +751,7 @@ in scale factor have very little effect. However, level's insertion performance degrades linearly with scale factor, and this is well demonstrated in the plot. -The store is a bit clearer in Figure~\ref{fig:design-knn-tradeoff}. The +The story is a bit clearer in Figure~\ref{fig:design-knn-tradeoff}. The VPTree has a much greater construction time, both asymptotically and in absolute terms, and the average query latency is also significantly greater. These result in the configuration changes showing much more @@ -759,7 +760,7 @@ trade-off space. The same general trends hold as in ISAM, just amplified. Leveling has better query performance than tiering and sees increased query performance and decreased insert performance as the scale factor increases. Tiering has better insertion performance and worse query -performance than leveling, and sees improved insert and worstening +performance than leveling, and sees improved insert and worsening query performance as the scale factor is increased. The Bentley-Saxe method shows similar trends to leveling. diff --git a/chapters/dynamization.tex b/chapters/dynamization.tex index a2277c3..bbd5534 100644 --- a/chapters/dynamization.tex +++ b/chapters/dynamization.tex @@ -6,16 +6,14 @@ existing work in the area of data structure dynamization. We will first discuss the concept of a search problem, which is central to dynamization techniques. While one might imagine that restrictions on dynamization would be functions of the data structure to be dynamized, -in practice the requirements placed on the data structure are quite mild, -and it is the necessary properties of the search problem that the data -structure is used to address that provide the central difficulty to -applying dynamization techniques in a given area. After this, database -indices will be discussed briefly. Indices are the primary use of data -structures within the database context that is of interest to our work. -Following this, existing theoretical results in the area of data structure -dynamization will be discussed, which will serve as the building blocks -for our techniques in subsequent chapters. The chapter will conclude with -a discussion of some of the limitations of these existing techniques. +in practice the requirements placed on the data structure are quite mild. +Instead, the central difficulties to applying dynamization lie in the +necessary properties of the search problem that the data structure is +intended to solve. Following this, existing theoretical results in the +area of data structure dynamization will be discussed, which will serve +as the building blocks for our techniques in subsequent chapters. The +chapter will conclude with a discussion of some of the limitations of +these existing techniques. \section{Queries and Search Problems} \label{sec:dsp} @@ -517,11 +515,12 @@ an efficient merge operation isn't of much use in the equal block method, which doesn't perform data structure merges, and so it isn't considered in the above definition.\footnote{ In the equal block method, all reconstructions are due to either - inserting a record, in which case the reconstruction consists of - adding a single record to a structure, not merging two structures, - or due to re-partitioning, occurs when $f(n)$ increases sufficiently - that the existing structures must be made \emph{smaller}, and so, - again, no merging is done. + inserting a record or repartitioning of the records. In the former + case, the reconstruction pulls records from only a single structure + and merging is not possible. In the latter, records may come from + multiple structures, but the structures are not merged and only some + of the records from each are used. In either case, merging is not + useful as an optimization. } \subsection{Delete Support} @@ -596,8 +595,8 @@ from the ghost structure can be removed from the result set using the inverse merge operator. This simulates the result that would have been obtained had the records been physically removed from the main structure. -Two examples of invertible search problems are set membership -and range count. Range count was formally defined in +Two examples of invertible search problems are range count and set +membership. Range count was formally defined in Definition~\ref{def:range-count}. \begin{theorem} @@ -863,12 +862,12 @@ the records in the structure. Overmars and van Leeuwen~\cite{overmars81, overmars83} proposed an alteration to the Bentley-Saxe method that is capable of bringing the -worst-case insertion cost in in line with amortized, $I(n) \in \Theta +worst-case insertion cost in line with amortized, $I(n) \in \Theta \left(\frac{B(n)}{n} \log n\right)$. To accomplish this, they introduce a structure that is capable of spreading the work of reconstructions out across multiple inserts. Their structure consists of $\log_2 n$ levels, like the Bentley-Saxe method, but each level contains four data -structures, rather than one,called $Oldest_i$, $Older_i$, $Old_i$, $New_i$ +structures, rather than one, called $Oldest_i$, $Older_i$, $Old_i$, $New_i$ respectively.\footnote{ We are here adopting nomenclature used by Erickson in his lecture notes on the topic~\cite{erickson-bsm-notes}, which is a bit clearer @@ -884,7 +883,7 @@ additionally appear in a new structure as well. When inserting into this structure, the algorithm first examines every level, $i$. If both $Older_{i-1}$ and $Oldest_{i-1}$ are full, then the algorithm will execute $\frac{B(2^i)}{2^i}$ steps of the algorithm -to construction $New_i$ from $\text{unbuild}(Older_{i-1}) \cup +to construct $New_i$ from $\text{unbuild}(Older_{i-1}) \cup \text{unbuild}(Oldest_{i-1})$. Once enough inserts have been performed to completely build some block, $New_i$, the source blocks for the reconstruction, $Oldest_{i-1}$ and $Older_{i-1}$ are deleted, $Old_{i-1}$ @@ -1165,7 +1164,7 @@ form of configurability~\cite{pgm,almodaresi23}, usually inspired by the design space of LSM trees~\cite{oneil96}, but the full consequences of this parametrization in the context of dynamization have, to the best of our knowledge, not been explored. We will discuss this topic -in Chapter~\ref{chap:design-space} +in Chapter~\ref{chap:design-space}. \subsection{Insertion Tail Latency} \label{ssec:bsm-tail-latency-problem} diff --git a/chapters/introduction.tex b/chapters/introduction.tex index 050a58b..6b6904a 100644 --- a/chapters/introduction.tex +++ b/chapters/introduction.tex @@ -1,7 +1,7 @@ \chapter{Introduction} \label{chap:intro} -\section{Motiviation} +\section{Motivation} Modern relational database management systems (RDBMS) are founded upon a set-based representation of data~\cite{codd70}. This model is @@ -39,17 +39,19 @@ data structures, which often already exist, are at the heart of such systems, meaningfully using such a data structure in a database requires adding a large number of additional features. -To be useful within the context of a database, a data structure must +A recent work on extending Datalog with support for user-defined data +structures demonstrates both the benefits and challenges associated +with the use of specialized indices. It showed showed significant +improvements in query processing time and space requirements when +using custom indices, but required that the user-defined structures +have support for concurrent updates~\cite{byods-datalog}. In practice, +to be useful within the context of a database, a data structure must support inserts and deletes (collectively referred to as updates), as well as concurrency support that satisfies standardized isolation semantics~\cite{cowbook}, support for crash recovery of the index in the -case of a system failure~\cite{aries}, and possibly more. As an example, -a recent work on extended Datalog with support for user-defined data -structures showed significant improvements in query processing time and -space requirements, but required that the user-defined structures have -support for concurrent updates~\cite{byods-datalog}. The process of -adding these features to data structures that currently lack them is -not straightfoward and can take an extensive amount of time and effort. +case of a system failure~\cite{aries}, and possibly more. The process +of extending an existing or novel data structure with support for all +of these functions is a major barrier to their use. As a current example that demonstrates this problem, consider the recent development of learned indices. These are a broad class of data structure @@ -91,7 +93,7 @@ step in this direction. \section{Existing Attempts} -At present, there are several lines of work targetted at reducing +At present, there are several lines of work targeted at reducing the development burden associated with creating specialized indices. We classify them into three broad categories, @@ -134,7 +136,7 @@ to maximize the overall performance of the workload. Although some work in this area suggests generalization to more complex data types, such as multi-dimensional data~\cite{fluid-ds}, this line is broadly focused on creating instance-optimal indices for workloads that databases are -already well equiped to handle. While this task is quite important, it +already well equipped to handle. While this task is quite important, it is not precisely the work that we are trying to accomplish here. And, because the techniques are limited to specified sets of structural primitives, it isn't clear that the approach can be usefully extended @@ -163,7 +165,7 @@ difficulties of index development. The final approach is automatic feature extension. More specifically, we will consider dynamization,\footnote{ - This is alternative called a static-to-dynamic transformation, + This is alternatively called a static-to-dynamic transformation, or dynamic extension, depending upon the source. These terms all refer to the same process. } the automatic extension of an existing static data structure with @@ -209,7 +211,7 @@ faced by most classical dynamization techniques. Specifically, the proposed work will address the following points, \begin{enumerate} - \item The proposal of a theoretical framework for analysing queries + \item The proposal of a theoretical framework for analyzing queries and data structures that extends existing theoretical approaches and allows for more data structures to be dynamized. \item The design of a system based upon this theoretical framework diff --git a/chapters/sigmod23/background.tex b/chapters/sigmod23/background.tex index 88f2585..42a52de 100644 --- a/chapters/sigmod23/background.tex +++ b/chapters/sigmod23/background.tex @@ -104,7 +104,7 @@ sampling} (WIRS), positive weights $w: D\to \mathbb{R}^+$. Given a query interval $q = [x, y]$ and an integer $k$, an independent range sampling query returns $k$ independent samples from $D \cap q$ with each - point having a probability of $\nicefrac{w(d)}{\sum_{p \in D \cap q}w(p)}$ + point having a probability of $\frac{w(d)}{\sum_{p \in D \cap q}w(p)}$ of being sampled. \end{definition} @@ -118,7 +118,7 @@ SQL's \texttt{TABLESAMPLE} operator~\cite{postgres-doc}. However, the algorithms used to implement this operator have significant limitations and do not allow users to maintain statistical independence of the results without also running the query to be sampled from in full. Thus, users must -choose between independece and performance. +choose between independence and performance. To maintain statistical independence, Bernoulli sampling is used. This technique requires iterating over every record in the result set of the @@ -198,7 +198,7 @@ call static sampling indices (SSIs) in this chapter,\footnote{ am retaining the term SSI in this chapter for consistency with the original paper, but understand that in the terminology established in Chapter~\ref{chap:background}, SSIs are data structures, not indices. -}, +} that are capable of answering sampling queries more efficiently than Olken's method relative to the overall data size. An example of such a structure is used in Walker's alias method \cite{walker74,vose91}. diff --git a/chapters/sigmod23/framework.tex b/chapters/sigmod23/framework.tex index d51c2cb..b3a8215 100644 --- a/chapters/sigmod23/framework.tex +++ b/chapters/sigmod23/framework.tex @@ -532,7 +532,7 @@ rates, buffering, sub-partitioning of structures to allow finer-grained reconstruction~\cite{dayan22}, and approaches for allocating resources to auxiliary structures attached to the main ones for accelerating certain types of query~\cite{dayan18-1, zhu21, monkey}. This work is discussed -in greater depth in Chapter~\ref{chap:related-work} +in greater depth in Chapter~\ref{chap:related-work}. Many of the elements within the LSM Tree design space are based upon the specifics of the data structure itself, and are not applicable to our @@ -561,7 +561,7 @@ the case of sampling this isn't a serious problem. The implications of this will be discussed in Section~\ref{ssec:sampling-cost-funcs}. The size of this buffer, $N_B$ is a user-specified constant. Block capacities are defined in terms of multiples of $N_B$, such that each buffer flush -corresponds to an insert in the traditioanl Bentley-Saxe method. Thus, +corresponds to an insert in the traditional Bentley-Saxe method. Thus, rather than the $i$th block containing $2^i$ records, it contains $N_B \cdot 2^i$ records. We call this unsorted array the \emph{mutable buffer}. @@ -750,8 +750,8 @@ operations must be used, the the cost becomes $I_a(n) \in \Paragraph{Delete.} The framework supports both tombstone and tagged deletes, each with different performance. Using tombstones, the cost of a delete is identical to that of an insert. When using tagging, the -cost of a delete is the same as cost of doing a point lookup, as the -"delete" itself is simply setting a bit in the header of the record, +cost of a delete is the same as the cost of a point lookup, because the +"delete" itself only sets a bit in the header of the record, once it has been located. There will be $\Theta(\log_s n)$ total shards in the structure, each with a look-up cost of $L(n)$ using either the SSI's native point-lookup, or an auxiliary hash table, and the lookup diff --git a/chapters/tail-latency.tex b/chapters/tail-latency.tex index 8ec8d26..5c0e0ba 100644 --- a/chapters/tail-latency.tex +++ b/chapters/tail-latency.tex @@ -60,7 +60,7 @@ majority of inserts worse because of increased write amplification. \label{fig:tl-parm-sweep} \end{figure} -The other tuning nobs that are available to us are of limited usefulness +The other tuning knobs that are available to us are of limited usefulness in tuning the worst case behavior. Figure~\ref{fig:tl-parm-sweep} shows the latency distributions of our framework as we vary the scale factor (Figure~\ref{fig:tl-parm-sf}) and buffer size @@ -227,7 +227,7 @@ Figure~\ref{fig:tl-floodl0-insert} shows that it is possible to obtain insertion latency distributions using amortized global reconstruction that are directly comparable to dynamic structures based on amortized local reconstruction, at least in some cases. In particular, the -worst-case insertion tail latency in this model is direct function +worst-case insertion tail latency in this model is a direct function of the buffer size, as the worst-case insert occurs when the buffer must be flushed to a shard. However, this performance comes at the cost of queries, which are incredibly slow compared to B+Trees, as @@ -947,10 +947,10 @@ These tests were run on a system with sufficient available resources to fully parallelize all reconstructions. First, Figure~\ref{fig:tl-stall-200m} shows the results of testing -insertion of the 200 million record SOSD \texttt{OSM} dataset in -a dynamized ISAM tree. Using our insertion stalling technique, as -well as strict tiering. We inserted $30\%$ of the records, and then -measured the individual latency of each insert after that point to produce +insertion of the 200 million record SOSD \texttt{OSM} dataset in a +dynamized ISAM tree, using both our insertion stalling technique and +strict tiering. We inserted $30\%$ of the records, and then measured +the individual latency of each insert after that point to produce Figure~\ref{fig:tl-stall-200m-dist}. Figure~\ref{fig:tl-stall-200m-shard} was produced by recording the number of shards in the dynamized structure each time the buffer flushed. Note that a stall value of one indicates @@ -961,14 +961,14 @@ scale factor of $s=6$. It uses the concurrency control scheme described in Section~\ref{ssec:dyn-concurrency}. -Figure~\ref{fig:tl-stall-200m-dist} clearly shows that all of insertion +Figure~\ref{fig:tl-stall-200m-dist} clearly shows that all insertion rejection probabilities succeed in greatly reducing tail latency relative to tiering. Additionally, it shows a small amount of available tuning of the worst-case insertion latencies, with higher stall amounts reducing the tail latencies slightly at various points in the distribution. This latter effect results from the buffer flush latency hiding mechanism, which was retained from Chapter~\ref{chap:framework}. The buffer actually -has space to two two versions, and the second version can be filled while +has space for two versions, and the second version can be filled while the first is flushing. This means that, for more aggressive stalling, some of the time spent blocking on the buffer flush is redistributed over the inserts into the second version of the buffer, rather than @@ -1121,7 +1121,7 @@ are available to leverage parallel reconstructions. Our new system retains the concept of buffer size and scale factor from the previous version, although these have very different performance implications given our different compaction strategy. In this test, we -examine the effects of these parameters on the insertion-query tradeoff +examine the effects of these parameters on the insertion-query trade-off curves noted above, as well as on insertion tail latency. The results are shown in Figure~\ref{fig:tl-design-space}, for a dynamized ISAM Tree using the SOSD \texttt{OSM} dataset and point lookup queries. @@ -1140,13 +1140,13 @@ Figure~\ref{fig:tl-sf-curve}. Recall that our system of reconstruction in this chapter does not explicitly enforce any structural invariants, and so the scale factor's only role is in determining at what point a given level will have a reconstruction scheduled for it. Lower scale factors will -more aggresively compact shards, while higher scale factors will allow +more aggressively compact shards, while higher scale factors will allow more shards to accumulate before attempting to perform a reconstruction. Interestingly, there are clear differences in the curves, particularly at higher insertion throughputs. For lower throughputs, a scale factor of $s=2$ appears strictly inferior, while the other tested scale factors result in roughly equivalent curves. However, as the insertion throughput is -increased, the curves begin to seperate more, with $s = 6$ emerging as +increased, the curves begin to separate more, with $s = 6$ emerging as the superior option for the majority of the space. Next, we consider the effect that buffer size has on insertion @@ -1176,10 +1176,10 @@ threads, which was more than enough to run all reconstructions and queries fully in parallel. However, it's important to determine how well the system works in more resource constrained environments. The system shares internal threads between reconstructions and queries, and that -flushing occurs on a dedicated thread seperate from these. During the -benchmark, one client thread issued queries continously and another +flushing occurs on a dedicated thread separate from these. During the +benchmark, one client thread issued queries continuously and another issued inserts. The index accumulated a total of five levels, so -the maximum amount of parralelism available during the testing was 4 +the maximum amount of parallelism available during the testing was 4 parallel reconstructions, along with the dedicated flushing thread and any concurrent queries. In these tests, we used the SOSD \texttt{OSM} dataset (200M records) and point-lookup queries without early abort @@ -1189,7 +1189,7 @@ For our first test, we considered the insertion throughput vs. query latency trade-off for various stall amounts with several internal thread counts. We inserted 30\% of the dataset first, and then measured the insertion throughput over the insertion of the rest of the data -on a client thread, while another client thread continously issued +on a client thread, while another client thread continuously issued queries against the structure. The results of this test are shown in Figure~\ref{fig:tl-latency-threads}. The first note is that the change in the number of available internal threads has little effect on the @@ -1210,7 +1210,7 @@ query latency in two ways, shard count. \end{enumerate} Interestingly, at least in this test, both of these effects are largely -supressed with only a moderate reduction in insertion throughput. But, +suppressed with only a moderate reduction in insertion throughput. But, insufficient parallelism does result in the higher-throughput configurations suffering a significant query latency increase in general. |