From eb38f2002e2dd275dd4e47c0b96c0405b655f71c Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Wed, 5 Dec 2018 14:26:15 -0500 Subject: [PATCH] storage: replace CommandQueue with spanlatch.Manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit replaces the CommandQueue with the spanlatch.Manager, which was introduced in #31997. See that PR for an introduction to how the structure differs from the CommandQueue and how it improves performance on microbenchmarks. This is mostly a mechanical change. One important detail is that it removes the CommandQueue debug change. We found that the page was buggy (or straight up broken) and it wasn't actively used by members of Core when debugging problems. In its place, the commit revives the "slow requests" metric for latching, which hasn't been hooked up in over a year. _### Benchmarks _#### Standard Benchmarks These benchmarks are standard benchmarks that we commonly run. They were run with varying node sizes, cluster sizes, and pre-split counts. ``` name old ops/sec new ops/sec delta kv0/cores=4/nodes=1/splits=0 1.99k ± 2% 2.06k ± 1% +3.22% (p=0.008 n=5+5) kv0/cores=4/nodes=1/splits=100 2.25k ± 1% 2.38k ± 1% +6.01% (p=0.008 n=5+5) kv0/cores=4/nodes=3/splits=0 1.60k ± 0% 1.69k ± 2% +5.53% (p=0.008 n=5+5) kv0/cores=4/nodes=3/splits=100 3.52k ± 6% 3.65k ± 9% ~ (p=0.421 n=5+5) kv0/cores=16/nodes=1/splits=0 19.9k ± 1% 21.8k ± 1% +9.34% (p=0.008 n=5+5) kv0/cores=16/nodes=1/splits=100 24.4k ± 1% 26.1k ± 1% +7.17% (p=0.008 n=5+5) kv0/cores=16/nodes=3/splits=0 14.9k ± 1% 16.1k ± 1% +8.03% (p=0.008 n=5+5) kv0/cores=16/nodes=3/splits=100 20.6k ± 1% 22.8k ± 1% +10.79% (p=0.008 n=5+5) kv0/cores=36/nodes=1/splits=0 31.2k ± 2% 35.3k ± 1% +13.28% (p=0.008 n=5+5) kv0/cores=36/nodes=1/splits=100 45.7k ± 1% 51.1k ± 1% +11.80% (p=0.008 n=5+5) kv0/cores=36/nodes=3/splits=0 23.7k ± 2% 27.1k ± 2% +14.39% (p=0.008 n=5+5) kv0/cores=36/nodes=3/splits=100 34.9k ± 2% 45.1k ± 1% +29.44% (p=0.008 n=5+5) kv95/cores=4/nodes=1/splits=0 12.7k ± 2% 12.9k ± 2% +1.39% (p=0.151 n=5+5) kv95/cores=4/nodes=1/splits=100 12.8k ± 2% 13.1k ± 2% +2.10% (p=0.032 n=5+5) kv95/cores=4/nodes=3/splits=0 10.6k ± 1% 10.8k ± 1% +1.58% (p=0.056 n=5+5) kv95/cores=4/nodes=3/splits=100 12.3k ± 7% 12.6k ± 8% +2.61% (p=0.095 n=5+5) kv95/cores=16/nodes=1/splits=0 50.9k ± 1% 52.2k ± 1% +2.37% (p=0.008 n=5+5) kv95/cores=16/nodes=1/splits=100 52.2k ± 1% 53.0k ± 1% +1.49% (p=0.008 n=5+5) kv95/cores=16/nodes=3/splits=0 46.2k ± 1% 46.8k ± 1% +1.32% (p=0.032 n=5+5) kv95/cores=16/nodes=3/splits=100 51.0k ± 1% 53.2k ± 1% +4.25% (p=0.008 n=5+5) kv95/cores=36/nodes=1/splits=0 79.8k ± 2% 101.6k ± 1% +27.31% (p=0.008 n=5+5) kv95/cores=36/nodes=1/splits=100 104k ± 1% 107k ± 1% +2.60% (p=0.008 n=5+5) kv95/cores=36/nodes=3/splits=0 85.8k ± 1% 91.8k ± 1% +7.08% (p=0.008 n=5+5) kv95/cores=36/nodes=3/splits=100 106k ± 1% 112k ± 1% +5.51% (p=0.008 n=5+5) name old p50(ms) new p50(ms) delta kv0/cores=4/nodes=1/splits=0 3.52 ± 5% 3.40 ± 0% -3.41% (p=0.016 n=5+4) kv0/cores=4/nodes=1/splits=100 3.30 ± 0% 3.00 ± 0% -9.09% (p=0.008 n=5+5) kv0/cores=4/nodes=3/splits=0 4.70 ± 0% 4.14 ± 9% -11.91% (p=0.008 n=5+5) kv0/cores=4/nodes=3/splits=100 1.50 ± 0% 1.48 ± 8% ~ (p=0.968 n=4+5) kv0/cores=16/nodes=1/splits=0 1.40 ± 0% 1.40 ± 0% ~ (all equal) kv0/cores=16/nodes=1/splits=100 1.20 ± 0% 1.20 ± 0% ~ (all equal) kv0/cores=16/nodes=3/splits=0 2.00 ± 0% 1.90 ± 0% -5.00% (p=0.000 n=5+4) kv0/cores=16/nodes=3/splits=100 1.40 ± 0% 1.40 ± 0% ~ (all equal) kv0/cores=36/nodes=1/splits=0 1.76 ± 3% 1.60 ± 0% -9.09% (p=0.008 n=5+5) kv0/cores=36/nodes=1/splits=100 1.40 ± 0% 1.30 ± 0% -7.14% (p=0.008 n=5+5) kv0/cores=36/nodes=3/splits=0 2.56 ± 2% 2.40 ± 0% -6.25% (p=0.000 n=5+4) kv0/cores=36/nodes=3/splits=100 1.70 ± 0% 1.40 ± 0% -17.65% (p=0.008 n=5+5) kv95/cores=4/nodes=1/splits=0 0.50 ± 0% 0.50 ± 0% ~ (all equal) kv95/cores=4/nodes=1/splits=100 0.50 ± 0% 0.50 ± 0% ~ (all equal) kv95/cores=4/nodes=3/splits=0 0.60 ± 0% 0.60 ± 0% ~ (all equal) kv95/cores=4/nodes=3/splits=100 0.60 ± 0% 0.60 ± 0% ~ (all equal) kv95/cores=16/nodes=1/splits=0 0.50 ± 0% 0.50 ± 0% ~ (all equal) kv95/cores=16/nodes=1/splits=100 0.50 ± 0% 0.50 ± 0% ~ (all equal) kv95/cores=16/nodes=3/splits=0 0.70 ± 0% 0.64 ± 9% -8.57% (p=0.167 n=5+5) kv95/cores=16/nodes=3/splits=100 0.60 ± 0% 0.60 ± 0% ~ (all equal) kv95/cores=36/nodes=1/splits=0 0.50 ± 0% 0.50 ± 0% ~ (all equal) kv95/cores=36/nodes=1/splits=100 0.50 ± 0% 0.50 ± 0% ~ (all equal) kv95/cores=36/nodes=3/splits=0 0.66 ± 9% 0.60 ± 0% -9.09% (p=0.167 n=5+5) kv95/cores=36/nodes=3/splits=100 0.60 ± 0% 0.60 ± 0% ~ (all equal) name old p99(ms) new p99(ms) delta kv0/cores=4/nodes=1/splits=0 11.0 ± 0% 10.5 ± 0% -4.55% (p=0.000 n=5+4) kv0/cores=4/nodes=1/splits=100 7.90 ± 0% 7.60 ± 0% -3.80% (p=0.000 n=5+4) kv0/cores=4/nodes=3/splits=0 15.7 ± 0% 15.2 ± 0% -3.18% (p=0.008 n=5+5) kv0/cores=4/nodes=3/splits=100 8.90 ± 0% 8.12 ± 3% -8.76% (p=0.016 n=4+5) kv0/cores=16/nodes=1/splits=0 3.46 ± 2% 3.00 ± 0% -13.29% (p=0.000 n=5+4) kv0/cores=16/nodes=1/splits=100 4.50 ± 0% 3.36 ± 2% -25.33% (p=0.008 n=5+5) kv0/cores=16/nodes=3/splits=0 4.50 ± 0% 3.90 ± 0% -13.33% (p=0.008 n=5+5) kv0/cores=16/nodes=3/splits=100 5.80 ± 0% 4.10 ± 0% -29.31% (p=0.029 n=4+4) kv0/cores=36/nodes=1/splits=0 6.80 ± 0% 5.20 ± 0% -23.53% (p=0.008 n=5+5) kv0/cores=36/nodes=1/splits=100 5.80 ± 0% 4.32 ± 4% -25.52% (p=0.008 n=5+5) kv0/cores=36/nodes=3/splits=0 7.72 ± 2% 6.30 ± 0% -18.39% (p=0.000 n=5+4) kv0/cores=36/nodes=3/splits=100 7.98 ± 2% 5.20 ± 0% -34.84% (p=0.000 n=5+4) kv95/cores=4/nodes=1/splits=0 5.38 ± 3% 5.20 ± 0% -3.35% (p=0.167 n=5+5) kv95/cores=4/nodes=1/splits=100 5.00 ± 0% 5.00 ± 0% ~ (all equal) kv95/cores=4/nodes=3/splits=0 5.68 ± 3% 5.50 ± 0% -3.17% (p=0.095 n=5+4) kv95/cores=4/nodes=3/splits=100 3.60 ±31% 2.93 ± 3% -18.75% (p=0.016 n=5+4) kv95/cores=16/nodes=1/splits=0 4.10 ± 0% 4.10 ± 0% ~ (all equal) kv95/cores=16/nodes=1/splits=100 4.50 ± 0% 4.10 ± 0% -8.89% (p=0.000 n=5+4) kv95/cores=16/nodes=3/splits=0 2.60 ± 0% 2.60 ± 0% ~ (all equal) kv95/cores=16/nodes=3/splits=100 2.50 ± 0% 1.90 ± 5% -24.00% (p=0.008 n=5+5) kv95/cores=36/nodes=1/splits=0 6.60 ± 0% 6.00 ± 0% -9.09% (p=0.029 n=4+4) kv95/cores=36/nodes=1/splits=100 5.50 ± 0% 5.12 ± 2% -6.91% (p=0.008 n=5+5) kv95/cores=36/nodes=3/splits=0 4.18 ± 2% 4.02 ± 3% -3.71% (p=0.000 n=4+5) kv95/cores=36/nodes=3/splits=100 3.80 ± 0% 2.80 ± 0% -26.32% (p=0.008 n=5+5) ``` _#### Large-machine Benchmarks These benchmarks are standard benchmarks run on a single-node cluster with 72 vCPUs. ``` name old ops/sec new ops/sec delta kv0/cores=72/nodes=1/splits=0 31.0k ± 4% 36.4k ± 1% +17.57% (p=0.008 n=5+5) kv0/cores=72/nodes=1/splits=100 44.0k ± 0% 49.0k ± 1% +11.41% (p=0.008 n=5+5) kv95/cores=72/nodes=1/splits=0 52.7k ±18% 72.6k ±26% +37.70% (p=0.016 n=5+5) kv95/cores=72/nodes=1/splits=100 66.8k ±17% 68.5k ± 5% ~ (p=0.286 n=5+4) name old p50(ms) new p50(ms) delta kv0/cores=72/nodes=1/splits=0 2.30 ±13% 2.52 ± 5% ~ (p=0.214 n=5+5) kv0/cores=72/nodes=1/splits=100 3.00 ± 0% 2.90 ± 0% -3.33% (p=0.008 n=5+5) kv95/cores=72/nodes=1/splits=0 0.46 ±13% 0.50 ± 0% ~ (p=0.444 n=5+5) kv95/cores=72/nodes=1/splits=100 0.44 ±14% 0.50 ± 0% +13.64% (p=0.167 n=5+5) name old p99(ms) new p99(ms) delta kv0/cores=72/nodes=1/splits=0 18.9 ± 6% 13.3 ± 5% -29.56% (p=0.008 n=5+5) kv0/cores=72/nodes=1/splits=100 13.4 ± 2% 11.0 ± 0% -17.91% (p=0.008 n=5+5) kv95/cores=72/nodes=1/splits=0 34.4 ±34% 23.5 ±24% -31.74% (p=0.048 n=5+5) kv95/cores=72/nodes=1/splits=100 21.0 ± 0% 19.1 ± 4% -8.81% (p=0.029 n=4+4) ``` _#### Motivating Benchmarks These are benchmarks that used to generate a lot of contention in the CommandQueue. They have small cycle-lengths, indicated by the `c` specifier. The last one also includes 20% scan operations, which increases contention between non-overlapping point operations. ``` name old ops/sec new ops/sec delta kv95-c5/cores=16/nodes=1/splits=0 45.1k ± 1% 47.2k ± 4% +4.59% (p=0.008 n=5+5) kv95-c5/cores=36/nodes=1/splits=0 44.6k ± 1% 76.3k ± 1% +71.05% (p=0.008 n=5+5) kv50-c128/cores=16/nodes=1/splits=0 27.2k ± 2% 29.4k ± 1% +8.12% (p=0.008 n=5+5) kv50-c128/cores=36/nodes=1/splits=0 42.6k ± 2% 50.0k ± 1% +17.39% (p=0.008 n=5+5) kv70-20-c128/cores=16/nodes=1/splits=0 28.7k ± 1% 29.8k ± 3% +3.87% (p=0.008 n=5+5) kv70-20-c128/cores=36/nodes=1/splits=0 41.9k ± 4% 52.8k ± 2% +25.97% (p=0.008 n=5+5) name old p50(ms) new p50(ms) delta kv95-c5/cores=16/nodes=1/splits=0 0.60 ± 0% 0.60 ± 0% ~ (all equal) kv95-c5/cores=36/nodes=1/splits=0 0.90 ± 0% 0.80 ± 0% -11.11% (p=0.008 n=5+5) kv50-c128/cores=16/nodes=1/splits=0 1.10 ± 0% 1.06 ± 6% ~ (p=0.444 n=5+5) kv50-c128/cores=36/nodes=1/splits=0 1.26 ± 5% 1.30 ± 0% ~ (p=0.444 n=5+5) kv70-20-c128/cores=16/nodes=1/splits=0 0.66 ± 9% 0.60 ± 0% -9.09% (p=0.167 n=5+5) kv70-20-c128/cores=36/nodes=1/splits=0 0.70 ± 0% 0.50 ± 0% -28.57% (p=0.008 n=5+5) name old p99(ms) new p99(ms) delta kv95-c5/cores=16/nodes=1/splits=0 2.40 ± 0% 2.10 ± 0% -12.50% (p=0.000 n=5+4) kv95-c5/cores=36/nodes=1/splits=0 5.80 ± 0% 3.30 ± 0% -43.10% (p=0.000 n=5+4) kv50-c128/cores=16/nodes=1/splits=0 3.50 ± 0% 3.00 ± 0% -14.29% (p=0.008 n=5+5) kv50-c128/cores=36/nodes=1/splits=0 6.80 ± 0% 4.70 ± 0% -30.88% (p=0.079 n=4+5) kv70-20-c128/cores=16/nodes=1/splits=0 5.00 ± 0% 4.70 ± 0% -6.00% (p=0.029 n=4+4) kv70-20-c128/cores=36/nodes=1/splits=0 11.0 ± 0% 6.8 ± 0% -38.18% (p=0.008 n=5+5) ``` _#### Batching Benchmarks One optimization left out of the new spanlatch.Manager was the "covering" optimization, where commands were initially added to the interval tree as a single spanning interval and only expanded later. I ran a series of benchmarks to verify that this optimization was not needed. My hypothesis was that the order of magnitude increase the speed of the interval tree would make the optimization unnecessary. It turns out that removing the optimization hurt a few benchmarks to a small degree but speed up others tremendously (some benchmarks improved by over 400%). I suspect that the covering optimization could actually hurt in cases where it causes non-overlapping requests to overlap. It is interesting how quickly a few of these benchmarks oscillate from small losses to big wins. It makes me think that there's some non-linear behavior with the old CommandQueue that would cause its performance to quickly degrade once it became a contention bottleneck. ``` name old ops/sec new ops/sec delta kv0-b16/cores=4/nodes=1/splits=0 2.41k ± 0% 2.06k ± 3% -14.75% (p=0.008 n=5+5) kv0-b16/cores=4/nodes=1/splits=100 514 ± 0% 534 ± 1% +3.88% (p=0.008 n=5+5) kv0-b16/cores=16/nodes=1/splits=0 2.95k ± 0% 4.35k ± 0% +47.74% (p=0.008 n=5+5) kv0-b16/cores=16/nodes=1/splits=100 1.80k ± 1% 1.88k ± 1% +4.46% (p=0.008 n=5+5) kv0-b16/cores=36/nodes=1/splits=0 2.74k ± 0% 4.92k ± 1% +79.55% (p=0.008 n=5+5) kv0-b16/cores=36/nodes=1/splits=100 2.39k ± 1% 2.45k ± 1% +2.41% (p=0.008 n=5+5) kv0-b128/cores=4/nodes=1/splits=0 422 ± 0% 518 ± 1% +22.60% (p=0.008 n=5+5) kv0-b128/cores=4/nodes=1/splits=100 98.4 ± 1% 98.8 ± 1% ~ (p=0.810 n=5+5) kv0-b128/cores=16/nodes=1/splits=0 532 ± 0% 1059 ± 0% +99.16% (p=0.008 n=5+5) kv0-b128/cores=16/nodes=1/splits=100 291 ± 1% 307 ± 1% +5.18% (p=0.008 n=5+5) kv0-b128/cores=36/nodes=1/splits=0 483 ± 0% 1288 ± 1% +166.37% (p=0.008 n=5+5) kv0-b128/cores=36/nodes=1/splits=100 394 ± 1% 408 ± 1% +3.51% (p=0.008 n=5+5) kv0-b1024/cores=4/nodes=1/splits=0 49.7 ± 1% 72.8 ± 1% +46.52% (p=0.008 n=5+5) kv0-b1024/cores=4/nodes=1/splits=100 30.8 ± 0% 23.4 ± 0% -24.03% (p=0.008 n=5+5) kv0-b1024/cores=16/nodes=1/splits=0 48.9 ± 2% 160.6 ± 0% +228.38% (p=0.008 n=5+5) kv0-b1024/cores=16/nodes=1/splits=100 101 ± 1% 80 ± 0% -21.64% (p=0.008 n=5+5) kv0-b1024/cores=36/nodes=1/splits=0 37.5 ± 0% 208.1 ± 1% +454.99% (p=0.016 n=4+5) kv0-b1024/cores=36/nodes=1/splits=100 162 ± 0% 124 ± 0% -23.22% (p=0.008 n=5+5) kv95-b16/cores=4/nodes=1/splits=0 5.93k ± 0% 6.20k ± 1% +4.55% (p=0.008 n=5+5) kv95-b16/cores=4/nodes=1/splits=100 2.27k ± 1% 2.32k ± 1% +2.28% (p=0.008 n=5+5) kv95-b16/cores=16/nodes=1/splits=0 5.15k ± 1% 18.79k ± 1% +264.73% (p=0.008 n=5+5) kv95-b16/cores=16/nodes=1/splits=100 8.31k ± 1% 8.57k ± 1% +3.16% (p=0.008 n=5+5) kv95-b16/cores=36/nodes=1/splits=0 3.96k ± 0% 10.67k ± 1% +169.81% (p=0.008 n=5+5) kv95-b16/cores=36/nodes=1/splits=100 15.7k ± 2% 16.2k ± 4% +2.75% (p=0.151 n=5+5) kv95-b128/cores=4/nodes=1/splits=0 1.12k ± 1% 1.27k ± 0% +13.28% (p=0.008 n=5+5) kv95-b128/cores=4/nodes=1/splits=100 290 ± 1% 299 ± 1% +3.02% (p=0.008 n=5+5) kv95-b128/cores=16/nodes=1/splits=0 1.06k ± 0% 3.31k ± 0% +213.09% (p=0.008 n=5+5) kv95-b128/cores=16/nodes=1/splits=100 662 ±91% 1095 ± 1% +65.42% (p=0.016 n=5+4) kv95-b128/cores=36/nodes=1/splits=0 715 ± 2% 3586 ± 0% +401.21% (p=0.008 n=5+5) kv95-b128/cores=36/nodes=1/splits=100 1.15k ±90% 2.01k ± 2% +74.79% (p=0.016 n=5+4) kv95-b1024/cores=4/nodes=1/splits=0 134 ± 1% 170 ± 1% +26.59% (p=0.008 n=5+5) kv95-b1024/cores=4/nodes=1/splits=100 54.8 ± 3% 53.3 ± 3% -2.84% (p=0.056 n=5+5) kv95-b1024/cores=16/nodes=1/splits=0 104 ± 3% 367 ± 1% +252.37% (p=0.008 n=5+5) kv95-b1024/cores=16/nodes=1/splits=100 210 ± 1% 214 ± 1% +1.86% (p=0.008 n=5+5) kv95-b1024/cores=36/nodes=1/splits=0 76.5 ± 2% 383.9 ± 1% +401.67% (p=0.008 n=5+5) kv95-b1024/cores=36/nodes=1/splits=100 431 ± 1% 436 ± 1% +1.17% (p=0.016 n=5+5) name old p50(ms) new p50(ms) delta kv0-b16/cores=4/nodes=1/splits=0 3.00 ± 0% 3.40 ± 0% +13.33% (p=0.016 n=5+4) kv0-b16/cores=4/nodes=1/splits=100 15.2 ± 0% 14.7 ± 0% -3.29% (p=0.008 n=5+5) kv0-b16/cores=16/nodes=1/splits=0 10.5 ± 0% 7.7 ± 2% -26.48% (p=0.008 n=5+5) kv0-b16/cores=16/nodes=1/splits=100 17.8 ± 0% 16.8 ± 0% -5.62% (p=0.008 n=5+5) kv0-b16/cores=36/nodes=1/splits=0 26.2 ± 0% 14.2 ± 0% -45.80% (p=0.008 n=5+5) kv0-b16/cores=36/nodes=1/splits=100 29.0 ± 2% 28.3 ± 0% -2.28% (p=0.095 n=5+4) kv0-b128/cores=4/nodes=1/splits=0 17.8 ± 0% 15.2 ± 0% -14.61% (p=0.000 n=5+4) kv0-b128/cores=4/nodes=1/splits=100 79.7 ± 0% 79.7 ± 0% ~ (all equal) kv0-b128/cores=16/nodes=1/splits=0 65.0 ± 0% 32.5 ± 0% -50.00% (p=0.029 n=4+4) kv0-b128/cores=16/nodes=1/splits=100 109 ± 0% 105 ± 0% -3.85% (p=0.008 n=5+5) kv0-b128/cores=36/nodes=1/splits=0 168 ± 0% 50 ± 0% -70.02% (p=0.008 n=5+5) kv0-b128/cores=36/nodes=1/splits=100 184 ± 0% 176 ± 0% -4.50% (p=0.008 n=5+5) kv0-b1024/cores=4/nodes=1/splits=0 159 ± 0% 109 ± 0% -31.56% (p=0.000 n=5+4) kv0-b1024/cores=4/nodes=1/splits=100 252 ± 0% 319 ± 0% +26.66% (p=0.008 n=5+5) kv0-b1024/cores=16/nodes=1/splits=0 705 ± 0% 193 ± 0% -72.62% (p=0.000 n=5+4) kv0-b1024/cores=16/nodes=1/splits=100 319 ± 0% 386 ± 0% +21.05% (p=0.008 n=5+5) kv0-b1024/cores=36/nodes=1/splits=0 1.88k ± 0% 0.24k ± 0% -87.05% (p=0.008 n=5+5) kv0-b1024/cores=36/nodes=1/splits=100 436 ± 0% 570 ± 0% +30.77% (p=0.008 n=5+5) kv95-b16/cores=4/nodes=1/splits=0 1.20 ± 0% 1.20 ± 0% ~ (all equal) kv95-b16/cores=4/nodes=1/splits=100 2.60 ± 0% 2.60 ± 0% ~ (all equal) kv95-b16/cores=16/nodes=1/splits=0 6.30 ± 0% 1.40 ± 0% -77.78% (p=0.000 n=5+4) kv95-b16/cores=16/nodes=1/splits=100 1.74 ± 3% 1.76 ± 3% ~ (p=1.000 n=5+5) kv95-b16/cores=36/nodes=1/splits=0 11.5 ± 0% 5.5 ± 0% -52.17% (p=0.000 n=5+4) kv95-b16/cores=36/nodes=1/splits=100 2.42 ±20% 2.42 ±45% ~ (p=0.579 n=5+5) kv95-b128/cores=4/nodes=1/splits=0 6.60 ± 0% 6.00 ± 0% -9.09% (p=0.008 n=5+5) kv95-b128/cores=4/nodes=1/splits=100 21.4 ± 3% 21.0 ± 0% ~ (p=0.444 n=5+5) kv95-b128/cores=16/nodes=1/splits=0 30.4 ± 0% 9.4 ± 0% -69.08% (p=0.008 n=5+5) kv95-b128/cores=16/nodes=1/splits=100 38.2 ±76% 21.2 ± 4% -44.31% (p=0.063 n=5+4) kv95-b128/cores=36/nodes=1/splits=0 88.1 ± 0% 16.8 ± 0% -80.93% (p=0.000 n=5+4) kv95-b128/cores=36/nodes=1/splits=100 56.6 ±85% 29.6 ±15% ~ (p=0.873 n=5+4) kv95-b1024/cores=4/nodes=1/splits=0 52.4 ± 0% 44.0 ± 0% -16.03% (p=0.029 n=4+4) kv95-b1024/cores=4/nodes=1/splits=100 132 ± 2% 143 ± 0% +8.29% (p=0.016 n=5+4) kv95-b1024/cores=16/nodes=1/splits=0 325 ± 3% 80 ± 0% -75.51% (p=0.008 n=5+5) kv95-b1024/cores=16/nodes=1/splits=100 151 ± 0% 151 ± 0% ~ (all equal) kv95-b1024/cores=36/nodes=1/splits=0 973 ± 0% 180 ± 3% -81.55% (p=0.008 n=5+5) kv95-b1024/cores=36/nodes=1/splits=100 168 ± 0% 168 ± 0% ~ (all equal) name old p99(ms) new p99(ms) delta kv0-b16/cores=4/nodes=1/splits=0 8.40 ± 0% 10.30 ± 3% +22.62% (p=0.016 n=4+5) kv0-b16/cores=4/nodes=1/splits=100 29.4 ± 0% 27.3 ± 0% -7.14% (p=0.000 n=5+4) kv0-b16/cores=16/nodes=1/splits=0 16.3 ± 0% 15.5 ± 2% -4.91% (p=0.008 n=5+5) kv0-b16/cores=16/nodes=1/splits=100 31.5 ± 0% 29.4 ± 0% -6.67% (p=0.000 n=5+4) kv0-b16/cores=36/nodes=1/splits=0 37.7 ± 0% 28.7 ± 2% -23.77% (p=0.008 n=5+5) kv0-b16/cores=36/nodes=1/splits=100 62.1 ± 2% 68.4 ±10% +10.15% (p=0.008 n=5+5) kv0-b128/cores=4/nodes=1/splits=0 37.7 ± 0% 39.4 ± 6% +4.46% (p=0.167 n=5+5) kv0-b128/cores=4/nodes=1/splits=100 143 ± 0% 151 ± 0% +5.89% (p=0.016 n=4+5) kv0-b128/cores=16/nodes=1/splits=0 79.7 ± 0% 55.8 ± 2% -30.04% (p=0.008 n=5+5) kv0-b128/cores=16/nodes=1/splits=100 198 ± 3% 188 ± 3% -5.09% (p=0.048 n=5+5) kv0-b128/cores=36/nodes=1/splits=0 184 ± 0% 126 ± 3% -31.82% (p=0.008 n=5+5) kv0-b128/cores=36/nodes=1/splits=100 319 ± 0% 336 ± 0% +5.24% (p=0.008 n=5+5) kv0-b1024/cores=4/nodes=1/splits=0 322 ± 6% 253 ± 4% -21.35% (p=0.008 n=5+5) kv0-b1024/cores=4/nodes=1/splits=100 470 ± 0% 772 ± 4% +64.28% (p=0.016 n=4+5) kv0-b1024/cores=16/nodes=1/splits=0 1.41k ± 0% 0.56k ±11% -60.00% (p=0.000 n=4+5) kv0-b1024/cores=16/nodes=1/splits=100 530 ± 2% 772 ± 0% +45.57% (p=0.008 n=5+5) kv0-b1024/cores=36/nodes=1/splits=0 4.05k ± 7% 1.17k ± 3% -71.19% (p=0.008 n=5+5) kv0-b1024/cores=36/nodes=1/splits=100 792 ±14% 1020 ± 2% +28.81% (p=0.008 n=5+5) kv95-b16/cores=4/nodes=1/splits=0 3.90 ± 0% 3.22 ± 4% -17.44% (p=0.008 n=5+5) kv95-b16/cores=4/nodes=1/splits=100 21.0 ± 0% 19.9 ± 0% -5.24% (p=0.079 n=4+5) kv95-b16/cores=16/nodes=1/splits=0 15.2 ± 0% 7.1 ± 0% -53.29% (p=0.079 n=4+5) kv95-b16/cores=16/nodes=1/splits=100 38.5 ± 3% 37.7 ± 0% ~ (p=0.333 n=5+4) kv95-b16/cores=36/nodes=1/splits=0 128 ± 2% 52 ± 0% -59.16% (p=0.000 n=5+4) kv95-b16/cores=36/nodes=1/splits=100 41.1 ±13% 39.2 ±33% ~ (p=0.984 n=5+5) kv95-b128/cores=4/nodes=1/splits=0 17.8 ± 0% 14.7 ± 0% -17.42% (p=0.079 n=4+5) kv95-b128/cores=4/nodes=1/splits=100 107 ± 2% 106 ± 5% ~ (p=0.683 n=5+5) kv95-b128/cores=16/nodes=1/splits=0 75.5 ± 0% 23.1 ± 0% -69.40% (p=0.008 n=5+5) kv95-b128/cores=16/nodes=1/splits=100 107 ±34% 120 ± 2% ~ (p=1.000 n=5+4) kv95-b128/cores=36/nodes=1/splits=0 253 ± 4% 71 ± 0% -71.86% (p=0.016 n=5+4) kv95-b128/cores=36/nodes=1/splits=100 166 ±19% 164 ±74% ~ (p=0.310 n=5+5) kv95-b1024/cores=4/nodes=1/splits=0 146 ± 3% 101 ± 0% -31.01% (p=0.000 n=5+4) kv95-b1024/cores=4/nodes=1/splits=100 348 ± 4% 366 ± 6% ~ (p=0.317 n=4+5) kv95-b1024/cores=16/nodes=1/splits=0 624 ± 3% 221 ± 2% -64.52% (p=0.008 n=5+5) kv95-b1024/cores=16/nodes=1/splits=100 325 ± 3% 319 ± 0% ~ (p=0.444 n=5+5) kv95-b1024/cores=36/nodes=1/splits=0 1.56k ± 5% 0.41k ± 2% -73.71% (p=0.008 n=5+5) kv95-b1024/cores=36/nodes=1/splits=100 336 ± 0% 336 ± 0% ~ (all equal) ``` Release note (performance improvement): Replace Replica latching mechanism with new optimized data structure that improves throughput, especially under heavy contention. --- pkg/server/serverpb/admin.pb.go | 3 - pkg/server/serverpb/status.pb.go | 1196 +++++------------ pkg/server/serverpb/status.pb.gw.go | 60 - pkg/server/serverpb/status.proto | 23 +- pkg/server/status.go | 30 +- pkg/server/status/health_check.go | 2 +- pkg/storage/client_merge_test.go | 29 +- pkg/storage/command_queue.go | 976 -------------- pkg/storage/command_queue_test.go | 878 ------------ pkg/storage/metrics.go | 89 +- pkg/storage/replica.go | 410 ++---- pkg/storage/replica_test.go | 958 +------------ pkg/storage/spanlatch/manager.go | 92 +- pkg/storage/spanlatch/manager_test.go | 2 +- pkg/storage/spanset/spanset.go | 11 +- pkg/storage/storagebase/base.go | 27 +- pkg/storage/storagepb/lease_status.pb.go | 2 +- pkg/storage/storagepb/state.pb.go | 821 ++--------- pkg/storage/storagepb/state.proto | 23 +- pkg/storage/store.go | 72 - pkg/storage/testing_knobs.go | 15 +- pkg/ui/package.json | 2 - pkg/ui/src/index.tsx | 2 - pkg/ui/src/redux/apiReducers.ts | 14 - pkg/ui/src/util/api.ts | 8 - .../nodeGraphs/dashboards/requests.tsx | 6 +- .../commandQueue/commandQueueViz.tsx | 158 --- .../commandQueue/command_queue.styl | 60 - .../reports/containers/commandQueue/index.tsx | 144 -- .../reports/containers/range/rangeTable.tsx | 61 +- pkg/ui/yarn.lock | 19 +- 31 files changed, 729 insertions(+), 5464 deletions(-) delete mode 100644 pkg/storage/command_queue.go delete mode 100644 pkg/storage/command_queue_test.go delete mode 100644 pkg/ui/src/views/reports/containers/commandQueue/commandQueueViz.tsx delete mode 100644 pkg/ui/src/views/reports/containers/commandQueue/command_queue.styl delete mode 100644 pkg/ui/src/views/reports/containers/commandQueue/index.tsx diff --git a/pkg/server/serverpb/admin.pb.go b/pkg/server/serverpb/admin.pb.go index d2e1aedd22ef..3f7df6e3e3b4 100644 --- a/pkg/server/serverpb/admin.pb.go +++ b/pkg/server/serverpb/admin.pb.go @@ -75,7 +75,6 @@ RangeProblems RangeStatistics PrettySpan - CommandQueueMetrics RangeInfo RangesRequest RangesResponse @@ -118,8 +117,6 @@ ProblemRangesResponse RangeRequest RangeResponse - CommandQueueRequest - CommandQueueResponse DiagnosticsRequest StoresRequest StoreDetails diff --git a/pkg/server/serverpb/status.pb.go b/pkg/server/serverpb/status.pb.go index 421b250c25cb..4a0131217153 100644 --- a/pkg/server/serverpb/status.pb.go +++ b/pkg/server/serverpb/status.pb.go @@ -113,7 +113,7 @@ var ProfileRequest_Type_value = map[string]int32{ func (x ProfileRequest_Type) String() string { return proto.EnumName(ProfileRequest_Type_name, int32(x)) } -func (ProfileRequest_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorStatus, []int{33, 0} } +func (ProfileRequest_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorStatus, []int{32, 0} } // Enum for phase of execution. type ActiveQuery_Phase int32 @@ -135,7 +135,7 @@ var ActiveQuery_Phase_value = map[string]int32{ func (x ActiveQuery_Phase) String() string { return proto.EnumName(ActiveQuery_Phase_name, int32(x)) } -func (ActiveQuery_Phase) EnumDescriptor() ([]byte, []int) { return fileDescriptorStatus, []int{40, 0} } +func (ActiveQuery_Phase) EnumDescriptor() ([]byte, []int) { return fileDescriptorStatus, []int{39, 0} } type CertificatesRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -321,18 +321,6 @@ func (m *PrettySpan) String() string { return proto.CompactTextString func (*PrettySpan) ProtoMessage() {} func (*PrettySpan) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{11} } -type CommandQueueMetrics struct { - WriteCommands int64 `protobuf:"varint,1,opt,name=write_commands,json=writeCommands,proto3" json:"write_commands,omitempty"` - ReadCommands int64 `protobuf:"varint,2,opt,name=read_commands,json=readCommands,proto3" json:"read_commands,omitempty"` - MaxOverlapsSeen int64 `protobuf:"varint,3,opt,name=max_overlaps_seen,json=maxOverlapsSeen,proto3" json:"max_overlaps_seen,omitempty"` - TreeSize int32 `protobuf:"varint,4,opt,name=tree_size,json=treeSize,proto3" json:"tree_size,omitempty"` -} - -func (m *CommandQueueMetrics) Reset() { *m = CommandQueueMetrics{} } -func (m *CommandQueueMetrics) String() string { return proto.CompactTextString(m) } -func (*CommandQueueMetrics) ProtoMessage() {} -func (*CommandQueueMetrics) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{12} } - type RangeInfo struct { Span PrettySpan `protobuf:"bytes,1,opt,name=span" json:"span"` RaftState RaftState `protobuf:"bytes,2,opt,name=raft_state,json=raftState" json:"raft_state"` @@ -343,8 +331,8 @@ type RangeInfo struct { LeaseHistory []cockroach_roachpb1.Lease `protobuf:"bytes,8,rep,name=lease_history,json=leaseHistory" json:"lease_history"` Problems RangeProblems `protobuf:"bytes,9,opt,name=problems" json:"problems"` Stats RangeStatistics `protobuf:"bytes,10,opt,name=stats" json:"stats"` - CmdQLocal CommandQueueMetrics `protobuf:"bytes,11,opt,name=cmd_q_local,json=cmdQLocal" json:"cmd_q_local"` - CmdQGlobal CommandQueueMetrics `protobuf:"bytes,12,opt,name=cmd_q_global,json=cmdQGlobal" json:"cmd_q_global"` + LatchesLocal cockroach_storage_storagepb.LatchManagerInfo `protobuf:"bytes,11,opt,name=latches_local,json=latchesLocal" json:"latches_local"` + LatchesGlobal cockroach_storage_storagepb.LatchManagerInfo `protobuf:"bytes,12,opt,name=latches_global,json=latchesGlobal" json:"latches_global"` LeaseStatus cockroach_storage1.LeaseStatus `protobuf:"bytes,13,opt,name=lease_status,json=leaseStatus" json:"lease_status"` Quiescent bool `protobuf:"varint,14,opt,name=quiescent,proto3" json:"quiescent,omitempty"` Ticking bool `protobuf:"varint,15,opt,name=ticking,proto3" json:"ticking,omitempty"` @@ -353,7 +341,7 @@ type RangeInfo struct { func (m *RangeInfo) Reset() { *m = RangeInfo{} } func (m *RangeInfo) String() string { return proto.CompactTextString(m) } func (*RangeInfo) ProtoMessage() {} -func (*RangeInfo) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{13} } +func (*RangeInfo) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{12} } type RangesRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -365,7 +353,7 @@ type RangesRequest struct { func (m *RangesRequest) Reset() { *m = RangesRequest{} } func (m *RangesRequest) String() string { return proto.CompactTextString(m) } func (*RangesRequest) ProtoMessage() {} -func (*RangesRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{14} } +func (*RangesRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{13} } type RangesResponse struct { Ranges []RangeInfo `protobuf:"bytes,1,rep,name=ranges" json:"ranges"` @@ -374,7 +362,7 @@ type RangesResponse struct { func (m *RangesResponse) Reset() { *m = RangesResponse{} } func (m *RangesResponse) String() string { return proto.CompactTextString(m) } func (*RangesResponse) ProtoMessage() {} -func (*RangesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{15} } +func (*RangesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{14} } type GossipRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -385,7 +373,7 @@ type GossipRequest struct { func (m *GossipRequest) Reset() { *m = GossipRequest{} } func (m *GossipRequest) String() string { return proto.CompactTextString(m) } func (*GossipRequest) ProtoMessage() {} -func (*GossipRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{16} } +func (*GossipRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{15} } type TraceEvent struct { Time time.Time `protobuf:"bytes,1,opt,name=time,stdtime" json:"time"` @@ -395,7 +383,7 @@ type TraceEvent struct { func (m *TraceEvent) Reset() { *m = TraceEvent{} } func (m *TraceEvent) String() string { return proto.CompactTextString(m) } func (*TraceEvent) ProtoMessage() {} -func (*TraceEvent) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{17} } +func (*TraceEvent) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{16} } type AllocatorDryRun struct { RangeID github_com_cockroachdb_cockroach_pkg_roachpb.RangeID `protobuf:"varint,1,opt,name=range_id,json=rangeId,proto3,casttype=github.com/cockroachdb/cockroach/pkg/roachpb.RangeID" json:"range_id,omitempty"` @@ -405,7 +393,7 @@ type AllocatorDryRun struct { func (m *AllocatorDryRun) Reset() { *m = AllocatorDryRun{} } func (m *AllocatorDryRun) String() string { return proto.CompactTextString(m) } func (*AllocatorDryRun) ProtoMessage() {} -func (*AllocatorDryRun) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{18} } +func (*AllocatorDryRun) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{17} } type AllocatorRangeRequest struct { RangeId int64 `protobuf:"varint,1,opt,name=range_id,json=rangeId,proto3" json:"range_id,omitempty"` @@ -414,7 +402,7 @@ type AllocatorRangeRequest struct { func (m *AllocatorRangeRequest) Reset() { *m = AllocatorRangeRequest{} } func (m *AllocatorRangeRequest) String() string { return proto.CompactTextString(m) } func (*AllocatorRangeRequest) ProtoMessage() {} -func (*AllocatorRangeRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{19} } +func (*AllocatorRangeRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{18} } type AllocatorRangeResponse struct { // The NodeID of the store whose dry run is returned. Only the leaseholder @@ -426,7 +414,7 @@ type AllocatorRangeResponse struct { func (m *AllocatorRangeResponse) Reset() { *m = AllocatorRangeResponse{} } func (m *AllocatorRangeResponse) String() string { return proto.CompactTextString(m) } func (*AllocatorRangeResponse) ProtoMessage() {} -func (*AllocatorRangeResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{20} } +func (*AllocatorRangeResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{19} } type AllocatorRequest struct { NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` @@ -436,7 +424,7 @@ type AllocatorRequest struct { func (m *AllocatorRequest) Reset() { *m = AllocatorRequest{} } func (m *AllocatorRequest) String() string { return proto.CompactTextString(m) } func (*AllocatorRequest) ProtoMessage() {} -func (*AllocatorRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{21} } +func (*AllocatorRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{20} } type AllocatorResponse struct { DryRuns []*AllocatorDryRun `protobuf:"bytes,1,rep,name=dry_runs,json=dryRuns" json:"dry_runs,omitempty"` @@ -445,7 +433,7 @@ type AllocatorResponse struct { func (m *AllocatorResponse) Reset() { *m = AllocatorResponse{} } func (m *AllocatorResponse) String() string { return proto.CompactTextString(m) } func (*AllocatorResponse) ProtoMessage() {} -func (*AllocatorResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{22} } +func (*AllocatorResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{21} } type JSONResponse struct { Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` @@ -454,7 +442,7 @@ type JSONResponse struct { func (m *JSONResponse) Reset() { *m = JSONResponse{} } func (m *JSONResponse) String() string { return proto.CompactTextString(m) } func (*JSONResponse) ProtoMessage() {} -func (*JSONResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{23} } +func (*JSONResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{22} } type LogsRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -470,7 +458,7 @@ type LogsRequest struct { func (m *LogsRequest) Reset() { *m = LogsRequest{} } func (m *LogsRequest) String() string { return proto.CompactTextString(m) } func (*LogsRequest) ProtoMessage() {} -func (*LogsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{24} } +func (*LogsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{23} } type LogEntriesResponse struct { Entries []cockroach_util_log.Entry `protobuf:"bytes,1,rep,name=entries" json:"entries"` @@ -479,7 +467,7 @@ type LogEntriesResponse struct { func (m *LogEntriesResponse) Reset() { *m = LogEntriesResponse{} } func (m *LogEntriesResponse) String() string { return proto.CompactTextString(m) } func (*LogEntriesResponse) ProtoMessage() {} -func (*LogEntriesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{25} } +func (*LogEntriesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{24} } type LogFilesListRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -490,7 +478,7 @@ type LogFilesListRequest struct { func (m *LogFilesListRequest) Reset() { *m = LogFilesListRequest{} } func (m *LogFilesListRequest) String() string { return proto.CompactTextString(m) } func (*LogFilesListRequest) ProtoMessage() {} -func (*LogFilesListRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{26} } +func (*LogFilesListRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{25} } type LogFilesListResponse struct { Files []cockroach_util_log.FileInfo `protobuf:"bytes,1,rep,name=files" json:"files"` @@ -499,7 +487,7 @@ type LogFilesListResponse struct { func (m *LogFilesListResponse) Reset() { *m = LogFilesListResponse{} } func (m *LogFilesListResponse) String() string { return proto.CompactTextString(m) } func (*LogFilesListResponse) ProtoMessage() {} -func (*LogFilesListResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{27} } +func (*LogFilesListResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{26} } type LogFileRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -511,7 +499,7 @@ type LogFileRequest struct { func (m *LogFileRequest) Reset() { *m = LogFileRequest{} } func (m *LogFileRequest) String() string { return proto.CompactTextString(m) } func (*LogFileRequest) ProtoMessage() {} -func (*LogFileRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{28} } +func (*LogFileRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{27} } type StacksRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -522,7 +510,7 @@ type StacksRequest struct { func (m *StacksRequest) Reset() { *m = StacksRequest{} } func (m *StacksRequest) String() string { return proto.CompactTextString(m) } func (*StacksRequest) ProtoMessage() {} -func (*StacksRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{29} } +func (*StacksRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{28} } type File struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -534,7 +522,7 @@ type File struct { func (m *File) Reset() { *m = File{} } func (m *File) String() string { return proto.CompactTextString(m) } func (*File) ProtoMessage() {} -func (*File) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{30} } +func (*File) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{29} } type GetFilesRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -554,7 +542,7 @@ type GetFilesRequest struct { func (m *GetFilesRequest) Reset() { *m = GetFilesRequest{} } func (m *GetFilesRequest) String() string { return proto.CompactTextString(m) } func (*GetFilesRequest) ProtoMessage() {} -func (*GetFilesRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{31} } +func (*GetFilesRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{30} } type GetFilesResponse struct { Files []*File `protobuf:"bytes,1,rep,name=files" json:"files,omitempty"` @@ -563,7 +551,7 @@ type GetFilesResponse struct { func (m *GetFilesResponse) Reset() { *m = GetFilesResponse{} } func (m *GetFilesResponse) String() string { return proto.CompactTextString(m) } func (*GetFilesResponse) ProtoMessage() {} -func (*GetFilesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{32} } +func (*GetFilesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{31} } type ProfileRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -576,7 +564,7 @@ type ProfileRequest struct { func (m *ProfileRequest) Reset() { *m = ProfileRequest{} } func (m *ProfileRequest) String() string { return proto.CompactTextString(m) } func (*ProfileRequest) ProtoMessage() {} -func (*ProfileRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{33} } +func (*ProfileRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{32} } type MetricsRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -587,7 +575,7 @@ type MetricsRequest struct { func (m *MetricsRequest) Reset() { *m = MetricsRequest{} } func (m *MetricsRequest) String() string { return proto.CompactTextString(m) } func (*MetricsRequest) ProtoMessage() {} -func (*MetricsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{34} } +func (*MetricsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{33} } type RaftRangeNode struct { NodeID github_com_cockroachdb_cockroach_pkg_roachpb.NodeID `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3,casttype=github.com/cockroachdb/cockroach/pkg/roachpb.NodeID" json:"node_id,omitempty"` @@ -597,7 +585,7 @@ type RaftRangeNode struct { func (m *RaftRangeNode) Reset() { *m = RaftRangeNode{} } func (m *RaftRangeNode) String() string { return proto.CompactTextString(m) } func (*RaftRangeNode) ProtoMessage() {} -func (*RaftRangeNode) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{35} } +func (*RaftRangeNode) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{34} } type RaftRangeError struct { Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` @@ -606,7 +594,7 @@ type RaftRangeError struct { func (m *RaftRangeError) Reset() { *m = RaftRangeError{} } func (m *RaftRangeError) String() string { return proto.CompactTextString(m) } func (*RaftRangeError) ProtoMessage() {} -func (*RaftRangeError) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{36} } +func (*RaftRangeError) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{35} } type RaftRangeStatus struct { RangeID github_com_cockroachdb_cockroach_pkg_roachpb.RangeID `protobuf:"varint,1,opt,name=range_id,json=rangeId,proto3,casttype=github.com/cockroachdb/cockroach/pkg/roachpb.RangeID" json:"range_id,omitempty"` @@ -617,7 +605,7 @@ type RaftRangeStatus struct { func (m *RaftRangeStatus) Reset() { *m = RaftRangeStatus{} } func (m *RaftRangeStatus) String() string { return proto.CompactTextString(m) } func (*RaftRangeStatus) ProtoMessage() {} -func (*RaftRangeStatus) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{37} } +func (*RaftRangeStatus) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{36} } type RaftDebugRequest struct { RangeIDs []github_com_cockroachdb_cockroach_pkg_roachpb.RangeID `protobuf:"varint,1,rep,packed,name=range_ids,json=rangeIds,casttype=github.com/cockroachdb/cockroach/pkg/roachpb.RangeID" json:"range_ids,omitempty"` @@ -626,7 +614,7 @@ type RaftDebugRequest struct { func (m *RaftDebugRequest) Reset() { *m = RaftDebugRequest{} } func (m *RaftDebugRequest) String() string { return proto.CompactTextString(m) } func (*RaftDebugRequest) ProtoMessage() {} -func (*RaftDebugRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{38} } +func (*RaftDebugRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{37} } type RaftDebugResponse struct { Ranges map[github_com_cockroachdb_cockroach_pkg_roachpb.RangeID]RaftRangeStatus `protobuf:"bytes,1,rep,name=ranges,castkey=github.com/cockroachdb/cockroach/pkg/roachpb.RangeID" json:"ranges" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` @@ -636,7 +624,7 @@ type RaftDebugResponse struct { func (m *RaftDebugResponse) Reset() { *m = RaftDebugResponse{} } func (m *RaftDebugResponse) String() string { return proto.CompactTextString(m) } func (*RaftDebugResponse) ProtoMessage() {} -func (*RaftDebugResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{39} } +func (*RaftDebugResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{38} } // ActiveQuery represents a query in flight on some Session. type ActiveQuery struct { @@ -655,7 +643,7 @@ type ActiveQuery struct { func (m *ActiveQuery) Reset() { *m = ActiveQuery{} } func (m *ActiveQuery) String() string { return proto.CompactTextString(m) } func (*ActiveQuery) ProtoMessage() {} -func (*ActiveQuery) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{40} } +func (*ActiveQuery) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{39} } // Request object for ListSessions and ListLocalSessions. type ListSessionsRequest struct { @@ -666,7 +654,7 @@ type ListSessionsRequest struct { func (m *ListSessionsRequest) Reset() { *m = ListSessionsRequest{} } func (m *ListSessionsRequest) String() string { return proto.CompactTextString(m) } func (*ListSessionsRequest) ProtoMessage() {} -func (*ListSessionsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{41} } +func (*ListSessionsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{40} } // Session represents one SQL session. type Session struct { @@ -698,7 +686,7 @@ type Session struct { func (m *Session) Reset() { *m = Session{} } func (m *Session) String() string { return proto.CompactTextString(m) } func (*Session) ProtoMessage() {} -func (*Session) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{42} } +func (*Session) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{41} } // An error wrapper object for ListSessionsResponse. type ListSessionsError struct { @@ -711,7 +699,7 @@ type ListSessionsError struct { func (m *ListSessionsError) Reset() { *m = ListSessionsError{} } func (m *ListSessionsError) String() string { return proto.CompactTextString(m) } func (*ListSessionsError) ProtoMessage() {} -func (*ListSessionsError) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{43} } +func (*ListSessionsError) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{42} } // Response object for ListSessions and ListLocalSessions. type ListSessionsResponse struct { @@ -724,7 +712,7 @@ type ListSessionsResponse struct { func (m *ListSessionsResponse) Reset() { *m = ListSessionsResponse{} } func (m *ListSessionsResponse) String() string { return proto.CompactTextString(m) } func (*ListSessionsResponse) ProtoMessage() {} -func (*ListSessionsResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{44} } +func (*ListSessionsResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{43} } // Request object for issing a query cancel request. type CancelQueryRequest struct { @@ -745,7 +733,7 @@ type CancelQueryRequest struct { func (m *CancelQueryRequest) Reset() { *m = CancelQueryRequest{} } func (m *CancelQueryRequest) String() string { return proto.CompactTextString(m) } func (*CancelQueryRequest) ProtoMessage() {} -func (*CancelQueryRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{45} } +func (*CancelQueryRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{44} } // Response returned by target query's gateway node. type CancelQueryResponse struct { @@ -758,7 +746,7 @@ type CancelQueryResponse struct { func (m *CancelQueryResponse) Reset() { *m = CancelQueryResponse{} } func (m *CancelQueryResponse) String() string { return proto.CompactTextString(m) } func (*CancelQueryResponse) ProtoMessage() {} -func (*CancelQueryResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{46} } +func (*CancelQueryResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{45} } type CancelSessionRequest struct { // TODO(abhimadan): use [(gogoproto.customname) = "NodeID"] below. Need to @@ -774,7 +762,7 @@ type CancelSessionRequest struct { func (m *CancelSessionRequest) Reset() { *m = CancelSessionRequest{} } func (m *CancelSessionRequest) String() string { return proto.CompactTextString(m) } func (*CancelSessionRequest) ProtoMessage() {} -func (*CancelSessionRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{47} } +func (*CancelSessionRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{46} } type CancelSessionResponse struct { Canceled bool `protobuf:"varint,1,opt,name=canceled,proto3" json:"canceled,omitempty"` @@ -784,7 +772,7 @@ type CancelSessionResponse struct { func (m *CancelSessionResponse) Reset() { *m = CancelSessionResponse{} } func (m *CancelSessionResponse) String() string { return proto.CompactTextString(m) } func (*CancelSessionResponse) ProtoMessage() {} -func (*CancelSessionResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{48} } +func (*CancelSessionResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{47} } type SpanStatsRequest struct { NodeID string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` @@ -795,7 +783,7 @@ type SpanStatsRequest struct { func (m *SpanStatsRequest) Reset() { *m = SpanStatsRequest{} } func (m *SpanStatsRequest) String() string { return proto.CompactTextString(m) } func (*SpanStatsRequest) ProtoMessage() {} -func (*SpanStatsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{49} } +func (*SpanStatsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{48} } type SpanStatsResponse struct { RangeCount int32 `protobuf:"varint,2,opt,name=range_count,json=rangeCount,proto3" json:"range_count,omitempty"` @@ -806,7 +794,7 @@ type SpanStatsResponse struct { func (m *SpanStatsResponse) Reset() { *m = SpanStatsResponse{} } func (m *SpanStatsResponse) String() string { return proto.CompactTextString(m) } func (*SpanStatsResponse) ProtoMessage() {} -func (*SpanStatsResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{50} } +func (*SpanStatsResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{49} } type ProblemRangesRequest struct { NodeID string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` @@ -815,7 +803,7 @@ type ProblemRangesRequest struct { func (m *ProblemRangesRequest) Reset() { *m = ProblemRangesRequest{} } func (m *ProblemRangesRequest) String() string { return proto.CompactTextString(m) } func (*ProblemRangesRequest) ProtoMessage() {} -func (*ProblemRangesRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{51} } +func (*ProblemRangesRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{50} } type ProblemRangesResponse struct { // NodeID is the node that submitted all the requests. @@ -826,7 +814,7 @@ type ProblemRangesResponse struct { func (m *ProblemRangesResponse) Reset() { *m = ProblemRangesResponse{} } func (m *ProblemRangesResponse) String() string { return proto.CompactTextString(m) } func (*ProblemRangesResponse) ProtoMessage() {} -func (*ProblemRangesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{52} } +func (*ProblemRangesResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{51} } type ProblemRangesResponse_NodeProblems struct { ErrorMessage string `protobuf:"bytes,1,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` @@ -843,7 +831,7 @@ func (m *ProblemRangesResponse_NodeProblems) Reset() { *m = ProblemRange func (m *ProblemRangesResponse_NodeProblems) String() string { return proto.CompactTextString(m) } func (*ProblemRangesResponse_NodeProblems) ProtoMessage() {} func (*ProblemRangesResponse_NodeProblems) Descriptor() ([]byte, []int) { - return fileDescriptorStatus, []int{52, 0} + return fileDescriptorStatus, []int{51, 0} } type RangeRequest struct { @@ -853,7 +841,7 @@ type RangeRequest struct { func (m *RangeRequest) Reset() { *m = RangeRequest{} } func (m *RangeRequest) String() string { return proto.CompactTextString(m) } func (*RangeRequest) ProtoMessage() {} -func (*RangeRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{53} } +func (*RangeRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{52} } type RangeResponse struct { // NodeID is the node that submitted all the requests. @@ -865,7 +853,7 @@ type RangeResponse struct { func (m *RangeResponse) Reset() { *m = RangeResponse{} } func (m *RangeResponse) String() string { return proto.CompactTextString(m) } func (*RangeResponse) ProtoMessage() {} -func (*RangeResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{54} } +func (*RangeResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{53} } type RangeResponse_NodeResponse struct { Response bool `protobuf:"varint,1,opt,name=response,proto3" json:"response,omitempty"` @@ -877,27 +865,9 @@ func (m *RangeResponse_NodeResponse) Reset() { *m = RangeResponse_NodeRe func (m *RangeResponse_NodeResponse) String() string { return proto.CompactTextString(m) } func (*RangeResponse_NodeResponse) ProtoMessage() {} func (*RangeResponse_NodeResponse) Descriptor() ([]byte, []int) { - return fileDescriptorStatus, []int{54, 0} -} - -type CommandQueueRequest struct { - RangeId int64 `protobuf:"varint,1,opt,name=range_id,json=rangeId,proto3" json:"range_id,omitempty"` + return fileDescriptorStatus, []int{53, 0} } -func (m *CommandQueueRequest) Reset() { *m = CommandQueueRequest{} } -func (m *CommandQueueRequest) String() string { return proto.CompactTextString(m) } -func (*CommandQueueRequest) ProtoMessage() {} -func (*CommandQueueRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{55} } - -type CommandQueueResponse struct { - Snapshot cockroach_storage_storagepb.CommandQueuesSnapshot `protobuf:"bytes,1,opt,name=snapshot" json:"snapshot"` -} - -func (m *CommandQueueResponse) Reset() { *m = CommandQueueResponse{} } -func (m *CommandQueueResponse) String() string { return proto.CompactTextString(m) } -func (*CommandQueueResponse) ProtoMessage() {} -func (*CommandQueueResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{56} } - // DiagnosticsRequest requests a diagnostics report. type DiagnosticsRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -908,7 +878,7 @@ type DiagnosticsRequest struct { func (m *DiagnosticsRequest) Reset() { *m = DiagnosticsRequest{} } func (m *DiagnosticsRequest) String() string { return proto.CompactTextString(m) } func (*DiagnosticsRequest) ProtoMessage() {} -func (*DiagnosticsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{57} } +func (*DiagnosticsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{54} } type StoresRequest struct { // node_id is a string so that "local" can be used to specify that no @@ -919,7 +889,7 @@ type StoresRequest struct { func (m *StoresRequest) Reset() { *m = StoresRequest{} } func (m *StoresRequest) String() string { return proto.CompactTextString(m) } func (*StoresRequest) ProtoMessage() {} -func (*StoresRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{58} } +func (*StoresRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{55} } type StoreDetails struct { StoreID github_com_cockroachdb_cockroach_pkg_roachpb.StoreID `protobuf:"varint,1,opt,name=store_id,json=storeId,proto3,casttype=github.com/cockroachdb/cockroach/pkg/roachpb.StoreID" json:"store_id,omitempty"` @@ -938,7 +908,7 @@ type StoreDetails struct { func (m *StoreDetails) Reset() { *m = StoreDetails{} } func (m *StoreDetails) String() string { return proto.CompactTextString(m) } func (*StoreDetails) ProtoMessage() {} -func (*StoreDetails) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{59} } +func (*StoreDetails) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{56} } type StoresResponse struct { Stores []StoreDetails `protobuf:"bytes,1,rep,name=stores" json:"stores"` @@ -947,7 +917,7 @@ type StoresResponse struct { func (m *StoresResponse) Reset() { *m = StoresResponse{} } func (m *StoresResponse) String() string { return proto.CompactTextString(m) } func (*StoresResponse) ProtoMessage() {} -func (*StoresResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{60} } +func (*StoresResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{57} } type StatementsRequest struct { NodeID string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` @@ -956,7 +926,7 @@ type StatementsRequest struct { func (m *StatementsRequest) Reset() { *m = StatementsRequest{} } func (m *StatementsRequest) String() string { return proto.CompactTextString(m) } func (*StatementsRequest) ProtoMessage() {} -func (*StatementsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{61} } +func (*StatementsRequest) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{58} } type StatementsResponse struct { Statements []StatementsResponse_CollectedStatementStatistics `protobuf:"bytes,1,rep,name=statements" json:"statements"` @@ -967,7 +937,7 @@ type StatementsResponse struct { func (m *StatementsResponse) Reset() { *m = StatementsResponse{} } func (m *StatementsResponse) String() string { return proto.CompactTextString(m) } func (*StatementsResponse) ProtoMessage() {} -func (*StatementsResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{62} } +func (*StatementsResponse) Descriptor() ([]byte, []int) { return fileDescriptorStatus, []int{59} } type StatementsResponse_ExtendedStatementStatisticsKey struct { KeyData cockroach_sql.StatementStatisticsKey `protobuf:"bytes,1,opt,name=key_data,json=keyData" json:"key_data"` @@ -982,7 +952,7 @@ func (m *StatementsResponse_ExtendedStatementStatisticsKey) String() string { } func (*StatementsResponse_ExtendedStatementStatisticsKey) ProtoMessage() {} func (*StatementsResponse_ExtendedStatementStatisticsKey) Descriptor() ([]byte, []int) { - return fileDescriptorStatus, []int{62, 0} + return fileDescriptorStatus, []int{59, 0} } type StatementsResponse_CollectedStatementStatistics struct { @@ -998,7 +968,7 @@ func (m *StatementsResponse_CollectedStatementStatistics) String() string { } func (*StatementsResponse_CollectedStatementStatistics) ProtoMessage() {} func (*StatementsResponse_CollectedStatementStatistics) Descriptor() ([]byte, []int) { - return fileDescriptorStatus, []int{62, 1} + return fileDescriptorStatus, []int{59, 1} } func init() { @@ -1016,7 +986,6 @@ func init() { proto.RegisterType((*RangeProblems)(nil), "cockroach.server.serverpb.RangeProblems") proto.RegisterType((*RangeStatistics)(nil), "cockroach.server.serverpb.RangeStatistics") proto.RegisterType((*PrettySpan)(nil), "cockroach.server.serverpb.PrettySpan") - proto.RegisterType((*CommandQueueMetrics)(nil), "cockroach.server.serverpb.CommandQueueMetrics") proto.RegisterType((*RangeInfo)(nil), "cockroach.server.serverpb.RangeInfo") proto.RegisterType((*RangesRequest)(nil), "cockroach.server.serverpb.RangesRequest") proto.RegisterType((*RangesResponse)(nil), "cockroach.server.serverpb.RangesResponse") @@ -1061,8 +1030,6 @@ func init() { proto.RegisterType((*RangeRequest)(nil), "cockroach.server.serverpb.RangeRequest") proto.RegisterType((*RangeResponse)(nil), "cockroach.server.serverpb.RangeResponse") proto.RegisterType((*RangeResponse_NodeResponse)(nil), "cockroach.server.serverpb.RangeResponse.NodeResponse") - proto.RegisterType((*CommandQueueRequest)(nil), "cockroach.server.serverpb.CommandQueueRequest") - proto.RegisterType((*CommandQueueResponse)(nil), "cockroach.server.serverpb.CommandQueueResponse") proto.RegisterType((*DiagnosticsRequest)(nil), "cockroach.server.serverpb.DiagnosticsRequest") proto.RegisterType((*StoresRequest)(nil), "cockroach.server.serverpb.StoresRequest") proto.RegisterType((*StoreDetails)(nil), "cockroach.server.serverpb.StoreDetails") @@ -1143,7 +1110,6 @@ type StatusClient interface { Logs(ctx context.Context, in *LogsRequest, opts ...grpc.CallOption) (*LogEntriesResponse, error) ProblemRanges(ctx context.Context, in *ProblemRangesRequest, opts ...grpc.CallOption) (*ProblemRangesResponse, error) Range(ctx context.Context, in *RangeRequest, opts ...grpc.CallOption) (*RangeResponse, error) - CommandQueue(ctx context.Context, in *CommandQueueRequest, opts ...grpc.CallOption) (*CommandQueueResponse, error) Diagnostics(ctx context.Context, in *DiagnosticsRequest, opts ...grpc.CallOption) (*cockroach_server_diagnosticspb.DiagnosticReport, error) Stores(ctx context.Context, in *StoresRequest, opts ...grpc.CallOption) (*StoresResponse, error) Statements(ctx context.Context, in *StatementsRequest, opts ...grpc.CallOption) (*StatementsResponse, error) @@ -1364,15 +1330,6 @@ func (c *statusClient) Range(ctx context.Context, in *RangeRequest, opts ...grpc return out, nil } -func (c *statusClient) CommandQueue(ctx context.Context, in *CommandQueueRequest, opts ...grpc.CallOption) (*CommandQueueResponse, error) { - out := new(CommandQueueResponse) - err := grpc.Invoke(ctx, "/cockroach.server.serverpb.Status/CommandQueue", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *statusClient) Diagnostics(ctx context.Context, in *DiagnosticsRequest, opts ...grpc.CallOption) (*cockroach_server_diagnosticspb.DiagnosticReport, error) { out := new(cockroach_server_diagnosticspb.DiagnosticReport) err := grpc.Invoke(ctx, "/cockroach.server.serverpb.Status/Diagnostics", in, out, c.cc, opts...) @@ -1431,7 +1388,6 @@ type StatusServer interface { Logs(context.Context, *LogsRequest) (*LogEntriesResponse, error) ProblemRanges(context.Context, *ProblemRangesRequest) (*ProblemRangesResponse, error) Range(context.Context, *RangeRequest) (*RangeResponse, error) - CommandQueue(context.Context, *CommandQueueRequest) (*CommandQueueResponse, error) Diagnostics(context.Context, *DiagnosticsRequest) (*cockroach_server_diagnosticspb.DiagnosticReport, error) Stores(context.Context, *StoresRequest) (*StoresResponse, error) Statements(context.Context, *StatementsRequest) (*StatementsResponse, error) @@ -1855,24 +1811,6 @@ func _Status_Range_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } -func _Status_CommandQueue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CommandQueueRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(StatusServer).CommandQueue(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/cockroach.server.serverpb.Status/CommandQueue", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(StatusServer).CommandQueue(ctx, req.(*CommandQueueRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Status_Diagnostics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(DiagnosticsRequest) if err := dec(in); err != nil { @@ -2023,10 +1961,6 @@ var _Status_serviceDesc = grpc.ServiceDesc{ MethodName: "Range", Handler: _Status_Range_Handler, }, - { - MethodName: "CommandQueue", - Handler: _Status_CommandQueue_Handler, - }, { MethodName: "Diagnostics", Handler: _Status_Diagnostics_Handler, @@ -2666,44 +2600,6 @@ func (m *PrettySpan) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *CommandQueueMetrics) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CommandQueueMetrics) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.WriteCommands != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintStatus(dAtA, i, uint64(m.WriteCommands)) - } - if m.ReadCommands != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintStatus(dAtA, i, uint64(m.ReadCommands)) - } - if m.MaxOverlapsSeen != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintStatus(dAtA, i, uint64(m.MaxOverlapsSeen)) - } - if m.TreeSize != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintStatus(dAtA, i, uint64(m.TreeSize)) - } - return i, nil -} - func (m *RangeInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2789,16 +2685,16 @@ func (m *RangeInfo) MarshalTo(dAtA []byte) (int, error) { i += n9 dAtA[i] = 0x5a i++ - i = encodeVarintStatus(dAtA, i, uint64(m.CmdQLocal.Size())) - n10, err := m.CmdQLocal.MarshalTo(dAtA[i:]) + i = encodeVarintStatus(dAtA, i, uint64(m.LatchesLocal.Size())) + n10, err := m.LatchesLocal.MarshalTo(dAtA[i:]) if err != nil { return 0, err } i += n10 dAtA[i] = 0x62 i++ - i = encodeVarintStatus(dAtA, i, uint64(m.CmdQGlobal.Size())) - n11, err := m.CmdQGlobal.MarshalTo(dAtA[i:]) + i = encodeVarintStatus(dAtA, i, uint64(m.LatchesGlobal.Size())) + n11, err := m.LatchesGlobal.MarshalTo(dAtA[i:]) if err != nil { return 0, err } @@ -4518,55 +4414,6 @@ func (m *RangeResponse_NodeResponse) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *CommandQueueRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CommandQueueRequest) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.RangeId != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintStatus(dAtA, i, uint64(m.RangeId)) - } - return i, nil -} - -func (m *CommandQueueResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CommandQueueResponse) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintStatus(dAtA, i, uint64(m.Snapshot.Size())) - n43, err := m.Snapshot.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n43 - return i, nil -} - func (m *DiagnosticsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4748,11 +4595,11 @@ func (m *StatementsResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintStatus(dAtA, i, uint64(types.SizeOfStdTime(m.LastReset))) - n44, err := types.StdTimeMarshalTo(m.LastReset, dAtA[i:]) + n43, err := types.StdTimeMarshalTo(m.LastReset, dAtA[i:]) if err != nil { return 0, err } - i += n44 + i += n43 return i, nil } @@ -4774,11 +4621,11 @@ func (m *StatementsResponse_ExtendedStatementStatisticsKey) MarshalTo(dAtA []byt dAtA[i] = 0xa i++ i = encodeVarintStatus(dAtA, i, uint64(m.KeyData.Size())) - n45, err := m.KeyData.MarshalTo(dAtA[i:]) + n44, err := m.KeyData.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n45 + i += n44 if m.NodeID != 0 { dAtA[i] = 0x10 i++ @@ -4805,19 +4652,19 @@ func (m *StatementsResponse_CollectedStatementStatistics) MarshalTo(dAtA []byte) dAtA[i] = 0xa i++ i = encodeVarintStatus(dAtA, i, uint64(m.Key.Size())) - n46, err := m.Key.MarshalTo(dAtA[i:]) + n45, err := m.Key.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n46 + i += n45 dAtA[i] = 0x12 i++ i = encodeVarintStatus(dAtA, i, uint64(m.Stats.Size())) - n47, err := m.Stats.MarshalTo(dAtA[i:]) + n46, err := m.Stats.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n47 + i += n46 return i, nil } @@ -5083,24 +4930,6 @@ func (m *PrettySpan) Size() (n int) { return n } -func (m *CommandQueueMetrics) Size() (n int) { - var l int - _ = l - if m.WriteCommands != 0 { - n += 1 + sovStatus(uint64(m.WriteCommands)) - } - if m.ReadCommands != 0 { - n += 1 + sovStatus(uint64(m.ReadCommands)) - } - if m.MaxOverlapsSeen != 0 { - n += 1 + sovStatus(uint64(m.MaxOverlapsSeen)) - } - if m.TreeSize != 0 { - n += 1 + sovStatus(uint64(m.TreeSize)) - } - return n -} - func (m *RangeInfo) Size() (n int) { var l int _ = l @@ -5130,9 +4959,9 @@ func (m *RangeInfo) Size() (n int) { n += 1 + l + sovStatus(uint64(l)) l = m.Stats.Size() n += 1 + l + sovStatus(uint64(l)) - l = m.CmdQLocal.Size() + l = m.LatchesLocal.Size() n += 1 + l + sovStatus(uint64(l)) - l = m.CmdQGlobal.Size() + l = m.LatchesGlobal.Size() n += 1 + l + sovStatus(uint64(l)) l = m.LeaseStatus.Size() n += 1 + l + sovStatus(uint64(l)) @@ -5850,23 +5679,6 @@ func (m *RangeResponse_NodeResponse) Size() (n int) { return n } -func (m *CommandQueueRequest) Size() (n int) { - var l int - _ = l - if m.RangeId != 0 { - n += 1 + sovStatus(uint64(m.RangeId)) - } - return n -} - -func (m *CommandQueueResponse) Size() (n int) { - var l int - _ = l - l = m.Snapshot.Size() - n += 1 + l + sovStatus(uint64(l)) - return n -} - func (m *DiagnosticsRequest) Size() (n int) { var l int _ = l @@ -7854,132 +7666,6 @@ func (m *PrettySpan) Unmarshal(dAtA []byte) error { } return nil } -func (m *CommandQueueMetrics) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CommandQueueMetrics: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CommandQueueMetrics: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field WriteCommands", wireType) - } - m.WriteCommands = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.WriteCommands |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ReadCommands", wireType) - } - m.ReadCommands = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ReadCommands |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxOverlapsSeen", wireType) - } - m.MaxOverlapsSeen = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxOverlapsSeen |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TreeSize", wireType) - } - m.TreeSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TreeSize |= (int32(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipStatus(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthStatus - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *RangeInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -8259,7 +7945,7 @@ func (m *RangeInfo) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 11: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CmdQLocal", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LatchesLocal", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -8283,13 +7969,13 @@ func (m *RangeInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.CmdQLocal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.LatchesLocal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 12: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CmdQGlobal", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LatchesGlobal", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -8313,7 +7999,7 @@ func (m *RangeInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.CmdQGlobal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.LatchesGlobal.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -13910,155 +13596,6 @@ func (m *RangeResponse_NodeResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *CommandQueueRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CommandQueueRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CommandQueueRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RangeId", wireType) - } - m.RangeId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.RangeId |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipStatus(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthStatus - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CommandQueueResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CommandQueueResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CommandQueueResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Snapshot", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowStatus - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthStatus - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Snapshot.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipStatus(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthStatus - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *DiagnosticsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -14981,301 +14518,292 @@ var ( func init() { proto.RegisterFile("server/serverpb/status.proto", fileDescriptorStatus) } var fileDescriptorStatus = []byte{ - // 4729 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5b, 0xed, 0x6f, 0x24, 0x47, - 0x5a, 0xdf, 0xb6, 0xe7, 0xf5, 0x19, 0xbf, 0x8c, 0xcb, 0xde, 0xdd, 0xd9, 0xd9, 0x8d, 0x67, 0xd3, - 0x9b, 0x6c, 0xbc, 0x9b, 0x64, 0x26, 0xf1, 0x25, 0xb0, 0x04, 0x72, 0x89, 0xdf, 0x76, 0xd7, 0x59, - 0x67, 0xd7, 0xdb, 0xb6, 0xef, 0x20, 0x42, 0x69, 0xda, 0xd3, 0xe5, 0x71, 0x9f, 0x7b, 0xba, 0xc7, - 0xdd, 0x3d, 0xc6, 0x73, 0x51, 0x8e, 0x10, 0x74, 0x88, 0x03, 0x71, 0xdc, 0x1d, 0x2f, 0x42, 0x02, - 0x24, 0x74, 0x1f, 0x00, 0x21, 0x81, 0x0e, 0xf1, 0x09, 0xbe, 0x9c, 0x84, 0x10, 0x0a, 0xdf, 0x40, - 0xf0, 0x81, 0x17, 0xc9, 0x01, 0xc3, 0x07, 0xe0, 0x4f, 0x38, 0x09, 0x09, 0xd5, 0x53, 0xd5, 0x3d, - 0xd5, 0x33, 0xb3, 0x3d, 0xe3, 0x38, 0x7b, 0xe2, 0xc3, 0xee, 0x74, 0x3d, 0xf5, 0xd4, 0x53, 0xbf, - 0x7a, 0xaa, 0xea, 0xa9, 0xa7, 0x9e, 0x7a, 0x0c, 0xd7, 0x7c, 0xea, 0x1d, 0x51, 0xaf, 0xc6, 0x7f, - 0x5a, 0xbb, 0x35, 0x3f, 0x30, 0x82, 0xb6, 0x5f, 0x6d, 0x79, 0x6e, 0xe0, 0x92, 0x2b, 0x75, 0xb7, - 0x7e, 0xe0, 0xb9, 0x46, 0x7d, 0xbf, 0xca, 0x19, 0xaa, 0x21, 0x5f, 0xb9, 0xb8, 0xdb, 0xb6, 0x6c, - 0xb3, 0x66, 0x39, 0x7b, 0x2e, 0x67, 0x2e, 0xcf, 0x36, 0x5c, 0xdf, 0xb7, 0x5a, 0x35, 0xfe, 0x23, - 0x88, 0x97, 0xb1, 0x75, 0x6b, 0xb7, 0x66, 0xb4, 0x5a, 0x3a, 0x93, 0x2d, 0x44, 0x97, 0x49, 0x58, - 0x61, 0x1a, 0x81, 0x21, 0x68, 0x37, 0x05, 0x18, 0xd3, 0x32, 0x1a, 0x8e, 0xeb, 0x07, 0x56, 0xdd, - 0x67, 0x0c, 0xdd, 0x92, 0xe0, 0xbb, 0x11, 0x82, 0x46, 0xac, 0xe2, 0xa7, 0x07, 0x7b, 0x59, 0xf5, - 0x03, 0xd7, 0x33, 0x1a, 0xb4, 0x46, 0x9d, 0x86, 0xe5, 0x84, 0x3f, 0xad, 0xdd, 0x5a, 0xf3, 0xa8, - 0x5e, 0x17, 0x3c, 0xcf, 0x85, 0x3c, 0xe2, 0xb7, 0xb5, 0x5b, 0xb3, 0xa9, 0xe1, 0x53, 0x3d, 0x26, - 0xe9, 0x99, 0x7e, 0x2e, 0x56, 0x4f, 0xc3, 0x91, 0xb4, 0x03, 0xcb, 0xae, 0xd9, 0x6e, 0x83, 0xfd, - 0x13, 0xb4, 0x32, 0xd2, 0xda, 0x8e, 0x47, 0x7d, 0xd7, 0x3e, 0xa2, 0xa6, 0x6e, 0x98, 0xa6, 0x27, - 0xea, 0xae, 0xd2, 0xa0, 0x6e, 0xd6, 0x3c, 0x63, 0x2f, 0xc0, 0xff, 0x5a, 0xbb, 0xf8, 0x23, 0x2a, - 0xe7, 0x1a, 0x6e, 0xc3, 0xc5, 0xcf, 0x1a, 0xfb, 0x12, 0xd4, 0x6b, 0x0d, 0xd7, 0x6d, 0xd8, 0xb4, - 0x66, 0xb4, 0xac, 0x9a, 0xe1, 0x38, 0x6e, 0x60, 0x04, 0x96, 0xeb, 0x84, 0xf8, 0x2a, 0xa2, 0x16, - 0x4b, 0xbb, 0xed, 0xbd, 0x5a, 0x60, 0x35, 0xa9, 0x1f, 0x18, 0x4d, 0x31, 0x09, 0x6a, 0x15, 0x66, - 0x57, 0xa8, 0x17, 0x58, 0x7b, 0x56, 0xdd, 0x08, 0xa8, 0xaf, 0xd1, 0xc3, 0x36, 0xf5, 0x03, 0x72, - 0x19, 0xb2, 0x8e, 0x6b, 0x52, 0xdd, 0x32, 0x4b, 0xca, 0x75, 0x65, 0x21, 0xaf, 0x65, 0x58, 0x71, - 0xdd, 0x54, 0xff, 0x37, 0x05, 0x44, 0x6a, 0xb0, 0x4a, 0x03, 0xc3, 0xb2, 0x7d, 0xf2, 0x18, 0x52, - 0x41, 0xa7, 0x45, 0x91, 0x79, 0x6a, 0xf1, 0xcd, 0xea, 0x13, 0x17, 0x47, 0xb5, 0xbf, 0xb1, 0x4c, - 0xda, 0xee, 0xb4, 0xa8, 0x86, 0xa2, 0xc8, 0x0d, 0x98, 0xa4, 0x9e, 0xe7, 0x7a, 0x7a, 0x93, 0xfa, - 0xbe, 0xd1, 0xa0, 0xa5, 0x31, 0x04, 0x32, 0x81, 0xc4, 0x77, 0x39, 0x8d, 0x10, 0x48, 0xb1, 0x45, - 0x52, 0x1a, 0xbf, 0xae, 0x2c, 0x4c, 0x68, 0xf8, 0x4d, 0x34, 0xc8, 0xec, 0x59, 0xd4, 0x36, 0xfd, - 0x52, 0xea, 0xfa, 0xf8, 0x42, 0x61, 0xf1, 0xb5, 0xb3, 0xa1, 0xb9, 0x8b, 0x6d, 0x97, 0x53, 0x9f, - 0x9c, 0x54, 0x2e, 0x68, 0x42, 0x52, 0xf9, 0xcf, 0xc7, 0x20, 0xc3, 0x2b, 0xc8, 0x25, 0xc8, 0x58, - 0xbe, 0xdf, 0xa6, 0x5e, 0xa8, 0x19, 0x5e, 0x22, 0x25, 0xc8, 0xfa, 0xed, 0xdd, 0xaf, 0xd0, 0x7a, - 0x20, 0x90, 0x86, 0x45, 0xf2, 0x0c, 0xc0, 0x91, 0x61, 0x5b, 0xa6, 0xbe, 0xe7, 0xb9, 0x4d, 0x84, - 0x3a, 0xae, 0xe5, 0x91, 0x72, 0xd7, 0x73, 0x9b, 0xa4, 0x02, 0x05, 0x5e, 0xdd, 0x76, 0x02, 0xcb, - 0x2e, 0xa5, 0xb0, 0x9e, 0xb7, 0xd8, 0x61, 0x14, 0x72, 0x0d, 0xf2, 0x6c, 0x8d, 0x50, 0xdf, 0xa7, - 0x7e, 0x29, 0x7d, 0x7d, 0x7c, 0x21, 0xaf, 0x75, 0x09, 0xa4, 0x06, 0xb3, 0xbe, 0xd5, 0x70, 0x8c, - 0xa0, 0xed, 0x51, 0xdd, 0xb0, 0x1b, 0xae, 0x67, 0x05, 0xfb, 0xcd, 0x52, 0x06, 0x31, 0x90, 0xa8, - 0x6a, 0x29, 0xac, 0x61, 0x70, 0x5a, 0xed, 0x5d, 0xdb, 0xaa, 0xeb, 0x07, 0xb4, 0x53, 0xca, 0x22, - 0x5f, 0x9e, 0x53, 0x1e, 0xd0, 0x0e, 0xb9, 0x0a, 0xf9, 0x03, 0xda, 0xd1, 0xdb, 0xa8, 0xf3, 0x1c, - 0xf6, 0x96, 0x3b, 0xa0, 0x9d, 0x1d, 0xd4, 0xf7, 0x4b, 0x40, 0xe8, 0x71, 0x40, 0x1d, 0x93, 0x9a, - 0x7a, 0x97, 0x2b, 0x8f, 0x5c, 0xc5, 0xb0, 0xe6, 0x81, 0xe0, 0x56, 0x1f, 0xc3, 0x74, 0xcf, 0xdc, - 0x92, 0x0c, 0x8c, 0xad, 0x2c, 0x15, 0x2f, 0x90, 0x1c, 0xa4, 0x1e, 0x3e, 0x5a, 0x5d, 0x2b, 0x2a, - 0x64, 0x12, 0xf2, 0x2b, 0x1b, 0xeb, 0x6b, 0x0f, 0xb7, 0xf5, 0x95, 0xa5, 0xe2, 0x18, 0x01, 0xc8, - 0xf0, 0x62, 0x71, 0x9c, 0xe4, 0x21, 0xbd, 0xb3, 0xce, 0xc8, 0x29, 0xd6, 0x6e, 0x67, 0xbd, 0x98, - 0x56, 0x5d, 0x98, 0x8b, 0xaf, 0x57, 0xbf, 0xe5, 0x3a, 0x3e, 0x25, 0x5f, 0x86, 0x89, 0xba, 0x44, - 0x2f, 0x29, 0x38, 0xf5, 0x2f, 0x9f, 0x69, 0xea, 0xc5, 0x9c, 0xc7, 0x04, 0xa9, 0x6f, 0xc1, 0x94, - 0xa8, 0x1e, 0xb6, 0x37, 0xc8, 0x1c, 0xa4, 0x3d, 0x6a, 0x98, 0x1d, 0x9c, 0xff, 0x9c, 0xc6, 0x0b, - 0xea, 0x7f, 0x2b, 0x30, 0x1d, 0x49, 0x10, 0x68, 0xdf, 0x8b, 0x8b, 0x48, 0x2f, 0x2f, 0x9d, 0x9e, - 0x54, 0x32, 0x0f, 0x99, 0x98, 0xd5, 0x1f, 0x9c, 0x54, 0xbe, 0xd0, 0xb0, 0x82, 0xfd, 0xf6, 0x6e, - 0xb5, 0xee, 0x36, 0x6b, 0xd1, 0x00, 0xcc, 0xdd, 0xee, 0x77, 0xad, 0x75, 0xd0, 0xa8, 0x09, 0x2b, - 0x59, 0xe5, 0xcd, 0x22, 0x14, 0x5f, 0x84, 0xac, 0x58, 0x1c, 0x88, 0xa3, 0xb0, 0x38, 0x2f, 0x29, - 0x81, 0xd9, 0x9e, 0xea, 0x4e, 0x64, 0x7b, 0x96, 0x4c, 0xd3, 0x13, 0xa3, 0x0e, 0x1b, 0x91, 0x37, - 0x00, 0xd0, 0x7e, 0xeb, 0xcc, 0x7e, 0xe3, 0x6a, 0x2d, 0x2c, 0x5e, 0x94, 0x44, 0x60, 0x65, 0x75, - 0xdd, 0xd9, 0x73, 0x45, 0xcb, 0x3c, 0x52, 0x18, 0x41, 0x9d, 0x82, 0x09, 0x86, 0x26, 0x54, 0x95, - 0xfa, 0x53, 0x30, 0x29, 0xca, 0x62, 0xe0, 0xf7, 0x21, 0xcd, 0x60, 0x86, 0xf3, 0xf3, 0xd2, 0x80, - 0xf9, 0xe1, 0xe6, 0x35, 0x34, 0xdc, 0x38, 0xba, 0x2d, 0x2c, 0x88, 0xee, 0xb8, 0x00, 0xf5, 0x26, - 0x14, 0x58, 0xd5, 0x50, 0x83, 0xf5, 0xbd, 0x14, 0xe4, 0x35, 0x63, 0x2f, 0x60, 0x32, 0xd8, 0xfa, - 0x05, 0x8f, 0xb6, 0x6c, 0xab, 0x6e, 0x84, 0x9c, 0xa9, 0xe5, 0xc9, 0xd3, 0x93, 0x4a, 0x5e, 0xe3, - 0xd4, 0xf5, 0x55, 0x2d, 0x2f, 0x18, 0xd6, 0x4d, 0xf2, 0x23, 0x00, 0xfb, 0x86, 0x67, 0xa2, 0xc9, - 0xa7, 0x42, 0x9b, 0x33, 0x55, 0x6e, 0x99, 0xab, 0xf7, 0x0d, 0xcf, 0x44, 0xa1, 0xa1, 0x1a, 0xf6, - 0x43, 0x02, 0xb3, 0x4a, 0x36, 0x35, 0x4c, 0x54, 0x5e, 0x4a, 0xc3, 0x6f, 0xb6, 0x38, 0xb8, 0x98, - 0x14, 0xc2, 0xe3, 0x05, 0x66, 0x34, 0x8c, 0x56, 0xcb, 0xb6, 0xa8, 0x59, 0x4a, 0x23, 0x73, 0x58, - 0x24, 0xdb, 0x90, 0x6b, 0x79, 0x6e, 0x03, 0xe7, 0x31, 0x83, 0xca, 0x5a, 0x4c, 0x58, 0xcc, 0xd1, - 0x08, 0xab, 0x9b, 0xa2, 0xd1, 0x9a, 0x13, 0x78, 0x1d, 0x01, 0x2d, 0x92, 0x44, 0x5e, 0x80, 0x69, - 0x86, 0x46, 0x0f, 0x3c, 0xc3, 0xf1, 0xf7, 0xa8, 0x47, 0x29, 0x1a, 0x80, 0x94, 0x36, 0xc5, 0xc8, - 0xdb, 0x11, 0xb5, 0xfc, 0xab, 0x0a, 0xe4, 0x42, 0x51, 0x0c, 0x7b, 0xd3, 0x08, 0xea, 0xfb, 0x5c, - 0x61, 0x1a, 0x2f, 0xb0, 0x51, 0x3a, 0xf4, 0x98, 0x5b, 0xbb, 0x94, 0x86, 0xdf, 0xdd, 0x51, 0x8e, - 0xcb, 0xa3, 0xbc, 0x04, 0x99, 0x96, 0xd1, 0xf6, 0xa9, 0x89, 0x83, 0xcf, 0x69, 0xa2, 0x44, 0x6e, - 0x41, 0xb1, 0x45, 0x1d, 0xd3, 0x72, 0x1a, 0xba, 0xef, 0x18, 0x2d, 0x7f, 0xdf, 0x0d, 0x84, 0x1a, - 0xa6, 0x05, 0x7d, 0x4b, 0x90, 0xcb, 0x5f, 0x81, 0xc9, 0xd8, 0xc8, 0x48, 0x11, 0xc6, 0x99, 0xf9, - 0xe2, 0x88, 0xd8, 0x27, 0x59, 0x81, 0xf4, 0x91, 0x61, 0xb7, 0xc3, 0x89, 0x7a, 0xf9, 0x4c, 0xea, - 0xd2, 0x78, 0xdb, 0x37, 0xc6, 0xee, 0x28, 0xea, 0x5f, 0x8e, 0xc1, 0xa4, 0x66, 0x38, 0x0d, 0xba, - 0xe9, 0xb9, 0xbb, 0x36, 0x6d, 0xfa, 0xe4, 0x3a, 0x14, 0xda, 0x8e, 0x71, 0x64, 0x58, 0xb6, 0xb1, - 0x6b, 0xf3, 0x53, 0x2e, 0xa7, 0xc9, 0x24, 0xf2, 0x3a, 0x5c, 0x66, 0x1a, 0xa4, 0x9e, 0xee, 0xb8, - 0x81, 0xce, 0x3d, 0x85, 0x7d, 0xd7, 0x36, 0xa9, 0x27, 0xac, 0xc1, 0x1c, 0xaf, 0x7e, 0xe8, 0x06, - 0x1b, 0xac, 0xf2, 0x3e, 0xd6, 0x91, 0xe7, 0x60, 0xca, 0x71, 0x75, 0xb6, 0xa2, 0x74, 0x5e, 0x8f, - 0x8a, 0xcb, 0x69, 0x13, 0x8e, 0xcb, 0x30, 0x6e, 0x20, 0x8d, 0x2c, 0xc0, 0x74, 0xdb, 0x31, 0xa9, - 0x27, 0x56, 0x66, 0x10, 0x29, 0xb2, 0x97, 0x4c, 0xae, 0x40, 0xce, 0x71, 0x79, 0xf7, 0xa8, 0xc9, - 0x9c, 0x96, 0x75, 0x5c, 0xec, 0x90, 0xdc, 0x81, 0xd2, 0x61, 0xdb, 0xa2, 0x7e, 0x9d, 0x3a, 0x81, - 0x4e, 0x0f, 0xdb, 0x86, 0xed, 0xeb, 0x81, 0x55, 0x3f, 0xb0, 0x9c, 0x06, 0x1e, 0x16, 0x39, 0xed, - 0x52, 0x54, 0xbf, 0x86, 0xd5, 0xdb, 0xbc, 0x96, 0xbc, 0x08, 0x84, 0x23, 0x74, 0x1b, 0x7a, 0xe0, - 0xba, 0xba, 0x6d, 0x78, 0x0d, 0xbe, 0x6e, 0x72, 0xda, 0x34, 0xab, 0xd9, 0x70, 0x1b, 0xdb, 0xae, - 0xbb, 0xc1, 0xc8, 0xea, 0x01, 0x4c, 0xa3, 0xee, 0x98, 0x7a, 0x2d, 0xf4, 0xcc, 0xd8, 0xa1, 0x71, - 0xd8, 0xa6, 0x9e, 0x45, 0x7d, 0xbd, 0x45, 0x3d, 0xdd, 0xa7, 0x75, 0xd7, 0xe1, 0x9b, 0x4f, 0xd1, - 0x8a, 0xa2, 0x66, 0x93, 0x7a, 0x5b, 0x48, 0x27, 0xb7, 0x61, 0xe6, 0x67, 0x3d, 0x2b, 0x88, 0x33, - 0x8f, 0x21, 0xf3, 0x34, 0xaf, 0x88, 0x78, 0xd5, 0xfb, 0x00, 0x9b, 0x1e, 0x0d, 0x82, 0xce, 0x56, - 0xcb, 0x70, 0xd8, 0xc9, 0xe5, 0x07, 0x86, 0x17, 0xe8, 0xe1, 0xc2, 0xc8, 0x6b, 0x39, 0x24, 0xb0, - 0x63, 0xed, 0x32, 0x64, 0xa9, 0x83, 0x87, 0x96, 0x38, 0x9e, 0x33, 0xd4, 0x61, 0x27, 0xd5, 0x1b, - 0xa9, 0xff, 0xfa, 0xfd, 0x8a, 0xa2, 0xfe, 0xb1, 0x02, 0xb3, 0x2b, 0x6e, 0xb3, 0x69, 0x38, 0xe6, - 0xe3, 0x36, 0x6d, 0xd3, 0x77, 0x69, 0xe0, 0x31, 0xec, 0xcf, 0xc3, 0x14, 0x76, 0xaa, 0xd7, 0x79, - 0xa5, 0x8f, 0x82, 0xc7, 0xb5, 0x49, 0xa4, 0x8a, 0x16, 0x3e, 0x73, 0x56, 0x98, 0xb5, 0xef, 0x72, - 0x8d, 0x21, 0xd7, 0x04, 0x23, 0x46, 0x4c, 0xb7, 0x61, 0xa6, 0x69, 0x1c, 0xeb, 0xee, 0x11, 0xf5, - 0x6c, 0xa3, 0xe5, 0xeb, 0x3e, 0xa5, 0x8e, 0x70, 0x07, 0xa6, 0x9b, 0xc6, 0xf1, 0x23, 0x41, 0xdf, - 0xa2, 0x14, 0xc7, 0x12, 0x78, 0x94, 0xea, 0xbe, 0xf5, 0x55, 0x6e, 0x32, 0xd2, 0x5a, 0x8e, 0x11, - 0xb6, 0xac, 0xaf, 0x52, 0xf5, 0x7f, 0xb2, 0xcc, 0xa6, 0x39, 0x0d, 0xca, 0x8c, 0x2e, 0x79, 0x0b, - 0x52, 0x7e, 0xcb, 0x70, 0x10, 0x58, 0x61, 0xf1, 0xf9, 0x84, 0x65, 0xdf, 0xd5, 0x95, 0x30, 0x0c, - 0xd8, 0x90, 0xac, 0x03, 0xe0, 0xfc, 0xca, 0x66, 0xee, 0xb9, 0x51, 0x76, 0x4f, 0x68, 0xf9, 0xbc, - 0xc8, 0xbe, 0x2e, 0xcb, 0x56, 0xae, 0xb0, 0x78, 0x53, 0x96, 0xc2, 0x3d, 0xe4, 0x6a, 0xe4, 0x29, - 0x57, 0xa3, 0x21, 0x84, 0x96, 0x9d, 0x5b, 0x8b, 0x26, 0x4c, 0xf9, 0x6e, 0xdb, 0xab, 0x53, 0x3d, - 0xb4, 0xe8, 0x69, 0x3c, 0x23, 0xef, 0x9d, 0x9e, 0x54, 0x26, 0xb6, 0xb0, 0xe6, 0x7c, 0x27, 0xe5, - 0x84, 0xdf, 0x15, 0x62, 0x92, 0x43, 0x98, 0x16, 0xdd, 0x31, 0x64, 0xd8, 0x5f, 0x06, 0xfb, 0x5b, - 0x3f, 0x3d, 0xa9, 0x4c, 0xf2, 0xfe, 0xb6, 0x58, 0x0d, 0x76, 0xf8, 0xda, 0x99, 0x3a, 0x14, 0xed, - 0xb4, 0x49, 0x5f, 0x12, 0x63, 0xf6, 0xbb, 0xb6, 0xd9, 0x01, 0xae, 0xed, 0x0a, 0x4c, 0x0a, 0x33, - 0x62, 0x31, 0x60, 0x1d, 0xf4, 0xc5, 0x0a, 0x8b, 0x25, 0x49, 0xa5, 0x61, 0x37, 0xb8, 0xc1, 0x43, - 0xef, 0x05, 0x1b, 0xdd, 0xe7, 0x6d, 0xc8, 0x3b, 0x78, 0x8a, 0xa0, 0x11, 0x2b, 0xe5, 0x71, 0x4a, - 0x16, 0x12, 0x27, 0x56, 0x32, 0x7a, 0xd2, 0xd9, 0xc1, 0x8d, 0xe0, 0x5d, 0x3e, 0xb7, 0x7e, 0x09, - 0x50, 0xd0, 0xed, 0x61, 0x82, 0xba, 0x16, 0x40, 0x9e, 0x5f, 0x9f, 0x6c, 0x43, 0xa1, 0xde, 0x34, - 0xf5, 0x43, 0xdd, 0x76, 0xeb, 0x86, 0x5d, 0x2a, 0xa0, 0xb4, 0x6a, 0x92, 0xa7, 0xd6, 0xbf, 0x2f, - 0xc3, 0x95, 0x57, 0x6f, 0x9a, 0x8f, 0x37, 0x98, 0x18, 0xf2, 0x25, 0x98, 0xe0, 0x52, 0x1b, 0xb6, - 0xbb, 0x6b, 0xd8, 0xa5, 0x89, 0x73, 0x88, 0x05, 0x26, 0xf6, 0x1e, 0xca, 0x21, 0xf7, 0x60, 0x42, - 0xbe, 0xf7, 0x95, 0x26, 0xfb, 0x7c, 0xaa, 0x70, 0x61, 0xe3, 0x2c, 0xc4, 0x5c, 0x95, 0x82, 0xdd, - 0x25, 0x31, 0x2f, 0x3e, 0xb2, 0xaf, 0xa5, 0x29, 0x34, 0x9e, 0x5d, 0x02, 0x73, 0x04, 0x42, 0x63, - 0x3c, 0xcd, 0xed, 0xb6, 0x28, 0xaa, 0xbf, 0xa2, 0x88, 0xd3, 0x68, 0xb8, 0x03, 0x6a, 0x40, 0xde, - 0x63, 0x9c, 0xba, 0x85, 0x16, 0x68, 0x7c, 0x61, 0x7c, 0x79, 0xf5, 0xf4, 0xa4, 0x92, 0xe3, 0x1b, - 0x6d, 0xd5, 0x3f, 0xf3, 0xfa, 0x15, 0x0d, 0xb5, 0x1c, 0x8a, 0x5d, 0x37, 0x7d, 0x75, 0x1b, 0xa6, - 0x42, 0x30, 0xc2, 0xa5, 0x5b, 0x86, 0x0c, 0xd6, 0x86, 0x3e, 0xdd, 0x73, 0xc3, 0xd6, 0x85, 0xb4, - 0xe3, 0x45, 0x4b, 0x75, 0x01, 0x26, 0xef, 0x61, 0x68, 0x60, 0xa8, 0x3b, 0xf7, 0x33, 0x00, 0xdb, - 0x9e, 0x51, 0xa7, 0x6b, 0x47, 0x4c, 0x6b, 0x77, 0x20, 0xc5, 0x2e, 0xb4, 0xc2, 0xf4, 0x95, 0xab, - 0xfc, 0xb6, 0x5b, 0x0d, 0x6f, 0xbb, 0xd5, 0xed, 0xf0, 0xb6, 0xbb, 0x9c, 0x63, 0xfd, 0x7d, 0xeb, - 0xd3, 0x8a, 0xa2, 0x61, 0x0b, 0xa6, 0xef, 0xf8, 0xbd, 0x32, 0x2c, 0xaa, 0xdf, 0x53, 0x60, 0x7a, - 0xc9, 0x66, 0x6b, 0x33, 0x70, 0xbd, 0x55, 0xaf, 0xa3, 0xb5, 0x1d, 0xf2, 0x3e, 0xe4, 0x42, 0xc5, - 0x72, 0xfb, 0xbf, 0xbc, 0x72, 0x7a, 0x52, 0xc9, 0x0a, 0xf5, 0x7c, 0x66, 0xb5, 0x66, 0x85, 0x5a, - 0xc9, 0x9b, 0x90, 0xa1, 0x6c, 0x40, 0x7c, 0xd6, 0x92, 0x8d, 0x78, 0x77, 0xf8, 0x9a, 0x68, 0xa4, - 0x2e, 0xc2, 0xc5, 0x08, 0x31, 0xca, 0x0e, 0xd5, 0x78, 0xa5, 0x17, 0x77, 0xd4, 0xa5, 0xfa, 0x17, - 0x0a, 0x5c, 0xea, 0x6d, 0x34, 0xf8, 0x76, 0x32, 0xfe, 0x79, 0xde, 0x4e, 0x56, 0x20, 0x6b, 0x7a, - 0x1d, 0xdd, 0x6b, 0x3b, 0xe2, 0xa0, 0x49, 0x32, 0x23, 0x3d, 0xd3, 0xa0, 0x65, 0x4c, 0xfc, 0x55, - 0xbf, 0xa9, 0x40, 0xb1, 0x8b, 0xfd, 0xff, 0xc1, 0xae, 0x78, 0x0f, 0x66, 0x24, 0x3c, 0x42, 0x8d, - 0x6b, 0x90, 0x13, 0x43, 0x0d, 0xb7, 0xc6, 0x59, 0xc6, 0x9a, 0xe5, 0x63, 0xf5, 0x55, 0x15, 0x26, - 0xde, 0xd9, 0x7a, 0xf4, 0x30, 0x12, 0x1b, 0x86, 0x3c, 0x94, 0x6e, 0xc8, 0x43, 0xfd, 0xae, 0x02, - 0x85, 0x0d, 0xb7, 0x31, 0xd2, 0x15, 0xd5, 0xa6, 0x47, 0xd4, 0x16, 0x8b, 0x9e, 0x17, 0xc8, 0x33, - 0x00, 0xdc, 0x71, 0xc2, 0xcd, 0xc4, 0x5d, 0x77, 0xee, 0x4a, 0xb1, 0x0d, 0xc4, 0x56, 0x11, 0x73, - 0x9d, 0xb0, 0x92, 0xdf, 0x5e, 0x98, 0x2b, 0x85, 0x55, 0x45, 0x18, 0x6f, 0x1a, 0xc7, 0x78, 0x40, - 0xe7, 0x35, 0xf6, 0xc9, 0x36, 0x56, 0xcb, 0x08, 0x02, 0xea, 0x39, 0x22, 0x04, 0x11, 0x16, 0xd5, - 0x47, 0x40, 0x36, 0xdc, 0x06, 0xf3, 0xde, 0x2d, 0xc9, 0x7c, 0xfc, 0x18, 0xf3, 0xcb, 0x90, 0x24, - 0x94, 0x74, 0xa5, 0xf7, 0xba, 0x6a, 0xbb, 0x8d, 0xaa, 0x7c, 0x9b, 0x09, 0xf9, 0xd5, 0x2a, 0xcc, - 0x6e, 0xb8, 0x8d, 0xbb, 0x96, 0x4d, 0xfd, 0x0d, 0xcb, 0x0f, 0x86, 0xda, 0x8e, 0x4d, 0x98, 0x8b, - 0xf3, 0x0b, 0x08, 0x77, 0x20, 0xbd, 0xc7, 0x88, 0x02, 0xc0, 0xb5, 0x41, 0x00, 0x58, 0x2b, 0xd9, - 0x55, 0xc1, 0x06, 0xea, 0x9b, 0x30, 0x25, 0x24, 0x0e, 0xd5, 0x3c, 0x81, 0x14, 0x6b, 0x23, 0x14, - 0x8f, 0xdf, 0xcc, 0xec, 0x6d, 0x05, 0x46, 0xfd, 0x60, 0x78, 0xd8, 0x6d, 0x0b, 0x52, 0xac, 0x17, - 0xbc, 0x73, 0x19, 0xc2, 0xe0, 0xe5, 0x35, 0xfc, 0x66, 0xae, 0x22, 0x93, 0xc6, 0x5d, 0x45, 0xee, - 0x77, 0xe6, 0x18, 0x81, 0xb9, 0x8a, 0xa4, 0x0c, 0xb9, 0xba, 0xeb, 0x04, 0x68, 0x5b, 0x78, 0x90, - 0x2c, 0x2a, 0xab, 0xbf, 0xab, 0xc0, 0xf4, 0x3d, 0x1a, 0xa0, 0x42, 0x86, 0xe2, 0xbf, 0x0a, 0x79, - 0xdb, 0xf2, 0x03, 0xdd, 0x75, 0xec, 0x30, 0xc0, 0x91, 0x63, 0x84, 0x47, 0x8e, 0xdd, 0x21, 0x3f, - 0x2a, 0xc2, 0x7f, 0x69, 0x0c, 0xff, 0xdd, 0x48, 0x58, 0xe6, 0xac, 0x33, 0x29, 0xc8, 0x57, 0x86, - 0x9c, 0x58, 0x1e, 0xfc, 0x96, 0x9b, 0xd7, 0xa2, 0xb2, 0xba, 0x0e, 0xc5, 0x2e, 0x3a, 0x31, 0x55, - 0xaf, 0xc7, 0xa7, 0xaa, 0x32, 0xa4, 0xa7, 0x70, 0x9e, 0x7e, 0x0e, 0xa6, 0x36, 0x3d, 0x77, 0x6f, - 0x94, 0x79, 0x5a, 0x8e, 0x0d, 0xa5, 0x9a, 0xe8, 0x4d, 0xcb, 0x12, 0xab, 0xdd, 0x51, 0xa9, 0x45, - 0x48, 0x61, 0xb0, 0x2b, 0x07, 0xa9, 0xfb, 0x6b, 0x4b, 0x9b, 0xc5, 0x0b, 0xea, 0x2d, 0x98, 0x12, - 0x2e, 0xc6, 0xd0, 0xa9, 0xfe, 0x13, 0x3c, 0xef, 0xf7, 0x02, 0xb4, 0x32, 0xcc, 0x7a, 0x3e, 0xd5, - 0x68, 0xd1, 0xdb, 0x90, 0x46, 0x2b, 0x36, 0x92, 0xdb, 0xdf, 0xe3, 0xae, 0x63, 0x43, 0xf5, 0x36, - 0xf3, 0x08, 0x04, 0xdc, 0x35, 0xe6, 0xc0, 0xca, 0x67, 0xab, 0x12, 0x3f, 0x5b, 0x3f, 0x1a, 0x63, - 0xb7, 0x43, 0xc1, 0x2c, 0xfc, 0xa2, 0xa7, 0x7d, 0xb6, 0xde, 0x83, 0x0c, 0xfa, 0xd5, 0xe1, 0xd9, - 0x7a, 0x6b, 0xc8, 0xcd, 0xa6, 0x3b, 0x90, 0xd0, 0x49, 0xe1, 0xcd, 0xc9, 0x6a, 0x18, 0xbb, 0x1a, - 0x47, 0x39, 0x0b, 0xa3, 0xc8, 0x61, 0xda, 0x8e, 0xc7, 0xad, 0xda, 0x50, 0x64, 0xb5, 0xab, 0x74, - 0xb7, 0xdd, 0x08, 0xd7, 0x42, 0xec, 0x84, 0x52, 0x9e, 0xca, 0x09, 0xf5, 0x8f, 0x63, 0x30, 0x23, - 0xf5, 0x2b, 0xb6, 0xd3, 0x37, 0x95, 0x1e, 0xe7, 0xed, 0xce, 0x90, 0x41, 0xc5, 0x9a, 0xf3, 0x6e, - 0x44, 0xa4, 0xe9, 0x27, 0xd8, 0x20, 0x3f, 0xfe, 0xf4, 0x33, 0x02, 0x15, 0x28, 0x3e, 0xb7, 0xc9, - 0x2a, 0x53, 0x28, 0x48, 0xe8, 0xe4, 0x68, 0xd1, 0x38, 0x8f, 0x16, 0xbd, 0x1d, 0x8f, 0x16, 0xdd, - 0x1e, 0xa5, 0x23, 0xbe, 0x62, 0xe5, 0x50, 0xd1, 0xd7, 0xc7, 0xa0, 0xb0, 0x54, 0x0f, 0xac, 0x23, - 0xfa, 0xb8, 0x4d, 0xbd, 0x0e, 0xb9, 0x04, 0x63, 0xe1, 0x86, 0x5e, 0xce, 0x9c, 0x9e, 0x54, 0xc6, - 0xd6, 0x57, 0xb5, 0x31, 0xcb, 0x64, 0xfd, 0xfb, 0x87, 0xe1, 0xa9, 0xcb, 0x3e, 0xc9, 0x1b, 0x78, - 0x9b, 0xf2, 0x02, 0x11, 0x61, 0x1d, 0xcd, 0x77, 0xe5, 0x4d, 0xc8, 0xf3, 0x30, 0x65, 0xf9, 0xba, - 0x69, 0xf9, 0x81, 0x67, 0xed, 0xb6, 0xbb, 0xe1, 0xa0, 0x49, 0xcb, 0x5f, 0xed, 0x12, 0xd9, 0x65, - 0xbc, 0xb5, 0x1f, 0x46, 0x82, 0xa6, 0x06, 0x06, 0x5b, 0x23, 0xef, 0xa3, 0x3b, 0x86, 0xea, 0x26, - 0x6b, 0xa3, 0xf1, 0xa6, 0xea, 0xf3, 0x90, 0xc6, 0x32, 0x99, 0x84, 0xfc, 0xa6, 0xb6, 0xb6, 0xb9, - 0xa4, 0xad, 0x3f, 0xbc, 0x57, 0xbc, 0xc0, 0x8a, 0x6b, 0x3f, 0xb9, 0xb6, 0xb2, 0xb3, 0xcd, 0x8a, - 0x8a, 0xfa, 0x2a, 0xcc, 0xb2, 0x23, 0x75, 0x8b, 0xfa, 0xbe, 0xe5, 0x3a, 0x91, 0x91, 0x2b, 0x43, - 0xae, 0xed, 0x53, 0x4f, 0x3a, 0xb2, 0xa2, 0xb2, 0xfa, 0xf7, 0x29, 0xc8, 0x0a, 0xfe, 0xa7, 0x6a, - 0xe1, 0x64, 0x0c, 0x63, 0x71, 0x0c, 0x4c, 0x91, 0x75, 0xdb, 0xa2, 0x4e, 0xa0, 0x87, 0x21, 0x73, - 0xee, 0xfc, 0x4c, 0x72, 0xea, 0x92, 0x08, 0x89, 0xdf, 0x82, 0x22, 0x86, 0x65, 0xeb, 0xf8, 0xb6, - 0xa6, 0xa3, 0x28, 0xee, 0x08, 0x4d, 0x4b, 0xf4, 0x87, 0x4c, 0xe2, 0x16, 0x4c, 0x19, 0xa8, 0x4b, - 0x5d, 0x04, 0xb6, 0xf0, 0xc1, 0xa6, 0x27, 0x12, 0xf2, 0x64, 0xe5, 0x8b, 0x55, 0x3c, 0x69, 0x44, - 0x24, 0x8b, 0xfa, 0xdd, 0xb5, 0x92, 0x39, 0xfb, 0x5a, 0x79, 0x1f, 0xf2, 0x07, 0x47, 0x7a, 0x70, - 0xec, 0x30, 0xe5, 0x66, 0x99, 0x07, 0xb0, 0xbc, 0xfc, 0x2f, 0xa3, 0xaa, 0x94, 0x3f, 0x55, 0xb6, - 0x2d, 0xb3, 0xba, 0xb3, 0xb3, 0xce, 0x4c, 0x52, 0xf6, 0xc1, 0xd1, 0xf6, 0xb1, 0xc3, 0xcc, 0xeb, - 0x01, 0x7e, 0x60, 0xb8, 0xce, 0x36, 0xfc, 0x40, 0x97, 0x46, 0xdd, 0x29, 0xe5, 0xb8, 0x72, 0x58, - 0x45, 0xff, 0xee, 0xc8, 0x23, 0x08, 0x79, 0x77, 0x54, 0xa0, 0x60, 0x30, 0xf7, 0x57, 0xdf, 0xed, - 0x04, 0x94, 0xc7, 0x17, 0xc6, 0x35, 0x40, 0xd2, 0x32, 0xa3, 0x90, 0x9b, 0x30, 0xdd, 0x34, 0x8e, - 0x75, 0x99, 0xa9, 0xc0, 0xc3, 0x70, 0x4d, 0xe3, 0x78, 0x29, 0xe2, 0x53, 0xbf, 0xa1, 0xc0, 0x8c, - 0xbc, 0x0e, 0xf9, 0x79, 0xf4, 0x34, 0x57, 0xd7, 0x93, 0xef, 0x91, 0x7f, 0xa4, 0xc0, 0x5c, 0x7c, - 0x4f, 0x08, 0xa3, 0xbb, 0x0a, 0x39, 0x5f, 0xd0, 0x84, 0xd5, 0x55, 0x13, 0x16, 0x87, 0x68, 0x1e, - 0x46, 0x63, 0xc2, 0x96, 0xe4, 0x9d, 0x1e, 0x4b, 0x99, 0xb4, 0xbb, 0xfb, 0x54, 0x12, 0x37, 0x96, - 0xea, 0x21, 0x90, 0x15, 0xc3, 0xa9, 0x53, 0x1b, 0xa7, 0x69, 0xa8, 0x8b, 0x74, 0x13, 0x72, 0x38, - 0xcd, 0xac, 0x06, 0x07, 0xbd, 0x5c, 0x60, 0x4b, 0x03, 0x1b, 0xb3, 0xa5, 0x81, 0x95, 0x3d, 0x3b, - 0x6f, 0xbc, 0x67, 0xf7, 0xdf, 0x83, 0xd9, 0x58, 0x97, 0x42, 0x37, 0xcc, 0x5d, 0x45, 0x32, 0x35, - 0x45, 0x94, 0x3d, 0x2a, 0xb3, 0xbb, 0x0b, 0xe2, 0x0d, 0xef, 0x2e, 0x58, 0x50, 0x3b, 0x30, 0xc7, - 0x05, 0x89, 0x01, 0x0e, 0x45, 0xff, 0x12, 0x80, 0x50, 0x62, 0x88, 0x7f, 0x82, 0x3f, 0x01, 0x09, - 0x01, 0xeb, 0xab, 0x5a, 0x5e, 0x30, 0x0c, 0x19, 0xc3, 0x3a, 0x5c, 0xec, 0xe9, 0xfa, 0x33, 0x8f, - 0xe2, 0x5f, 0x15, 0x28, 0x6e, 0xb5, 0x0c, 0x87, 0x9d, 0x30, 0x91, 0xf5, 0xbc, 0xd1, 0x33, 0x84, - 0x65, 0xe8, 0xae, 0xdb, 0x68, 0x38, 0x9a, 0x1c, 0xf4, 0xe6, 0xa3, 0x79, 0xfd, 0x07, 0x27, 0x95, - 0x57, 0xcf, 0x76, 0x0c, 0x3f, 0xa0, 0x1d, 0x29, 0x56, 0xfe, 0xb0, 0x1b, 0x2b, 0x1f, 0x3f, 0x8f, - 0x44, 0x11, 0x62, 0x57, 0xbf, 0xaf, 0xc0, 0x8c, 0x34, 0x3a, 0xa1, 0xa5, 0x2d, 0x28, 0x04, 0x6e, - 0x60, 0xd8, 0x3c, 0xf7, 0x43, 0xc4, 0x70, 0x5e, 0x1a, 0x10, 0x58, 0xe3, 0xe9, 0x19, 0xd5, 0x30, - 0x4b, 0xa3, 0xfa, 0xee, 0x97, 0x56, 0x56, 0x50, 0x54, 0x18, 0xae, 0x43, 0x31, 0x48, 0x61, 0xa6, - 0x84, 0xbb, 0x52, 0x75, 0xb7, 0xed, 0xf0, 0xb7, 0xa9, 0xb4, 0x06, 0x48, 0x5a, 0x61, 0x14, 0xf2, - 0x1a, 0x5c, 0x32, 0x5a, 0x2d, 0xcf, 0x3d, 0xb6, 0x9a, 0x46, 0x40, 0xd9, 0x21, 0x7a, 0x20, 0x2c, - 0x0a, 0x7f, 0xad, 0x9b, 0x93, 0x6a, 0x57, 0x2d, 0xff, 0x80, 0x1b, 0x96, 0x1f, 0x87, 0x39, 0x11, - 0x17, 0x8d, 0x87, 0xe2, 0x46, 0x99, 0x22, 0xf5, 0x1b, 0x13, 0x70, 0xb1, 0xa7, 0x75, 0x7f, 0xa4, - 0x25, 0xf7, 0x79, 0x5b, 0xa6, 0xbf, 0x51, 0x60, 0x36, 0x8c, 0xdd, 0xea, 0xbb, 0x9d, 0x28, 0x98, - 0x9e, 0x47, 0x73, 0x71, 0x37, 0xf9, 0x62, 0xd3, 0x8f, 0xb5, 0x1a, 0xc5, 0x85, 0x3b, 0x3c, 0x70, - 0xce, 0xdd, 0xbe, 0x47, 0x6c, 0x06, 0x4e, 0x4f, 0x2a, 0xc5, 0x9e, 0xea, 0xd5, 0x8f, 0x3f, 0xfd, - 0x6c, 0xf0, 0x8b, 0xad, 0x9e, 0x7e, 0xca, 0xdf, 0xcf, 0xf1, 0x57, 0xe5, 0xe8, 0x35, 0xae, 0x2f, - 0x7c, 0xae, 0x0c, 0x08, 0x9f, 0xff, 0x82, 0x02, 0x17, 0xa5, 0x07, 0x3a, 0xbd, 0x37, 0x04, 0xf4, - 0xe8, 0xf4, 0xa4, 0x32, 0xbb, 0xd3, 0x65, 0x38, 0xb7, 0xaf, 0x3d, 0xdb, 0xee, 0x15, 0x66, 0xfa, - 0xe4, 0x4f, 0x15, 0xb8, 0x29, 0xbd, 0xee, 0xf5, 0x3d, 0x0e, 0x4a, 0xb0, 0xc6, 0x11, 0xd6, 0x4f, - 0x9f, 0x9e, 0x54, 0xae, 0x77, 0x9f, 0xfe, 0xe2, 0xcf, 0x85, 0xe7, 0xc6, 0x78, 0xdd, 0x4b, 0x94, - 0x6c, 0xfa, 0xe4, 0x97, 0x14, 0x28, 0xc5, 0x5f, 0x24, 0x25, 0x88, 0x29, 0x84, 0xb8, 0x79, 0x7a, - 0x52, 0x99, 0x7b, 0x28, 0xbd, 0x4f, 0x9e, 0x1b, 0xd6, 0x9c, 0xd3, 0x27, 0xcd, 0xf4, 0xc9, 0x31, - 0x90, 0xf0, 0x2d, 0x53, 0xc2, 0x90, 0x46, 0x0c, 0x0f, 0x4e, 0x4f, 0x2a, 0xd3, 0x0f, 0xf9, 0xcb, - 0xe6, 0xb9, 0xbb, 0x9f, 0x76, 0x64, 0x41, 0xa6, 0x4f, 0x7e, 0x4d, 0x81, 0x2b, 0x3d, 0x2f, 0xab, - 0x12, 0x82, 0x0c, 0x22, 0xd8, 0x3a, 0x3d, 0xa9, 0x5c, 0xde, 0x89, 0x33, 0x9d, 0x1b, 0xc9, 0xe5, - 0xf6, 0x20, 0x81, 0xa6, 0x4f, 0xfe, 0x40, 0x01, 0xf5, 0x49, 0xaf, 0xb7, 0x12, 0xb4, 0x2c, 0x42, - 0x7b, 0xef, 0xf4, 0xa4, 0x32, 0xff, 0x78, 0xe0, 0x5b, 0xee, 0xb9, 0x11, 0xce, 0x1f, 0x26, 0xc8, - 0x35, 0x7d, 0xf2, 0x1d, 0x05, 0xae, 0xf5, 0x3f, 0x16, 0x4b, 0x10, 0x73, 0x5d, 0xed, 0x69, 0xf1, - 0xa7, 0xe3, 0xf3, 0x6b, 0xcf, 0x1b, 0x24, 0xd0, 0xf4, 0xcb, 0x1f, 0x2b, 0x91, 0x01, 0x8e, 0x9b, - 0x2f, 0xf9, 0x5e, 0x98, 0xe6, 0xf7, 0xc2, 0xad, 0xf8, 0xbd, 0xf0, 0xcd, 0x33, 0xdb, 0x49, 0xd9, - 0x54, 0x49, 0x57, 0xc5, 0x77, 0x52, 0x39, 0xa5, 0x98, 0x53, 0x6f, 0xc1, 0xc4, 0xa8, 0x11, 0xfa, - 0x3f, 0x4c, 0x8b, 0x87, 0x9f, 0x1f, 0x4a, 0xda, 0x90, 0x1c, 0x86, 0x19, 0x7b, 0x0a, 0x61, 0x98, - 0xbf, 0x52, 0x60, 0xce, 0x13, 0x03, 0x89, 0x9d, 0x47, 0x3c, 0x9a, 0xf2, 0xd6, 0xb0, 0xc0, 0x53, - 0x37, 0xe8, 0x10, 0x0a, 0x89, 0x1f, 0x44, 0x9b, 0xe2, 0x20, 0x9a, 0xe9, 0xad, 0xff, 0xcc, 0x27, - 0xd1, 0x8c, 0xd7, 0xdb, 0x53, 0xf9, 0xdb, 0x0a, 0x3f, 0x8a, 0x64, 0x4f, 0x2f, 0xe4, 0x0a, 0x3d, - 0xbd, 0xb0, 0x3c, 0x5a, 0x02, 0xe3, 0xdb, 0x90, 0xb6, 0x9c, 0x3d, 0x37, 0x0c, 0x2a, 0x9d, 0x29, - 0xfe, 0x86, 0x0d, 0xcb, 0x1f, 0xc0, 0xa5, 0xc1, 0x2a, 0x19, 0xb0, 0xb8, 0x1f, 0xc4, 0x17, 0xf7, - 0xeb, 0x23, 0x2b, 0x5d, 0x1e, 0x74, 0x7c, 0x51, 0xa7, 0x8a, 0x69, 0xf5, 0x95, 0x78, 0xee, 0xc4, - 0x08, 0x6b, 0xdb, 0x86, 0xb9, 0x78, 0x0b, 0xa1, 0xb3, 0x6d, 0xc8, 0x45, 0x99, 0x40, 0xdc, 0x21, - 0x5c, 0x4c, 0x4c, 0x21, 0x90, 0x85, 0xf8, 0x61, 0xb2, 0x50, 0x74, 0x57, 0x12, 0x65, 0xf5, 0x65, - 0x20, 0xab, 0xdd, 0x4c, 0xe1, 0xa1, 0x11, 0x58, 0x0c, 0xcb, 0xbb, 0xde, 0x08, 0xd9, 0xb0, 0x7f, - 0x36, 0x06, 0x13, 0xc8, 0x1a, 0xe6, 0xc1, 0xbe, 0x0f, 0xb9, 0x28, 0x8b, 0x80, 0x6f, 0x51, 0xdc, - 0x45, 0xe7, 0xcd, 0x1f, 0xc8, 0xfa, 0x22, 0x73, 0xe0, 0x45, 0x98, 0xa1, 0x4e, 0xdd, 0xeb, 0xb4, - 0x30, 0x10, 0x21, 0x9e, 0xa4, 0xd1, 0xeb, 0xd7, 0x8a, 0xdd, 0x0a, 0x11, 0x59, 0xad, 0x84, 0x0e, - 0x36, 0x0f, 0x99, 0x73, 0xff, 0x96, 0x3b, 0xcb, 0x18, 0x55, 0xef, 0x32, 0x70, 0x07, 0x38, 0x25, - 0x31, 0xf0, 0x7b, 0xf7, 0x02, 0x14, 0xc5, 0xbd, 0xfe, 0x80, 0x76, 0x84, 0x18, 0x9e, 0xa0, 0x25, - 0xa2, 0x1c, 0x0f, 0x68, 0x87, 0x8b, 0x8a, 0x73, 0x72, 0x79, 0x99, 0x1e, 0x4e, 0xee, 0x4a, 0x7f, - 0x19, 0xa6, 0x42, 0xed, 0x46, 0x0f, 0x65, 0x19, 0x1c, 0x5f, 0x78, 0x1d, 0x7e, 0x21, 0xe9, 0x3a, - 0x2c, 0x69, 0x3b, 0xbc, 0xc5, 0xf2, 0xc6, 0xea, 0x1d, 0x98, 0xc1, 0x24, 0x94, 0x26, 0x75, 0xce, - 0x76, 0x87, 0x52, 0xff, 0x39, 0x05, 0x44, 0x6e, 0x2a, 0x70, 0xb5, 0xf0, 0x59, 0x4c, 0x50, 0x05, - 0xb6, 0x77, 0x12, 0xb1, 0xf5, 0x8a, 0xa8, 0xae, 0xb8, 0xb6, 0x4d, 0xeb, 0x01, 0x35, 0xa3, 0xba, - 0xbe, 0xac, 0x08, 0xa9, 0x0f, 0xb2, 0x02, 0x80, 0xc1, 0x14, 0x8f, 0xfa, 0xf4, 0x6c, 0x91, 0xc1, - 0x3c, 0x6b, 0xa7, 0xb1, 0x66, 0xe5, 0xbf, 0x56, 0x60, 0x7e, 0x4d, 0xa4, 0xe2, 0x0e, 0xe8, 0x96, - 0x5d, 0xf0, 0xee, 0x42, 0x8e, 0x4d, 0x53, 0xf4, 0x8e, 0xd8, 0xf3, 0xe2, 0x7c, 0x68, 0x57, 0x07, - 0x37, 0x0c, 0x5f, 0xe0, 0x0e, 0x68, 0x67, 0xd5, 0x08, 0x0c, 0xf9, 0x40, 0x1a, 0xfb, 0x9c, 0x0f, - 0x24, 0x36, 0x8c, 0x6b, 0x49, 0xea, 0x23, 0x66, 0xd7, 0xbc, 0x15, 0x16, 0x37, 0xce, 0x36, 0x2f, - 0xc9, 0xfa, 0x11, 0xc3, 0x44, 0x93, 0xf9, 0xc5, 0x30, 0xeb, 0x85, 0x9b, 0x4c, 0x75, 0xb8, 0x9e, - 0x62, 0xd9, 0x2e, 0xb7, 0xe7, 0x20, 0x17, 0xbe, 0x79, 0x75, 0xdf, 0x83, 0x16, 0xff, 0xf6, 0x19, - 0xc8, 0x88, 0x5d, 0xfa, 0xdb, 0x0a, 0x4c, 0xc8, 0x29, 0xcd, 0xa4, 0x3a, 0x5a, 0xd2, 0x72, 0xb8, - 0xc4, 0xcb, 0xb5, 0x91, 0xf9, 0xf9, 0xe0, 0xd5, 0x17, 0x3e, 0xfe, 0x87, 0xff, 0xfc, 0xf5, 0xb1, - 0x67, 0x49, 0xa5, 0x26, 0x2c, 0x48, 0x4d, 0xce, 0x78, 0xae, 0x7d, 0x20, 0xa6, 0xf4, 0x43, 0xe6, - 0x07, 0x67, 0x43, 0xcb, 0x96, 0x14, 0x89, 0x8f, 0x27, 0x48, 0x97, 0x6f, 0x8f, 0xc2, 0x2a, 0xb0, - 0xbc, 0x8c, 0x58, 0x5e, 0x20, 0xe5, 0x08, 0x8b, 0xc9, 0x39, 0xba, 0x30, 0xde, 0xcb, 0x93, 0x6c, - 0x6d, 0x9f, 0x1a, 0x76, 0xb0, 0x4f, 0x3c, 0x48, 0x63, 0x42, 0x31, 0x49, 0xb2, 0x11, 0x72, 0x0a, - 0x72, 0x79, 0x61, 0x38, 0xa3, 0x80, 0x72, 0x09, 0xa1, 0x14, 0xc9, 0x54, 0x04, 0x05, 0x5f, 0x6c, - 0xc8, 0xd7, 0x20, 0x85, 0xcf, 0x70, 0x37, 0x87, 0x48, 0x0a, 0x7b, 0x3c, 0x53, 0x52, 0xb3, 0x7a, - 0x1d, 0x7b, 0x2d, 0x93, 0x52, 0xbc, 0x57, 0x69, 0x16, 0x3e, 0xe4, 0x09, 0xcc, 0xf8, 0xf4, 0x42, - 0x5e, 0x1c, 0xed, 0x81, 0xe6, 0xc9, 0x48, 0x9e, 0xf8, 0x9a, 0xa3, 0x5e, 0x44, 0x24, 0xd3, 0x64, - 0x32, 0x42, 0xc2, 0xfc, 0x69, 0xf2, 0x91, 0x02, 0x19, 0xee, 0xe2, 0x92, 0xa1, 0xb9, 0x63, 0x91, - 0xd6, 0x6f, 0x8d, 0xc0, 0x29, 0xba, 0x7d, 0x16, 0xbb, 0xbd, 0x4a, 0xae, 0x48, 0xdd, 0x32, 0x06, - 0x49, 0x03, 0x3e, 0x64, 0x78, 0x7a, 0x50, 0x22, 0x82, 0x58, 0x06, 0x51, 0x59, 0x7e, 0xc5, 0x17, - 0x7f, 0x76, 0xc4, 0x7c, 0x27, 0xa1, 0xf5, 0xfe, 0x4e, 0xc5, 0x5f, 0x28, 0x75, 0x3b, 0xfd, 0xb6, - 0x02, 0xf9, 0x28, 0x29, 0x23, 0x51, 0xef, 0xbd, 0xa9, 0x28, 0x89, 0x7a, 0xef, 0xcb, 0x13, 0x51, - 0x6f, 0x21, 0x96, 0x1b, 0xe4, 0xd9, 0x08, 0x8b, 0x11, 0xf2, 0xe0, 0x5a, 0x90, 0x30, 0x7d, 0x57, - 0x81, 0xa9, 0x78, 0xd2, 0x0e, 0x79, 0x65, 0xa4, 0xbe, 0xa4, 0x2b, 0x47, 0xf9, 0xd5, 0x33, 0xb4, - 0x10, 0x10, 0x5f, 0x44, 0x88, 0xcf, 0x93, 0x1b, 0x03, 0x20, 0xe2, 0x6c, 0xd5, 0x3e, 0x08, 0x3d, - 0xbd, 0x0f, 0xc9, 0x2f, 0x2b, 0x30, 0x21, 0x47, 0x9c, 0x13, 0x0d, 0xda, 0x80, 0x57, 0xa3, 0x44, - 0x83, 0x36, 0x28, 0xa2, 0xae, 0x5e, 0x41, 0x78, 0xb3, 0x64, 0x26, 0x82, 0x17, 0x85, 0xc9, 0x7f, - 0x53, 0xbc, 0x08, 0x60, 0x92, 0xe0, 0x0f, 0x0f, 0x51, 0x05, 0x11, 0x5d, 0x21, 0x97, 0x23, 0x44, - 0x98, 0xec, 0xa8, 0xcb, 0xb8, 0x0a, 0x52, 0x00, 0x9c, 0x24, 0xfe, 0xa5, 0x4a, 0x5f, 0x6c, 0xbe, - 0x5c, 0x1d, 0x95, 0xfd, 0xc9, 0x26, 0x1f, 0xb9, 0xf8, 0x7b, 0x8d, 0xb4, 0xc2, 0x7e, 0x4f, 0x81, - 0xc9, 0x58, 0x50, 0x9b, 0xd4, 0x86, 0x76, 0x15, 0x8f, 0xbc, 0x97, 0x5f, 0x19, 0xbd, 0xc1, 0x13, - 0x77, 0x80, 0x40, 0x27, 0xd4, 0x25, 0xe1, 0xfb, 0x48, 0x81, 0x7c, 0x14, 0x4a, 0x4e, 0xdc, 0x95, - 0xbd, 0xe1, 0xf4, 0xc4, 0x5d, 0xd9, 0x17, 0x9d, 0x56, 0x4b, 0x88, 0x89, 0xa8, 0x5d, 0x6b, 0xe8, - 0xb7, 0x0c, 0xe7, 0x0d, 0xe5, 0x36, 0xf9, 0x1a, 0x1e, 0xdd, 0xf5, 0x83, 0x64, 0x7b, 0x18, 0x4b, - 0xec, 0x29, 0x27, 0x1d, 0x57, 0x72, 0x76, 0xd7, 0x00, 0xc3, 0xe4, 0xa3, 0x20, 0x49, 0x05, 0x3f, - 0xaf, 0x40, 0x56, 0xe4, 0x9e, 0x24, 0x9e, 0xca, 0xf1, 0xfc, 0x94, 0xd1, 0x21, 0xa8, 0x08, 0xe1, - 0x9a, 0x74, 0x24, 0xb7, 0xb8, 0xa4, 0x1e, 0x0c, 0x61, 0x8a, 0x7c, 0x12, 0x86, 0x78, 0xd2, 0xcb, - 0x79, 0x30, 0x34, 0xb9, 0x24, 0x09, 0xc3, 0xd7, 0x15, 0xc8, 0x85, 0x09, 0x42, 0x24, 0xc9, 0xe7, - 0xe8, 0xc9, 0x71, 0x2a, 0xbf, 0x38, 0x12, 0xaf, 0x40, 0xd2, 0x7f, 0x3e, 0xe3, 0x35, 0x48, 0xc2, - 0xf1, 0x1b, 0xcc, 0xde, 0x49, 0x79, 0x65, 0xc9, 0xd6, 0xa5, 0x3f, 0x61, 0x2d, 0xd9, 0xba, 0x0c, - 0x48, 0x58, 0x53, 0x6f, 0x20, 0xa6, 0x67, 0xc8, 0x55, 0xc9, 0xba, 0x34, 0x7a, 0x61, 0x31, 0xe7, - 0x4d, 0xb4, 0x4e, 0x9c, 0xa2, 0x78, 0x02, 0x5b, 0xf9, 0xe5, 0x64, 0xd6, 0x9e, 0xf4, 0x3d, 0xf5, - 0x36, 0x42, 0x79, 0x8e, 0xa8, 0x09, 0x50, 0x6a, 0x1f, 0x30, 0xc2, 0x87, 0xcc, 0x91, 0xda, 0x70, - 0x1b, 0x7e, 0xa2, 0x23, 0x25, 0x65, 0x31, 0x9e, 0x15, 0xca, 0x20, 0x9b, 0xdb, 0x90, 0x35, 0xf2, - 0x1d, 0x05, 0xff, 0x88, 0xa8, 0x1b, 0xb3, 0x4b, 0xb4, 0x6d, 0x83, 0xde, 0x7b, 0x12, 0x6d, 0xdb, - 0xc0, 0x70, 0xa0, 0x3a, 0x8f, 0xa8, 0x4a, 0xe4, 0x92, 0xbc, 0x9b, 0x18, 0x9f, 0xc8, 0x78, 0xf9, - 0x10, 0xd2, 0xfc, 0x20, 0x7f, 0x61, 0x78, 0x30, 0x66, 0xb8, 0x47, 0x1b, 0x3f, 0xb6, 0x9f, 0xe0, - 0x5a, 0xc9, 0x87, 0xf5, 0xef, 0xb0, 0xdb, 0x87, 0x14, 0x44, 0x21, 0xa3, 0x66, 0xcc, 0x8f, 0x74, - 0xfb, 0x18, 0x10, 0xe2, 0x19, 0xb0, 0x62, 0x7a, 0x41, 0xd5, 0xea, 0x4d, 0xf3, 0x10, 0xc1, 0xfc, - 0x96, 0x02, 0x05, 0x29, 0x72, 0x93, 0x78, 0x4a, 0xf6, 0x47, 0x78, 0x06, 0xcd, 0x56, 0xec, 0xef, - 0xc7, 0xa5, 0x36, 0x1a, 0x6d, 0xb9, 0x5e, 0xa0, 0xde, 0x44, 0x70, 0xd7, 0xc9, 0x7c, 0xf7, 0x3a, - 0xd2, 0x6d, 0x10, 0x3f, 0x86, 0x32, 0x3c, 0x8a, 0x31, 0xe4, 0x10, 0x90, 0xc2, 0x48, 0x89, 0x4e, - 0x71, 0x3c, 0x24, 0x32, 0xf0, 0x18, 0x60, 0x0c, 0x12, 0x84, 0x5f, 0x54, 0x00, 0xba, 0x37, 0x5b, - 0xf2, 0xd2, 0x88, 0x17, 0xe0, 0xe1, 0x5b, 0xab, 0xff, 0xba, 0xac, 0x5e, 0x45, 0x38, 0x17, 0xc9, - 0xac, 0x7c, 0x2a, 0x09, 0xa6, 0x65, 0xf5, 0x93, 0x7f, 0x9f, 0xbf, 0xf0, 0xc9, 0xe9, 0xbc, 0xf2, - 0x77, 0xa7, 0xf3, 0xca, 0x3f, 0x9d, 0xce, 0x2b, 0xff, 0x76, 0x3a, 0xaf, 0x7c, 0xeb, 0x3f, 0xe6, - 0x2f, 0xbc, 0x97, 0x0b, 0x65, 0xee, 0x66, 0x30, 0x78, 0xf1, 0x85, 0xff, 0x0b, 0x00, 0x00, 0xff, - 0xff, 0xe3, 0x6d, 0x35, 0x69, 0x54, 0x40, 0x00, 0x00, + // 4579 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5b, 0x5f, 0x6c, 0x1c, 0x49, + 0x5a, 0x4f, 0xdb, 0xf3, 0xf7, 0x1b, 0xff, 0x19, 0x97, 0x9d, 0x64, 0x32, 0xc9, 0x7a, 0xb2, 0x9d, + 0xdd, 0xac, 0xf3, 0x6f, 0xe6, 0xd6, 0xb7, 0x0b, 0x21, 0xb0, 0xb7, 0xeb, 0x7f, 0x49, 0x9c, 0x78, + 0x1d, 0x6f, 0xdb, 0xe6, 0x8e, 0x08, 0x6d, 0xd3, 0x9e, 0x2e, 0x8f, 0xfb, 0xdc, 0xee, 0x9e, 0x74, + 0xf7, 0x98, 0xcc, 0xad, 0x72, 0x2c, 0x8b, 0x0e, 0x71, 0x20, 0x8e, 0xbb, 0xe3, 0x8f, 0x78, 0x00, + 0x09, 0xdd, 0x03, 0x20, 0x21, 0xd0, 0x21, 0x9e, 0xe0, 0xe5, 0x24, 0x84, 0xd0, 0x3e, 0x82, 0xe0, + 0x81, 0x3f, 0x92, 0x17, 0x0c, 0x0f, 0xf0, 0xca, 0xe3, 0x49, 0x48, 0xa8, 0xbe, 0xaa, 0xee, 0xa9, + 0x9e, 0x99, 0xf4, 0x8c, 0xe3, 0xcd, 0x89, 0x87, 0x64, 0xba, 0xbe, 0xfa, 0xea, 0xab, 0x5f, 0x7d, + 0x55, 0xf5, 0xd5, 0x57, 0x5f, 0x7d, 0x86, 0x4b, 0x3e, 0xf5, 0x0e, 0xa9, 0x57, 0xe3, 0x3f, 0xcd, + 0x9d, 0x9a, 0x1f, 0x18, 0x41, 0xcb, 0xaf, 0x36, 0x3d, 0x37, 0x70, 0xc9, 0x85, 0xba, 0x5b, 0xdf, + 0xf7, 0x5c, 0xa3, 0xbe, 0x57, 0xe5, 0x0c, 0xd5, 0x90, 0xaf, 0x5c, 0xdc, 0x69, 0x59, 0xb6, 0x59, + 0xb3, 0x9c, 0x5d, 0x97, 0x33, 0x97, 0xa7, 0x1b, 0xae, 0xef, 0x5b, 0xcd, 0x1a, 0xff, 0x11, 0xc4, + 0xf3, 0xd8, 0xba, 0xb9, 0x53, 0x33, 0x9a, 0x4d, 0x9d, 0xc9, 0x16, 0xa2, 0xcb, 0x24, 0xac, 0x30, + 0x8d, 0xc0, 0x10, 0xb4, 0xab, 0x02, 0x8c, 0x69, 0x19, 0x0d, 0xc7, 0xf5, 0x03, 0xab, 0xee, 0x33, + 0x86, 0x4e, 0x49, 0xf0, 0x5d, 0x09, 0x41, 0x23, 0x56, 0xf1, 0xd3, 0x85, 0xbd, 0xac, 0xfa, 0x81, + 0xeb, 0x19, 0x0d, 0x5a, 0xa3, 0x4e, 0xc3, 0x72, 0xc2, 0x9f, 0xe6, 0x4e, 0xed, 0xe0, 0xb0, 0x5e, + 0x17, 0x3c, 0xaf, 0x85, 0x3c, 0xe2, 0xb7, 0xb9, 0x53, 0xb3, 0xa9, 0xe1, 0x53, 0x3d, 0x26, 0xe9, + 0x95, 0x5e, 0x2e, 0x56, 0x4f, 0xc3, 0x91, 0xb4, 0x02, 0xcb, 0xae, 0xd9, 0x6e, 0x83, 0xfd, 0x13, + 0xb4, 0x32, 0xd2, 0x5a, 0x8e, 0x47, 0x7d, 0xd7, 0x3e, 0xa4, 0xa6, 0x6e, 0x98, 0xa6, 0x27, 0xea, + 0x2e, 0xd2, 0xa0, 0x6e, 0xd6, 0x3c, 0x63, 0x37, 0xc0, 0xff, 0x9a, 0x3b, 0xf8, 0x23, 0x2a, 0x67, + 0x1a, 0x6e, 0xc3, 0xc5, 0xcf, 0x1a, 0xfb, 0x12, 0xd4, 0x4b, 0x0d, 0xd7, 0x6d, 0xd8, 0xb4, 0x66, + 0x34, 0xad, 0x9a, 0xe1, 0x38, 0x6e, 0x60, 0x04, 0x96, 0xeb, 0x84, 0xf8, 0x2a, 0xa2, 0x16, 0x4b, + 0x3b, 0xad, 0xdd, 0x5a, 0x60, 0x1d, 0x50, 0x3f, 0x30, 0x0e, 0xc4, 0x24, 0xa8, 0x55, 0x98, 0x5e, + 0xa2, 0x5e, 0x60, 0xed, 0x5a, 0x75, 0x23, 0xa0, 0xbe, 0x46, 0x9f, 0xb4, 0xa8, 0x1f, 0x90, 0xf3, + 0x90, 0x75, 0x5c, 0x93, 0xea, 0x96, 0x59, 0x52, 0x2e, 0x2b, 0x73, 0x79, 0x2d, 0xc3, 0x8a, 0xab, + 0xa6, 0xfa, 0xbf, 0x29, 0x20, 0x52, 0x83, 0x65, 0x1a, 0x18, 0x96, 0xed, 0x93, 0x0f, 0x20, 0x15, + 0xb4, 0x9b, 0x14, 0x99, 0x27, 0xe6, 0xdf, 0xa9, 0x3e, 0x77, 0x71, 0x54, 0x7b, 0x1b, 0xcb, 0xa4, + 0xad, 0x76, 0x93, 0x6a, 0x28, 0x8a, 0x5c, 0x81, 0x71, 0xea, 0x79, 0xae, 0xa7, 0x1f, 0x50, 0xdf, + 0x37, 0x1a, 0xb4, 0x34, 0x82, 0x40, 0xc6, 0x90, 0xf8, 0x3e, 0xa7, 0x11, 0x02, 0x29, 0xb6, 0x48, + 0x4a, 0xa3, 0x97, 0x95, 0xb9, 0x31, 0x0d, 0xbf, 0x89, 0x06, 0x99, 0x5d, 0x8b, 0xda, 0xa6, 0x5f, + 0x4a, 0x5d, 0x1e, 0x9d, 0x2b, 0xcc, 0xbf, 0x75, 0x32, 0x34, 0x77, 0xb1, 0xed, 0x62, 0xea, 0xd3, + 0xa3, 0xca, 0x19, 0x4d, 0x48, 0x2a, 0xff, 0xc5, 0x08, 0x64, 0x78, 0x05, 0x39, 0x07, 0x19, 0xcb, + 0xf7, 0x5b, 0xd4, 0x0b, 0x35, 0xc3, 0x4b, 0xa4, 0x04, 0x59, 0xbf, 0xb5, 0xf3, 0x55, 0x5a, 0x0f, + 0x04, 0xd2, 0xb0, 0x48, 0x5e, 0x01, 0x38, 0x34, 0x6c, 0xcb, 0xd4, 0x77, 0x3d, 0xf7, 0x00, 0xa1, + 0x8e, 0x6a, 0x79, 0xa4, 0xdc, 0xf5, 0xdc, 0x03, 0x52, 0x81, 0x02, 0xaf, 0x6e, 0x39, 0x81, 0x65, + 0x97, 0x52, 0x58, 0xcf, 0x5b, 0x6c, 0x33, 0x0a, 0xb9, 0x04, 0x79, 0xb6, 0x46, 0xa8, 0xef, 0x53, + 0xbf, 0x94, 0xbe, 0x3c, 0x3a, 0x97, 0xd7, 0x3a, 0x04, 0x52, 0x83, 0x69, 0xdf, 0x6a, 0x38, 0x46, + 0xd0, 0xf2, 0xa8, 0x6e, 0xd8, 0x0d, 0xd7, 0xb3, 0x82, 0xbd, 0x83, 0x52, 0x06, 0x31, 0x90, 0xa8, + 0x6a, 0x21, 0xac, 0x61, 0x70, 0x9a, 0xad, 0x1d, 0xdb, 0xaa, 0xeb, 0xfb, 0xb4, 0x5d, 0xca, 0x22, + 0x5f, 0x9e, 0x53, 0x1e, 0xd2, 0x36, 0xb9, 0x08, 0xf9, 0x7d, 0xda, 0xd6, 0x5b, 0xa8, 0xf3, 0x1c, + 0xf6, 0x96, 0xdb, 0xa7, 0xed, 0x6d, 0xd4, 0xf7, 0x4d, 0x20, 0xf4, 0x69, 0x40, 0x1d, 0x93, 0x9a, + 0x7a, 0x87, 0x2b, 0x8f, 0x5c, 0xc5, 0xb0, 0xe6, 0xa1, 0xe0, 0x56, 0x3f, 0x80, 0xc9, 0xae, 0xb9, + 0x25, 0x19, 0x18, 0x59, 0x5a, 0x28, 0x9e, 0x21, 0x39, 0x48, 0xad, 0x3f, 0x5a, 0x5e, 0x29, 0x2a, + 0x64, 0x1c, 0xf2, 0x4b, 0x6b, 0xab, 0x2b, 0xeb, 0x5b, 0xfa, 0xd2, 0x42, 0x71, 0x84, 0x00, 0x64, + 0x78, 0xb1, 0x38, 0x4a, 0xf2, 0x90, 0xde, 0x5e, 0x65, 0xe4, 0x14, 0x6b, 0xb7, 0xbd, 0x5a, 0x4c, + 0xab, 0x2e, 0xcc, 0xc4, 0xd7, 0xab, 0xdf, 0x74, 0x1d, 0x9f, 0x92, 0x2f, 0xc3, 0x58, 0x5d, 0xa2, + 0x97, 0x14, 0x9c, 0xfa, 0x5b, 0x27, 0x9a, 0x7a, 0x31, 0xe7, 0x31, 0x41, 0xea, 0xbb, 0x30, 0x21, + 0xaa, 0x07, 0xed, 0x0d, 0x32, 0x03, 0x69, 0x8f, 0x1a, 0x66, 0x1b, 0xe7, 0x3f, 0xa7, 0xf1, 0x82, + 0xfa, 0xdf, 0x0a, 0x4c, 0x46, 0x12, 0x04, 0xda, 0xc7, 0x71, 0x11, 0xe9, 0xc5, 0x85, 0xe3, 0xa3, + 0x4a, 0x66, 0x9d, 0x89, 0x59, 0xfe, 0xe1, 0x51, 0xe5, 0x8b, 0x0d, 0x2b, 0xd8, 0x6b, 0xed, 0x54, + 0xeb, 0xee, 0x41, 0x2d, 0x1a, 0x80, 0xb9, 0xd3, 0xf9, 0xae, 0x35, 0xf7, 0x1b, 0x35, 0x61, 0x25, + 0xab, 0xbc, 0x59, 0x84, 0xe2, 0x4b, 0x90, 0x15, 0x8b, 0x03, 0x71, 0x14, 0xe6, 0x67, 0x25, 0x25, + 0x30, 0xdb, 0x53, 0xdd, 0x8e, 0x6c, 0xcf, 0x82, 0x69, 0x7a, 0x62, 0xd4, 0x61, 0x23, 0x72, 0x07, + 0x00, 0xed, 0xb7, 0xce, 0xec, 0x37, 0xae, 0xd6, 0xc2, 0xfc, 0x59, 0x49, 0x04, 0x56, 0x56, 0x57, + 0x9d, 0x5d, 0x57, 0xb4, 0xcc, 0x23, 0x85, 0x11, 0xd4, 0x09, 0x18, 0x63, 0x68, 0x42, 0x55, 0xa9, + 0x3f, 0x03, 0xe3, 0xa2, 0x2c, 0x06, 0x7e, 0x1f, 0xd2, 0x0c, 0x66, 0x38, 0x3f, 0x37, 0xfb, 0xcc, + 0x0f, 0x37, 0xaf, 0xa1, 0xe1, 0xc6, 0xd1, 0x6d, 0x62, 0x41, 0x74, 0xc7, 0x05, 0xa8, 0x57, 0xa1, + 0xc0, 0xaa, 0x06, 0x1a, 0xac, 0xef, 0xa7, 0x20, 0xaf, 0x19, 0xbb, 0x01, 0x93, 0xc1, 0xd6, 0x2f, + 0x78, 0xb4, 0x69, 0x5b, 0x75, 0x23, 0xe4, 0x4c, 0x2d, 0x8e, 0x1f, 0x1f, 0x55, 0xf2, 0x1a, 0xa7, + 0xae, 0x2e, 0x6b, 0x79, 0xc1, 0xb0, 0x6a, 0x92, 0x1f, 0x03, 0xd8, 0x33, 0x3c, 0x13, 0x4d, 0x3e, + 0x15, 0xda, 0x9c, 0xaa, 0x72, 0xcb, 0x5c, 0xbd, 0x6f, 0x78, 0x26, 0x0a, 0x0d, 0xd5, 0xb0, 0x17, + 0x12, 0x98, 0x55, 0xb2, 0xa9, 0x61, 0xa2, 0xf2, 0x52, 0x1a, 0x7e, 0xb3, 0xc5, 0xc1, 0xc5, 0xa4, + 0x10, 0x1e, 0x2f, 0x30, 0xa3, 0x61, 0x34, 0x9b, 0xb6, 0x45, 0xcd, 0x52, 0x1a, 0x99, 0xc3, 0x22, + 0xd9, 0x82, 0x5c, 0xd3, 0x73, 0x1b, 0x38, 0x8f, 0x19, 0x54, 0xd6, 0x7c, 0xc2, 0x62, 0x8e, 0x46, + 0x58, 0xdd, 0x10, 0x8d, 0x56, 0x9c, 0xc0, 0x6b, 0x0b, 0x68, 0x91, 0x24, 0xf2, 0x06, 0x4c, 0x32, + 0x34, 0x7a, 0xe0, 0x19, 0x8e, 0xbf, 0x4b, 0x3d, 0x4a, 0xd1, 0x00, 0xa4, 0xb4, 0x09, 0x46, 0xde, + 0x8a, 0xa8, 0xe5, 0x5f, 0x57, 0x20, 0x17, 0x8a, 0x62, 0xd8, 0x0f, 0x8c, 0xa0, 0xbe, 0xc7, 0x15, + 0xa6, 0xf1, 0x02, 0x1b, 0xa5, 0x43, 0x9f, 0x72, 0x6b, 0x97, 0xd2, 0xf0, 0xbb, 0x33, 0xca, 0x51, + 0x79, 0x94, 0xe7, 0x20, 0xd3, 0x34, 0x5a, 0x3e, 0x35, 0x71, 0xf0, 0x39, 0x4d, 0x94, 0xc8, 0x35, + 0x28, 0x36, 0xa9, 0x63, 0x5a, 0x4e, 0x43, 0xf7, 0x1d, 0xa3, 0xe9, 0xef, 0xb9, 0x81, 0x50, 0xc3, + 0xa4, 0xa0, 0x6f, 0x0a, 0x72, 0xf9, 0xab, 0x30, 0x1e, 0x1b, 0x19, 0x29, 0xc2, 0x28, 0x33, 0x5f, + 0x1c, 0x11, 0xfb, 0x24, 0x4b, 0x90, 0x3e, 0x34, 0xec, 0x56, 0x38, 0x51, 0xb7, 0x4e, 0xa4, 0x2e, + 0x8d, 0xb7, 0xbd, 0x33, 0x72, 0x5b, 0x51, 0xff, 0x6a, 0x04, 0xc6, 0x35, 0xc3, 0x69, 0xd0, 0x0d, + 0xcf, 0xdd, 0xb1, 0xe9, 0x81, 0x4f, 0x2e, 0x43, 0xa1, 0xe5, 0x18, 0x87, 0x86, 0x65, 0x1b, 0x3b, + 0x36, 0x3f, 0xe5, 0x72, 0x9a, 0x4c, 0x22, 0x6f, 0xc3, 0x79, 0xa6, 0x41, 0xea, 0xe9, 0x8e, 0x1b, + 0xe8, 0xdc, 0x53, 0xd8, 0x73, 0x6d, 0x93, 0x7a, 0xc2, 0x1a, 0xcc, 0xf0, 0xea, 0x75, 0x37, 0x58, + 0x63, 0x95, 0xf7, 0xb1, 0x8e, 0xbc, 0x06, 0x13, 0x8e, 0xab, 0xb3, 0x15, 0xa5, 0xf3, 0x7a, 0x54, + 0x5c, 0x4e, 0x1b, 0x73, 0x5c, 0x86, 0x71, 0x0d, 0x69, 0x64, 0x0e, 0x26, 0x5b, 0x8e, 0x49, 0x3d, + 0xb1, 0x32, 0x83, 0x48, 0x91, 0xdd, 0x64, 0x72, 0x01, 0x72, 0x8e, 0xcb, 0xbb, 0x47, 0x4d, 0xe6, + 0xb4, 0xac, 0xe3, 0x62, 0x87, 0xe4, 0x36, 0x94, 0x9e, 0xb4, 0x2c, 0xea, 0xd7, 0xa9, 0x13, 0xe8, + 0xf4, 0x49, 0xcb, 0xb0, 0x7d, 0x3d, 0xb0, 0xea, 0xfb, 0x96, 0xd3, 0xc0, 0xc3, 0x22, 0xa7, 0x9d, + 0x8b, 0xea, 0x57, 0xb0, 0x7a, 0x8b, 0xd7, 0x92, 0x1b, 0x40, 0x38, 0x42, 0xb7, 0xa1, 0x07, 0xae, + 0xab, 0xdb, 0x86, 0xd7, 0xe0, 0xeb, 0x26, 0xa7, 0x4d, 0xb2, 0x9a, 0x35, 0xb7, 0xb1, 0xe5, 0xba, + 0x6b, 0x8c, 0xac, 0xee, 0xc3, 0x24, 0xea, 0x8e, 0xa9, 0xd7, 0x42, 0xcf, 0x8c, 0x1d, 0x1a, 0x4f, + 0x5a, 0xd4, 0xb3, 0xa8, 0xaf, 0x37, 0xa9, 0xa7, 0xfb, 0xb4, 0xee, 0x3a, 0x7c, 0xf3, 0x29, 0x5a, + 0x51, 0xd4, 0x6c, 0x50, 0x6f, 0x13, 0xe9, 0xe4, 0x3a, 0x4c, 0xfd, 0xbc, 0x67, 0x05, 0x71, 0xe6, + 0x11, 0x64, 0x9e, 0xe4, 0x15, 0x11, 0xaf, 0x7a, 0x1f, 0x60, 0xc3, 0xa3, 0x41, 0xd0, 0xde, 0x6c, + 0x1a, 0x0e, 0x3b, 0xb9, 0xfc, 0xc0, 0xf0, 0x02, 0x3d, 0x5c, 0x18, 0x79, 0x2d, 0x87, 0x04, 0x76, + 0xac, 0x9d, 0x87, 0x2c, 0x75, 0xf0, 0xd0, 0x12, 0xc7, 0x73, 0x86, 0x3a, 0xec, 0xa4, 0xba, 0x93, + 0xfa, 0xaf, 0x3f, 0xa8, 0x28, 0xea, 0xff, 0x64, 0x99, 0x99, 0x70, 0x1a, 0x94, 0xd9, 0x31, 0xf2, + 0x2e, 0xa4, 0xfc, 0xa6, 0xe1, 0xa0, 0x90, 0xc2, 0xfc, 0xeb, 0x09, 0x2b, 0xa9, 0xd3, 0xbd, 0xd8, + 0x6b, 0xd8, 0x90, 0xac, 0x02, 0xa0, 0xca, 0x64, 0xcb, 0xf1, 0xda, 0x30, 0x0b, 0x32, 0x34, 0x26, + 0x5e, 0x64, 0xb2, 0x16, 0x65, 0xc3, 0x51, 0x98, 0xbf, 0x2a, 0x4b, 0xe1, 0x4e, 0x67, 0x35, 0x72, + 0x3e, 0xab, 0xd1, 0x10, 0x42, 0x63, 0xc9, 0x37, 0xe0, 0x01, 0x4c, 0xf8, 0x6e, 0xcb, 0xab, 0x53, + 0x3d, 0x34, 0x92, 0x69, 0x3c, 0x76, 0xee, 0x1d, 0x1f, 0x55, 0xc6, 0x36, 0xb1, 0xe6, 0x74, 0x87, + 0xcf, 0x98, 0xdf, 0x11, 0x62, 0x92, 0x27, 0x30, 0x29, 0xba, 0x63, 0xc8, 0xb0, 0xbf, 0x0c, 0xf6, + 0xb7, 0x7a, 0x7c, 0x54, 0x19, 0xe7, 0xfd, 0x6d, 0xb2, 0x1a, 0xec, 0xf0, 0xad, 0x13, 0x75, 0x28, + 0xda, 0x69, 0xe3, 0xbe, 0x24, 0xc6, 0xec, 0xf5, 0x16, 0xb3, 0x7d, 0xbc, 0xc5, 0x25, 0x18, 0x17, + 0x3b, 0xd3, 0x62, 0xc0, 0xda, 0xe8, 0xde, 0x14, 0xe6, 0x4b, 0x92, 0x4a, 0xc3, 0x6e, 0x70, 0xcf, + 0x84, 0x0e, 0x01, 0x36, 0xba, 0xcf, 0xdb, 0x90, 0x07, 0x68, 0x98, 0xd1, 0x2e, 0x94, 0xf2, 0x38, + 0x25, 0x73, 0x89, 0x13, 0x2b, 0xd9, 0x11, 0xc9, 0x1c, 0x73, 0xbb, 0x72, 0x97, 0xcf, 0xad, 0x5f, + 0x02, 0x14, 0x74, 0x7d, 0x90, 0xa0, 0xce, 0xa6, 0x92, 0xe7, 0xd7, 0x27, 0x5f, 0x81, 0x71, 0x9b, + 0xd9, 0x64, 0xea, 0xeb, 0xb6, 0x5b, 0x37, 0xec, 0x52, 0xa1, 0xd7, 0x04, 0xf6, 0xac, 0x95, 0x35, + 0xd6, 0xe2, 0x7d, 0xc3, 0x31, 0x1a, 0xd4, 0x93, 0x96, 0xcc, 0x98, 0x90, 0xb4, 0xc6, 0x04, 0x91, + 0xc7, 0x30, 0x11, 0x4a, 0x6e, 0xd8, 0xee, 0x8e, 0x61, 0x97, 0xc6, 0x5e, 0x5c, 0x74, 0x08, 0xf2, + 0x1e, 0x4a, 0x22, 0xf7, 0x60, 0x4c, 0xbe, 0x52, 0x95, 0xc6, 0x7b, 0xdc, 0x95, 0x50, 0x32, 0xce, + 0x46, 0xcc, 0x0b, 0x28, 0xd8, 0x1d, 0x12, 0x73, 0x90, 0x23, 0xd3, 0x55, 0x9a, 0x40, 0xbb, 0xd4, + 0x21, 0xb0, 0x33, 0x36, 0xb4, 0x73, 0x93, 0xdc, 0x24, 0x8a, 0xa2, 0xfa, 0x6b, 0x8a, 0x30, 0xf4, + 0x83, 0x7d, 0x3b, 0x03, 0xf2, 0x1e, 0xe3, 0xd4, 0x2d, 0x93, 0xf9, 0x55, 0xa3, 0x73, 0xa3, 0x8b, + 0xcb, 0xc7, 0x47, 0x95, 0x1c, 0xdf, 0x70, 0xcb, 0xfe, 0x89, 0xd7, 0xb1, 0x68, 0xa8, 0xe5, 0x50, + 0xec, 0xaa, 0xe9, 0xab, 0x5b, 0x30, 0x11, 0x82, 0x11, 0xde, 0xd2, 0x22, 0x64, 0xb0, 0x36, 0x74, + 0x97, 0x5e, 0x1b, 0xb4, 0x3e, 0x24, 0x5d, 0x8b, 0x96, 0xea, 0x1c, 0x8c, 0xdf, 0xc3, 0x5b, 0xf7, + 0x40, 0x4f, 0xe9, 0xe7, 0x00, 0xb6, 0x3c, 0xa3, 0x4e, 0x57, 0x0e, 0x99, 0xd6, 0x6e, 0x43, 0x8a, + 0xdd, 0x15, 0x85, 0x09, 0x2c, 0x57, 0xf9, 0x45, 0xb2, 0x1a, 0x5e, 0x24, 0xab, 0x5b, 0xe1, 0x45, + 0x72, 0x31, 0xc7, 0xfa, 0xfb, 0xf6, 0x67, 0x15, 0x45, 0xc3, 0x16, 0x4c, 0xdf, 0xf1, 0x2b, 0x5b, + 0x58, 0x54, 0xbf, 0xaf, 0xc0, 0xe4, 0x82, 0xcd, 0x56, 0x68, 0xe0, 0x7a, 0xcb, 0x5e, 0x5b, 0x6b, + 0x39, 0xe4, 0x43, 0xc8, 0x85, 0x8a, 0xc5, 0xbe, 0x46, 0x17, 0x97, 0x8e, 0x8f, 0x2a, 0x59, 0xa1, + 0x9e, 0x17, 0x56, 0x6b, 0x56, 0xa8, 0x95, 0xbc, 0x03, 0x19, 0xca, 0x06, 0xc4, 0x67, 0x2d, 0xd9, + 0x98, 0x77, 0x86, 0xaf, 0x89, 0x46, 0xea, 0x3c, 0x9c, 0x8d, 0x10, 0xa3, 0xec, 0x50, 0x8d, 0x17, + 0xba, 0x71, 0x47, 0x5d, 0xaa, 0x7f, 0xa9, 0xc0, 0xb9, 0xee, 0x46, 0xfd, 0x1d, 0xff, 0xd1, 0xcf, + 0xd3, 0xf1, 0x5f, 0x82, 0xac, 0xe9, 0xb5, 0x75, 0xaf, 0xe5, 0x88, 0x03, 0x27, 0xc9, 0x9c, 0x74, + 0x4d, 0x83, 0x96, 0x31, 0xf1, 0x57, 0xfd, 0x96, 0x02, 0xc5, 0x0e, 0xf6, 0xff, 0x07, 0xbb, 0xe2, + 0x31, 0x4c, 0x49, 0x78, 0x84, 0x1a, 0x57, 0x20, 0x27, 0x86, 0x1a, 0x6e, 0x8d, 0x93, 0x8c, 0x35, + 0xcb, 0xc7, 0xea, 0xab, 0x2a, 0x8c, 0x3d, 0xd8, 0x7c, 0xb4, 0x1e, 0x89, 0x0d, 0xa3, 0x09, 0x4a, + 0x27, 0x9a, 0xa0, 0x7e, 0x4f, 0x81, 0xc2, 0x9a, 0xdb, 0x18, 0xea, 0xf6, 0x67, 0xd3, 0x43, 0x6a, + 0x8b, 0x45, 0xcf, 0x0b, 0xec, 0xb2, 0xcd, 0x7d, 0x12, 0xdc, 0x4c, 0xdc, 0x2b, 0xe6, 0x5e, 0x0a, + 0xdb, 0x40, 0x6c, 0x15, 0x31, 0xaf, 0x04, 0x2b, 0xf9, 0xc5, 0x80, 0x79, 0x29, 0x58, 0x55, 0x84, + 0xd1, 0x03, 0xe3, 0x29, 0x1e, 0xd4, 0x79, 0x8d, 0x7d, 0xb2, 0x8d, 0xd5, 0x34, 0x82, 0x80, 0x7a, + 0x8e, 0xb8, 0xdd, 0x87, 0x45, 0xf5, 0x11, 0x90, 0x35, 0xb7, 0xc1, 0x1c, 0x63, 0x4b, 0x32, 0x1f, + 0x3f, 0xc1, 0x5c, 0x1e, 0x24, 0x09, 0x25, 0x5d, 0xe8, 0xbe, 0x09, 0xda, 0x6e, 0xa3, 0x2a, 0x5f, + 0x14, 0x42, 0x7e, 0xb5, 0x0a, 0xd3, 0x6b, 0x6e, 0xe3, 0xae, 0x65, 0x53, 0x7f, 0xcd, 0xf2, 0x83, + 0x81, 0xb6, 0x63, 0x03, 0x66, 0xe2, 0xfc, 0x02, 0xc2, 0x6d, 0x48, 0xef, 0x32, 0xa2, 0x00, 0x70, + 0xa9, 0x1f, 0x00, 0xd6, 0x4a, 0x76, 0x59, 0xb0, 0x81, 0xfa, 0x0e, 0x4c, 0x08, 0x89, 0x03, 0x35, + 0x4f, 0x20, 0xc5, 0xda, 0x08, 0xc5, 0xe3, 0x37, 0x33, 0x7b, 0x9b, 0x81, 0x51, 0xdf, 0x1f, 0x1c, + 0xd1, 0xda, 0x84, 0x14, 0xeb, 0x05, 0xaf, 0x33, 0x86, 0x30, 0x78, 0x79, 0x0d, 0xbf, 0x99, 0x47, + 0xc9, 0xa4, 0xe9, 0xbe, 0xf5, 0x35, 0x2e, 0x7e, 0x54, 0xcb, 0x31, 0xc2, 0xa6, 0xf5, 0x35, 0x4a, + 0xca, 0x90, 0xab, 0xbb, 0x4e, 0x80, 0xb6, 0x85, 0xc7, 0x9f, 0xa2, 0xb2, 0xfa, 0x7b, 0x0a, 0x4c, + 0xde, 0xa3, 0x01, 0x2a, 0x64, 0x20, 0xfe, 0x8b, 0x90, 0xb7, 0x2d, 0x3f, 0xd0, 0x5d, 0xc7, 0x0e, + 0x63, 0x07, 0x39, 0x46, 0x78, 0xe4, 0xd8, 0x6d, 0xf2, 0xe3, 0x22, 0xb2, 0x96, 0xc6, 0xc8, 0xda, + 0x95, 0x84, 0x65, 0xce, 0x3a, 0x93, 0xe2, 0x67, 0x65, 0xc8, 0x89, 0xe5, 0xc1, 0x2f, 0x90, 0x79, + 0x2d, 0x2a, 0xab, 0xab, 0x50, 0xec, 0xa0, 0x13, 0x53, 0xf5, 0x76, 0x7c, 0xaa, 0x2a, 0x03, 0x7a, + 0x0a, 0xe7, 0xe9, 0x17, 0x60, 0x62, 0xc3, 0x73, 0x77, 0x87, 0x99, 0xa7, 0xc5, 0xd8, 0x50, 0xaa, + 0x89, 0x5e, 0xb5, 0x2c, 0xb1, 0xda, 0x19, 0x95, 0x5a, 0x84, 0x14, 0xc6, 0x91, 0x72, 0x90, 0xba, + 0xbf, 0xb2, 0xb0, 0x51, 0x3c, 0xa3, 0x5e, 0x83, 0x89, 0xf7, 0x69, 0xe0, 0x59, 0xf5, 0xc1, 0x53, + 0xfd, 0xa7, 0x78, 0xde, 0xef, 0x06, 0x68, 0x65, 0x98, 0xf5, 0x7c, 0xa9, 0x81, 0x98, 0xf7, 0x20, + 0x8d, 0x56, 0x6c, 0x28, 0xf7, 0xbf, 0xcb, 0x6d, 0xc7, 0x86, 0xea, 0x75, 0xe6, 0x11, 0x08, 0xb8, + 0x2b, 0xcc, 0x91, 0x95, 0xcf, 0x56, 0x25, 0x7e, 0xb6, 0x7e, 0x3c, 0xc2, 0x2e, 0x5e, 0x82, 0x59, + 0xf8, 0x45, 0x2f, 0xfb, 0x6c, 0xbd, 0x07, 0x19, 0xf4, 0xaf, 0xc3, 0xb3, 0xf5, 0xda, 0x80, 0x1b, + 0x4e, 0x67, 0x20, 0xa1, 0x93, 0xc2, 0x9b, 0x93, 0xe5, 0x30, 0x2c, 0x34, 0x8a, 0x72, 0xe6, 0x86, + 0x91, 0xc3, 0xb4, 0x1d, 0x0f, 0x09, 0xb5, 0xa0, 0xc8, 0x6a, 0x97, 0xe9, 0x4e, 0xab, 0x11, 0xae, + 0x85, 0xd8, 0x09, 0xa5, 0xbc, 0x94, 0x13, 0xea, 0x1f, 0x47, 0x60, 0x4a, 0xea, 0x57, 0x6c, 0xa7, + 0x6f, 0x29, 0x5d, 0xce, 0xdb, 0xed, 0x01, 0x83, 0x8a, 0x35, 0xe7, 0xdd, 0x88, 0x20, 0xce, 0x4f, + 0xb1, 0x41, 0x7e, 0xf2, 0xd9, 0x0b, 0x02, 0x15, 0x28, 0x3e, 0xb7, 0xc9, 0x2a, 0x53, 0x28, 0x48, + 0xe8, 0xe4, 0x40, 0xcc, 0x28, 0x0f, 0xc4, 0xbc, 0x17, 0x0f, 0xc4, 0x5c, 0x1f, 0xa6, 0x23, 0xbe, + 0x62, 0xe5, 0x28, 0xcc, 0x37, 0x46, 0xa0, 0xb0, 0x50, 0x0f, 0xac, 0x43, 0xfa, 0x41, 0x8b, 0x7a, + 0x6d, 0x72, 0x0e, 0x46, 0xc2, 0x0d, 0xbd, 0x98, 0x39, 0x3e, 0xaa, 0x8c, 0xac, 0x2e, 0x6b, 0x23, + 0x96, 0xc9, 0xfa, 0xf7, 0x9f, 0x84, 0xa7, 0x2e, 0xfb, 0x24, 0x77, 0xf0, 0x56, 0xe5, 0x05, 0x22, + 0x78, 0x39, 0x9c, 0xef, 0xca, 0x9b, 0x90, 0xd7, 0x61, 0xc2, 0xf2, 0x75, 0xd3, 0xf2, 0x03, 0xcf, + 0xda, 0x69, 0x75, 0x22, 0x2d, 0xe3, 0x96, 0xbf, 0xdc, 0x21, 0xb2, 0x4b, 0x79, 0x73, 0x2f, 0x0c, + 0xb2, 0x4c, 0xf4, 0x8d, 0x63, 0x46, 0xde, 0x47, 0x67, 0x0c, 0xd5, 0x0d, 0xd6, 0x46, 0xe3, 0x4d, + 0xd5, 0xd7, 0x21, 0x8d, 0x65, 0x32, 0x0e, 0xf9, 0x0d, 0x6d, 0x65, 0x63, 0x41, 0x5b, 0x5d, 0xbf, + 0x57, 0x3c, 0xc3, 0x8a, 0x2b, 0x5f, 0x59, 0x59, 0xda, 0xde, 0x62, 0x45, 0x45, 0x7d, 0x13, 0xa6, + 0xd9, 0x91, 0xba, 0x49, 0x7d, 0xdf, 0x72, 0x9d, 0xc8, 0xc8, 0x95, 0x21, 0xd7, 0xf2, 0xa9, 0x27, + 0x1d, 0x59, 0x51, 0x59, 0xfd, 0xfb, 0x14, 0x64, 0x05, 0xff, 0x4b, 0xb5, 0x70, 0x32, 0x86, 0x91, + 0x38, 0x06, 0xa6, 0xc8, 0xba, 0x6d, 0x51, 0x27, 0xd0, 0xc3, 0x68, 0x34, 0x77, 0x7e, 0xc6, 0x39, + 0x75, 0x41, 0x44, 0x9b, 0xaf, 0x41, 0x11, 0x23, 0x9e, 0x75, 0x7c, 0xb6, 0xd2, 0x51, 0x14, 0x77, + 0x84, 0x26, 0x25, 0xfa, 0x3a, 0x93, 0xb8, 0x09, 0x13, 0x06, 0xea, 0x52, 0x17, 0x31, 0x23, 0x7c, + 0x0b, 0xe9, 0x8a, 0x88, 0x3c, 0x5f, 0xf9, 0xe1, 0x1d, 0xd4, 0x88, 0x48, 0x16, 0xf5, 0x3b, 0x6b, + 0x25, 0x73, 0xf2, 0xb5, 0xf2, 0x21, 0xe4, 0xf7, 0x0f, 0xf5, 0xe0, 0xa9, 0xc3, 0x94, 0x9b, 0x65, + 0x1e, 0xc0, 0xe2, 0xe2, 0xbf, 0x0c, 0xab, 0x52, 0xfe, 0x0a, 0xd8, 0xb2, 0xcc, 0xea, 0xf6, 0xf6, + 0x2a, 0x33, 0x49, 0xd9, 0x87, 0x87, 0x5b, 0x4f, 0x1d, 0x66, 0x5e, 0xf7, 0xf1, 0x03, 0x23, 0x61, + 0xb6, 0xe1, 0x07, 0xba, 0x34, 0xea, 0x76, 0x29, 0xc7, 0x95, 0xc3, 0x2a, 0x7a, 0x77, 0x47, 0x1e, + 0x41, 0xc8, 0xbb, 0xa3, 0x02, 0x05, 0x83, 0xb9, 0xbf, 0xfa, 0x4e, 0x3b, 0xa0, 0x3c, 0xce, 0x30, + 0xaa, 0x01, 0x92, 0x16, 0x19, 0x85, 0x5c, 0x85, 0xc9, 0x03, 0xe3, 0xa9, 0x2e, 0x33, 0x15, 0x90, + 0x69, 0xfc, 0xc0, 0x78, 0xba, 0x10, 0xf1, 0xa9, 0xdf, 0x54, 0x60, 0x4a, 0x5e, 0x87, 0xfc, 0x3c, + 0x7a, 0x99, 0xab, 0xeb, 0xf9, 0xf7, 0xc8, 0x3f, 0x56, 0x60, 0x26, 0xbe, 0x27, 0x84, 0xd1, 0x5d, + 0x86, 0x9c, 0x2f, 0x68, 0xc2, 0xea, 0xaa, 0x09, 0x8b, 0x43, 0x34, 0x0f, 0xa3, 0x32, 0x61, 0x4b, + 0xf2, 0xa0, 0xcb, 0x52, 0x26, 0xed, 0xee, 0x1e, 0x95, 0xc4, 0x8d, 0xa5, 0xfa, 0x04, 0xc8, 0x92, + 0xe1, 0xd4, 0xa9, 0x8d, 0xd3, 0x34, 0xd0, 0x45, 0xba, 0x0a, 0x39, 0x9c, 0x66, 0x56, 0x83, 0x83, + 0x5e, 0x2c, 0xb0, 0xa5, 0x81, 0x8d, 0xd9, 0xd2, 0xc0, 0xca, 0xae, 0x9d, 0x37, 0xda, 0xb5, 0xfb, + 0xef, 0xc1, 0x74, 0xac, 0x4b, 0xa1, 0x1b, 0xe6, 0xae, 0x22, 0x99, 0x9a, 0x22, 0x80, 0x1d, 0x95, + 0xd9, 0xdd, 0x05, 0xf1, 0x86, 0x77, 0x17, 0x2c, 0xa8, 0x6d, 0x98, 0xe1, 0x82, 0xc4, 0x00, 0x07, + 0xa2, 0xbf, 0x09, 0x20, 0x94, 0x18, 0xe2, 0x1f, 0xe3, 0xaf, 0x2b, 0x42, 0xc0, 0xea, 0xb2, 0x96, + 0x17, 0x0c, 0x03, 0xc6, 0xb0, 0x0a, 0x67, 0xbb, 0xba, 0x7e, 0xe1, 0x51, 0xfc, 0xab, 0x02, 0xc5, + 0xcd, 0xa6, 0xe1, 0xb0, 0x13, 0x26, 0xb2, 0x9e, 0x57, 0xba, 0x86, 0xb0, 0x08, 0x9d, 0x75, 0x1b, + 0x0d, 0x47, 0x93, 0xe3, 0xc9, 0x7c, 0x34, 0x6f, 0xff, 0xf0, 0xa8, 0xf2, 0xe6, 0xc9, 0x8e, 0xe1, + 0x87, 0xb4, 0x2d, 0x85, 0xa1, 0xd7, 0x3b, 0x61, 0xe8, 0xd1, 0xd3, 0x48, 0x14, 0xd1, 0x6b, 0xf5, + 0x07, 0x0a, 0x4c, 0x49, 0xa3, 0x13, 0x5a, 0xda, 0x84, 0x42, 0xe0, 0x06, 0x86, 0xcd, 0xd3, 0x2a, + 0x44, 0x0c, 0xe7, 0x66, 0x9f, 0xc0, 0x1a, 0xcf, 0x7c, 0xa8, 0x86, 0x09, 0x10, 0xd5, 0xf7, 0x7f, + 0x7a, 0x69, 0x09, 0x45, 0x89, 0x65, 0x0c, 0x28, 0x06, 0x29, 0xcc, 0x94, 0x70, 0x57, 0xaa, 0xee, + 0xb6, 0x1c, 0xfe, 0xec, 0x93, 0xd6, 0x00, 0x49, 0x4b, 0x8c, 0x42, 0xde, 0x82, 0x73, 0x46, 0xb3, + 0xe9, 0xb9, 0x4f, 0xad, 0x03, 0x23, 0xa0, 0xec, 0x10, 0xdd, 0x17, 0x16, 0x85, 0x3f, 0x84, 0xcd, + 0x48, 0xb5, 0xcb, 0x96, 0xbf, 0xcf, 0x0d, 0xcb, 0x4f, 0xc2, 0x8c, 0x88, 0x8f, 0xc6, 0x43, 0x71, + 0xc3, 0x4c, 0x91, 0xfa, 0xcd, 0x31, 0x38, 0xdb, 0xd5, 0xba, 0x37, 0xd2, 0x92, 0xfb, 0xbc, 0x2d, + 0xd3, 0xdf, 0x2a, 0x30, 0x1d, 0xc6, 0x70, 0xf5, 0x9d, 0x76, 0x14, 0x54, 0xcf, 0xa3, 0xb9, 0xb8, + 0x9b, 0x7c, 0xb1, 0xe9, 0xc5, 0x5a, 0x8d, 0xe2, 0xc3, 0x6d, 0x1e, 0x40, 0xe7, 0x6e, 0xdf, 0x23, + 0x36, 0x03, 0xc7, 0x47, 0x95, 0x62, 0x57, 0xf5, 0xf2, 0x27, 0x9f, 0xbd, 0x18, 0xfc, 0x62, 0xb3, + 0xab, 0x9f, 0xf2, 0x0f, 0x72, 0xfc, 0xc1, 0x36, 0x7a, 0xe8, 0xea, 0x09, 0xa3, 0x2b, 0x7d, 0xc2, + 0xe8, 0xbf, 0xa4, 0xc0, 0x59, 0xe9, 0xed, 0x4b, 0xef, 0x0e, 0x01, 0x3d, 0x3a, 0x3e, 0xaa, 0x4c, + 0x6f, 0x77, 0x18, 0x4e, 0xed, 0x6b, 0x4f, 0xb7, 0xba, 0x85, 0x99, 0x3e, 0xf9, 0x33, 0x05, 0xae, + 0x4a, 0x0f, 0x67, 0x3d, 0xef, 0x6e, 0x12, 0xac, 0x51, 0x84, 0xf5, 0xb3, 0xc7, 0x47, 0x95, 0xcb, + 0x9d, 0x57, 0xb5, 0xf8, 0x4b, 0xdc, 0xa9, 0x31, 0x5e, 0xf6, 0x12, 0x25, 0x9b, 0x3e, 0xf9, 0x15, + 0x05, 0x4a, 0xf1, 0xc7, 0x3e, 0x09, 0x62, 0x0a, 0x21, 0x6e, 0x1c, 0x1f, 0x55, 0x66, 0xd6, 0xa5, + 0xa7, 0xbf, 0x53, 0xc3, 0x9a, 0x71, 0x7a, 0xa4, 0x99, 0x3e, 0x79, 0x0a, 0x24, 0x7c, 0x26, 0x94, + 0x30, 0xa4, 0x11, 0xc3, 0xc3, 0xe3, 0xa3, 0xca, 0xe4, 0x3a, 0x7f, 0x34, 0x3c, 0x75, 0xf7, 0x93, + 0x8e, 0x2c, 0xc8, 0xf4, 0xc9, 0x6f, 0x28, 0x70, 0xa1, 0xeb, 0xd1, 0x52, 0x42, 0x90, 0x41, 0x04, + 0x9b, 0xc7, 0x47, 0x95, 0xf3, 0xdb, 0x71, 0xa6, 0x53, 0x23, 0x39, 0xdf, 0xea, 0x27, 0xd0, 0xf4, + 0xc9, 0x1f, 0x2a, 0xa0, 0x3e, 0xef, 0x61, 0x54, 0x82, 0x96, 0x45, 0x68, 0x8f, 0x8f, 0x8f, 0x2a, + 0xb3, 0x1f, 0xf4, 0x7d, 0x26, 0x3d, 0x35, 0xc2, 0xd9, 0x27, 0x09, 0x72, 0x4d, 0x9f, 0x7c, 0x57, + 0x81, 0x4b, 0xbd, 0xef, 0xb0, 0x12, 0xc4, 0x5c, 0x47, 0x7b, 0x5a, 0xfc, 0x55, 0xf6, 0xf4, 0xda, + 0xf3, 0xfa, 0x09, 0x34, 0xfd, 0xf2, 0x27, 0x4a, 0x64, 0x80, 0xe3, 0xe6, 0x4b, 0xbe, 0x17, 0xa6, + 0xf9, 0xbd, 0x70, 0x33, 0x7e, 0x2f, 0x7c, 0xe7, 0xc4, 0x76, 0x52, 0x36, 0x55, 0xd2, 0x55, 0xf1, + 0x41, 0x2a, 0xa7, 0x14, 0x73, 0xea, 0x35, 0x18, 0x1b, 0x36, 0x42, 0xff, 0x47, 0x69, 0xf1, 0xf0, + 0xf3, 0x23, 0xc9, 0xc8, 0x91, 0xc3, 0x30, 0x23, 0x2f, 0x21, 0x0c, 0xf3, 0xd7, 0x0a, 0xcc, 0x78, + 0x62, 0x20, 0xb1, 0xf3, 0x88, 0x47, 0x53, 0xde, 0x1d, 0x14, 0x78, 0xea, 0x04, 0x1d, 0x42, 0x21, + 0xf1, 0x83, 0x68, 0x43, 0x1c, 0x44, 0x53, 0xdd, 0xf5, 0x2f, 0x7c, 0x12, 0x4d, 0x79, 0xdd, 0x3d, + 0x95, 0xbf, 0xa3, 0xf0, 0xa3, 0x48, 0xf6, 0xf4, 0x42, 0xae, 0xd0, 0xd3, 0x0b, 0xcb, 0xc3, 0xe5, + 0x06, 0xbe, 0x07, 0x69, 0xcb, 0xd9, 0x75, 0xc3, 0xa0, 0xd2, 0x89, 0xe2, 0x6f, 0xd8, 0xb0, 0xfc, + 0x11, 0x9c, 0xeb, 0xaf, 0x92, 0x3e, 0x8b, 0xfb, 0x61, 0x7c, 0x71, 0xbf, 0x3d, 0xb4, 0xd2, 0xe5, + 0x41, 0xc7, 0x17, 0x75, 0xaa, 0x98, 0x56, 0x6f, 0x01, 0x59, 0xee, 0x24, 0xb9, 0x0e, 0x8c, 0x70, + 0x62, 0xd8, 0xdb, 0xf5, 0x86, 0x48, 0xe4, 0xfc, 0xf3, 0x11, 0x18, 0x43, 0xd6, 0x30, 0x85, 0xf3, + 0x43, 0xc8, 0x45, 0xaf, 0xf5, 0x7c, 0x0b, 0xe0, 0x2a, 0x3d, 0xed, 0x3b, 0x7d, 0xd6, 0x17, 0x2f, + 0xf4, 0x37, 0x60, 0x8a, 0x3a, 0x75, 0xaf, 0xdd, 0xc4, 0x8b, 0xbe, 0x78, 0xf2, 0x45, 0xaf, 0x5a, + 0x2b, 0x76, 0x2a, 0x44, 0xe4, 0xb2, 0x12, 0x3a, 0xb0, 0x3c, 0x24, 0xcd, 0xfd, 0x47, 0xee, 0x8c, + 0x62, 0xd4, 0xba, 0xc3, 0xc0, 0x1d, 0xcc, 0x94, 0xc4, 0xc0, 0xef, 0xb5, 0x73, 0x50, 0x14, 0xf7, + 0xe6, 0x7d, 0xda, 0x16, 0x62, 0x78, 0x6e, 0x91, 0x88, 0x22, 0x3c, 0xa4, 0x6d, 0x2e, 0x2a, 0xce, + 0xc9, 0xe5, 0x65, 0xba, 0x38, 0xb9, 0xab, 0xfa, 0x65, 0x98, 0x08, 0xb5, 0x1b, 0x3d, 0x44, 0x65, + 0x70, 0x7c, 0xe1, 0x75, 0xf3, 0x8d, 0xa4, 0xeb, 0xa6, 0xa4, 0xed, 0xf0, 0x96, 0xc8, 0x1b, 0xab, + 0xb7, 0x61, 0x0a, 0x93, 0x3d, 0x0e, 0xa8, 0x73, 0xb2, 0x3b, 0x8a, 0xfa, 0xcf, 0x29, 0x20, 0x72, + 0x53, 0x81, 0xab, 0x89, 0xcf, 0x4e, 0x82, 0x2a, 0xb0, 0x3d, 0x48, 0xc4, 0xd6, 0x2d, 0xa2, 0xba, + 0xe4, 0xda, 0x36, 0xad, 0x07, 0xd4, 0x8c, 0xea, 0x7a, 0xb2, 0x0f, 0xa4, 0x3e, 0xc8, 0x12, 0x00, + 0x06, 0x2b, 0x3c, 0xea, 0xd3, 0x93, 0x45, 0xde, 0xf2, 0xac, 0x9d, 0xc6, 0x9a, 0x95, 0xff, 0x46, + 0x81, 0xd9, 0x15, 0x91, 0x45, 0xda, 0xa7, 0x5b, 0x76, 0x81, 0xba, 0x0b, 0x39, 0x36, 0x4d, 0xd1, + 0x3b, 0x5d, 0xd7, 0x8b, 0xee, 0x13, 0xbb, 0xda, 0xbf, 0x61, 0xf8, 0xc2, 0xb5, 0x4f, 0xdb, 0xcb, + 0x46, 0x60, 0xc8, 0x06, 0x7f, 0xe4, 0x73, 0x36, 0xf8, 0x6c, 0x18, 0x97, 0x92, 0xd4, 0x47, 0xcc, + 0x8e, 0xf9, 0x28, 0xcc, 0xaf, 0x9d, 0x6c, 0x5e, 0x92, 0xf5, 0x23, 0x86, 0x89, 0x26, 0xe9, 0x4b, + 0x61, 0x76, 0x09, 0x37, 0x49, 0xea, 0x60, 0x3d, 0xc5, 0xb2, 0x4a, 0xae, 0xcf, 0x40, 0x2e, 0x7c, + 0x53, 0xea, 0xbc, 0xb7, 0xcc, 0xff, 0xc9, 0x25, 0xc8, 0x88, 0x5d, 0xfa, 0xbb, 0x0a, 0x8c, 0xc9, + 0xd9, 0xb8, 0xa4, 0x3a, 0x5c, 0xbe, 0x6d, 0xb8, 0xc4, 0xcb, 0xb5, 0xa1, 0xf9, 0xf9, 0xe0, 0xd5, + 0x37, 0x3e, 0xf9, 0x87, 0xff, 0xfc, 0xcd, 0x91, 0x57, 0x49, 0xa5, 0x26, 0x2c, 0x48, 0x4d, 0x4e, + 0xd6, 0xad, 0x7d, 0x24, 0xa6, 0xf4, 0x19, 0xf3, 0x33, 0xb3, 0xa1, 0x65, 0x4b, 0x8a, 0x74, 0xc7, + 0x73, 0x7b, 0xcb, 0xd7, 0x87, 0x61, 0x15, 0x58, 0x6e, 0x21, 0x96, 0x37, 0x48, 0x39, 0xc2, 0x62, + 0x72, 0x8e, 0x0e, 0x8c, 0xc7, 0x79, 0x92, 0xad, 0xed, 0x51, 0xc3, 0x0e, 0xf6, 0x88, 0x07, 0x69, + 0xcc, 0x85, 0x25, 0x49, 0x36, 0x42, 0xce, 0x9e, 0x2d, 0xcf, 0x0d, 0x66, 0x14, 0x50, 0xce, 0x21, + 0x94, 0x22, 0x99, 0x88, 0xa0, 0xe0, 0x8b, 0x08, 0xf9, 0x3a, 0xa4, 0xf0, 0x99, 0xeb, 0xea, 0x00, + 0x49, 0x61, 0x8f, 0x27, 0xca, 0xc7, 0x55, 0x2f, 0x63, 0xaf, 0x65, 0x52, 0x8a, 0xf7, 0x2a, 0xcd, + 0xc2, 0x33, 0x9e, 0x7b, 0x8b, 0x4f, 0x1b, 0xe4, 0xc6, 0x70, 0x0f, 0x20, 0xcf, 0x47, 0xf2, 0xdc, + 0xd7, 0x12, 0xf5, 0x2c, 0x22, 0x99, 0x24, 0xe3, 0x11, 0x12, 0xe6, 0xaf, 0x92, 0x8f, 0x15, 0xc8, + 0x70, 0x17, 0x92, 0x0c, 0xcc, 0xd1, 0x8a, 0xb4, 0x7e, 0x6d, 0x08, 0x4e, 0xd1, 0xed, 0xab, 0xd8, + 0xed, 0x45, 0x72, 0x41, 0xea, 0x96, 0x31, 0x48, 0x1a, 0xf0, 0x21, 0xc3, 0xd3, 0x6f, 0x12, 0x11, + 0xc4, 0x32, 0x74, 0xca, 0xf2, 0x2b, 0xb9, 0xf8, 0x8b, 0x19, 0xe6, 0x9b, 0x08, 0xad, 0xf7, 0x76, + 0x2a, 0xfe, 0xb8, 0xa6, 0xd3, 0xe9, 0x77, 0x14, 0xc8, 0x47, 0x49, 0x0f, 0x89, 0x7a, 0xef, 0x4e, + 0xf5, 0x48, 0xd4, 0x7b, 0x4f, 0x1e, 0x86, 0x7a, 0x0d, 0xb1, 0x5c, 0x21, 0xaf, 0x46, 0x58, 0x8c, + 0x90, 0x07, 0xd7, 0x82, 0x84, 0xe9, 0x7b, 0x0a, 0x4c, 0xc4, 0x93, 0x62, 0xc8, 0x17, 0x86, 0xea, + 0x4b, 0x72, 0xe9, 0xcb, 0x6f, 0x9e, 0xa0, 0x85, 0x80, 0x78, 0x03, 0x21, 0xbe, 0x4e, 0xae, 0xf4, + 0x81, 0x88, 0xb3, 0x55, 0xfb, 0x28, 0x74, 0xce, 0x9f, 0x91, 0x5f, 0x55, 0x60, 0x4c, 0x8e, 0xe8, + 0x26, 0x1a, 0xb4, 0x3e, 0xaf, 0x32, 0x89, 0x06, 0xad, 0x5f, 0xc4, 0x5a, 0xbd, 0x80, 0xf0, 0xa6, + 0xc9, 0x54, 0x04, 0x2f, 0x0a, 0x43, 0xff, 0xb6, 0x88, 0xb8, 0x63, 0x22, 0xde, 0x8f, 0x0e, 0x51, + 0x05, 0x11, 0x5d, 0x20, 0xe7, 0x23, 0x44, 0x98, 0x52, 0xa8, 0xcb, 0xb8, 0x0a, 0x52, 0x80, 0x99, + 0x24, 0xfe, 0x91, 0x45, 0x4f, 0xec, 0xbb, 0x5c, 0x1d, 0x96, 0xfd, 0xf9, 0x26, 0x1f, 0xb9, 0xf8, + 0x7b, 0x88, 0xb4, 0xc2, 0x7e, 0x5f, 0x81, 0xf1, 0x58, 0xd0, 0x98, 0xd4, 0x06, 0x76, 0x15, 0x8f, + 0x6c, 0x97, 0xbf, 0x30, 0x7c, 0x83, 0xe7, 0xee, 0x00, 0x81, 0x4e, 0xa8, 0x4b, 0xc2, 0xf7, 0xb1, + 0x02, 0xf9, 0x28, 0x54, 0x9b, 0xb8, 0x2b, 0xbb, 0xc3, 0xd5, 0x89, 0xbb, 0xb2, 0x27, 0xfa, 0xab, + 0x96, 0x10, 0x13, 0x51, 0x3b, 0xd6, 0xd0, 0x6f, 0x1a, 0xce, 0x1d, 0xe5, 0x3a, 0xf9, 0x3a, 0x1e, + 0xdd, 0xf5, 0xfd, 0x64, 0x7b, 0x18, 0x4b, 0x9c, 0x29, 0x27, 0x1d, 0x57, 0x72, 0xf6, 0x54, 0x1f, + 0xc3, 0xe4, 0xa3, 0x20, 0x49, 0x05, 0xbf, 0xa8, 0x40, 0x56, 0xe4, 0x76, 0x24, 0x9e, 0xca, 0xf1, + 0xfc, 0x8f, 0xe1, 0x21, 0xa8, 0x08, 0xe1, 0x92, 0x74, 0x24, 0x37, 0xb9, 0xa4, 0x2e, 0x0c, 0x22, + 0x61, 0x24, 0x11, 0x43, 0x3c, 0xa9, 0xe4, 0x34, 0x18, 0x0e, 0xb8, 0x24, 0x09, 0xc3, 0x37, 0x14, + 0xc8, 0x85, 0x09, 0x38, 0x24, 0xc9, 0xe7, 0xe8, 0xca, 0x21, 0x2a, 0xdf, 0x18, 0x8a, 0x57, 0x20, + 0xe9, 0x3d, 0x9f, 0xf1, 0x1a, 0x24, 0xe1, 0xf8, 0x2d, 0x66, 0xef, 0xa4, 0xbc, 0xad, 0x64, 0xeb, + 0xd2, 0x9b, 0x10, 0x96, 0x6c, 0x5d, 0xfa, 0x24, 0x84, 0xa9, 0x57, 0x10, 0xd3, 0x2b, 0xe4, 0xa2, + 0x64, 0x5d, 0x1a, 0xdd, 0xb0, 0x98, 0xf3, 0x26, 0x5a, 0x27, 0x4e, 0x51, 0x3c, 0x41, 0xac, 0x7c, + 0x2b, 0x99, 0xb5, 0x2b, 0x3d, 0x4e, 0xbd, 0x8e, 0x50, 0x5e, 0x23, 0x6a, 0x02, 0x94, 0xda, 0x47, + 0x8c, 0xf0, 0x8c, 0x39, 0x52, 0x6b, 0x6e, 0xc3, 0x4f, 0x74, 0xa4, 0xa4, 0x2c, 0xc1, 0x93, 0x42, + 0xe9, 0x67, 0x73, 0x1b, 0xb2, 0x46, 0xbe, 0xab, 0xe0, 0xdf, 0xbf, 0x74, 0x62, 0x62, 0x89, 0xb6, + 0xad, 0xdf, 0x7b, 0x4a, 0xa2, 0x6d, 0xeb, 0x1b, 0x6e, 0x53, 0x67, 0x11, 0x55, 0x89, 0x9c, 0x93, + 0x77, 0x13, 0xe3, 0x13, 0x19, 0x25, 0xcf, 0x20, 0xcd, 0x0f, 0xf2, 0x37, 0x06, 0x07, 0x3b, 0x06, + 0x7b, 0xb4, 0xf1, 0x63, 0xfb, 0x39, 0xae, 0x95, 0x7c, 0x58, 0xff, 0x8e, 0x02, 0x05, 0x29, 0x36, + 0x92, 0x78, 0x0e, 0xf5, 0xc6, 0x50, 0xfa, 0xe9, 0x23, 0xf6, 0xc7, 0xc5, 0x52, 0x1b, 0x8d, 0x36, + 0x5d, 0x2f, 0x50, 0xaf, 0x22, 0xa6, 0xcb, 0x64, 0xb6, 0xe3, 0xf0, 0x77, 0x1a, 0xc4, 0x0d, 0x7d, + 0x86, 0xc7, 0x09, 0x06, 0x98, 0x59, 0x29, 0x50, 0x93, 0xe8, 0x76, 0xc6, 0x83, 0x0e, 0x7d, 0x0d, + 0x2d, 0x63, 0x90, 0x20, 0xfc, 0xb2, 0x02, 0xd0, 0xb9, 0x3b, 0x92, 0x9b, 0x43, 0x5e, 0x31, 0x07, + 0x2f, 0xde, 0xde, 0x0b, 0xa9, 0x7a, 0x11, 0xe1, 0x9c, 0x25, 0xd3, 0xb2, 0xdd, 0x17, 0x4c, 0x8b, + 0xea, 0xa7, 0xff, 0x3e, 0x7b, 0xe6, 0xd3, 0xe3, 0x59, 0xe5, 0xef, 0x8e, 0x67, 0x95, 0x7f, 0x3a, + 0x9e, 0x55, 0xfe, 0xed, 0x78, 0x56, 0xf9, 0xf6, 0x7f, 0xcc, 0x9e, 0x79, 0x9c, 0x0b, 0x65, 0xee, + 0x64, 0x30, 0x3c, 0xf0, 0xc5, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x83, 0xe3, 0x93, 0xa3, 0x71, + 0x3e, 0x00, 0x00, } diff --git a/pkg/server/serverpb/status.pb.gw.go b/pkg/server/serverpb/status.pb.gw.go index 04af59708c74..784f09541abd 100644 --- a/pkg/server/serverpb/status.pb.gw.go +++ b/pkg/server/serverpb/status.pb.gw.go @@ -670,33 +670,6 @@ func request_Status_Range_0(ctx context.Context, marshaler runtime.Marshaler, cl } -func request_Status_CommandQueue_0(ctx context.Context, marshaler runtime.Marshaler, client StatusClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq CommandQueueRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["range_id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "range_id") - } - - protoReq.RangeId, err = runtime.Int64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "range_id", err) - } - - msg, err := client.CommandQueue(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - func request_Status_Diagnostics_0(ctx context.Context, marshaler runtime.Marshaler, client StatusClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq DiagnosticsRequest var metadata runtime.ServerMetadata @@ -1502,35 +1475,6 @@ func RegisterStatusHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli }) - mux.Handle("GET", pattern_Status_CommandQueue_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Status_CommandQueue_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Status_CommandQueue_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Status_Diagnostics_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1670,8 +1614,6 @@ var ( pattern_Status_Range_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"_status", "range", "range_id"}, "")) - pattern_Status_CommandQueue_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"_status", "range", "range_id", "cmdqueue"}, "")) - pattern_Status_Diagnostics_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"_status", "diagnostics", "node_id"}, "")) pattern_Status_Stores_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"_status", "stores", "node_id"}, "")) @@ -1728,8 +1670,6 @@ var ( forward_Status_Range_0 = runtime.ForwardResponseMessage - forward_Status_CommandQueue_0 = runtime.ForwardResponseMessage - forward_Status_Diagnostics_0 = runtime.ForwardResponseMessage forward_Status_Stores_0 = runtime.ForwardResponseMessage diff --git a/pkg/server/serverpb/status.proto b/pkg/server/serverpb/status.proto index 53aa3a052c95..7cac1c402a07 100644 --- a/pkg/server/serverpb/status.proto +++ b/pkg/server/serverpb/status.proto @@ -164,13 +164,6 @@ message PrettySpan { string end_key = 2; } -message CommandQueueMetrics { - int64 write_commands = 1; - int64 read_commands = 2; - int64 max_overlaps_seen = 3; - int32 tree_size = 4; -} - message RangeInfo { PrettySpan span = 1 [ (gogoproto.nullable) = false ]; RaftState raft_state = 2 [ (gogoproto.nullable) = false ]; @@ -189,8 +182,8 @@ message RangeInfo { repeated roachpb.Lease lease_history = 8 [ (gogoproto.nullable) = false ]; RangeProblems problems = 9 [ (gogoproto.nullable) = false ]; RangeStatistics stats = 10 [ (gogoproto.nullable) = false ]; - CommandQueueMetrics cmd_q_local = 11 [ (gogoproto.nullable) = false ]; - CommandQueueMetrics cmd_q_global = 12 [ (gogoproto.nullable) = false ]; + storage.storagepb.LatchManagerInfo latches_local = 11 [ (gogoproto.nullable) = false ]; + storage.storagepb.LatchManagerInfo latches_global = 12 [ (gogoproto.nullable) = false ]; storage.LeaseStatus lease_status = 13 [ (gogoproto.nullable) = false ]; bool quiescent = 14; bool ticking = 15; @@ -611,13 +604,6 @@ message RangeResponse { reserved 4; // Previously used. } -message CommandQueueRequest { int64 range_id = 1; } - -message CommandQueueResponse { - storage.storagepb.CommandQueuesSnapshot snapshot = 1 - [ (gogoproto.nullable) = false ]; -} - // DiagnosticsRequest requests a diagnostics report. message DiagnosticsRequest { // node_id is a string so that "local" can be used to specify that no @@ -805,11 +791,6 @@ service Status { get : "/_status/range/{range_id}" }; } - rpc CommandQueue(CommandQueueRequest) returns (CommandQueueResponse) { - option (google.api.http) = { - get : "/_status/range/{range_id}/cmdqueue" - }; - } rpc Diagnostics(DiagnosticsRequest) returns (cockroach.server.diagnosticspb.DiagnosticReport) { option (google.api.http) = { diff --git a/pkg/server/status.go b/pkg/server/status.go index 609f23640b7c..734456a512d8 100644 --- a/pkg/server/status.go +++ b/pkg/server/status.go @@ -1214,11 +1214,11 @@ func (s *statusServer) Ranges( QuiescentEqualsTicking: raftStatus != nil && metrics.Quiescent == metrics.Ticking, RaftLogTooLarge: metrics.RaftLogTooLarge, }, - CmdQLocal: serverpb.CommandQueueMetrics(metrics.CmdQMetricsLocal), - CmdQGlobal: serverpb.CommandQueueMetrics(metrics.CmdQMetricsGlobal), - LeaseStatus: metrics.LeaseStatus, - Quiescent: metrics.Quiescent, - Ticking: metrics.Ticking, + LatchesLocal: metrics.LatchInfoLocal, + LatchesGlobal: metrics.LatchInfoGlobal, + LeaseStatus: metrics.LeaseStatus, + Quiescent: metrics.Quiescent, + Ticking: metrics.Ticking, } } @@ -1321,26 +1321,6 @@ func (s *statusServer) Range( return response, nil } -// CommandQueue returns a snapshot of the command queue state for the -// specified range. -func (s *statusServer) CommandQueue( - ctx context.Context, req *serverpb.CommandQueueRequest, -) (*serverpb.CommandQueueResponse, error) { - rangeID := roachpb.RangeID(req.RangeId) - replica, err := s.stores.GetReplicaForRangeID(rangeID) - if err != nil { - return nil, err - } - - if replica == nil { - return nil, roachpb.NewRangeNotFoundError(rangeID, 0) - } - - return &serverpb.CommandQueueResponse{ - Snapshot: replica.GetCommandQueueSnapshot(), - }, nil -} - // ListLocalSessions returns a list of SQL sessions on this node. func (s *statusServer) ListLocalSessions( ctx context.Context, req *serverpb.ListSessionsRequest, diff --git a/pkg/server/status/health_check.go b/pkg/server/status/health_check.go index 27264064b625..7d4d85b93525 100644 --- a/pkg/server/status/health_check.go +++ b/pkg/server/status/health_check.go @@ -50,7 +50,7 @@ var trackedMetrics = map[string]threshold{ "ranges.unavailable": gaugeZero, "ranges.underreplicated": gaugeZero, "requests.backpressure.split": gaugeZero, - "requests.slow.commandqueue": gaugeZero, + "requests.slow.latch": gaugeZero, "requests.slow.lease": gaugeZero, "requests.slow.raft": gaugeZero, "sys.goroutines": {gauge: true, min: 5000}, diff --git a/pkg/storage/client_merge_test.go b/pkg/storage/client_merge_test.go index 520bef6c7aa8..498049562f37 100644 --- a/pkg/storage/client_merge_test.go +++ b/pkg/storage/client_merge_test.go @@ -1201,18 +1201,17 @@ func TestStoreRangeMergeRHSLeaseExpiration(t *testing.T) { } // Install a hook to observe when a get request for a special key, - // rhsSentinel, exits the command queue. + // rhsSentinel, acquires latches and begins evaluating. const getConcurrency = 10 rhsSentinel := roachpb.Key("rhs-sentinel") - getExitedCommandQueue := make(chan struct{}, getConcurrency) - storeCfg.TestingKnobs.OnCommandQueueAction = func(ba *roachpb.BatchRequest, action storagebase.CommandQueueAction) { - if action == storagebase.CommandQueueBeginExecuting { - for _, r := range ba.Requests { - if get := r.GetGet(); get != nil && get.RequestHeader.Key.Equal(rhsSentinel) { - getExitedCommandQueue <- struct{}{} - } + getAcquiredLatch := make(chan struct{}, getConcurrency) + storeCfg.TestingKnobs.TestingLatchFilter = func(ba roachpb.BatchRequest) *roachpb.Error { + for _, r := range ba.Requests { + if get := r.GetGet(); get != nil && get.RequestHeader.Key.Equal(rhsSentinel) { + getAcquiredLatch <- struct{}{} } } + return nil } mtc := &multiTestContext{storeConfig: &storeCfg} @@ -1271,7 +1270,7 @@ func TestStoreRangeMergeRHSLeaseExpiration(t *testing.T) { // Note that the first request would never hit this race on its own. Nor would // any request that arrived early enough to see an outdated lease in // Replica.mu.state.Lease. All of these requests joined the in-progress lease - // acquisition and blocked until the lease command exited the command queue, + // acquisition and blocked until the lease command acquires its latches, // at which point the mergeComplete channel was updated. To hit the race, the // request needed to arrive exactly between the update to // Replica.mu.state.Lease and the update to Replica.mu.mergeComplete. @@ -1300,12 +1299,12 @@ func TestStoreRangeMergeRHSLeaseExpiration(t *testing.T) { time.Sleep(time.Millisecond) } - // Wait for the get requests to fall out of the command queue, which is as far - // as they can get while the merge is in progress. Then wait a little bit - // longer. This tests that the requests really do get stuck waiting for the - // merge to complete without depending too heavily on implementation details. + // Wait for the get requests to acquire latches, which is as far as they can + // get while the merge is in progress. Then wait a little bit longer. This + // tests that the requests really do get stuck waiting for the merge to + // complete without depending too heavily on implementation details. for i := 0; i < getConcurrency; i++ { - <-getExitedCommandQueue + <-getAcquiredLatch } time.Sleep(50 * time.Millisecond) @@ -1361,7 +1360,7 @@ func TestStoreRangeMergeConcurrentRequests(t *testing.T) { // // This scenario previously caused deadlock. The merge was not able to // complete until the Subsume request completed, but the Subsume request - // was stuck in the command queue until the Get request finished, which + // was unable to acquire latches until the Get request finished, which // was itself waiting for the merge to complete. Whoops! mtc.advanceClock(ctx) } diff --git a/pkg/storage/command_queue.go b/pkg/storage/command_queue.go deleted file mode 100644 index 338f8e149189..000000000000 --- a/pkg/storage/command_queue.go +++ /dev/null @@ -1,976 +0,0 @@ -// Copyright 2014 The Cockroach Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. - -package storage - -import ( - "bytes" - "container/heap" - "context" - "fmt" - "strings" - - "github.com/cockroachdb/cockroach/pkg/keys" - "github.com/cockroachdb/cockroach/pkg/roachpb" - "github.com/cockroachdb/cockroach/pkg/storage/storagepb" - "github.com/cockroachdb/cockroach/pkg/util/hlc" - "github.com/cockroachdb/cockroach/pkg/util/interval" - "github.com/cockroachdb/cockroach/pkg/util/log" -) - -// A CommandQueue maintains an interval tree of keys or key ranges for -// executing commands. New commands affecting keys or key ranges must -// wait on already-executing commands which overlap their key range. -// -// Before executing, a command invokes getPrereqs() to acquire a slice of -// references to overlapping commands that are already in the command queue. -// After determining its prerequisite commands, the command is added to the -// queue via add(). getPrereqs() and add() accept a parameter indicating whether -// the command is read-only. Read-only commands don't need to wait on other -// read-only commands, so the commands returned via getPrereqs() don't include -// read-only on read-only overlapping commands as an optimization. Both getPrereqs() -// and add() must see an atomic view of the command queue, so in a concurrent setting, -// their execution must be synchronized under the same lock. -// -// After determining prerequisite commands and adding the new command to the -// command queue, the new command must wait on each prerequisite command's -// pending channel for confirmation that all overlapping commands have completed -// and that the new command can proceed. -// -// Once commands complete, remove() is invoked to remove the executing -// command and close its channel, possibly signaling waiting commands -// who were gated by the executing command's affected key(s). -// -// CommandQueue is not thread safe. -type CommandQueue struct { - readsBuffer map[*cmd]struct{} - reads interval.Tree - writes interval.Tree - idAlloc int64 - - // avoids allocating in getPrereqs - wRg, rwRg interval.RangeGroup - oHeap overlapHeap - // avoids allocating in getOverlaps - overlaps []*cmd - readOnly bool - timestamp hlc.Timestamp - collectOverlappingReadsRef interval.Operation - collectOverlappingWritesRef interval.Operation - - coveringOptimization bool // if true, use covering span optimization - - // Used to temporarily store metrics local to a single CommandQueue. These - // will periodically be processed by the Store. - localMetrics struct { - readCommands int64 - writeCommands int64 - maxOverlapsSeen int64 // will be reset to 0 during metrics processing. - } -} - -type cmd struct { - id int64 - key interval.Range - readOnly bool - timestamp hlc.Timestamp - debugInfo summaryWriter - - buffered bool // is this cmd buffered in readsBuffer - expanded bool // have the children been added - children []cmd - - // In both child and parent cmds, prereqs points to - // the prereqsBuf of the parent cmd. This means we - // don't need to keep multiple *cmd slices in-sync. - prereqs *[]*cmd - prereqsBuf []*cmd - // Only initialized if needed and only ever initialized - // on a parent cmd. Stores all of the IDs of commands - // in the prereq slice to avoid duplicates. - prereqIDs map[int64]struct{} - - pending chan struct{} // closed when complete -} - -// A summaryWriter is capable of writing a summary about itself. It is typically -// implemented by *roachpb.BatchRequest, but the interface allows us to avoid -// establishing a dependency on the full batch request on a *cmd, which could be -// abused. -type summaryWriter interface { - WriteSummary(*strings.Builder) -} - -// ID implements interval.Interface. -func (c *cmd) ID() uintptr { - return uintptr(c.id) -} - -// Range implements interval.Interface. -func (c *cmd) Range() interval.Range { - return c.key -} - -// cmdCount returns the number of spans in c, taking into account the -// "covering" optimization (see CommandQueue.add). If a cmd was added to the -// CommandQueue with only a single span, it will have 0 children, behaving like -// the optimization does not exist. If a cmd was added to the CommandQueue with -// multiple spans, each span will be retained as a child command in a covering cmd, -// even if the covering cmd is expanded. As a result, len(c.children) will never be 1. -func (c *cmd) cmdCount() int { - if len(c.children) == 0 { - return 1 - } - return len(c.children) -} - -func (c *cmd) String() string { - if c == nil { - return "" - } - var b strings.Builder - var readOnly string - if c.readOnly { - readOnly = " readonly" - } - fmt.Fprintf(&b, "%d %s%s [%s", c.id, c.timestamp, readOnly, roachpb.Key(c.key.Start)) - if !roachpb.Key(c.key.End).Equal(roachpb.Key(c.key.Start).Next()) { - fmt.Fprintf(&b, ",%s", roachpb.Key(c.key.End)) - } - b.WriteString(")") - if c.debugInfo != nil { - b.WriteString(" [") - c.debugInfo.WriteSummary(&b) - b.WriteString("]") - } - - if !c.expanded { - for i := range c.children { - fmt.Fprintf(&b, "\n %d: %s", i, &c.children[i]) - } - } - return b.String() -} - -// SetDebugInfo adds extra debug information to the command. -func (c *cmd) SetDebugInfo(s summaryWriter) { - c.debugInfo = s - for i := range c.children { - c.children[i].debugInfo = s - } -} - -// PrereqLen returns the number of immediate prerequisite command that the -// command is waiting on. -func (c *cmd) PrereqLen() int { - if c == nil { - return 0 - } - return len(*c.prereqs) -} - -// PendingPrereq returns the prerequisite command that should be waited on next, -// or nil if the receiver has no more prerequisites to wait on. -func (c *cmd) PendingPrereq() *cmd { - if c.PrereqLen() == 0 { - return nil - } - return (*c.prereqs)[0] -} - -// ResolvePendingPrereq removes the first prerequisite in the cmd's prereq -// slice. While doing so, transfer any prerequisites of this prereq that were -// still pending when this prereq was removed from the CommandQueue. -// -// cmd.PendingPrereq().pending must be closed for this call to be safe. -func (c *cmd) ResolvePendingPrereq() { - pre := c.PendingPrereq() - if pre == nil { - panic("ResolvePendingPrereq with no pending prereq") - } - - // Either the prerequisite command finished executing or it was canceled. - // If the command finished cleanly, there's nothing for us to do except - // remove it from our list and wait for the next prerequisite to finish. - // Here, len(prereq.prereqs) == 0 so the append below will be a no-op. - // Removing the prereq from our own list is important so that it is not - // transferred to our dependents when we finish pending (either from - // completion or cancellation). - // - // If the prerequisite command was canceled, we have to handle the - // cancellation here. We do this by migrating transitive dependencies from - // canceled prerequisite to the current command. All prerequisites of the - // prerequisite that was just canceled that were still pending at the time - // of cancellation are now this command's direct prerequisites. The append - // does not need to be synchronized, because prereq.prereqs will only ever - // be mutated on the other side of the prereq.pending closing, which the Go - // Memory Model promises is safe. - // - // While it may be possible that some of these transitive dependencies no - // longer overlap the current command, they are still required, because they - // themselves might be dependent on a command that overlaps both the current - // and prerequisite command. - // - // For instance, take the following dependency graph, where command 3 was - // canceled. We need to set command 2 as a prerequisite of command 4 even - // though they do not overlap because command 2 has a dependency on command - // 1, which does overlap command 4. We could try to catch this situation and - // set command 1 as a prerequisite of command 4 directly, but this approach - // would require much more complexity and would need to traverse all the way - // up the dependency graph in the worst case. - // - // cmd 1: ------------- - // | - // cmd 2: ----- - // | - // cmd 3: xxxxxxxxxxx - // | - // cmd 4: ----- - // - // It is also be possible that some of the transitive dependencies are - // unnecessary and that we're being pessimistic here. An example case for - // this is shown in the following dependency graph, where a write separating - // two reads is canceled. During the cancellation, command 3 will take - // command 1 as it's prerequisite even though reads do not need to wait on - // other reads. We could be smarter here and detect these cases, but the - // pessimism does not affect correctness. - // - // cmd 1 [R]: ----- - // | - // cmd 2 [W]: xxxxx - // | - // cmd 3 [R]: ----- - // - // The interaction between commands' timestamps and their resulting - // dependencies (see rules in command_queue.go) will work as expected with - // regard to properly transferring dependencies. This is because these - // timestamp rules all exhibit a transitive relationship. - if len(*pre.prereqs) > 0 { - // Avoid adding duplicate prereqs into the prereq slice. If we naively - // inserted duplicate prereqs into the slice then it could grow - // quadratically in cases where multiple prereqs of cmd each share - // common prerequisites themselves. - if c.prereqIDs == nil { - // Lazily compute prereq ID set. This is only necessary during - // command cancellation scenario. - c.prereqIDs = make(map[int64]struct{}, len(*c.prereqs)) - for _, pre := range *c.prereqs { - c.prereqIDs[pre.id] = struct{}{} - } - } - for _, newPre := range *pre.prereqs { - if _, ok := c.prereqIDs[newPre.id]; !ok { - *c.prereqs = append(*c.prereqs, newPre) - c.prereqIDs[newPre.id] = struct{}{} - } - } - } - - // Truncate the command's prerequisite list so that it no longer includes - // the first prerequisite. Before doing so, nil out prefix of slice to allow - // GC of the first command. Without this, large chunks of the dependency - // graph would be prevented from being GCed longer than necessary, - // especially during cascade command cancellation. - (*c.prereqs)[0] = nil - (*c.prereqs) = (*c.prereqs)[1:] - - // Delete from the prereq ID set (if c.prereqIDs is nil, this is a no-op). - delete(c.prereqIDs, pre.id) -} - -// OptimisticallyResolvePrereqs removes all prerequisite in the cmd's prereq -// slice that have already finished without blocking on pending commands. -// Prerequisite commands that are still pending or that were canceled are left -// in the prereq slice. -func (c *cmd) OptimisticallyResolvePrereqs() { - j := 0 - for i, pre := range *c.prereqs { - select { - case <-pre.pending: - if len(*pre.prereqs) == 0 { - // Nil to allow GC. - (*c.prereqs)[i] = nil - continue - } - // Command canceled. Don't expand. - default: - // Command still pending. - } - (*c.prereqs)[j] = pre - j++ - } - (*c.prereqs) = (*c.prereqs)[:j] -} - -// NewCommandQueue returns a new command queue. The boolean specifies whether -// to enable the covering span optimization. With this optimization, whenever -// a command consisting of multiple spans is added, a covering span is computed -// and only that covering span inserted. The individual spans are inserted -// (i.e. the covering span expanded) only when required by a later overlapping -// command, the hope being that that occurs infrequently, and that in the -// common case savings are made due to the reduced number of spans active in -// the tree. -// As such, the optimization makes sense for workloads in which commands -// typically contain many spans, but are spatially disjoint. -func NewCommandQueue(coveringOptimization bool) *CommandQueue { - cq := &CommandQueue{ - readsBuffer: make(map[*cmd]struct{}), - reads: interval.NewTree(interval.ExclusiveOverlapper), - writes: interval.NewTree(interval.ExclusiveOverlapper), - wRg: interval.NewRangeTree(), - rwRg: interval.NewRangeTree(), - coveringOptimization: coveringOptimization, - } - // We store a reference to each of these methods in fields on the - // CommandQueue. This allows us to pass them to Tree.DoMatching - // without allocating in getOverlaps. Passing a closure to DoMatching - // will allocate as expected, but even passing the method reference - // directly allocates. - cq.collectOverlappingReadsRef = cq.collectOverlappingReads - cq.collectOverlappingWritesRef = cq.collectOverlappingWrites - return cq -} - -// String dumps the contents of the command queue for testing. -func (cq *CommandQueue) String() string { - var buf bytes.Buffer - var keysPrinted int - const keysToPrint = 10 - f := func(i interval.Interface) bool { - fmt.Fprintf(&buf, " %s\n", i) - keysPrinted++ - return keysPrinted >= keysToPrint - } - - cq.reads.Do(f) - if keysPrinted >= keysToPrint { - fmt.Fprintf(&buf, " ...remaining %d reads omitted\n", cq.reads.Len()-keysPrinted) - } - keysPrinted = 0 - - cq.writes.Do(f) - if keysPrinted >= keysToPrint { - fmt.Fprintf(&buf, " ...remaining %d writes omitted", cq.writes.Len()-keysPrinted) - } - keysPrinted = 0 - - return buf.String() -} - -// prepareSpans ensures the spans all have an end key. Note that this function -// mutates its arguments. -func prepareSpans(spans []roachpb.Span) { - for i, span := range spans { - // This gives us a memory-efficient end key if end is empty. - if len(span.EndKey) == 0 { - span.EndKey = span.Key.Next() - span.Key = span.EndKey[:len(span.Key)] - spans[i] = span - } - } -} - -// expand replaces the command with its children, returning true if work was -// done in the process. The boolean parameter must be true if the covering span -// was previously inserted into the tree. -func (cq *CommandQueue) expand(c *cmd, isInserted bool) bool { - if c.expanded || len(c.children) == 0 { - return false - } - c.expanded = true - - tree := cq.tree(c) - if isInserted { - if err := tree.Delete(c, false /* fast */); err != nil { - panic(err) - } - } - for i := range c.children { - child := &c.children[i] - if err := tree.Insert(child, false /* fast */); err != nil { - panic(err) - } - } - return true -} - -// flushReadsBuffer moves read commands from the reads buffer to the `reads` -// interval tree. -func (cq *CommandQueue) flushReadsBuffer() { - for cmd := range cq.readsBuffer { - cmd.buffered = false - cq.insertIntoTree(cmd) - } - if len(cq.readsBuffer) > 0 { - // Allocate a new map, thereby deleting all previous entries. - cq.readsBuffer = make(map[*cmd]struct{}) - } -} - -// getPrereqs returns a slice of the prerequisite commands which overlap the -// specified key ranges. The caller should invoke add() to add the keys to the -// command queue and then wait for confirmation that all gating commands have -// completed or failed by waiting for each of their pending channels to close. -// -// readOnly is true if the requester is a read-only command; false for read-write. -// The provided timestamp, if non-zero, is used to allow reads to proceed if they -// are at earlier timestamps than pending writes, and writes to proceed if they are -// at later timestamps than pending reads. -func (cq *CommandQueue) getPrereqs( - readOnly bool, timestamp hlc.Timestamp, spans []roachpb.Span, -) (prereqs []*cmd) { - prepareSpans(spans) - - addPrereq := func(prereq *cmd) { - if prereq.pending == nil { - prereq.pending = make(chan struct{}) - } - prereqs = append(prereqs, prereq) - } - - // Loop over all spans. This cannot be a for-range loop, because the - // loop counter may be adjusted within the loop. - for i := 0; i < len(spans); i++ { - span := spans[i] - if span.EndKey == nil { - panic(fmt.Sprintf("%d: unexpected nil EndKey: %s", i, span)) - } - newCmdRange := span.AsRange() - overlaps := cq.getOverlaps(readOnly, timestamp, newCmdRange) - - // Check to see if any of the overlapping entries are "covering" - // entries. If we encounter a covering entry, we remove it from the - // interval tree and add all of its children. - restart := false - for _, c := range overlaps { - // Operand order matters: call cq.expand() for its side effects - // even if `restart` is already true. - restart = cq.expand(c, true /* isInserted */) || restart - } - if restart { - i-- - continue - } - if overlapCount := int64(len(overlaps)); overlapCount > cq.localMetrics.maxOverlapsSeen { - cq.localMetrics.maxOverlapsSeen = overlapCount - } - - // Sort overlapping commands by command ID and iterate from latest to earliest, - // adding the commands' ranges to the RangeGroup to determine gating keyspace - // command dependencies. Because all commands are given dependencies to the most - // recent commands that they are dependent on, and because of the causality provided - // by the strictly increasing command ID allocation, this approach will construct - // a DAG-like dependency graph between returned prerequisite commands with - // overlapping keys. This comes as an alternative to returning explicit prerequisite - // dependencies to all gating commands for each new command, which could result - // in an exponential dependency explosion. - // - // For example, consider the following 5 write commands, each with key ranges - // represented on the x axis and dependencies represented by vertical lines: - // - // cmd 1: -------------- - // | | - // cmd 2: | ------------- - // | | | - // cmd 3: ------- | - // | | - // cmd 4: ------- - // | - // cmd 5: ------- - // - // Instead of having each command establish explicit dependencies on all previous - // overlapping commands, each command only needs to establish explicit dependencies - // on the set of overlapping commands closest to the new command that together span - // the new command's key range. Following this strategy, the other dependencies - // will be implicitly enforced, which reduces memory utilization and synchronization - // costs. - // - // This approach is improved further by noting that dependencies on overlapping - // commands (even those that cover additional portions of the new command) that are - // transitive dependencies of commands that we have already established a dependency - // on can be safely ignored. This is safe because dependencies will be transitively - // enforced. Following this strategy, all command dependencies will be enforced - // without the need for the majority of dependencies to be held explicitly, which - // reduces memory utilization and synchronization costs. All together, the final - // dependency graph will look something like: - // - // cmd 1: -------------- - // | - // cmd 2: ------------- - // | - // cmd 3: ------- - // | - // cmd 4: ------- - // | - // cmd 5: ------- - // - // The exception are existing reads: since reads don't wait for each other, an incoming - // write must wait for reads even when they are covered by a "later" read (since that - // "later" read won't wait for the earlier read to complete). However, if that read is - // covered by a "later" write, we don't need to wait because writes can't be reordered. - // - // Two examples of how this logic works are shown below. Notice in the first example how - // the overlapping reads do not establish dependencies on each other, and can therefore - // be reordered. Also notice in the second example that once read command 4 overlaps - // a "later" write, it no longer needs to be a dependency for the new write command 5. - // However, because read command 3 does not overlap a "later" write, it is still a - // dependency for the new write, but can be safely reordered before or after command 4. - // - // cmd 1 [R]: ----- ---------- - // | | - // cmd 2 [W]: ======== ======== - // | | | | - // cmd 3 [R]: --+------ --+------ - // | | | | - // cmd 4 [R]: -------+----- -----------+----- - // | | | | - // cmd 5 [W]: ===== | | ======= | - // | | | | | - // cmd 5 [W]: ==================== ==================== - // - // Things get more interesting with timestamps: - // ------------------------------------------- - // - For a read-only command, overlaps will include only writes which have occurred - // with earlier timestamps. Because writes all must depend on each other, things - // work as expected. - // - // - Write commands overlap both reads and writes. The writes that a write command - // overlaps will depend reliably on each other if they in turn overlap. However, reads - // that a write command overlaps may not in turn be depended on by overlapping writes, - // if the reads have earlier timestamps. This means that writes don't necessarily - // subsume overlapping reads. - // - // We solve this problem by always including read commands with timestamps less than - // the latest write timestamp seen so far, which guarantees that we will wait on any - // reads which might not be dependend on by writes with higher IDs. Similarly, we - // include write commands with timestamps greater than or equal to the earliest - // read timestamp seen so far. - // - // TODO(spencer): this mechanism is a blunt instrument and will lead to reads rarely - // being consolidated because of range group overlaps. - maxWriteTS, minReadTS := hlc.Timestamp{}, hlc.MaxTimestamp - cq.oHeap.Init(overlaps) - for cq.oHeap.Len() > 0 { - cmd := cq.oHeap.PopOverlap() - keyRange := cmd.key - cmdHasTimestamp := cmd.timestamp != hlc.Timestamp{} - mustWait := false - - if cmd.readOnly { - if cmdHasTimestamp { - if cmd.timestamp.Less(minReadTS) { - minReadTS = cmd.timestamp - } - if cmd.timestamp.Less(maxWriteTS) { - mustWait = true - } - } - // If the current overlap is a read (meaning we're a write because other reads will - // be filtered out if we're a read as well), we only need to wait if the write RangeGroup - // doesn't already overlap the read. Otherwise, we know that this current read is a dependent - // itself to a command already accounted for in our write RangeGroup. Either way, we need to add - // this current command to the combined RangeGroup. - cq.rwRg.Add(keyRange) - if mustWait || !cq.wRg.Overlaps(keyRange) { - addPrereq(cmd) - } - } else { - if cmdHasTimestamp { - if maxWriteTS.Less(cmd.timestamp) { - maxWriteTS = cmd.timestamp - } - if minReadTS.Less(cmd.timestamp) { - mustWait = true - } - } - // If the current overlap is a write, pick which RangeGroup will be used to determine necessary - // dependencies based on if we are a read or write. - overlapRg := cq.wRg - if !readOnly { - // We only use the combined read-write RangeGroup when we are a new write command, because - // otherwise all read commands would have been filtered out so we can avoid using a second - // RangeGroup. Here, the previous reads rely on a distinction between a write command RangeGroup - // and an all command RangeGroup. This is so that they can avoid establishing a dependency - // if they are already dependent on previous writes, but can remain independent from other - // reads. - overlapRg = cq.rwRg - } - - // We only need to establish a dependency when this write command key range is not overlapping - // any other reads or writes in its future. If it is overlapping, we know there was already a - // dependency established with a dependent of the current overlap, meaning we already established - // an implicit transitive dependency to the current overlap. - if mustWait || !overlapRg.Overlaps(keyRange) { - addPrereq(cmd) - } - - // The current command is a write, so add it to the write RangeGroup. - cq.wRg.Add(keyRange) - - // Make sure the current command's range gets added to the combined RangeGroup if we are using it. - if overlapRg == cq.rwRg { - cq.rwRg.Add(keyRange) - } - } - } - - // Clear heap to avoid leaking anything it is currently storing. - cq.oHeap.Clear() - - // Clear the RangeGroups so that they can be used again. This is an alternative - // to using local variables that must be allocated in every iteration. - cq.wRg.Clear() - cq.rwRg.Clear() - } - return prereqs -} - -// getOverlaps returns a slice of values which overlap the specified -// interval. The slice is only valid until the next call to getOverlaps. -func (cq *CommandQueue) getOverlaps( - readOnly bool, timestamp hlc.Timestamp, rng interval.Range, -) []*cmd { - cq.readOnly = readOnly - cq.timestamp = timestamp - if !cq.readOnly { - // Upon a write cmd, flush out cmds from readsBuffer to the read interval - // tree. - cq.flushReadsBuffer() - cq.reads.DoMatching(cq.collectOverlappingReadsRef, rng) - } - // Both reads and writes must wait on other writes, depending on timestamps. - cq.writes.DoMatching(cq.collectOverlappingWritesRef, rng) - overlaps := cq.overlaps - cq.overlaps = cq.overlaps[:0] - return overlaps -} - -// collectOverlappingReads implements the tree.Operation interface. -func (cq *CommandQueue) collectOverlappingReads(i interval.Interface) bool { - c := i.(*cmd) - // Writes only wait on equal or later reads (we always wait - // if the pending read didn't have a timestamp specified). - if (c.timestamp == hlc.Timestamp{}) || !c.timestamp.Less(cq.timestamp) { - cq.overlaps = append(cq.overlaps, c) - } - return false -} - -// collectOverlappingWrites implements the tree.Operation interface. -func (cq *CommandQueue) collectOverlappingWrites(i interval.Interface) bool { - c := i.(*cmd) - // Writes always wait on other writes. Reads must wait on writes - // which occur at the same or an earlier timestamp. Note that - // timestamps for write commands may be pushed forward by the - // timestamp cache. This is fine because it doesn't matter how far - // forward the timestamp is pushed if it's already ahead of this read. - if !cq.readOnly || (cq.timestamp == hlc.Timestamp{}) || !cq.timestamp.Less(c.timestamp) { - cq.overlaps = append(cq.overlaps, c) - } - return false -} - -// overlapHeap is a max-heap ordered by cmd.id. -type overlapHeap []*cmd - -func (o overlapHeap) Len() int { return len(o) } -func (o overlapHeap) Less(i, j int) bool { - return o[i].id > o[j].id -} -func (o overlapHeap) Swap(i, j int) { o[i], o[j] = o[j], o[i] } - -func (o *overlapHeap) Push(x interface{}) { - panic("unimplemented") -} - -func (o *overlapHeap) Pop() interface{} { - n := len(*o) - 1 - x := (*o)[n] - *o = (*o)[:n] - return x -} - -func (o *overlapHeap) Init(overlaps []*cmd) { - *o = overlaps - heap.Init(o) -} - -func (o *overlapHeap) Clear() { - *o = nil -} - -func (o *overlapHeap) PopOverlap() *cmd { - x := heap.Pop(o) - return x.(*cmd) -} - -// add adds commands to the queue which affect the specified key ranges with the provided -// prerequisites, determined by getPrereqs(). Ranges without an end key affect only the -// start key. The returned command must be re-supplied on subsequent invocation of remove(). -// -// Either all supplied spans must be range-global or range-local. Failure to -// obey with this restriction results in a fatal error. -// -// Returns a nil `cmd` when no spans are given. -func (cq *CommandQueue) add( - readOnly bool, timestamp hlc.Timestamp, prereqs []*cmd, spans []roachpb.Span, -) *cmd { - if len(spans) == 0 { - return nil - } - prepareSpans(spans) - - // Compute the min and max key that covers all of the spans. - minKey, maxKey := spans[0].Key, spans[0].EndKey - for i := 1; i < len(spans); i++ { - start, end := spans[i].Key, spans[i].EndKey - if minKey.Compare(start) > 0 { - minKey = start - } - if maxKey.Compare(end) < 0 { - maxKey = end - } - } - coveringSpan := roachpb.Span{ - Key: minKey, - EndKey: maxKey, - } - - if keys.IsLocal(minKey) != keys.IsLocal(maxKey) { - log.Fatalf( - context.TODO(), - "mixed range-global and range-local keys: %s and %s", - minKey, maxKey, - ) - } - - numCmds := 1 - if len(spans) > 1 { - numCmds += len(spans) - } - cmds := make([]cmd, numCmds) - - // Create the covering entry. - cmd := &cmds[0] - cmd.id = cq.nextID() - cmd.key = coveringSpan.AsRange() - cmd.readOnly = readOnly - cmd.timestamp = timestamp - cmd.prereqsBuf = prereqs - cmd.prereqs = &cmd.prereqsBuf - - cmd.expanded = false - if len(spans) > 1 { - // Populate the covering entry's children. - cmd.children = cmds[1:] - for i, span := range spans { - child := &cmd.children[i] - child.id = cq.nextID() - child.key = span.AsRange() - child.readOnly = readOnly - child.timestamp = timestamp - child.prereqs = &cmd.prereqsBuf - - child.expanded = true - } - } - - if cmd.readOnly { - cq.localMetrics.readCommands += int64(cmd.cmdCount()) - } else { - cq.localMetrics.writeCommands += int64(cmd.cmdCount()) - } - - // Insert a readOnly command into the readsBuffer instead of mutating the - // interval tree. - if cmd.readOnly { - cmd.buffered = true - cq.readsBuffer[cmd] = struct{}{} - return cmd - } - - cq.insertIntoTree(cmd) - return cmd -} - -func (cq *CommandQueue) insertIntoTree(cmd *cmd) { - if cq.coveringOptimization || len(cmd.children) == 0 { - tree := cq.tree(cmd) - if err := tree.Insert(cmd, false /* fast */); err != nil { - panic(err) - } - } else { - cq.expand(cmd, false /* isInserted */) - } -} - -// remove is invoked to signal that the command associated with the -// specified key has completed and should be removed. Any pending -// commands waiting on this command will be signaled if this is the -// only command upon which they are still waiting. -// -// Removing a `nil` cmd is a no-op. -func (cq *CommandQueue) remove(cmd *cmd) { - if cmd == nil { - return - } - - if cmd.readOnly { - cq.localMetrics.readCommands -= int64(cmd.cmdCount()) - } else { - cq.localMetrics.writeCommands -= int64(cmd.cmdCount()) - } - - // If cmd is buffered, just remove it from readsBuffer and be done. - if cmd.buffered { - if _, ok := cq.readsBuffer[cmd]; !ok { - panic(fmt.Sprintf("buffered cmd %d not found in readsBuffer", cmd.id)) - } - delete(cq.readsBuffer, cmd) - // Nobody can be waiting on a buffered read, assert that its channel is nil - if cmd.pending != nil { - panic(fmt.Sprintf("buffered cmd %d has non-nil pending chan", cmd.id)) - } - return - } - - tree := cq.tree(cmd) - if !cmd.expanded { - n := tree.Len() - if err := tree.Delete(cmd, false /* fast */); err != nil { - panic(err) - } - if d := n - tree.Len(); d != 1 { - panic(fmt.Sprintf("%d: expected 1 deletion, found %d", cmd.id, d)) - } - if ch := cmd.pending; ch != nil { - close(ch) - } - } else { - for i := range cmd.children { - child := &cmd.children[i] - n := tree.Len() - if err := tree.Delete(child, false /* fast */); err != nil { - panic(err) - } - if d := n - tree.Len(); d != 1 { - panic(fmt.Sprintf("%d: expected 1 deletion, found %d", child.id, d)) - } - if ch := child.pending; ch != nil { - close(ch) - } - } - } -} - -func (cq *CommandQueue) tree(c *cmd) interval.Tree { - if c.readOnly { - return cq.reads - } - return cq.writes -} - -func (cq *CommandQueue) nextID() int64 { - cq.idAlloc++ - return cq.idAlloc -} - -func (cq *CommandQueue) treeSize() int { - return cq.reads.Len() + cq.writes.Len() -} - -// CommandQueueMetrics holds the metrics for a the command queue that are -// included in range metrics. -// TODO(bram): replace this struct with serverpb.CommandQueueMetrics. This -// will require moveing all protos out of storage into storagebase that are -// referenced in serverpb to prevent an import cycle. -type CommandQueueMetrics struct { - WriteCommands int64 - ReadCommands int64 - MaxOverlapsSeen int64 - TreeSize int32 -} - -func (cq *CommandQueue) metrics() CommandQueueMetrics { - return CommandQueueMetrics{ - WriteCommands: cq.localMetrics.writeCommands, - ReadCommands: cq.localMetrics.readCommands, - MaxOverlapsSeen: cq.localMetrics.maxOverlapsSeen, - TreeSize: int32(cq.treeSize()), - } -} - -// CommandQueueSnapshot is a map from command ids to commands. -type CommandQueueSnapshot map[int64]storagepb.CommandQueuesSnapshot_Command - -// GetSnapshot returns a snapshot of this command queue's state. -func (cq *CommandQueue) GetSnapshot() CommandQueueSnapshot { - // Before taking the snapshot, ensure all commands have been flushed into - // the interval trees. - cq.flushReadsBuffer() - commandMap := make(CommandQueueSnapshot) - commandMap.addCommandsFromTree(cq.reads) - commandMap.addCommandsFromTree(cq.writes) - commandMap.filterNonexistentPrereqs() - return commandMap -} - -func (cqs CommandQueueSnapshot) addCommandsFromTree(tree interval.Tree) { - tree.Do(func(item interval.Interface) (done bool) { - currentCmd := item.(*cmd) - cqs.addCommand(*currentCmd) - return false - }) -} - -// addCommand adds all leaf commands to the snapshot. This is done by -// either adding the given command if it's a leaf, or recursively calling -// itself on the given command's children. -func (cqs CommandQueueSnapshot) addCommand(command cmd) { - if len(command.children) > 0 { - for i := range command.children { - cqs.addCommand(command.children[i]) - } - return - } - - commandProto := storagepb.CommandQueuesSnapshot_Command{ - Id: command.id, - Readonly: command.readOnly, - Timestamp: command.timestamp, - Key: roachpb.Key(command.key.Start).String(), - EndKey: roachpb.Key(command.key.End).String(), - } - for _, prereqCmd := range *command.prereqs { - commandProto.Prereqs = append(commandProto.Prereqs, prereqCmd.id) - } - cqs[command.id] = commandProto -} - -// filterNonexistentPrereqs removes prereqs which point at commands that -// are no longer in the queue. For example, if command C has prereqs -// A and B, but B finishes and is removed from the queue while C is still -// waiting on A, this function will remove the edge from C to B. -func (cqs CommandQueueSnapshot) filterNonexistentPrereqs() { - for _, command := range cqs { - filteredPrereqs := make([]int64, 0, len(command.Prereqs)) - for _, prereq := range command.Prereqs { - if _, ok := cqs[prereq]; ok { - filteredPrereqs = append(filteredPrereqs, prereq) - } - } - command.Prereqs = filteredPrereqs - cqs[command.Id] = command - } -} diff --git a/pkg/storage/command_queue_test.go b/pkg/storage/command_queue_test.go deleted file mode 100644 index 0ff1e1d2208a..000000000000 --- a/pkg/storage/command_queue_test.go +++ /dev/null @@ -1,878 +0,0 @@ -// Copyright 2014 The Cockroach Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. - -package storage - -import ( - "bytes" - "fmt" - "math/rand" - "reflect" - "testing" - "time" - - "github.com/cockroachdb/cockroach/pkg/roachpb" - "github.com/cockroachdb/cockroach/pkg/util/hlc" - "github.com/cockroachdb/cockroach/pkg/util/leaktest" - "github.com/cockroachdb/cockroach/pkg/util/syncutil" -) - -var zeroTS = hlc.Timestamp{} - -func getPrereqs(cq *CommandQueue, from, to roachpb.Key, readOnly bool) []*cmd { - return cq.getPrereqs(readOnly, zeroTS, []roachpb.Span{{Key: from, EndKey: to}}) -} - -func add(cq *CommandQueue, from, to roachpb.Key, readOnly bool, prereqs []*cmd) *cmd { - return cq.add(readOnly, zeroTS, prereqs, []roachpb.Span{{Key: from, EndKey: to}}) -} - -func getPrereqsAndAdd(cq *CommandQueue, from, to roachpb.Key, readOnly bool) ([]*cmd, *cmd) { - prereqs := getPrereqs(cq, from, to, readOnly) - return prereqs, add(cq, from, to, readOnly, prereqs) -} - -func waitCmdDone(prereqs []*cmd) { - for _, prereq := range prereqs { - <-prereq.pending - } -} - -// testCmdDone waits for the prereqs' pending channels to be closed for at -// most the specified wait duration. Returns true if the command finished in -// the allotted time, false otherwise. -func testCmdDone(prereqs []*cmd, wait time.Duration) bool { - t := time.After(wait) - for _, prereq := range prereqs { - select { - case <-t: - return false - case <-prereq.pending: - } - } - return true -} - -// checkCmdDoesNotFinish makes sure that the command waiting on the provided channels -// does not finish, returning false if this assertion fails. -func checkCmdDoesNotFinish(prereqs []*cmd) bool { - return !testCmdDone(prereqs, 3*time.Millisecond) -} - -// checkCmdFinishes makes sure that the command waiting on the provided channels -// finishes, returning false if this assertion fails. -func checkCmdFinishes(prereqs []*cmd) bool { - return testCmdDone(prereqs, 15*time.Millisecond) -} - -func TestCommandQueue(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - // Try a command with no overlapping already-running commands. - waitCmdDone(getPrereqs(cq, roachpb.Key("a"), nil, false)) - waitCmdDone(getPrereqs(cq, roachpb.Key("a"), roachpb.Key("b"), false)) - - // Add a command and verify dependency on it. - cmd1 := add(cq, roachpb.Key("a"), nil, false, nil) - prereqs := getPrereqs(cq, roachpb.Key("a"), nil, false) - if !checkCmdDoesNotFinish(prereqs) { - t.Fatal("command should not finish with command outstanding") - } - cq.remove(cmd1) - if !checkCmdFinishes(prereqs) { - t.Fatal("command should finish with no commands outstanding") - } -} - -// TestCommandQueueWriteWaitForNonAdjacentRead tests that the command queue -// lets a writer wait for a read which is separated from it through another -// read. Since reads don't wait for reads, there was a bug in which the writer -// would wind up waiting only for one of the two readers under it. -func TestCommandQueueWriteWaitForNonAdjacentRead(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - key := roachpb.Key("a") - // Add a read-only command. - cmd1 := add(cq, key, nil, true, nil) - // Add another one on top. - cmd2 := add(cq, key, nil, true, nil) - - // A write should have to wait for **both** reads, not only the second - // one. - prereqs := getPrereqs(cq, key, nil, false /* readOnly */) - - // Certainly blocks now. - if !checkCmdDoesNotFinish(prereqs) { - t.Fatal("command should not finish with command outstanding") - } - - // The second read returns, but the first one remains. - cq.remove(cmd2) - - // Should still block. This being broken is why this test exists. - if !checkCmdDoesNotFinish(prereqs) { - t.Fatal("command should not finish with command outstanding") - } - - // First read returns. - cq.remove(cmd1) - - // Now it goes through. - if !checkCmdFinishes(prereqs) { - t.Fatal("command should finish with no commands outstanding") - } -} - -func TestCommandQueueNoWaitOnReadOnly(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - // Add a read-only command. - prereqs1, cmd1 := getPrereqsAndAdd(cq, roachpb.Key("a"), nil, true) - // Verify no wait on another read-only command. - waitCmdDone(prereqs1) - // Verify wait with a read-write command. - prereqs2 := getPrereqs(cq, roachpb.Key("a"), nil, false) - if !checkCmdDoesNotFinish(prereqs2) { - t.Fatal("command should not finish with command outstanding") - } - cq.remove(cmd1) - if !checkCmdFinishes(prereqs2) { - t.Fatal("command should finish with no commands outstanding") - } -} - -func TestCommandQueueMultipleExecutingCommands(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - // Add multiple commands and add a command which overlaps them all. - cmd1 := add(cq, roachpb.Key("a"), nil, false, nil) - cmd2 := add(cq, roachpb.Key("b"), roachpb.Key("c"), false, nil) - cmd3 := add(cq, roachpb.Key("0"), roachpb.Key("d"), false, nil) - prereqs := getPrereqs(cq, roachpb.Key("a"), roachpb.Key("cc"), false) - cq.remove(cmd1) - if !checkCmdDoesNotFinish(prereqs) { - t.Fatal("command should not finish with two commands outstanding") - } - cq.remove(cmd2) - if !checkCmdDoesNotFinish(prereqs) { - t.Fatal("command should not finish with one command outstanding") - } - cq.remove(cmd3) - if !checkCmdFinishes(prereqs) { - t.Fatal("command should finish with no commands outstanding") - } -} - -func TestCommandQueueMultiplePendingCommands(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - // Add a command which will overlap all commands. - wk0 := add(cq, roachpb.Key("a"), roachpb.Key("d"), false, nil) - prereqs1, cmd1 := getPrereqsAndAdd(cq, roachpb.Key("a"), roachpb.Key("b").Next(), false) - prereqs2 := getPrereqs(cq, roachpb.Key("b"), nil, false) - prereqs3 := getPrereqs(cq, roachpb.Key("c"), nil, false) - - for i, prereqs := range [][]*cmd{prereqs1, prereqs2, prereqs3} { - if !checkCmdDoesNotFinish(prereqs) { - t.Fatalf("command %d should not finish with command 0 outstanding", i+1) - } - } - - cq.remove(wk0) - if !checkCmdFinishes(prereqs1) { - t.Fatal("command 1 should finish") - } - if !checkCmdFinishes(prereqs3) { - t.Fatal("command 3 should finish") - } - if !checkCmdDoesNotFinish(prereqs2) { - t.Fatal("command 2 should remain outstanding") - } - cq.remove(cmd1) - if !checkCmdFinishes(prereqs2) { - t.Fatal("command 2 should finish with no commands outstanding") - } -} - -func TestCommandQueueRemove(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - // Add multiple commands and commands which access each. - cmd1 := add(cq, roachpb.Key("a"), nil, false, nil) - cmd2 := add(cq, roachpb.Key("b"), nil, false, nil) - prereqs1 := getPrereqs(cq, roachpb.Key("a"), nil, false) - prereqs2 := getPrereqs(cq, roachpb.Key("b"), nil, false) - - // Remove the commands from the queue and verify both commands are signaled. - cq.remove(cmd1) - cq.remove(cmd2) - - for i, prereqs := range [][]*cmd{prereqs1, prereqs2} { - if !checkCmdFinishes(prereqs) { - t.Fatalf("command %d should finish with clearing queue", i+1) - } - } -} - -// TestCommandQueueExclusiveEnd verifies that an end key is treated as -// an exclusive end when GetPrereqs calculates overlapping commands. Test -// it by calling GetPrereqs with a command whose start key is equal to -// the end key of a previous command. -func TestCommandQueueExclusiveEnd(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - add(cq, roachpb.Key("a"), roachpb.Key("b"), false, nil) - - // Verify no wait on the second writer command on "b" since - // it does not overlap with the first command on ["a", "b"). - waitCmdDone(getPrereqs(cq, roachpb.Key("b"), nil, false)) -} - -// TestCommandQueueSelfOverlap makes sure that GetPrereqs adds all of the -// key ranges simultaneously. If that weren't the case, all but the first -// span would wind up waiting on overlapping previous spans, resulting -// in deadlock. -func TestCommandQueueSelfOverlap(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - a := roachpb.Key("a") - cmd := add(cq, a, roachpb.Key("b"), false, nil) - prereqs := cq.getPrereqs(false, zeroTS, []roachpb.Span{{Key: a}, {Key: a}, {Key: a}}) - cq.remove(cmd) - waitCmdDone(prereqs) -} - -func TestCommandQueueCoveringOptimization(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - a := roachpb.Key("a") - b := roachpb.Key("b") - c := roachpb.Key("c") - - { - // Test adding a covering entry and then not expanding it. - cmd := add(cq, a, b, false, nil) - if n := cq.treeSize(); n != 1 { - t.Fatalf("expected a single covering span, but got %d", n) - } - waitCmdDone(getPrereqs(cq, c, nil, false)) - cq.remove(cmd) - } - - { - // Test adding a covering entry and expanding it. - cmd := add(cq, a, b, false, nil) - prereqs := getPrereqs(cq, a, nil, false) - cq.remove(cmd) - waitCmdDone(prereqs) - } -} - -func TestCommandQueueWithoutCoveringOptimization(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(false /* coveringOptimization */) - - a := roachpb.Span{Key: roachpb.Key("a")} - b := roachpb.Span{Key: roachpb.Key("b")} - c := roachpb.Span{Key: roachpb.Key("c")} - - { - cmd := cq.add(false, zeroTS, nil, []roachpb.Span{a, b}) - if !cmd.expanded { - t.Errorf("expected non-expanded command, not %+v", cmd) - } - if exp, act := 2, len(cmd.children); exp != act { - t.Errorf("expected %d children in command, got %d: %+v", exp, act, cmd) - } - if exp, act := 2, cq.treeSize(); act != exp { - t.Errorf("expected %d spans in tree, got %d", exp, act) - } - cq.remove(cmd) - } - - { - cmd := cq.add(false, zeroTS, nil, []roachpb.Span{c}) - if cmd.expanded { - t.Errorf("expected unexpanded command, not %+v", cmd) - } - if len(cmd.children) != 0 { - t.Errorf("expected no children in command %+v", cmd) - } - if act, exp := cq.treeSize(), 1; act != exp { - t.Errorf("expected %d spans in tree, got %d", exp, act) - } - cq.remove(cmd) - } -} - -func mkSpan(start, end string) roachpb.Span { - if len(end) == 0 { - return roachpb.Span{Key: roachpb.Key(start)} - } - return roachpb.Span{Key: roachpb.Key(start), EndKey: roachpb.Key(end)} -} - -func randBytes(n int) []byte { - b := make([]byte, n) - _, err := rand.Read(b) - if err != nil { - panic(err) - } - return b -} - -// Reconstruct a set of commands that tickled a bug in interval.Tree. See -// https://github.com/cockroachdb/cockroach/issues/6495 for details. -func TestCommandQueueIssue6495(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - cq.idAlloc = 1997 - - spans1998 := []roachpb.Span{ - mkSpan("\xbb\x89\x8b\x8a\x89", "\xbb\x89\x8b\x8a\x89\x00"), - } - spans1999 := []roachpb.Span{ - mkSpan("\xbb\x89\x88", "\xbb\x89\x89"), - mkSpan("\xbb\x89\x8b", "\xbb\x89\x8c"), - } - spans2002 := []roachpb.Span{ - mkSpan("\xbb\x89\x8b", "\xbb\x89\x8c"), - } - spans2003 := []roachpb.Span{ - mkSpan("\xbb\x89\x8a\x8a\x89", "\xbb\x89\x8a\x8a\x89\x00"), - mkSpan("\xbb\x89\x8b\x8a\x89", "\xbb\x89\x8b\x8a\x89\x00"), - mkSpan("\xbb\x89\x8a\x8a\x89", "\xbb\x89\x8a\x8a\x89\x00"), - } - - cq.getPrereqs(false, zeroTS, spans1998) - cmd1998 := cq.add(false, zeroTS, nil, spans1998) - - cq.getPrereqs(true, zeroTS, spans1999) - cmd1999 := cq.add(true, zeroTS, nil, spans1999) - - cq.getPrereqs(true, zeroTS, spans2002) - cq.add(true, zeroTS, nil, spans2002) - - cq.getPrereqs(false, zeroTS, spans2003) - cq.add(false, zeroTS, nil, spans2003) - - cq.remove(cmd1998) - cq.remove(cmd1999) -} - -// TestCommandQueueTimestamps creates a command queue with a mix of -// read and write spans and verifies that writes don't wait on -// earlier reads and reads don't wait on later writes. The spans -// are layered as follows (earlier spans have earlier timestamps): -// -// Span TS RO a b c d e f g -// 1 1 T ------ - -// 2 2 F - -// 3 3 F - ------ -// 4 4 T ------ -func TestCommandQueueTimestamps(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - spans1 := []roachpb.Span{ - mkSpan("a", "c"), - mkSpan("d", ""), - } - spans2 := []roachpb.Span{ - mkSpan("b", ""), - } - spans3 := []roachpb.Span{ - mkSpan("c", ""), - mkSpan("d", "f"), - } - spans4 := []roachpb.Span{ - mkSpan("e", "g"), - } - - cmd1 := cq.add(true, makeTS(1, 0), nil, spans1) - - pre2 := cq.getPrereqs(true, makeTS(2, 0), spans2) - if pre2 != nil { - t.Errorf("expected nil prereq slice; got %+v", pre2) - } - cmd2 := cq.add(false, makeTS(2, 0), pre2, spans2) - - pre3 := cq.getPrereqs(true, makeTS(3, 0), spans3) - if pre3 != nil { - t.Errorf("expected nil prereq slice; got %+v", pre3) - } - cmd3 := cq.add(false, makeTS(3, 0), pre3, spans3) - - // spans4 should wait on spans3.children[1]. - pre4 := cq.getPrereqs(true, makeTS(4, 0), spans4) - expPre := []*cmd{&cmd3.children[1]} - if !reflect.DeepEqual(expPre, pre4) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre4) - } - cmd4 := cq.add(true, makeTS(4, 0), pre4, spans4) - - // Verify that an earlier writer for whole span waits on all commands. - pre5 := cq.getPrereqs(false, makeTS(0, 1), []roachpb.Span{mkSpan("a", "g")}) - allCmds := []*cmd{ - cmd4, - // Skip cmd3.children[1] here because it's a dependency. - &cmd3.children[0], - cmd2, - &cmd1.children[1], - &cmd1.children[0], - } - expPre = allCmds - if !reflect.DeepEqual(expPre, pre5) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre5) - } - - // Verify that a later writer for whole span. At the same - // timestamp, we wait on the latest read. - expPre = []*cmd{cmd4, &cmd3.children[0], cmd2} - if pre := cq.getPrereqs(false, makeTS(4, 0), []roachpb.Span{mkSpan("a", "g")}); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - // At +1 logical tick, we skip the latest read and instead - // read the overlapped write just beneath the latest read. - expPre = []*cmd{&cmd3.children[1], &cmd3.children[0], cmd2} - if pre := cq.getPrereqs(false, makeTS(4, 1), []roachpb.Span{mkSpan("a", "g")}); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - - // Verify an earlier reader for whole span doesn't wait. - if pre := cq.getPrereqs(true, makeTS(0, 1), []roachpb.Span{mkSpan("a", "g")}); pre != nil { - t.Errorf("expected nil prereq command; got %+v", pre) - } - - // Verify a later reader for whole span waits on both writers. - expPre = []*cmd{&cmd3.children[1], &cmd3.children[0], cmd2} - if pre := cq.getPrereqs(true, makeTS(4, 0), []roachpb.Span{mkSpan("a", "g")}); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - - // Verify that if no timestamp is specified, we always wait (on writers and readers!). - expPre = allCmds - if pre := cq.getPrereqs(false, hlc.Timestamp{}, []roachpb.Span{mkSpan("a", "g")}); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - expPre = []*cmd{&cmd3.children[1], &cmd3.children[0], cmd2} - if pre := cq.getPrereqs(true, hlc.Timestamp{}, []roachpb.Span{mkSpan("a", "g")}); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } -} - -// TestCommandQueueEnclosedRead verifies that the command queue doesn't -// fail to return read-only dependencies that a candidate read/write -// span depends on, despite there being an overlapping span read/write -// which completely encloses the candidate. See #14434. -// -// Span TS RO a b depends -// 1 2 T - n/a -// 2 3 F --- n/a -// Candidate 1 F - spans 1, 2 -func TestCommandQueueEnclosedRead(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - spans1 := []roachpb.Span{ - mkSpan("a", ""), - } - spans2 := []roachpb.Span{ - mkSpan("a", "b"), - } - spansCandidate := []roachpb.Span{ - mkSpan("a", ""), - } - - // Add command 1. - cmd1 := cq.add(true, makeTS(2, 0), nil, spans1) - - // Add command 2. - pre := cq.getPrereqs(false, makeTS(3, 0), spans2) - if expPre := []*cmd(nil); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - cmd2 := cq.add(false, makeTS(3, 0), pre, spans2) - - // Add command 3. - pre = cq.getPrereqs(false, makeTS(1, 0), spansCandidate) - if expPre := []*cmd{cmd2, cmd1}; !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } -} - -// TestCommandQueueEnclosedWrite verifies that the command queue doesn't -// fail to return read/write dependencies that a candidate read/write -// span depends on, despite there being an overlapping read-only span -// which completely encloses the candidate. -// -// Span TS RO a b depends -// 1 3 F - n/a -// 2 2 T --- n/a -// Candidate 1 F - spans 1, 2 -func TestCommandQueueEnclosedWrite(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - spans1 := []roachpb.Span{ - mkSpan("a", ""), - } - spans2 := []roachpb.Span{ - mkSpan("a", "b"), - } - spansCandidate := []roachpb.Span{ - mkSpan("a", ""), - } - - // Add command 1. - cmd1 := cq.add(false, makeTS(3, 0), nil, spans1) - - // Add command 2. - pre := cq.getPrereqs(true, makeTS(2, 0), spans2) - if expPre := []*cmd(nil); !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - cmd2 := cq.add(true, makeTS(2, 0), nil, spans2) - - // Add command 3. - pre = cq.getPrereqs(false, makeTS(1, 0), spansCandidate) - if expPre := []*cmd{cmd2, cmd1}; !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } -} - -// TestCommandQueueTimestampsEmpty verifies command queue wait -// behavior when added commands have zero timestamps and when -// the waiter has a zero timestamp. -func TestCommandQueueTimestampsEmpty(t *testing.T) { - defer leaktest.AfterTest(t)() - cq := NewCommandQueue(true) - - spansR := []roachpb.Span{ - mkSpan("a", "c"), - } - spansW := []roachpb.Span{ - mkSpan("d", "f"), - } - spansRTS := []roachpb.Span{ - mkSpan("g", ""), - } - spansWTS := []roachpb.Span{ - mkSpan("h", ""), - } - - cmd1 := cq.add(true, zeroTS, nil, spansR) - cmd2 := cq.add(false, zeroTS, nil, spansW) - cmd3 := cq.add(true, makeTS(1, 0), nil, spansRTS) - cmd4 := cq.add(false, makeTS(1, 0), nil, spansWTS) - - // A writer will depend on both zero-timestamp spans. - pre := cq.getPrereqs(false, makeTS(1, 0), []roachpb.Span{mkSpan("a", "f")}) - expPre := []*cmd{cmd2, cmd1} - if !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - - // A reader will depend on the write span. - pre = cq.getPrereqs(true, makeTS(1, 0), []roachpb.Span{mkSpan("a", "f")}) - expPre = []*cmd{cmd2} - if !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - - // A zero-timestamp writer will depend on both ts=1 spans. - pre = cq.getPrereqs(false, hlc.Timestamp{}, []roachpb.Span{mkSpan("g", "i")}) - expPre = []*cmd{cmd4, cmd3} - if !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } - - // A zero-timestamp reader will depend on the write span. - pre = cq.getPrereqs(true, hlc.Timestamp{}, []roachpb.Span{mkSpan("g", "i")}) - expPre = []*cmd{cmd4} - if !reflect.DeepEqual(expPre, pre) { - t.Errorf("expected prereq commands %+v; got %+v", expPre, pre) - } -} - -// cmdOps holds options for commands inserted into the CommandQueue. -type cmdOps struct { - readOnly bool - ts hlc.Timestamp - spans []roachpb.Span -} - -func (ops cmdOps) String() string { - var b bytes.Buffer - if ops.readOnly { - b.WriteByte('R') - } else { - b.WriteByte('W') - } - fmt.Fprint(&b, ops.ts.WallTime) - fmt.Fprint(&b, ops.spans) - return b.String() -} - -// TestCommandQueueTransitiveDependencies verifies that if a dependency relation -// between commands inserted into the CommandQueue should exist, it is always -// transitively maintained even if other commands are inserted between them. This -// is important because the transitive dependency relation is required for the -// correctness of certain optimizations performed by the CommandQueue, as well as -// by our approach to command cancellation and prerequisite migration. -// -// In effect, this means that as more commands are added to the dependency graph, -// dependencies will always either be maintained directly or transitively through -// other commands. This does not assert that we maintain the minimal set of -// dependencies, but instead asserts that the addition of new commands never -// results in a loss of dependency information that could allow for a loss of -// serializability. -func TestCommandQueueTransitiveDependencies(t *testing.T) { - defer leaktest.AfterTest(t)() - - spansAB := []roachpb.Span{ - mkSpan("a", "b"), - } - spansAC := []roachpb.Span{ - mkSpan("a", "c"), - } - spansBC := []roachpb.Span{ - mkSpan("b", "c"), - } - - // forEachCmdOpsPerm calls the provided closure in a subtest for each permutation - // of different command options. - forEachCmdOpsPerm := func(t *testing.T, f func(*testing.T, cmdOps)) { - for _, readOnly := range []bool{false, true} { - for _, ts := range []hlc.Timestamp{zeroTS, makeTS(1, 0), makeTS(2, 0)} { - for _, spans := range [][]roachpb.Span{spansAB, spansAC, spansBC} { - f(t, cmdOps{readOnly: readOnly, ts: ts, spans: spans}) - } - } - } - } - - // Permute over all possible options for three different commands. - forEachCmdOpsPerm(t, func(t *testing.T, ops1 cmdOps) { - forEachCmdOpsPerm(t, func(t *testing.T, ops2 cmdOps) { - forEachCmdOpsPerm(t, func(t *testing.T, ops3 cmdOps) { - // First we add only the first and third command and test - // whether the third depends on the first. This will - // tell us whether a transitive relation should be expected. - { - cq := NewCommandQueue(true) - - cq.add(ops1.readOnly, ops1.ts, nil, ops1.spans) - - pre3 := cq.getPrereqs(ops3.readOnly, ops3.ts, ops3.spans) - if expectDependency := len(pre3) > 0; !expectDependency { - // Adding a new command between two independent commands - // can result in all three becoming dependent. For instance, - // adding a write between two reads. This means that we can't - // assert that no dependency will later exist in the case - // where we see none before, so we have nothing to test here. - return - } - } - - // Next we add all three commands to the command queue and - // verify that a dependency still exists between the first - // and third command. - { - cq := NewCommandQueue(true) - - // Add command 1. - cmd1 := cq.add(ops1.readOnly, ops1.ts, nil, ops1.spans) - - // Add command 2, taking note of whether it depends on command 1. - pre2 := cq.getPrereqs(ops2.readOnly, ops2.ts, ops2.spans) - dependency2to1 := len(pre2) > 0 - cmd2 := cq.add(ops2.readOnly, ops2.ts, pre2, ops2.spans) - - // Add command 3, taking note of whether it depends on command 1 - // or on command 2. - pre3 := cq.getPrereqs(ops3.readOnly, ops3.ts, ops3.spans) - pre3Set := make(map[*cmd]struct{}, len(pre3)) - for _, prereq := range pre3 { - pre3Set[prereq] = struct{}{} - } - _, dependency3to1 := pre3Set[cmd1] - _, dependency3to2 := pre3Set[cmd2] - - // Assert that a dependency still exists between command 3 - // and command 1, either directly or through command 2. - if !(dependency3to1 || (dependency3to2 && dependency2to1)) { - t.Errorf("1=%s, 2=%s, 3=%s: expected transitive dependency, found: "+ - "3->1=%t, 2->1=%t, 3->2=%t", ops1, ops2, ops2, - dependency3to1, dependency2to1, dependency3to2) - } - } - }) - }) - }) -} - -// TestCommandQueueGetSnapshotWithReadBuffer commands in the read buffer are -// returned in the snapshot. -func TestCommandQueueGetSnapshotWithReadBuffer(t *testing.T) { - defer leaktest.AfterTest(t)() - - // test that read command buffer is flushed to interval tree - cq := NewCommandQueue(true /* covering optimization */) - add(cq, roachpb.Key("a"), nil, true, nil) - add(cq, roachpb.Key("a"), nil, true, nil) - - snapshot := cq.GetSnapshot() - - assertExpectedPrereqs(t, snapshot, map[int64][]int64{ - 1: {}, - 2: {}, - }) -} - -// TestCommandQueueGetSnapshotWithChildren verifies that child commands are -// returned in the snapshot. -func TestCommandQueueGetSnapshotWithChildren(t *testing.T) { - defer leaktest.AfterTest(t)() - - cq := NewCommandQueue(true /* covering optimization */) - cmd1 := add(cq, roachpb.Key("a"), nil, false, nil) - cmd2 := add(cq, roachpb.Key("a"), nil, true, []*cmd{cmd1}) - // the following creates a node with two children because it has two spans - // only the children show up in the snapshot. - cq.add(true, zeroTS, []*cmd{cmd2}, []roachpb.Span{ - {Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}, - {Key: roachpb.Key("d"), EndKey: roachpb.Key("f")}, - }) - - snapshot := cq.GetSnapshot() - - assertExpectedPrereqs(t, snapshot, map[int64][]int64{ - 1: {}, - 2: {1}, - 4: {2}, - 5: {2}, - }) -} - -func TestCommandQueueGetSnapshotWithDisappearingPrereq(t *testing.T) { - defer leaktest.AfterTest(t)() - - cq := NewCommandQueue(true /* covering optimization */) - cmd1 := add(cq, roachpb.Key("a"), nil, false, nil) - cmdNotInQueue := &cmd{ - id: 55, - } - add(cq, roachpb.Key("b"), nil, false, []*cmd{cmd1, cmdNotInQueue}) - - snapshot := cq.GetSnapshot() - - assertExpectedPrereqs(t, snapshot, map[int64][]int64{ - 1: {}, - 2: {1}, - }) -} - -func assertExpectedPrereqs( - t *testing.T, snapshot CommandQueueSnapshot, expectedPrereqs map[int64][]int64, -) { - if len(snapshot) != len(expectedPrereqs) { - t.Fatalf("expected %d commands; got %d", len(expectedPrereqs), len(snapshot)) - } - for commandID, expectedPrereqs := range expectedPrereqs { - command, ok := snapshot[commandID] - if !ok { - t.Fatalf("expected command with id %v; none returned", commandID) - } - if !reflect.DeepEqual(expectedPrereqs, command.Prereqs) { - t.Fatalf("expected commands[%v].Prereqs to be %v, got %v", commandID, expectedPrereqs, command.Prereqs) - } - } -} - -func BenchmarkCommandQueueReadOnlyMix(b *testing.B) { - // Test read-only getPrereqs performance for various number of command queue - // entries. See #13627 where a previous implementation of - // CommandQueue.getOverlaps had O(n) performance in this setup. Since reads - // do not wait on other reads, expected performance is O(1). - for _, size := range []int{1, 4, 16, 64, 128, 256} { - b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) { - var mu syncutil.Mutex - cq := NewCommandQueue(true) - spans := []roachpb.Span{{ - Key: roachpb.Key("aaaaaaaaaa"), - EndKey: roachpb.Key("aaaaaaaaab"), - }} - for i := 0; i < size; i++ { - cq.add(true, zeroTS, nil, spans) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - mu.Lock() - prereqs := cq.getPrereqs(true, zeroTS, spans) - cq.add(true, zeroTS, prereqs, spans) - mu.Unlock() - } - }) - } -} - -func BenchmarkCommandQueueReadWriteMix(b *testing.B) { - // Test performance with a mixture of reads and writes with a high number - // of reads per write. - // See #15544. - for _, readsPerWrite := range []int{0, 1, 4, 16, 64, 128, 256} { - b.Run(fmt.Sprintf("readsPerWrite=%d", readsPerWrite), func(b *testing.B) { - var mu syncutil.Mutex - cq := NewCommandQueue(true /* coveringOptimization */) - liveCmdQueue := make(chan *cmd, 16) - - spans := make([][]roachpb.Span, b.N) - for i := range spans { - a, b := randBytes(100), randBytes(100) - // Overwrite first byte so that we do not mix local and global ranges - a[0], b[0] = 'a', 'a' - if bytes.Compare(a, b) > 0 { - a, b = b, a - } - spans[i] = []roachpb.Span{{ - Key: roachpb.Key(a), - EndKey: roachpb.Key(b), - }} - } - - b.ResetTimer() - for i := range spans { - mu.Lock() - readOnly := i%(readsPerWrite+1) != 0 - prereqs := cq.getPrereqs(readOnly, zeroTS, spans[i]) - cmd := cq.add(readOnly, zeroTS, prereqs, spans[i]) - mu.Unlock() - - if len(liveCmdQueue) == cap(liveCmdQueue) { - mu.Lock() - cq.remove(<-liveCmdQueue) - mu.Unlock() - } - liveCmdQueue <- cmd - } - }) - } -} diff --git a/pkg/storage/metrics.go b/pkg/storage/metrics.go index 97fdf70dbf70..7a4d02c876c3 100644 --- a/pkg/storage/metrics.go +++ b/pkg/storage/metrics.go @@ -66,57 +66,6 @@ var ( Unit: metric.Unit_COUNT, } - // Replica CommandQueue metrics. Max size metrics track the maximum value - // seen for all replicas during a single replica scan. - metaMaxCommandQueueSize = metric.Metadata{ - Name: "replicas.commandqueue.maxsize", - Help: "Largest number of commands in any CommandQueue", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - metaMaxCommandQueueWriteCount = metric.Metadata{ - Name: "replicas.commandqueue.maxwritecount", - Help: "Largest number of read-write commands in any CommandQueue", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - metaMaxCommandQueueReadCount = metric.Metadata{ - Name: "replicas.commandqueue.maxreadcount", - Help: "Largest number of read-only commands in any CommandQueue", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - metaMaxCommandQueueTreeSize = metric.Metadata{ - Name: "replicas.commandqueue.maxtreesize", - Help: "Largest number of intervals in any CommandQueue's interval tree", - Measurement: "Intervals", - Unit: metric.Unit_COUNT, - } - metaMaxCommandQueueOverlaps = metric.Metadata{ - Name: "replicas.commandqueue.maxoverlaps", - Help: "Largest number of overlapping commands seen when adding to any CommandQueue", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - metaCombinedCommandQueueSize = metric.Metadata{ - Name: "replicas.commandqueue.combinedqueuesize", - Help: "Number of commands in all CommandQueues combined", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - metaCombinedCommandWriteCount = metric.Metadata{ - Name: "replicas.commandqueue.combinedwritecount", - Help: "Number of read-write commands in all CommandQueues combined", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - metaCombinedCommandReadCount = metric.Metadata{ - Name: "replicas.commandqueue.combinedreadcount", - Help: "Number of read-only commands in all CommandQueues combined", - Measurement: "Commands", - Unit: metric.Unit_COUNT, - } - // Range metrics. metaRangeCount = metric.Metadata{ Name: "ranges", @@ -923,9 +872,9 @@ var ( } // Slow request metrics. - metaSlowCommandQueueRequests = metric.Metadata{ - Name: "requests.slow.commandqueue", - Help: "Number of requests that have been stuck for a long time in the command queue", + metaLatchRequests = metric.Metadata{ + Name: "requests.slow.latch", + Help: "Number of requests that have been stuck for a long time acquiring latches", Measurement: "Requests", Unit: metric.Unit_COUNT, } @@ -983,16 +932,6 @@ type StoreMetrics struct { LeaseHolderCount *metric.Gauge QuiescentCount *metric.Gauge - // Replica CommandQueue metrics. - MaxCommandQueueSize *metric.Gauge - MaxCommandQueueWriteCount *metric.Gauge - MaxCommandQueueReadCount *metric.Gauge - MaxCommandQueueTreeSize *metric.Gauge - MaxCommandQueueOverlaps *metric.Gauge - CombinedCommandQueueSize *metric.Gauge - CombinedCommandWriteCount *metric.Gauge - CombinedCommandReadCount *metric.Gauge - // Range metrics. RangeCount *metric.Gauge UnavailableRangeCount *metric.Gauge @@ -1160,9 +1099,9 @@ type StoreMetrics struct { IntentResolverAsyncThrottled *metric.Counter // Slow request counts. - SlowCommandQueueRequests *metric.Gauge - SlowLeaseRequests *metric.Gauge - SlowRaftRequests *metric.Gauge + SlowLatchRequests *metric.Gauge + SlowLeaseRequests *metric.Gauge + SlowRaftRequests *metric.Gauge // Backpressure counts. BackpressuredOnSplitRequests *metric.Gauge @@ -1193,16 +1132,6 @@ func newStoreMetrics(histogramWindow time.Duration) *StoreMetrics { LeaseHolderCount: metric.NewGauge(metaLeaseHolderCount), QuiescentCount: metric.NewGauge(metaQuiescentCount), - // Replica CommandQueue metrics. - MaxCommandQueueSize: metric.NewGauge(metaMaxCommandQueueSize), - MaxCommandQueueWriteCount: metric.NewGauge(metaMaxCommandQueueWriteCount), - MaxCommandQueueReadCount: metric.NewGauge(metaMaxCommandQueueReadCount), - MaxCommandQueueTreeSize: metric.NewGauge(metaMaxCommandQueueTreeSize), - MaxCommandQueueOverlaps: metric.NewGauge(metaMaxCommandQueueOverlaps), - CombinedCommandQueueSize: metric.NewGauge(metaCombinedCommandQueueSize), - CombinedCommandWriteCount: metric.NewGauge(metaCombinedCommandWriteCount), - CombinedCommandReadCount: metric.NewGauge(metaCombinedCommandReadCount), - // Range metrics. RangeCount: metric.NewGauge(metaRangeCount), UnavailableRangeCount: metric.NewGauge(metaUnavailableRangeCount), @@ -1363,9 +1292,9 @@ func newStoreMetrics(histogramWindow time.Duration) *StoreMetrics { IntentResolverAsyncThrottled: metric.NewCounter(metaIntentResolverAsyncThrottled), // Wedge request counters. - SlowCommandQueueRequests: metric.NewGauge(metaSlowCommandQueueRequests), - SlowLeaseRequests: metric.NewGauge(metaSlowLeaseRequests), - SlowRaftRequests: metric.NewGauge(metaSlowRaftRequests), + SlowLatchRequests: metric.NewGauge(metaLatchRequests), + SlowLeaseRequests: metric.NewGauge(metaSlowLeaseRequests), + SlowRaftRequests: metric.NewGauge(metaSlowRaftRequests), // Backpressure counters. BackpressuredOnSplitRequests: metric.NewGauge(metaBackpressuredOnSplitRequests), diff --git a/pkg/storage/replica.go b/pkg/storage/replica.go index 028101246a0a..511308581e36 100644 --- a/pkg/storage/replica.go +++ b/pkg/storage/replica.go @@ -23,7 +23,6 @@ import ( "os" "reflect" "sort" - "strings" "sync/atomic" "time" "unsafe" @@ -45,6 +44,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/storage/engine/enginepb" "github.com/cockroachdb/cockroach/pkg/storage/rangefeed" "github.com/cockroachdb/cockroach/pkg/storage/rditer" + "github.com/cockroachdb/cockroach/pkg/storage/spanlatch" "github.com/cockroachdb/cockroach/pkg/storage/spanset" "github.com/cockroachdb/cockroach/pkg/storage/split" "github.com/cockroachdb/cockroach/pkg/storage/stateloader" @@ -335,19 +335,11 @@ type Replica struct { // Contains the lease history when enabled. leaseHistory *leaseHistory - cmdQMu struct { - // Protects all fields in the cmdQMu struct. - // - // Locking notes: Replica.mu < Replica.cmdQMu - syncutil.Mutex - // Enforces at most one command is running per key(s) within each span - // scope. The globally-scoped component tracks user writes (i.e. all - // keys for which keys.Addr is the identity), the locally-scoped component - // the rest (e.g. RangeDescriptor, transaction record, Lease, ...). - // Commands with different accesses but the same scope are stored in the - // same component. - queues [spanset.NumSpanScope]*CommandQueue - } + // Enforces at most one command is running per key(s) within each span + // scope. The globally-scoped component tracks user writes (i.e. all + // keys for which keys.Addr is the identity), the locally-scoped component + // the rest (e.g. RangeDescriptor, transaction record, Lease, ...). + latchMgr spanlatch.Manager mu struct { // Protects all fields in the mu struct. @@ -401,8 +393,8 @@ type Replica struct { // This is used to protect against several hazards: // - leases held (or even proposed) before a restart cannot be used after a // restart. This is because: - // a) the command queue is wiped during the restart; there might be - // writes in flight that are not reflected in the new command queue. So, + // a) the spanlatch manager is wiped during the restart; there might be + // writes in flight that do not have the latches they held reflected. So, // we need to synchronize all new reads with those old in-flight writes. // Forcing acquisition of a new lease essentially flushes all the // previous raft commands. @@ -756,11 +748,7 @@ func (r *Replica) initRaftMuLockedReplicaMuLocked( return errors.Errorf("replicaID must be 0 when creating an initialized replica") } - r.cmdQMu.Lock() - r.cmdQMu.queues[spanset.SpanGlobal] = NewCommandQueue(true /* optimizeOverlap */) - r.cmdQMu.queues[spanset.SpanLocal] = NewCommandQueue(false /* optimizeOverlap */) - r.cmdQMu.Unlock() - + r.latchMgr.Init(r.store.metrics.SlowLatchRequests) r.mu.proposals = map[storagebase.CmdIDKey]*ProposalData{} r.mu.checksums = map[uuid.UUID]ReplicaChecksum{} // Clear the internal raft group in case we're being reset. Since we're @@ -769,7 +757,6 @@ func (r *Replica) initRaftMuLockedReplicaMuLocked( r.mu.internalRaftGroup = nil var err error - if r.mu.state, err = r.mu.stateLoader.Load(ctx, r.store.Engine(), desc); err != nil { return err } @@ -1503,15 +1490,14 @@ func (r *Replica) redirectOnOrAcquireLease( // commands may be proposed from followers, but not successfully so). For // all proposals, processRaftCommand checks that their ProposalLease is // compatible with the active lease for the log position. For commands - // proposed on the lease holder, the command queue then serializes + // proposed on the lease holder, the spanlatch manager then serializes // everything. But lease requests get created on followers based on their - // local state and thus without being sequenced through the command queue. - // Thus a recently removed follower (unaware of its own removal) could - // submit a proposal for the lease (correctly using as a ProposerLease the - // last active lease), and would receive it given the up-to-date - // ProposerLease. Hence, an extra check is in order: processRaftCommand - // makes sure that lease requests for a replica not in the descriptor are - // bounced. + // local state and thus without being sequenced through latching. Thus + // a recently removed follower (unaware of its own removal) could submit + // a proposal for the lease (correctly using as a ProposerLease the last + // active lease), and would receive it given the up-to-date ProposerLease. + // Hence, an extra check is in order: processRaftCommand makes sure that + // lease requests for a replica not in the descriptor are bounced. // // However, this is possible if the `cockroach debug // unsafe-remove-dead-replicas` command has been used, so @@ -2201,26 +2187,15 @@ func (r *Replica) checkBatchRequest(ba roachpb.BatchRequest, isReadOnly bool) er return nil } -// batchCmdSet holds a *cmd for each permutation of SpanAccess and spanScope. The -// batch is divided into separate *cmds for access type (read-only or read/write) -// and key scope (local or global; used to facilitate use by the separate local -// and global command queues). -type batchCmdSet [spanset.NumSpanAccess][spanset.NumSpanScope]*cmd - -// prereqCmdSet holds the set of all *cmds that a batch command can depend on. -// The prereq set is divided into seprate slices of *cmd for access type -// (read-only or read/write) and key scope (local or global). -type prereqCmdSet [spanset.NumSpanAccess][spanset.NumSpanScope][]*cmd - // endCmds holds necessary information to end a batch after Raft // command processing. type endCmds struct { repl *Replica - cmds batchCmdSet + lg *spanlatch.Guard ba roachpb.BatchRequest } -// done removes pending commands from the command queue and updates +// done releases the latches acquired by the command and updates // the timestamp cache using the final timestamp of each command. func (ec *endCmds) done(br *roachpb.BatchResponse, pErr *roachpb.Error, retry proposalRetryReason) { // Update the timestamp cache if the command is not being @@ -2231,10 +2206,11 @@ func (ec *endCmds) done(br *roachpb.BatchResponse, pErr *roachpb.Error, retry pr ec.repl.updateTimestampCache(&ec.ba, br, pErr) } - if fn := ec.repl.store.cfg.TestingKnobs.OnCommandQueueAction; fn != nil { - fn(&ec.ba, storagebase.CommandQueueFinishExecuting) + // Release the latches acquired by the request back to the spanlatch + // manager. Must be done AFTER the timestamp cache is updated. + if ec.lg != nil { + ec.repl.latchMgr.Release(ec.lg) } - ec.repl.removeCmdsFromCommandQueue(ec.cmds) } // updateTimestampCache updates the timestamp cache in order to set a low water @@ -2338,12 +2314,10 @@ func (r *Replica) updateTimestampCache( } } -func collectSpans( - desc roachpb.RangeDescriptor, ba *roachpb.BatchRequest, -) (*spanset.SpanSet, error) { +func (r *Replica) collectSpans(ba *roachpb.BatchRequest) (*spanset.SpanSet, error) { spans := &spanset.SpanSet{} - // TODO(bdarnell): need to make this less global when the local - // command queue is used more heavily. For example, a split will + // TODO(bdarnell): need to make this less global when local + // latches are used more heavily. For example, a split will // have a large read-only span but also a write (see #10084). // Currently local spans are the exception, so preallocate for the // common case in which all are global. We rarely mix read and @@ -2358,17 +2332,22 @@ func collectSpans( spans.Reserve(spanset.SpanReadWrite, spanset.SpanGlobal, len(ba.Requests)) } + desc := r.Desc() for _, union := range ba.Requests { inner := union.GetInner() if cmd, ok := batcheval.LookupCommand(inner.Method()); ok { - cmd.DeclareKeys(desc, ba.Header, inner, spans) + cmd.DeclareKeys(*desc, ba.Header, inner, spans) } else { return nil, errors.Errorf("unrecognized command %s", inner.Method()) } } + // Commands may create a large number of duplicate spans. De-duplicate + // them to reduce the number of spans we pass to the spanlatch manager. + spans.SortAndDedup() + // If any command gave us spans that are invalid, bail out early - // (before passing them to the command queue, which may panic). + // (before passing them to the spanlatch manager, which may panic). if err := spans.Validate(); err != nil { return nil, err } @@ -2379,8 +2358,8 @@ func collectSpans( // includes merges in their critical phase or overlapping, already-executing // commands. // -// More specifically, after waiting for in-flight merges, beginCmds adds the -// request to the command queue based on keys affected by the batched commands. +// More specifically, after waiting for in-flight merges, beginCmds acquires +// latches for the request based on keys affected by the batched commands. // This gates subsequent commands with overlapping keys or key ranges. It // returns a cleanup function to be called when the commands are done and can be // removed from the queue, and whose returned error is to be used in place of @@ -2388,129 +2367,39 @@ func collectSpans( func (r *Replica) beginCmds( ctx context.Context, ba *roachpb.BatchRequest, spans *spanset.SpanSet, ) (*endCmds, error) { - var newCmds batchCmdSet - clocklessReads := r.store.Clock().MaxOffset() == timeutil.ClocklessMaxOffset - // Don't use the command queue for inconsistent reads. + // Only acquire latches for consistent operations. + var lg *spanlatch.Guard if ba.ReadConsistency == roachpb.CONSISTENT { - - // Check for context cancellation before inserting into the - // command queue (and check again afterward). Once we're in the - // command queue we'll need to transfer our prerequisites to all - // dependent commands if we want to cancel, so it's good to bail - // out early if we can. + // Check for context cancellation before acquiring latches. if err := ctx.Err(); err != nil { - log.VEventf(ctx, 2, "%s before command queue: %s", err, ba.Summary()) - return nil, errors.Wrap(err, "aborted before command queue") - } - - // Get the requested timestamp for a given scope. This is used for - // non-interference of earlier reads with later writes, but only for - // the global command queue. Reads and writes to local keys are specified - // as having a zero timestamp which will cause them to always interfere. - // This is done to avoid confusion with local keys declared as part of - // proposer evaluated KV. - scopeTS := func(scope spanset.SpanScope) hlc.Timestamp { - switch scope { - case spanset.SpanGlobal: - // ba.Timestamp is always set appropriately, regardless of - // whether the batch is transactional or not. - return ba.Timestamp - case spanset.SpanLocal: - return hlc.Timestamp{} - } - panic(fmt.Sprintf("unexpected scope %d", scope)) - } - - r.cmdQMu.Lock() - var prereqs prereqCmdSet - var prereqCount int - // Collect all the channels to wait on before adding this batch to the - // command queue. - for i := spanset.SpanAccess(0); i < spanset.NumSpanAccess; i++ { - // With clockless reads, everything is treated as writing. - readOnly := i == spanset.SpanReadOnly && !clocklessReads - for j := spanset.SpanScope(0); j < spanset.NumSpanScope; j++ { - prereqs[i][j] = r.cmdQMu.queues[j].getPrereqs(readOnly, scopeTS(j), spans.GetSpans(i, j)) - prereqCount += len(prereqs[i][j]) - } + log.VEventf(ctx, 2, "%s before acquiring latches: %s", err, ba.Summary()) + return nil, errors.Wrap(err, "aborted before acquiring latches") } - for i := spanset.SpanAccess(0); i < spanset.NumSpanAccess; i++ { - readOnly := i == spanset.SpanReadOnly && !clocklessReads // ditto above - for j := spanset.SpanScope(0); j < spanset.NumSpanScope; j++ { - cmd := r.cmdQMu.queues[j].add(readOnly, scopeTS(j), prereqs[i][j], spans.GetSpans(i, j)) - if cmd != nil { - cmd.SetDebugInfo(ba) - newCmds[i][j] = cmd - } - } - } - r.cmdQMu.Unlock() - var beforeWait time.Time - var prereqSummary string - if prereqCount > 0 && log.ExpensiveLogEnabled(ctx, 2) { - beforeWait = timeutil.Now() - prereqSummary = prereqDebugSummary(prereqs) - log.VEventf(ctx, 2, "waiting for %d overlapping requests: %s", prereqCount, prereqSummary) - } - if fn := r.store.cfg.TestingKnobs.OnCommandQueueAction; fn != nil { - fn(ba, storagebase.CommandQueueWaitForPrereqs) + var beforeLatch time.Time + if log.ExpensiveLogEnabled(ctx, 2) { + beforeLatch = timeutil.Now() } - ctxDone := ctx.Done() - for _, accessCmds := range newCmds { - for _, newCmd := range accessCmds { - // If newCmd is nil it means that the BatchRequest contains no spans for this - // SpanAccess/spanScope permutation. - if newCmd == nil { - continue - } - // Loop until the command has no more pending prerequisites. Resolving canceled - // prerequisites can add new transitive dependencies to a command, so newCmd.prereqs - // should not be accessed directly (see ResolvePendingPrereq). - for { - pre := newCmd.PendingPrereq() - if pre == nil { - break - } - select { - case <-pre.pending: - // The prerequisite command has finished so remove it from our prereq list. - // If the prereq still has pending dependencies, migrate them. - newCmd.ResolvePendingPrereq() - case <-ctxDone: - err := ctx.Err() - log.VEventf(ctx, 2, "%s while in command queue: %s", err, ba) - - if fn := r.store.cfg.TestingKnobs.OnCommandQueueAction; fn != nil { - fn(ba, storagebase.CommandQueueCancellation) - } - - // Remove the command from the command queue immediately. New commands that - // would have established a dependency on this command will never see it, - // which is fine. Current dependents that already have a dependency on this - // command will transfer transitive dependencies when they try to block on - // this command, because our prereqs slice is not empty. This migration of - // dependencies will happen for each dependent in ResolvePendingPrereq, - // which will notice that our prereqs slice was not empty when we stopped - // pending and will adopt our prerequisites in turn. - r.removeCmdsFromCommandQueue(newCmds) - return nil, errors.Wrap(err, "aborted while in command queue") - case <-r.store.stopper.ShouldQuiesce(): - // While shutting down, commands may have been added to the - // command queue that will never finish. - return nil, &roachpb.NodeUnavailableError{} - } - } - } + // Acquire latches for all the request's declared spans to ensure + // protected access and to avoid interacting requests from operating at + // the same time. The latches will be held for the duration of request. + var err error + lg, err = r.latchMgr.Acquire(ctx, spans, ba.Timestamp) + if err != nil { + return nil, err } - if prereqSummary != "" { - dur := timeutil.Since(beforeWait) - log.VEventf(ctx, 2, "waited %s for overlapping requests: %s", dur, prereqSummary) + if !beforeLatch.IsZero() { + dur := timeutil.Since(beforeLatch) + log.VEventf(ctx, 2, "waited %s to acquire latches", dur) } - if fn := r.store.cfg.TestingKnobs.OnCommandQueueAction; fn != nil { - fn(ba, storagebase.CommandQueueBeginExecuting) + + if filter := r.store.cfg.TestingKnobs.TestingLatchFilter; filter != nil { + if pErr := filter(*ba); pErr != nil { + r.latchMgr.Release(lg) + return nil, pErr.GoError() + } } if r.getMergeCompleteCh() != nil && !ba.IsSingleSubsumeRequest() { @@ -2518,8 +2407,8 @@ func (r *Replica) beginCmds( // cannot proceed until the merge completes, signaled by the closing of // the channel. // - // It is very important that this check occur after the command queue has - // allowed us to proceed. Only after we exit the command queue are we + // It is very important that this check occur after we have acquired latches + // from the spanlatch manager. Only after we release these latches are we // guaranteed that we're not racing with a Subsume command. (Subsume // commands declare a conflict with all other commands.) // @@ -2552,12 +2441,12 @@ func (r *Replica) beginCmds( // We can't wait for the merge to complete here, though. The replica might // need to respond to a Subsume request in order for the merge to // complete, and blocking here would force that Subsume request to sit in - // the command queue forever, deadlocking the merge. Instead, we remove - // the commands from the command queue and return a MergeInProgressError. + // hold its latches forever, deadlocking the merge. Instead, we release + // the latches we acquired above and return a MergeInProgressError. // The store will catch that error and resubmit the request after // mergeCompleteCh closes. See #27442 for the full context. log.Event(ctx, "waiting on in-progress merge") - r.removeCmdsFromCommandQueue(newCmds) + r.latchMgr.Release(lg) return nil, &roachpb.MergeInProgressError{} } } else { @@ -2599,72 +2488,12 @@ func (r *Replica) beginCmds( ec := &endCmds{ repl: r, - cmds: newCmds, + lg: lg, ba: *ba, } return ec, nil } -// prereqDebugSummary constructs a debug summary of a command's prerequisite. -func prereqDebugSummary(prereqs prereqCmdSet) string { - var b strings.Builder - for i := spanset.SpanAccess(0); i < spanset.NumSpanAccess; i++ { - for j := spanset.SpanScope(0); j < spanset.NumSpanScope; j++ { - cmds := prereqs[i][j] - if len(cmds) == 0 { - continue - } - - if b.Len() > 0 { - b.WriteString(" ") - } - fmt.Fprintf(&b, "{%s/%s: ", i, j) - const max = 4 - var count int - for _, cmd := range cmds { - if count > 0 { - b.WriteString(", ") - if count > max { - b.WriteString("...") - break - } - } - b.WriteString("[") - cmd.debugInfo.WriteSummary(&b) - b.WriteString("]") - count++ - } - b.WriteString("}") - } - } - if b.Len() == 0 { - return "no prereqs" - } - return b.String() -} - -// removeCmdsFromCommandQueue removes a batch's set of commands for the -// replica's command queue. -func (r *Replica) removeCmdsFromCommandQueue(cmds batchCmdSet) { - r.cmdQMu.Lock() - for _, accessCmds := range cmds { - for scope, cmd := range accessCmds { - if cmd.PrereqLen() > 0 { - // The command was canceled while it still had prerequisites to - // wait on. To avoid transferring already resolved prerequisites - // to our dependencies, we perform one last optimistic scan over - // our prerequisites and resolve any that are no longer pending - // and were not canceled themselves. This helps bound the - // quadratic blowup of prerequisites during cascading - // cancellations. - cmd.OptimisticallyResolvePrereqs() - } - r.cmdQMu.queues[scope].remove(cmd) - } - } - r.cmdQMu.Unlock() -} - // applyTimestampCache moves the batch timestamp forward depending on // the presence of overlapping entries in the timestamp cache. If the // batch is transactional, the txn timestamp and the txn.WriteTooOld @@ -2783,7 +2612,7 @@ func (r *Replica) applyTimestampCache( } // executeAdminBatch executes the command directly. There is no interaction -// with the command queue or the timestamp cache, as admin commands +// with the spanlatch manager or the timestamp cache, as admin commands // are not meant to consistently access or modify the underlying data. // Admin commands must run on the lease holder replica. Batch support here is // limited to single-element batches; everything else catches an error. @@ -3112,7 +2941,7 @@ func (r *Replica) maybeWatchForMerge(ctx context.Context) error { // executeReadOnlyBatch updates the read timestamp cache and waits for any // overlapping writes currently processing through Raft ahead of us to -// clear via the command queue. +// clear via the latches. func (r *Replica) executeReadOnlyBatch( ctx context.Context, ba roachpb.BatchRequest, ) (br *roachpb.BatchResponse, pErr *roachpb.Error) { @@ -3155,14 +2984,14 @@ func (r *Replica) executeReadOnlyBatch( } r.limitTxnMaxTimestamp(ctx, &ba, status) - spans, err := collectSpans(*r.Desc(), &ba) + spans, err := r.collectSpans(&ba) if err != nil { return nil, roachpb.NewError(err) } - // Add the read to the command queue to gate subsequent - // overlapping commands until this command completes. - log.Event(ctx, "command queue") + // Acquire latches to prevent overlapping commands from executing + // until this command completes. + log.Event(ctx, "acquire latches") endCmds, err := r.beginCmds(ctx, &ba, spans) if err != nil { return nil, roachpb.NewError(err) @@ -3172,7 +3001,7 @@ func (r *Replica) executeReadOnlyBatch( r.readOnlyCmdMu.RLock() defer r.readOnlyCmdMu.RUnlock() - // Guarantee we remove the commands from the command queue. It is + // Guarantee we release the latches that we just acquired. It is // important that this is inside the readOnlyCmdMu lock so that the // timestamp cache update is synchronized. This is wrapped to delay // pErr evaluation to its value when returning. @@ -3299,10 +3128,9 @@ func (r *Replica) executeWriteBatch( // // Concretely, // -// - The keys affected by the command are added to the command queue (i.e. +// - Latches for the keys affected by the command are acquired (i.e. // tracked as in-flight mutations). -// - Wait until the command queue promises that no overlapping mutations are -// in flight. +// - In doing so, we wait until no overlapping mutations are in flight. // - The timestamp cache is checked to determine if the command's affected keys // were accessed with a timestamp exceeding that of the command; if so, the // command's timestamp is incremented accordingly. @@ -3313,8 +3141,8 @@ func (r *Replica) executeWriteBatch( // a lease index is assigned to it, and it is submitted to Raft, returning // a channel. // - The result of the Raft proposal is read from the channel and the command -// registered with the timestamp cache, removed from the command queue, and -// its result (which could be an error) returned to the client. +// registered with the timestamp cache, its latches are released, and +// its result (which could be an error) is returned to the client. // // TODO(tschottdorf): take special care with "special" commands and their // reorderings. For example, a batch of writes and a split could be in flight @@ -3333,19 +3161,18 @@ func (r *Replica) tryExecuteWriteBatch( return nil, roachpb.NewError(err), proposalNoRetry } - spans, err := collectSpans(*r.Desc(), &ba) + spans, err := r.collectSpans(&ba) if err != nil { return nil, roachpb.NewError(err), proposalNoRetry } var endCmds *endCmds if !ba.IsLeaseRequest() { - // Add the write to the command queue to gate subsequent overlapping - // commands until this command completes. Note that this must be - // done before getting the max timestamp for the key(s), as - // timestamp cache is only updated after preceding commands have - // been run to successful completion. - log.Event(ctx, "command queue") + // Acquire latches to prevent overlapping commands from executing until + // this command completes. Note that this must be done before getting + // the max timestamp for the key(s), as timestamp cache is only updated + // after preceding commands have been run to successful completion. + log.Event(ctx, "acquire latches") var err error endCmds, err = r.beginCmds(ctx, &ba, spans) if err != nil { @@ -3353,7 +3180,7 @@ func (r *Replica) tryExecuteWriteBatch( } } - // Guarantee we remove the commands from the command queue. This is + // Guarantee we release the latches that we just acquired. This is // wrapped to delay pErr evaluation to its value when returning. defer func() { if endCmds != nil { @@ -3764,10 +3591,10 @@ func (r *Replica) propose( return nil, nil, 0, roachpb.NewError(errors.Wrap(err, "aborted before proposing")) } - // Only need to check that the request is in bounds at proposal time, - // not at application time, because the command queue will synchronize - // all requests (notably EndTransaction with SplitTrigger) that may - // cause this condition to change. + // Only need to check that the request is in bounds at proposal time, not at + // application time, because the spanlatch manager will synchronize all + // requests (notably EndTransaction with SplitTrigger) that may cause this + // condition to change. if err := r.requestCanProceed(rSpan, ba.Timestamp); err != nil { return nil, nil, 0, roachpb.NewError(err) } @@ -5546,18 +5373,19 @@ func (r *Replica) processRaftCommand( // Verify that the batch timestamp is after the GC threshold. This is // necessary because not all commands declare read access on the GC // threshold key, even though they implicitly depend on it. This means - // that access to this state will not be serialized by the command queue, + // that access to this state will not be serialized by latching, // so we must perform this check upstream and downstream of raft. // See #14833. // // We provide an empty key span because we already know that the Raft // command is allowed to apply within its key range. This is guaranteed // by checks upstream of Raft, which perform the same validation, and by - // the CommandQueue, which assures that any modifications to the range's + // span latches, which assure that any modifications to the range's // boundaries will be serialized with this command. Finally, the // leaseAppliedIndex check in checkForcedErrLocked ensures that replays - // outside of the CommandQueue's control which break this serialization - // ordering will already by caught and an error will be thrown. + // outside of the spanlatch manager's control which break this + // serialization ordering will already by caught and an error will be + // thrown. forcedErr = roachpb.NewError(r.requestCanProceed(roachpb.RSpan{}, ts)) } @@ -6026,9 +5854,9 @@ func (r *Replica) applyRaftCommand( // remaining writes are the raft applied index and the updated MVCC stats. writer := batch.Distinct() - // Special-cased MVCC stats handling to exploit commutativity of stats - // delta upgrades. Thanks to commutativity, the command queue does not - // have to serialize on the stats key. + // Special-cased MVCC stats handling to exploit commutativity of stats delta + // upgrades. Thanks to commutativity, the spanlatch manager does not have to + // serialize on the stats key. deltaStats := rResult.Delta.ToStats() if !usingAppliedStateKey && rResult.State != nil && rResult.State.UsingAppliedStateKey { @@ -6891,7 +6719,7 @@ func (r *Replica) MaybeGossipNodeLiveness(ctx context.Context, span roachpb.Span ba := roachpb.BatchRequest{} ba.Timestamp = r.store.Clock().Now() ba.Add(&roachpb.ScanRequest{RequestHeader: roachpb.RequestHeaderFromSpan(span)}) - // Call evaluateBatch instead of Send to avoid command queue reentrance. + // Call evaluateBatch instead of Send to avoid reacquiring latches. rec := NewReplicaEvalContext(r, todoSpanSet) br, result, pErr := evaluateBatch(ctx, storagebase.CmdIDKey(""), r.store.Engine(), rec, nil, ba) @@ -6964,7 +6792,7 @@ func (r *Replica) loadSystemConfig(ctx context.Context) (*config.SystemConfigEnt ba.ReadConsistency = roachpb.INCONSISTENT ba.Timestamp = r.store.Clock().Now() ba.Add(&roachpb.ScanRequest{RequestHeader: roachpb.RequestHeaderFromSpan(keys.SystemConfigSpan)}) - // Call evaluateBatch instead of Send to avoid command queue reentrance. + // Call evaluateBatch instead of Send to avoid reacquiring latches. rec := NewReplicaEvalContext(r, todoSpanSet) br, result, pErr := evaluateBatch( ctx, storagebase.CmdIDKey(""), r.store.Engine(), rec, nil, ba, @@ -7164,13 +6992,13 @@ type ReplicaMetrics struct { // Is this the replica which collects per-range metrics? This is done either // on the leader or, if there is no leader, on the largest live replica ID. - RangeCounter bool - Unavailable bool - Underreplicated bool - BehindCount int64 - CmdQMetricsLocal CommandQueueMetrics - CmdQMetricsGlobal CommandQueueMetrics - RaftLogTooLarge bool + RangeCounter bool + Unavailable bool + Underreplicated bool + BehindCount int64 + LatchInfoLocal storagepb.LatchManagerInfo + LatchInfoGlobal storagepb.LatchManagerInfo + RaftLogTooLarge bool } // Metrics returns the current metrics for the replica. @@ -7184,16 +7012,14 @@ func (r *Replica) Metrics( desc := r.mu.state.Desc zone := r.mu.zone raftLogSize := r.mu.raftLogSize - r.cmdQMu.Lock() - cmdQMetricsLocal := r.cmdQMu.queues[spanset.SpanLocal].metrics() - cmdQMetricsGlobal := r.cmdQMu.queues[spanset.SpanGlobal].metrics() - r.cmdQMu.Unlock() r.mu.RUnlock() r.store.unquiescedReplicas.Lock() _, ticking := r.store.unquiescedReplicas.m[r.RangeID] r.store.unquiescedReplicas.Unlock() + latchInfoGlobal, latchInfoLocal := r.latchMgr.Info() + return calcReplicaMetrics( ctx, now, @@ -7207,8 +7033,8 @@ func (r *Replica) Metrics( r.store.StoreID(), quiescent, ticking, - cmdQMetricsLocal, - cmdQMetricsGlobal, + latchInfoLocal, + latchInfoGlobal, raftLogSize, ) } @@ -7235,8 +7061,8 @@ func calcReplicaMetrics( storeID roachpb.StoreID, quiescent bool, ticking bool, - cmdQMetricsLocal CommandQueueMetrics, - cmdQMetricsGlobal CommandQueueMetrics, + latchInfoLocal storagepb.LatchManagerInfo, + latchInfoGlobal storagepb.LatchManagerInfo, raftLogSize int64, ) ReplicaMetrics { var m ReplicaMetrics @@ -7262,8 +7088,8 @@ func calcReplicaMetrics( m.BehindCount = calcBehindCount(raftStatus, desc, livenessMap) } - m.CmdQMetricsLocal = cmdQMetricsLocal - m.CmdQMetricsGlobal = cmdQMetricsGlobal + m.LatchInfoLocal = latchInfoLocal + m.LatchInfoGlobal = latchInfoGlobal const raftLogTooLargeMultiple = 4 m.RaftLogTooLarge = raftLogSize > (raftLogTooLargeMultiple * raftCfg.RaftLogTruncationThreshold) @@ -7375,20 +7201,6 @@ func EnableLeaseHistory(maxEntries int) func() { } } -// GetCommandQueueSnapshot returns a snapshot of the command queue state for -// this replica. -func (r *Replica) GetCommandQueueSnapshot() storagepb.CommandQueuesSnapshot { - r.mu.RLock() - defer r.mu.RUnlock() - r.cmdQMu.Lock() - defer r.cmdQMu.Unlock() - return storagepb.CommandQueuesSnapshot{ - Timestamp: r.store.Clock().Now(), - LocalScope: r.cmdQMu.queues[spanset.SpanLocal].GetSnapshot(), - GlobalScope: r.cmdQMu.queues[spanset.SpanGlobal].GetSnapshot(), - } -} - // EmitMLAI registers the replica's last assigned max lease index with the // closed timestamp tracker. This is called to emit an update about this // replica in the absence of write activity. diff --git a/pkg/storage/replica_test.go b/pkg/storage/replica_test.go index f044c742b2eb..364d0df52b6a 100644 --- a/pkg/storage/replica_test.go +++ b/pkg/storage/replica_test.go @@ -55,7 +55,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/util/metric" "github.com/cockroachdb/cockroach/pkg/util/protoutil" "github.com/cockroachdb/cockroach/pkg/util/randutil" - "github.com/cockroachdb/cockroach/pkg/util/shuffle" "github.com/cockroachdb/cockroach/pkg/util/stop" "github.com/cockroachdb/cockroach/pkg/util/syncutil" "github.com/cockroachdb/cockroach/pkg/util/tracing" @@ -2121,10 +2120,10 @@ func TestReplicaUpdateTSCache(t *testing.T) { } } -// TestReplicaCommandQueue verifies that reads/writes must wait for +// TestReplicaLatching verifies that reads/writes must wait for // pending commands to complete through Raft before being executed on // range. -func TestReplicaCommandQueue(t *testing.T) { +func TestReplicaLatching(t *testing.T) { defer leaktest.AfterTest(t)() // Test all four combinations of reads & writes waiting. testCases := []struct { @@ -2210,7 +2209,7 @@ func TestReplicaCommandQueue(t *testing.T) { case "read", "write": // Additional reads and writes to unique keys do not // cause additional blocking; the read/write nature of - // the keys in the command queue is determined on a + // the keys for latching purposes is determined on a // per-request basis. key := roachpb.Key(fmt.Sprintf("unique-key-%s-%d", testName, atomic.AddInt32(&uniqueKeyCounter, 1))) if addReq == "read" { @@ -2237,11 +2236,11 @@ func TestReplicaCommandQueue(t *testing.T) { }); err != nil { t.Fatal(err) } - // Wait for cmd1 to get into the command queue. + // Wait for cmd1 to get acquire latches. select { case <-blockingStart: case <-time.After(tooLong): - t.Fatalf("waited %s for cmd1 to enter command queue", tooLong) + t.Fatalf("waited %s for cmd1 to acquire latches", tooLong) } // First, try a command for same key as cmd1 to verify whether it blocks. @@ -2330,9 +2329,9 @@ func TestReplicaCommandQueue(t *testing.T) { } } -// TestReplicaCommandQueueInconsistent verifies that inconsistent reads need +// TestReplicaLatchingInconsistent verifies that inconsistent reads need // not wait for pending commands to complete through Raft. -func TestReplicaCommandQueueInconsistent(t *testing.T) { +func TestReplicaLatchingInconsistent(t *testing.T) { defer leaktest.AfterTest(t)() for _, rc := range []roachpb.ReadConsistencyType{ @@ -2376,7 +2375,7 @@ func TestReplicaCommandQueueInconsistent(t *testing.T) { _, pErr := tc.SendWrapped(&args) cmd1Done <- pErr }() - // Wait for cmd1 to get into the command queue. + // Wait for cmd1 to get acquire latches. <-blockingStart // An inconsistent read to the key won't wait. @@ -2409,808 +2408,10 @@ func TestReplicaCommandQueueInconsistent(t *testing.T) { } } -// TestReplicaCommandQueueCancellation verifies that commands which are -// waiting on the command queue do not execute or deadlock if their context -// is canceled, and that commands dependent on canceled commands execute -// correctly. -func TestReplicaCommandQueueCancellation(t *testing.T) { - defer leaktest.AfterTest(t)() - - keyA := roachpb.Key("a") - keyB := roachpb.Key("b") - keyC := roachpb.Key("c") - keyD := roachpb.Key("d") - keyE := roachpb.Key("e") - keyF := roachpb.Key("e") - - makeSpan := func(start, end roachpb.Key) roachpb.Span { - return roachpb.Span{Key: start, EndKey: end.Next()} - } - spanAB := makeSpan(keyA, keyB) - spanAC := makeSpan(keyA, keyC) - spanAF := makeSpan(keyA, keyF) - spanBE := makeSpan(keyB, keyE) - spanCD := makeSpan(keyC, keyD) - spanDF := makeSpan(keyD, keyF) - spanEF := makeSpan(keyE, keyF) - - testCases := []struct { - name string - instrs []cancelInstr - }{ - // ----- ----- ----- xxxxx - // | -> | & | -> | etc. - // ----- xxxxx ----- ----- - {name: "SingleDependency", instrs: []cancelInstr{ - {span: spanAF}, - {span: spanAF}, - }}, - // -------- xxxxxxxx -------- xxxxxxxx -------- -------- - // | | -> | | & | | -> | | & | | -> | | etc. - // --- --- --- --- --- --- xxx xxx --- --- xxx xxx - {name: "MultipleDependencies", instrs: []cancelInstr{ - {span: spanAF}, - {span: spanAC}, - {span: spanDF}, - }}, - // ----- ----- ----- xxxxx ----- xxxxx - // | | | | | | - // ----- -> xxxxx & ----- -> xxxxx & ----- -> xxxxx etc. - // | | | | | | - // ----- ----- ----- ----- ----- xxxxx - {name: "DependencyChain", instrs: []cancelInstr{ - {span: spanAF}, - {span: spanAF}, - {span: spanAF}, - }}, - // --- --- --- --- --- --- xxx xxx - // | | | | | | | | - // ----------- -> xxxxxxxxxxx & ----------- -> ----------- etc. - // | | | | - // --- --- --- xxx - {name: "SplitDependencyChain", instrs: []cancelInstr{ - {span: spanAB}, - {span: spanEF}, - {span: spanAF}, - {span: spanCD}, - }}, - // ------------- ------------- ------------- ------------- - // | | | | - // ----- ----- ----- xxxxx - // | -> | & | -> | etc. - // --------- xxxxxxxxx --------- --------- - // | | | | - // ----- ----- ----- xxxxx - {name: "NonOverlappingDependencyChain", instrs: []cancelInstr{ - {span: spanAF}, - {span: spanDF}, - {span: spanBE}, - {span: spanAC}, - }}, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - // Run every permutation of command cancellation as a separate subtest - // for the current instruction configuration. - var permuteCancellation func(cancelCmds []bool, left int) - permuteCancellation = func(cancelCmds []bool, left int) { - if left == 0 { - var cancelOrder []int - - // Create a name for this permutation. - // C = cancel - // R = run - var permName bytes.Buffer - for i, cancel := range cancelCmds { - if cancel { - permName.WriteByte('C') - cancelOrder = append(cancelOrder, i) - } else { - permName.WriteByte('R') - } - } - - t.Run(permName.String(), func(t *testing.T) { - t.Run("Forward", func(t *testing.T) { - ct := newCmdQCancelTest(t) - ct.Run(tc.instrs, cancelOrder) - }) - if len(cancelOrder) > 1 { - t.Run("Reverse", func(t *testing.T) { - ct := newCmdQCancelTest(t) - reverse := make([]int, len(cancelOrder)) - for i, cancel := range cancelOrder { - reverse[len(reverse)-1-i] = cancel - } - ct.Run(tc.instrs, reverse) - }) - } - }) - return - } - - permuteCancellation(append(cancelCmds, false), left-1) - permuteCancellation(append(cancelCmds, true), left-1) - } - permuteCancellation(nil, len(tc.instrs)) - }) - } -} - -// TestReplicaCommandQueueCancellationCascade verifies that commands which are -// waiting on the command queue properly handle cascading cancellations without -// resulting in quadratic memory growth. -func TestReplicaCommandQueueCancellationCascade(t *testing.T) { - defer leaktest.AfterTest(t)() - - // Create a dependency graph that looks like: - // - // --- --- --- --- - // | | | | - // --------------- - // | | | | - // --- --- --- --- ... - // | | | | - // --------------- - // | | | | - // - // ... - // - // The test then creates a cascade cancellation scenario - // where most commands are canceled: - // - // --- xxx xxx xxx - // | | | | - // xxxxxxxxxxxxxxx - // | | | | - // --- xxx xxx xxx ... - // | | | | - // xxxxxxxxxxxxxxx - // | | | | - // - // ... - // - // Canceling commands in this pattern stresses two operations that - // are necessary to avoid quadratic prerequisite count growth: - // 1. Canceling all but the first command in each of the multi-command - // levels stresses OptimisticallyResolvePrereqs. Without scanning - // through all of a command's prereqs and ignoring already completed - // commands, commands that were finished would be transferred to - // dependent commands. - // 2. Alternating multi-command layers and single command layers creates - // a scenario where dependencies would add duplicate prereqs to their - // prereq slice if not careful. This duplication of commands would - // result in quadratic growth. - // - // Without these operations, the test fails. - const spansPerLevel = 25 - const levels = 25 - - var levelSpans [spansPerLevel]roachpb.Span - keyBuf := bytes.Repeat([]byte("a"), spansPerLevel+1) - for i := 0; i < len(levelSpans); i++ { - levelSpans[i] = roachpb.Span{ - Key: keyBuf[:i+1], - EndKey: keyBuf[:i+2], - } - } - globalSpan := roachpb.Span{ - Key: levelSpans[0].Key, - EndKey: levelSpans[len(levelSpans)-1].EndKey, - } - - var instrs []cancelInstr - var cancelOrder []int - for level := 0; level < levels; level++ { - for i, span := range levelSpans { - if i != 0 { - cancelOrder = append(cancelOrder, len(instrs)) - } - instrs = append(instrs, cancelInstr{span: span}) - } - - cancelOrder = append(cancelOrder, len(instrs)) - instrs = append(instrs, cancelInstr{span: globalSpan}) - } - - // Fails with "command never left CommandQueue after cancellation" - // timeout without proper handling of cascade cancellation. - ct := newCmdQCancelTest(t) - ct.Run(instrs, cancelOrder) -} - -// TestReplicaCommandQueueCancellationRandom verifies that commands in a -// random dependency graph which are waiting on the command queue do not -// execute or deadlock if their context is canceled, and that commands -// dependent on canceled commands execute correctly. -func TestReplicaCommandQueueCancellationRandom(t *testing.T) { - defer leaktest.AfterTest(t)() - - rng, seed := randutil.NewPseudoRand() - randKey := func() roachpb.Key { - return roachpb.Key(randutil.RandBytes(rng, 1)) - } - randBool := func() bool { - return rng.Int31n(2) == 0 - } - t.Logf("running with seed %d", seed) - - const trials = 25 - for i := 0; i < trials; i++ { - commandCount := randutil.RandIntInRange(rng, 0, 25) - instrs := make([]cancelInstr, commandCount) - var cancelOrder []int - for j := range instrs { - startKey := randKey() - endKey := randKey() - if startKey.Compare(endKey) >= 0 { - endKey = startKey.Next() - } - instrs[j] = cancelInstr{ - span: roachpb.Span{Key: startKey, EndKey: endKey}, - } - if randBool() { - cancelOrder = append(cancelOrder, j) - } - } - shuffle.Shuffle(sort.IntSlice(cancelOrder)) - ct := newCmdQCancelTest(t) - ct.Run(instrs, cancelOrder) - } -} - -// TestReplicaCommandQueueCancellationLocal tests various cancellation scenarios -// surrounding EndTxnReqs, PushTxnReqs, and HeartbeatTxnReqs. One of these -// scenarios was the cause of #16266. -func TestReplicaCommandQueueCancellationLocal(t *testing.T) { - defer leaktest.AfterTest(t)() - - now := hlc.Timestamp{WallTime: cmdQCancelTestTimestamp} - txn := roachpb.MakeTransaction("txn", roachpb.Key("foobar"), 0, now, 0) - intentKey := roachpb.Key("baz") - - newBa := func(withTxn bool) *roachpb.BatchRequest { - ba := roachpb.BatchRequest{} - ba.Timestamp = now - if withTxn { - ba.Txn = &txn - } - return &ba - } - - // Used only to block the other requests. Not a necessary part of the - // scenario. See the comment on RunWithoutInitialSpan. - heartbeatBa := newBa(true /* withTxn */) - heartbeatBa.Add(&roachpb.HeartbeatTxnRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: txn.Key, - }, - Now: now, - }) - - endTxnBa := newBa(true /* withTxn */) - endTxnBa.Add(&roachpb.EndTransactionRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: txn.Key, - }, - Commit: true, - IntentSpans: []roachpb.Span{ - {Key: intentKey}, - }, - }) - - splitBa := newBa(true /* withTxn */) - splitBa.Add(&roachpb.EndTransactionRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: txn.Key, - }, - Commit: true, - IntentSpans: []roachpb.Span{ - {Key: intentKey}, - }, - InternalCommitTrigger: &roachpb.InternalCommitTrigger{ - SplitTrigger: &roachpb.SplitTrigger{ - LeftDesc: roachpb.RangeDescriptor{ - RangeID: 100, - StartKey: roachpb.RKey("a"), - EndKey: roachpb.RKey("m"), - }, - RightDesc: roachpb.RangeDescriptor{ - RangeID: 101, - StartKey: roachpb.RKey("n"), - EndKey: roachpb.RKey("z"), - }, - }, - }, - }) - - pushBa := newBa(false /* withTxn */) - pushBa.Add(&roachpb.PushTxnRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: txn.Key, - }, - PusheeTxn: txn.TxnMeta, - Now: now, - PushType: roachpb.PUSH_ABORT, - Force: true, - }) - - resolveIntentBa := newBa(false /* withTxn */) - resolveIntentBa.Add(&roachpb.ResolveIntentRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: intentKey, - }, - IntentTxn: txn.TxnMeta, - // NB: This test originally used PENDING but the test requires the abort - // cache key to be declared here, and this is no more the case due to an - // optimization. Use an ABORTED resolve instead... - Status: roachpb.ABORTED, - // ... but with Poison=false which accesses the AbortSpan by *clearing* - // it. Poison=true would fail the test since the transaction would not be - // able to issue further commands. - Poison: false, - }) - - getKeyBa := newBa(true /* withTxn */) - getKeyBa.Add(&roachpb.GetRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: intentKey, - }, - }) - - putKeyBa := newBa(true /* withTxn */) - putKeyBa.Add(&roachpb.PutRequest{ - RequestHeader: roachpb.RequestHeader{ - Key: intentKey, - }, - Value: roachpb.MakeValueFromBytes([]byte("val")), - }) - - t.Run("16266", func(t *testing.T) { - instrs := []cancelInstr{ - {reqOverride: heartbeatBa, expErr: "txn record not found"}, - {reqOverride: endTxnBa, expErr: "txn record not found"}, - {reqOverride: pushBa}, - {reqOverride: pushBa}, - } - - ct := newCmdQCancelTest(t) - ct.RunWithoutInitialSpan(instrs, []int{2}) - }) - t.Run("CancelEndTxn", func(t *testing.T) { - instrs := []cancelInstr{ - {reqOverride: endTxnBa, expErr: "txn record not found"}, - {reqOverride: heartbeatBa, expErr: "txn record not found"}, - {reqOverride: pushBa}, - {reqOverride: heartbeatBa, expErr: "txn record not found"}, - {reqOverride: resolveIntentBa}, - {reqOverride: pushBa}, - } - - for _, cancelOrder := range [][]int{ - {1, 2}, - {2, 1}, - } { - t.Run(fmt.Sprint(cancelOrder), func(t *testing.T) { - ct := newCmdQCancelTest(t) - ct.RunWithoutInitialSpan(instrs, cancelOrder) - }) - } - }) - t.Run("CancelResolveIntent", func(t *testing.T) { - instrs := []cancelInstr{ - {reqOverride: resolveIntentBa}, - {reqOverride: getKeyBa}, - {reqOverride: putKeyBa}, - {reqOverride: resolveIntentBa}, - {reqOverride: putKeyBa, expErr: "retry txn"}, - {reqOverride: getKeyBa}, - {reqOverride: putKeyBa, expErr: "retry txn"}, - {reqOverride: resolveIntentBa}, - {reqOverride: pushBa}, - } - - for _, cancelOrder := range [][]int{ - {3, 4}, - {4, 3}, - {6, 3}, - {6, 5, 4, 3, 2}, - {2, 3, 4, 5, 6}, - {2, 6, 3, 5, 4}, - } { - t.Run(fmt.Sprint(cancelOrder), func(t *testing.T) { - ct := newCmdQCancelTest(t) - ct.RunWithoutInitialSpan(instrs, cancelOrder) - }) - } - }) - t.Run("CancelSplit", func(t *testing.T) { - instrs := []cancelInstr{ - {reqOverride: resolveIntentBa}, - {reqOverride: getKeyBa}, - {reqOverride: putKeyBa}, - {reqOverride: splitBa}, - {reqOverride: putKeyBa, expErr: "retry txn"}, - {reqOverride: getKeyBa}, - {reqOverride: endTxnBa, expErr: "txn record not found"}, - {reqOverride: resolveIntentBa}, - } - - for _, cancelOrder := range [][]int{ - {3}, - {3, 6}, - {6, 3}, - {1, 3, 5, 6}, - {5, 1, 6, 3}, - } { - t.Run(fmt.Sprint(cancelOrder), func(t *testing.T) { - ct := newCmdQCancelTest(t) - ct.RunWithoutInitialSpan(instrs, cancelOrder) - }) - } - }) -} - -type cancelInstr struct { - span roachpb.Span - reqOverride *roachpb.BatchRequest // overrides span when present - expErr string -} - -func (ci cancelInstr) req() *roachpb.BatchRequest { - if req := ci.reqOverride; req != nil { - if s := ci.span; s.Key != nil || s.EndKey != nil { - panic(fmt.Sprintf("if overriding instr request, span must be empty; found %v", ci)) - } - if req.Timestamp.WallTime != cmdQCancelTestTimestamp { - panic(fmt.Sprintf("BatchRequest should have WallTime %v; found %v", - cmdQCancelTestTimestamp, req.Timestamp.WallTime)) - } - if req.Txn != nil { - for _, ru := range req.Requests { - assignSeqNumsForReqs(req.Txn, ru.GetInner()) - } - } - return req - } - // Default to a DeleteRangeRequest because it performs a single write over its Span. - ba := roachpb.BatchRequest{} - ba.Timestamp = hlc.Timestamp{WallTime: cmdQCancelTestTimestamp} - ba.Add(&roachpb.DeleteRangeRequest{RequestHeader: roachpb.RequestHeaderFromSpan(ci.span)}) - return &ba -} - -type cmdQCancelTest struct { - testing.TB - s *stop.Stopper - tc testContext - tsc StoreConfig - - // the following channels intercept requests and block them. - blockCmdBegin, blockCmdFinish chan struct{} - // the following channels track CommandQueueActions. - enteredCmdQ, canceledCmd, startingCmd chan struct{} - - cmds map[int]*testCmd -} - -type testCmd struct { - id int - spanSet *spanset.SpanSet - prereqs map[int]struct{} - cancel context.CancelFunc - done <-chan *roachpb.Error - expErr string -} - -func newCmdQCancelTest(t *testing.T) *cmdQCancelTest { - ct := &cmdQCancelTest{ - TB: t, - s: stop.NewStopper(), - tsc: TestStoreConfig(nil), - blockCmdBegin: make(chan struct{}), - enteredCmdQ: make(chan struct{}), - canceledCmd: make(chan struct{}), - startingCmd: make(chan struct{}), - cmds: make(map[int]*testCmd), - } - ct.tsc.TestingKnobs.OnCommandQueueAction = ct.onCmdQAction - return ct -} - -// letCmdsRun unblocks commands in the CommandQueue that are ready to run. They -// will then be blocked when they try to exit the CommandQueue. -func (ct *cmdQCancelTest) letCmdsRun() { - ct.blockCmdFinish = make(chan struct{}) - close(ct.blockCmdBegin) -} - -// letCmdsFinish unblocks commands that are ready to exit the CommandQueue and -// finish. It resets the block on cmds in the CommandQueue so that they don't -// immediately start running. -func (ct *cmdQCancelTest) letCmdsFinish() { - ct.blockCmdBegin = make(chan struct{}) - close(ct.blockCmdFinish) -} - -const ( - // cmdQCancelTestTimestamp is the WallTime all BatchRequests in - // cmdQCancelTest should use. This allows them to be identified and - // intercepted by the onCmdQAction handler. - cmdQCancelTestTimestamp = 12345 - // cmdQCancelTestDeadlockTimeout is the timeout used in cmdQCancelTest to - // determine that a deadlock has occurred. - cmdQCancelTestDeadlockTimeout = 500 * time.Millisecond - // cmdQCancelTestProgressTimeout is the timeout used in cmdQCancelTest to - // wait for any unexpected progress, before determining that progress has - // properly halted. Once this timeout expires, the cmdQCancelTest unblocks - // other commands to allow for further progress. - cmdQCancelTestProgressTimeout = 10 * time.Millisecond -) - -// onCmdQAction instruments CommandQueueActions, sending to different channels -// depending on the action. The instrumentation is also used to block commands -// at different stages of execution. -func (ct *cmdQCancelTest) onCmdQAction( - ba *roachpb.BatchRequest, action storagebase.CommandQueueAction, -) { - if ba.Header.Timestamp.WallTime == cmdQCancelTestTimestamp { - quiesce := ct.s.ShouldQuiesce() - switch action { - case storagebase.CommandQueueWaitForPrereqs: - select { - case ct.enteredCmdQ <- struct{}{}: - case <-quiesce: - } - case storagebase.CommandQueueCancellation: - select { - case ct.canceledCmd <- struct{}{}: - case <-quiesce: - } - case storagebase.CommandQueueBeginExecuting: - select { - case <-ct.blockCmdBegin: - case <-quiesce: - } - select { - case ct.startingCmd <- struct{}{}: - case <-quiesce: - } - case storagebase.CommandQueueFinishExecuting: - select { - case <-ct.blockCmdFinish: - case <-quiesce: - } - } - } -} - -// startInstr will create a goroutine to send the BatchRequest. It returns a -// channel that will be given the result of the request when it completes. -func (ct *cmdQCancelTest) startInstr( - ctx context.Context, ba *roachpb.BatchRequest, -) <-chan *roachpb.Error { - done := make(chan *roachpb.Error) - if err := ct.s.RunAsyncTask(context.Background(), "test", func(_ context.Context) { - _, pErr := ct.tc.Sender().Send(ctx, *ba) - select { - case done <- pErr: - case <-ct.s.ShouldQuiesce(): - } - }); err != nil { - ct.Fatal(err) - } - return done -} - -func spanSetsOverlap(ss, ss2 *spanset.SpanSet) bool { - for ac1 := spanset.SpanAccess(0); ac1 < spanset.NumSpanAccess; ac1++ { - for ac2 := spanset.SpanAccess(0); ac2 < spanset.NumSpanAccess; ac2++ { - if ac1 == spanset.SpanReadOnly && ac2 == spanset.SpanReadOnly { - // Reads ignore other reads. - continue - } - for sc := spanset.SpanScope(0); sc < spanset.NumSpanScope; sc++ { - for _, s := range ss.GetSpans(ac1, sc) { - for _, s2 := range ss2.GetSpans(ac2, sc) { - if s.Overlaps(s2) { - return true - } - } - } - } - } - } - return false -} - -// insertCmds inserts each command into the CommandQueue, populating the cmds map -// while doing so. -func (ct *cmdQCancelTest) insertCmds(instrs []cancelInstr) { - for i, instr := range instrs { - // Create a new context for each instruction with a cancel function. - ctx, cancel := context.WithCancel(context.Background()) - - ba := instr.req() - spanSet, err := collectSpans(roachpb.RangeDescriptor{}, ba) - if err != nil { - ct.Fatal(err) - } - - // Start command and wait until the new command is in the command queue. - cmdDone := ct.startInstr(ctx, ba) - select { - case <-ct.enteredCmdQ: - case <-time.After(cmdQCancelTestDeadlockTimeout): - ct.Fatalf("request %v never entered CommandQueue", ba) - } - - // Determine the prereq set of each command, including all transitive - // dependencies. Add the new command to the cmds map. - prereqs := make(map[int]struct{}) - for j, prevCmd := range ct.cmds { - if spanSetsOverlap(spanSet, prevCmd.spanSet) { - prereqs[j] = struct{}{} - for trans := range prevCmd.prereqs { - prereqs[trans] = struct{}{} - } - } else if j == 0 { - ct.Fatalf("all instruction spans should overlap the initial span; found %v", - instr.span) - } - } - ct.cmds[i] = &testCmd{ - id: i, - spanSet: spanSet, - prereqs: prereqs, - cancel: cancel, - done: cmdDone, - expErr: instr.expErr, - } - } -} - -// cancelCmds cancels all testCmds that need to be canceled, in the provided -// order. -func (ct *cmdQCancelTest) cancelCmds(cancelOrder []int) { - for _, cancelID := range cancelOrder { - if cancelID == 0 { - ct.Fatalf("the first cancelInstr cannot be canceled") - } - - cmd, ok := ct.cmds[cancelID] - if !ok { - ct.Fatalf("command %d not found", cancelID) - } - - // Cancel the context on each cmd that should be canceled. - cmd.cancel() - - // If either of these deadlocks, the command was never canceled and may have - // unexpectedly begun executing. Indeed, the absence of such a deadlock is - // what's being tested here. - select { - case <-ct.canceledCmd: - case <-time.After(cmdQCancelTestDeadlockTimeout): - ct.Fatalf("command %d never left CommandQueue after cancellation", cancelID) - } - select { - case pErr := <-cmd.done: - if ctxCancelErr := context.Canceled; !testutils.IsPError(pErr, ctxCancelErr.Error()) { - ct.Fatalf("expected error %v for cmd %d, found %v", ctxCancelErr, cancelID, pErr) - } - case <-time.After(cmdQCancelTestDeadlockTimeout): - ct.Fatalf("command %d never returned to client after cancellation", cancelID) - } - - // Remove the command from the cmds map and delete it from the - // prereq sets of all pending cmds. - delete(ct.cmds, cancelID) - for _, cmd := range ct.cmds { - delete(cmd.prereqs, cancelID) - } - } -} - -// runCmds runs all testCmds that were not canceled. -func (ct *cmdQCancelTest) runCmds() { - for len(ct.cmds) > 0 { - // Determine the commands we expect to be ready to run. Remove these - // from the cmds map and from the prereq sets of all cmds still pending. - var readyToRun []*testCmd - for i, cmd := range ct.cmds { - if len(cmd.prereqs) == 0 { - readyToRun = append(readyToRun, cmd) - delete(ct.cmds, i) - } - } - - readyLen := len(readyToRun) - if readyLen == 0 { - ct.Fatal("found no commands ready to run") - } - for _, cmd := range ct.cmds { - for _, ready := range readyToRun { - delete(cmd.prereqs, ready.id) - } - } - - // We should see exactly this many commands begin executing. If we see - // fewer or more we'll deadlock, which is what we're testing for. - ct.letCmdsRun() - for i := range readyToRun { - select { - case <-ct.startingCmd: - case <-time.After(cmdQCancelTestDeadlockTimeout): - ct.Fatalf("expected %d commands to begin running together, saw %d", readyLen, i) - } - } - select { - case <-ct.startingCmd: - ct.Fatalf("expected %d commands to begin running together, saw extra", readyLen) - case <-time.After(cmdQCancelTestProgressTimeout): - } - - // We should see exactly this many command finish. Again, the absence - // of a deadlock is what we're testing for. - ct.letCmdsFinish() - for _, running := range readyToRun { - select { - case pErr := <-running.done: - if running.expErr == "" { - if pErr != nil { - ct.Fatalf("expected no error for cmd %d, found %v", running.id, pErr) - } - } else { - if !testutils.IsPError(pErr, running.expErr) { - ct.Fatalf("expected error %q for cmd %d, found %v", - running.expErr, running.id, pErr) - } - } - case <-time.After(cmdQCancelTestDeadlockTimeout): - ct.Fatalf("command %d never returned to client", running.id) - } - } - } -} - -// Run runs the cmdQCancelTest with the provided cancelInstrs. Commands will be -// canceled in the order provided. -func (ct *cmdQCancelTest) Run(instrs []cancelInstr, cancelOrder []int) { - // Create an initial span that will block all others until we're ready to - // begin monitoring. This initial span cannot be canceled before exiting - // the prereq wait period. - initial := cancelInstr{ - span: roachpb.Span{Key: keys.SystemMax, EndKey: keys.TableDataMin}, - } - - // Update the cancel order to account for the new instr. - newCancelOrder := make([]int, len(cancelOrder)) - for i, cancelID := range cancelOrder { - newCancelOrder[i] = cancelID + 1 - } - - ct.RunWithoutInitialSpan(append([]cancelInstr{initial}, instrs...), newCancelOrder) -} - -// RunWithoutInitialSpan runs the cmdQCancelTest with the provided cancelInstrs. -// Commands will be canceled in the order provided. The first cancelInstrs -// should be a prereq of all other instructions and cannot be canceled. Use -// ct.Run to assure this. -func (ct *cmdQCancelTest) RunWithoutInitialSpan(instrs []cancelInstr, cancelOrder []int) { - defer ct.s.Stop(context.Background()) - ct.tc.StartWithStoreConfig(ct, ct.s, ct.tsc) - - ct.insertCmds(instrs) - ct.cancelCmds(cancelOrder) - ct.runCmds() -} - -// TestReplicaCommandQueueSelfOverlap verifies that self-overlapping -// batches are allowed, and in particular do not deadlock by -// introducing command-queue dependencies between the parts of the -// batch. -func TestReplicaCommandQueueSelfOverlap(t *testing.T) { +// TestReplicaLatchingSelfOverlap verifies that self-overlapping batches are +// allowed, and in particular do not deadlock by introducing latch dependencies +// between the parts of the batch. +func TestReplicaLatchingSelfOverlap(t *testing.T) { defer leaktest.AfterTest(t)() tc := testContext{} stopper := stop.NewStopper() @@ -3240,9 +2441,9 @@ func TestReplicaCommandQueueSelfOverlap(t *testing.T) { }) } -// TestReplicaCommandQueueTimestampNonInterference verifies that +// TestReplicaLatchingTimestampNonInterference verifies that // reads with earlier timestamps do not interfere with writes. -func TestReplicaCommandQueueTimestampNonInterference(t *testing.T) { +func TestReplicaLatchingTimestampNonInterference(t *testing.T) { defer leaktest.AfterTest(t)() var blockKey, blockReader, blockWriter atomic.Value @@ -3352,13 +2553,13 @@ func TestReplicaCommandQueueTimestampNonInterference(t *testing.T) { } } -// TestReplicaCommandQueueSplitDeclaresWrites verifies that split +// TestReplicaLatchingSplitDeclaresWrites verifies that split // operations declare write access to their entire span. This is // necessary to avoid conflicting changes to the range's stats, even // though splits do not actually write to their data span (and // therefore a failure to declare writes are not caught directly by // any other test). -func TestReplicaCommandQueueSplitDeclaresWrites(t *testing.T) { +func TestReplicaLatchingSplitDeclaresWrites(t *testing.T) { defer leaktest.AfterTest(t)() var spans spanset.SpanSet @@ -3386,103 +2587,6 @@ func TestReplicaCommandQueueSplitDeclaresWrites(t *testing.T) { } } -// TestReplicaCommandQueuePrereqDebugSummary tests the debug summary logged -// about a request's prerequisites when entering the command queue. -func TestReplicaCommandQueuePrereqDebugSummary(t *testing.T) { - defer leaktest.AfterTest(t)() - - var ba1, ba2, ba3 roachpb.BatchRequest - txn := newTransaction("test", []byte("k"), 1, nil) - bt, _ := beginTxnArgs([]byte("k"), txn) - put := putArgs([]byte("k"), []byte("v")) - et, _ := endTxnArgs(txn, true) - ba1.Add(&bt) - ba2.Add(&put, &put, &put) - ba3.Add(&bt, &put, &et) - cmdForBatch := func(ba *roachpb.BatchRequest) *cmd { - return &cmd{debugInfo: ba} - } - - testCases := []struct { - prereqs prereqCmdSet - expect string - }{ - { - prereqs: prereqCmdSet{ - /* SpanReadOnly */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {}, - }, - /* SpanReadWrite */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {}, - }, - }, - expect: "no prereqs", - }, - { - prereqs: prereqCmdSet{ - /* SpanReadOnly */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {}, - }, - /* SpanReadWrite */ { - /* SpanGlobal */ {cmdForBatch(&ba3)}, - /* SpanLocal */ {}, - }, - }, - expect: "{write/global: [1 Put, 1 BeginTxn, 1 EndTxn]}", - }, - { - prereqs: prereqCmdSet{ - /* SpanReadOnly */ { - /* SpanGlobal */ {cmdForBatch(&ba1)}, - /* SpanLocal */ {cmdForBatch(&ba1)}, - }, - /* SpanReadWrite */ { - /* SpanGlobal */ {cmdForBatch(&ba2)}, - /* SpanLocal */ {cmdForBatch(&ba3)}, - }, - }, - expect: "{read/global: [1 BeginTxn]} {read/local: [1 BeginTxn]} {write/global: [3 Put]} {write/local: [1 Put, 1 BeginTxn, 1 EndTxn]}", - }, - { - prereqs: prereqCmdSet{ - /* SpanReadOnly */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {cmdForBatch(&ba1)}, - }, - /* SpanReadWrite */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {cmdForBatch(&ba1), cmdForBatch(&ba2), cmdForBatch(&ba3), cmdForBatch(&ba1)}, - }, - }, - expect: "{read/local: [1 BeginTxn]} {write/local: [1 BeginTxn], [3 Put], [1 Put, 1 BeginTxn, 1 EndTxn], [1 BeginTxn]}", - }, - { - prereqs: prereqCmdSet{ - /* SpanReadOnly */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {cmdForBatch(&ba1)}, - }, - /* SpanReadWrite */ { - /* SpanGlobal */ {}, - /* SpanLocal */ {cmdForBatch(&ba1), cmdForBatch(&ba2), cmdForBatch(&ba3), cmdForBatch(&ba1), cmdForBatch(&ba2), cmdForBatch(&ba3)}, - }, - }, - expect: "{read/local: [1 BeginTxn]} {write/local: [1 BeginTxn], [3 Put], [1 Put, 1 BeginTxn, 1 EndTxn], [1 BeginTxn], [3 Put], ...}", - }, - } - for _, test := range testCases { - t.Run(test.expect, func(t *testing.T) { - s := prereqDebugSummary(test.prereqs) - if s != test.expect { - t.Errorf("expected %q for %+v, found %q", test.expect, test.prereqs, s) - } - }) - } -} - // TestReplicaUseTSCache verifies that write timestamps are upgraded // based on the read timestamp cache. func TestReplicaUseTSCache(t *testing.T) { @@ -7545,8 +6649,8 @@ func TestReplicaCancelRaft(t *testing.T) { } // TestReplicaTryAbandon checks that canceling a request that has been -// proposed to Raft but before it has been executed correctly cleans up the -// command queue. See #11986. +// proposed to Raft but before it has been executed correctly releases +// its latches. See #11986. func TestReplicaTryAbandon(t *testing.T) { defer leaktest.AfterTest(t)() stopper := stop.NewStopper() @@ -7600,7 +6704,7 @@ func TestReplicaTryAbandon(t *testing.T) { } // Despite the cancellation the request should still be occupying the - // proposals map and command queue. + // proposals map and should still hold its latches. func() { tc.repl.mu.Lock() defer tc.repl.mu.Unlock() @@ -7609,13 +6713,10 @@ func TestReplicaTryAbandon(t *testing.T) { } }() - func() { - tc.repl.cmdQMu.Lock() - defer tc.repl.cmdQMu.Unlock() - if s := tc.repl.cmdQMu.queues[spanset.SpanGlobal].String(); s == "" { - t.Fatal("expected non-empty command queue") - } - }() + latchInfoGlobal, _ := tc.repl.latchMgr.Info() + if w := latchInfoGlobal.WriteCount; w == 0 { + t.Fatal("expected non-empty latch manager") + } // Allow the proposal to go through. close(proposalCh) @@ -7623,13 +6724,12 @@ func TestReplicaTryAbandon(t *testing.T) { t.Fatal(err) } - // Even though we canceled the command it will still get executed and the - // command queue cleaned up. + // Even though we canceled the command it will still get executed and its + // latches cleaned up. testutils.SucceedsSoon(t, func() error { - tc.repl.cmdQMu.Lock() - defer tc.repl.cmdQMu.Unlock() - if s := tc.repl.cmdQMu.queues[spanset.SpanGlobal].String(); s != "" { - return errors.Errorf("expected empty command queue, but found\n%s", s) + latchInfoGlobal, _ := tc.repl.latchMgr.Info() + if w := latchInfoGlobal.WriteCount; w != 0 { + return errors.Errorf("expected empty latch manager") } return nil }) @@ -9129,7 +8229,7 @@ func TestReplicaMetrics(t *testing.T) { context.Background(), hlc.Timestamp{}, &cfg.RaftConfig, &zoneConfig, c.liveness, 0, &c.desc, c.raftStatus, storagepb.LeaseStatus{}, c.storeID, c.expected.Quiescent, c.expected.Ticking, - CommandQueueMetrics{}, CommandQueueMetrics{}, c.raftLogSize) + storagepb.LatchManagerInfo{}, storagepb.LatchManagerInfo{}, c.raftLogSize) if c.expected != metrics { t.Fatalf("unexpected metrics:\n%s", pretty.Diff(c.expected, metrics)) } diff --git a/pkg/storage/spanlatch/manager.go b/pkg/storage/spanlatch/manager.go index 89fc6483b001..5ac733ea4828 100644 --- a/pkg/storage/spanlatch/manager.go +++ b/pkg/storage/spanlatch/manager.go @@ -16,12 +16,18 @@ package spanlatch import ( "context" + "fmt" "unsafe" + "github.com/cockroachdb/cockroach/pkg/base" "github.com/cockroachdb/cockroach/pkg/roachpb" "github.com/cockroachdb/cockroach/pkg/storage/spanset" + "github.com/cockroachdb/cockroach/pkg/storage/storagepb" "github.com/cockroachdb/cockroach/pkg/util/hlc" + "github.com/cockroachdb/cockroach/pkg/util/log" + "github.com/cockroachdb/cockroach/pkg/util/metric" "github.com/cockroachdb/cockroach/pkg/util/syncutil" + "github.com/cockroachdb/cockroach/pkg/util/timeutil" ) // A Manager maintains an interval tree of key and key range latches. Latch @@ -53,9 +59,10 @@ import ( // // Manager's zero value can be used directly. type Manager struct { - mu syncutil.Mutex - idAlloc uint64 - scopes [spanset.NumSpanScope]scopedManager + mu syncutil.Mutex + idAlloc uint64 + scopes [spanset.NumSpanScope]scopedManager + slowReqs *metric.Gauge } // scopedManager is a latch manager scoped to either local or global keys. @@ -65,6 +72,12 @@ type scopedManager struct { trees [spanset.NumSpanAccess]btree } +// Init initializes the Manager. Calling the method is optional as the type's +// zero value is valid to use directly. +func (m *Manager) Init(slowReqs *metric.Gauge) { + m.slowReqs = slowReqs +} + // latches are stored in the Manager's btrees. They represent the latching // of a single key span. type latch struct { @@ -75,6 +88,10 @@ type latch struct { next, prev *latch // readSet linked-list. } +func (la *latch) String() string { + return fmt.Sprintf("%s@%s", la.span, la.ts) +} + func (la *latch) inReadSet() bool { return la.next != nil } @@ -185,7 +202,7 @@ func (m *Manager) Acquire( lg, snap := m.sequence(spans, ts) defer snap.close() - err := m.wait(ctx, lg, ts, snap) + err := m.wait(ctx, lg, snap) if err != nil { m.Release(lg) return nil, err @@ -312,7 +329,11 @@ func ifGlobal(ts hlc.Timestamp, s spanset.SpanScope) hlc.Timestamp { // wait waits for all interfering latches in the provided snapshot to complete // before returning. -func (m *Manager) wait(ctx context.Context, lg *Guard, ts hlc.Timestamp, snap snapshot) error { +func (m *Manager) wait(ctx context.Context, lg *Guard, snap snapshot) error { + timer := timeutil.NewTimer() + timer.Reset(base.SlowRequestThreshold) + defer timer.Stop() + for s := spanset.SpanScope(0); s < spanset.NumSpanScope; s++ { tr := &snap.trees[s] for a := spanset.SpanAccess(0); a < spanset.NumSpanAccess; a++ { @@ -323,7 +344,7 @@ func (m *Manager) wait(ctx context.Context, lg *Guard, ts hlc.Timestamp, snap sn case spanset.SpanReadOnly: // Wait for writes at equal or lower timestamps. it := tr[spanset.SpanReadWrite].MakeIter() - if err := iterAndWait(ctx, &it, latch, ts, ignoreLater); err != nil { + if err := m.iterAndWait(ctx, timer, &it, latch, ignoreLater); err != nil { return err } case spanset.SpanReadWrite: @@ -334,12 +355,12 @@ func (m *Manager) wait(ctx context.Context, lg *Guard, ts hlc.Timestamp, snap sn // latches first. We expect writes to take longer than reads // to release their latches, so we wait on them first. it := tr[spanset.SpanReadWrite].MakeIter() - if err := iterAndWait(ctx, &it, latch, ts, ignoreNothing); err != nil { + if err := m.iterAndWait(ctx, timer, &it, latch, ignoreNothing); err != nil { return err } // Wait for reads at equal or higher timestamps. it = tr[spanset.SpanReadOnly].MakeIter() - if err := iterAndWait(ctx, &it, latch, ts, ignoreEarlier); err != nil { + if err := m.iterAndWait(ctx, timer, &it, latch, ignoreEarlier); err != nil { return err } default: @@ -354,25 +375,44 @@ func (m *Manager) wait(ctx context.Context, lg *Guard, ts hlc.Timestamp, snap sn // iterAndWait uses the provided iterator to wait on all latches that overlap // with the search latch and which should not be ignored given their timestamp // and the supplied ignoreFn. -func iterAndWait( - ctx context.Context, it *iterator, search *latch, ts hlc.Timestamp, ignore ignoreFn, +func (m *Manager) iterAndWait( + ctx context.Context, t *timeutil.Timer, it *iterator, wait *latch, ignore ignoreFn, ) error { - done := ctx.Done() - for it.FirstOverlap(search); it.Valid(); it.NextOverlap() { - latch := it.Cur() - if latch.done.signaled() { + for it.FirstOverlap(wait); it.Valid(); it.NextOverlap() { + held := it.Cur() + if held.done.signaled() { continue } - if ignore(ts, latch.ts) { + if ignore(wait.ts, held.ts) { continue } + if err := m.waitForSignal(ctx, t, wait, held); err != nil { + return err + } + } + return nil +} + +// waitForSignal waits for the latch that is currently held to be signaled. +func (m *Manager) waitForSignal(ctx context.Context, t *timeutil.Timer, wait, held *latch) error { + for { select { - case <-latch.done.signalChan(): - case <-done: + case <-held.done.signalChan(): + return nil + case <-t.C: + t.Read = true + defer t.Reset(base.SlowRequestThreshold) + + log.Warningf(ctx, "have been waiting %s to acquire latch %s, held by %s", + base.SlowRequestThreshold, wait, held) + if m.slowReqs != nil { + m.slowReqs.Inc(1) + defer m.slowReqs.Dec(1) + } + case <-ctx.Done(): return ctx.Err() } } - return nil } // Release releases the latches held by the provided Guard. After being called, @@ -404,3 +444,19 @@ func (m *Manager) removeLocked(lg *Guard) { } } } + +// Info returns information about the state of the Manager. +func (m *Manager) Info() (global, local storagepb.LatchManagerInfo) { + m.mu.Lock() + defer m.mu.Unlock() + global = m.scopes[spanset.SpanGlobal].infoLocked() + local = m.scopes[spanset.SpanLocal].infoLocked() + return global, local +} + +func (sm *scopedManager) infoLocked() storagepb.LatchManagerInfo { + var info storagepb.LatchManagerInfo + info.ReadCount = int64(sm.trees[spanset.SpanReadOnly].Len() + sm.readSet.len) + info.WriteCount = int64(sm.trees[spanset.SpanReadWrite].Len()) + return info +} diff --git a/pkg/storage/spanlatch/manager_test.go b/pkg/storage/spanlatch/manager_test.go index 10daa1a5a178..5b80d071036d 100644 --- a/pkg/storage/spanlatch/manager_test.go +++ b/pkg/storage/spanlatch/manager_test.go @@ -104,7 +104,7 @@ func (m *Manager) MustAcquireChCtx( ch := make(chan *Guard) lg, snap := m.sequence(spans, ts) go func() { - err := m.wait(ctx, lg, ts, snap) + err := m.wait(ctx, lg, snap) if err != nil { m.Release(lg) lg = nil diff --git a/pkg/storage/spanset/spanset.go b/pkg/storage/spanset/spanset.go index 7c0c5002cbea..c8e8f686e7bf 100644 --- a/pkg/storage/spanset/spanset.go +++ b/pkg/storage/spanset/spanset.go @@ -73,7 +73,7 @@ func (a SpanScope) String() string { // SpanSet tracks the set of key spans touched by a command. The set // is divided into subsets for access type (read-only or read/write) // and key scope (local or global; used to facilitate use by the -// separate local and global command queues). +// separate local and global latches). type SpanSet struct { spans [NumSpanAccess][NumSpanScope][]roachpb.Span } @@ -118,6 +118,15 @@ func (ss *SpanSet) Add(access SpanAccess, span roachpb.Span) { ss.spans[access][scope] = append(ss.spans[access][scope], span) } +// SortAndDedup sorts the spans in the SpanSet and removes any duplicates. +func (ss *SpanSet) SortAndDedup() { + for i := SpanAccess(0); i < NumSpanAccess; i++ { + for j := SpanScope(0); j < NumSpanScope; j++ { + ss.spans[i][j], _ /* distinct */ = roachpb.MergeSpans(ss.spans[i][j]) + } + } +} + // GetSpans returns a slice of spans with the given parameters. func (ss *SpanSet) GetSpans(access SpanAccess, scope SpanScope) []roachpb.Span { return ss.spans[access][scope] diff --git a/pkg/storage/storagebase/base.go b/pkg/storage/storagebase/base.go index 9cfd2d4e0601..c439b6a5efc2 100644 --- a/pkg/storage/storagebase/base.go +++ b/pkg/storage/storagebase/base.go @@ -79,9 +79,8 @@ func (f *FilterArgs) InRaftCmd() bool { } // ReplicaRequestFilter can be used in testing to influence the error returned -// from a request before it is evaluated. Notably, the filter is run before the -// request is added to the CommandQueue, so blocking in the filter will not -// block interfering requests. +// from a request before it is evaluated. Return nil to continue with regular +// processing or non-nil to terminate processing with the returned error. type ReplicaRequestFilter func(roachpb.BatchRequest) *roachpb.Error // ReplicaCommandFilter may be used in tests through the StoreTestingKnobs to @@ -103,28 +102,6 @@ type ReplicaApplyFilter func(args ApplyFilterArgs) *roachpb.Error // been processed. This filter is invoked only by the command proposer. type ReplicaResponseFilter func(roachpb.BatchRequest, *roachpb.BatchResponse) *roachpb.Error -// CommandQueueAction is an action taken by a BatchRequest's batchCmdSet on the -// CommandQueue. -type CommandQueueAction int - -const ( - // CommandQueueWaitForPrereqs represents the state of a batchCmdSet when it - // has just inserted itself into the CommandQueue and is beginning to wait - // for prereqs to finish execution. - CommandQueueWaitForPrereqs CommandQueueAction = iota - // CommandQueueCancellation represents the state of a batchCmdSet when it - // is canceled while waiting for prerequisites to finish and is forced to - // remove itself from the CommandQueue without executing. - CommandQueueCancellation - // CommandQueueBeginExecuting represents the state of a batchCmdSet when it - // has finished waiting for all prereqs to finish execution and is now free - // to execute itself. - CommandQueueBeginExecuting - // CommandQueueFinishExecuting represents the state of a batchCmdSet when it - // has finished executing and will remove itself from the CommandQueue. - CommandQueueFinishExecuting -) - // ContainsKey returns whether this range contains the specified key. func ContainsKey(desc roachpb.RangeDescriptor, key roachpb.Key) bool { if bytes.HasPrefix(key, keys.LocalRangeIDPrefix) { diff --git a/pkg/storage/storagepb/lease_status.pb.go b/pkg/storage/storagepb/lease_status.pb.go index 44f2ba82b76b..92e4185d7876 100644 --- a/pkg/storage/storagepb/lease_status.pb.go +++ b/pkg/storage/storagepb/lease_status.pb.go @@ -27,7 +27,7 @@ RaftCommand ReplicaState RangeInfo - CommandQueuesSnapshot + LatchManagerInfo */ package storagepb diff --git a/pkg/storage/storagepb/state.pb.go b/pkg/storage/storagepb/state.pb.go index b33d3885397b..8c56a488009f 100644 --- a/pkg/storage/storagepb/state.pb.go +++ b/pkg/storage/storagepb/state.pb.go @@ -12,8 +12,6 @@ import cockroach_roachpb "github.com/cockroachdb/cockroach/pkg/roachpb" import cockroach_roachpb1 "github.com/cockroachdb/cockroach/pkg/roachpb" import cockroach_util_hlc "github.com/cockroachdb/cockroach/pkg/util/hlc" -import sortkeys "github.com/gogo/protobuf/sortkeys" - import io "io" // Reference imports to suppress errors if they are not otherwise used. @@ -101,43 +99,22 @@ func (m *RangeInfo) String() string { return proto.CompactTextString( func (*RangeInfo) ProtoMessage() {} func (*RangeInfo) Descriptor() ([]byte, []int) { return fileDescriptorState, []int{1} } -// CommandQueueSnapshot is a snapshot of the command queue graph for rendering -// on an admin UI debug page. While the actual CommandQueue uses interval trees -// for fast mutation and lookups, all the UI needs is a simple map of commands. -type CommandQueuesSnapshot struct { - // Timestamp in nanoseconds when this snapshot was taken. - Timestamp cockroach_util_hlc.Timestamp `protobuf:"bytes,1,opt,name=timestamp" json:"timestamp"` - // localScope and globalScope are maps from command ids to commands. - LocalScope map[int64]CommandQueuesSnapshot_Command `protobuf:"bytes,2,rep,name=localScope" json:"localScope" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` - GlobalScope map[int64]CommandQueuesSnapshot_Command `protobuf:"bytes,3,rep,name=globalScope" json:"globalScope" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` -} - -func (m *CommandQueuesSnapshot) Reset() { *m = CommandQueuesSnapshot{} } -func (m *CommandQueuesSnapshot) String() string { return proto.CompactTextString(m) } -func (*CommandQueuesSnapshot) ProtoMessage() {} -func (*CommandQueuesSnapshot) Descriptor() ([]byte, []int) { return fileDescriptorState, []int{2} } - -type CommandQueuesSnapshot_Command struct { - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` - EndKey string `protobuf:"bytes,3,opt,name=end_key,json=endKey,proto3" json:"end_key,omitempty"` - Readonly bool `protobuf:"varint,4,opt,name=readonly,proto3" json:"readonly,omitempty"` - Timestamp cockroach_util_hlc.Timestamp `protobuf:"bytes,5,opt,name=timestamp" json:"timestamp"` - Prereqs []int64 `protobuf:"varint,6,rep,packed,name=prereqs" json:"prereqs,omitempty"` +// LatchManagerInfo is used for reporting status information about a spanlatch +// manager out through the status server. +type LatchManagerInfo struct { + ReadCount int64 `protobuf:"varint,1,opt,name=read_count,json=readCount,proto3" json:"read_count,omitempty"` + WriteCount int64 `protobuf:"varint,2,opt,name=write_count,json=writeCount,proto3" json:"write_count,omitempty"` } -func (m *CommandQueuesSnapshot_Command) Reset() { *m = CommandQueuesSnapshot_Command{} } -func (m *CommandQueuesSnapshot_Command) String() string { return proto.CompactTextString(m) } -func (*CommandQueuesSnapshot_Command) ProtoMessage() {} -func (*CommandQueuesSnapshot_Command) Descriptor() ([]byte, []int) { - return fileDescriptorState, []int{2, 0} -} +func (m *LatchManagerInfo) Reset() { *m = LatchManagerInfo{} } +func (m *LatchManagerInfo) String() string { return proto.CompactTextString(m) } +func (*LatchManagerInfo) ProtoMessage() {} +func (*LatchManagerInfo) Descriptor() ([]byte, []int) { return fileDescriptorState, []int{2} } func init() { proto.RegisterType((*ReplicaState)(nil), "cockroach.storage.storagepb.ReplicaState") proto.RegisterType((*RangeInfo)(nil), "cockroach.storage.storagepb.RangeInfo") - proto.RegisterType((*CommandQueuesSnapshot)(nil), "cockroach.storage.storagepb.CommandQueuesSnapshot") - proto.RegisterType((*CommandQueuesSnapshot_Command)(nil), "cockroach.storage.storagepb.CommandQueuesSnapshot.Command") + proto.RegisterType((*LatchManagerInfo)(nil), "cockroach.storage.storagepb.LatchManagerInfo") } func (this *ReplicaState) Equal(that interface{}) bool { if that == nil { @@ -383,93 +360,7 @@ func (m *RangeInfo) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *CommandQueuesSnapshot) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CommandQueuesSnapshot) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintState(dAtA, i, uint64(m.Timestamp.Size())) - n8, err := m.Timestamp.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n8 - if len(m.LocalScope) > 0 { - keysForLocalScope := make([]int64, 0, len(m.LocalScope)) - for k := range m.LocalScope { - keysForLocalScope = append(keysForLocalScope, int64(k)) - } - sortkeys.Int64s(keysForLocalScope) - for _, k := range keysForLocalScope { - dAtA[i] = 0x12 - i++ - v := m.LocalScope[int64(k)] - msgSize := 0 - if (&v) != nil { - msgSize = (&v).Size() - msgSize += 1 + sovState(uint64(msgSize)) - } - mapSize := 1 + sovState(uint64(k)) + msgSize - i = encodeVarintState(dAtA, i, uint64(mapSize)) - dAtA[i] = 0x8 - i++ - i = encodeVarintState(dAtA, i, uint64(k)) - dAtA[i] = 0x12 - i++ - i = encodeVarintState(dAtA, i, uint64((&v).Size())) - n9, err := (&v).MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n9 - } - } - if len(m.GlobalScope) > 0 { - keysForGlobalScope := make([]int64, 0, len(m.GlobalScope)) - for k := range m.GlobalScope { - keysForGlobalScope = append(keysForGlobalScope, int64(k)) - } - sortkeys.Int64s(keysForGlobalScope) - for _, k := range keysForGlobalScope { - dAtA[i] = 0x1a - i++ - v := m.GlobalScope[int64(k)] - msgSize := 0 - if (&v) != nil { - msgSize = (&v).Size() - msgSize += 1 + sovState(uint64(msgSize)) - } - mapSize := 1 + sovState(uint64(k)) + msgSize - i = encodeVarintState(dAtA, i, uint64(mapSize)) - dAtA[i] = 0x8 - i++ - i = encodeVarintState(dAtA, i, uint64(k)) - dAtA[i] = 0x12 - i++ - i = encodeVarintState(dAtA, i, uint64((&v).Size())) - n10, err := (&v).MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n10 - } - } - return i, nil -} - -func (m *CommandQueuesSnapshot_Command) Marshal() (dAtA []byte, err error) { +func (m *LatchManagerInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -479,63 +370,20 @@ func (m *CommandQueuesSnapshot_Command) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *CommandQueuesSnapshot_Command) MarshalTo(dAtA []byte) (int, error) { +func (m *LatchManagerInfo) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l - if m.Id != 0 { + if m.ReadCount != 0 { dAtA[i] = 0x8 i++ - i = encodeVarintState(dAtA, i, uint64(m.Id)) - } - if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintState(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) - } - if len(m.EndKey) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintState(dAtA, i, uint64(len(m.EndKey))) - i += copy(dAtA[i:], m.EndKey) - } - if m.Readonly { - dAtA[i] = 0x20 - i++ - if m.Readonly { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i++ + i = encodeVarintState(dAtA, i, uint64(m.ReadCount)) } - dAtA[i] = 0x2a - i++ - i = encodeVarintState(dAtA, i, uint64(m.Timestamp.Size())) - n11, err := m.Timestamp.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n11 - if len(m.Prereqs) > 0 { - dAtA13 := make([]byte, len(m.Prereqs)*10) - var j12 int - for _, num1 := range m.Prereqs { - num := uint64(num1) - for num >= 1<<7 { - dAtA13[j12] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j12++ - } - dAtA13[j12] = uint8(num) - j12++ - } - dAtA[i] = 0x32 + if m.WriteCount != 0 { + dAtA[i] = 0x10 i++ - i = encodeVarintState(dAtA, i, uint64(j12)) - i += copy(dAtA[i:], dAtA13[:j12]) + i = encodeVarintState(dAtA, i, uint64(m.WriteCount)) } return i, nil } @@ -614,57 +462,14 @@ func (m *RangeInfo) Size() (n int) { return n } -func (m *CommandQueuesSnapshot) Size() (n int) { +func (m *LatchManagerInfo) Size() (n int) { var l int _ = l - l = m.Timestamp.Size() - n += 1 + l + sovState(uint64(l)) - if len(m.LocalScope) > 0 { - for k, v := range m.LocalScope { - _ = k - _ = v - l = v.Size() - mapEntrySize := 1 + sovState(uint64(k)) + 1 + l + sovState(uint64(l)) - n += mapEntrySize + 1 + sovState(uint64(mapEntrySize)) - } - } - if len(m.GlobalScope) > 0 { - for k, v := range m.GlobalScope { - _ = k - _ = v - l = v.Size() - mapEntrySize := 1 + sovState(uint64(k)) + 1 + l + sovState(uint64(l)) - n += mapEntrySize + 1 + sovState(uint64(mapEntrySize)) - } - } - return n -} - -func (m *CommandQueuesSnapshot_Command) Size() (n int) { - var l int - _ = l - if m.Id != 0 { - n += 1 + sovState(uint64(m.Id)) - } - l = len(m.Key) - if l > 0 { - n += 1 + l + sovState(uint64(l)) - } - l = len(m.EndKey) - if l > 0 { - n += 1 + l + sovState(uint64(l)) + if m.ReadCount != 0 { + n += 1 + sovState(uint64(m.ReadCount)) } - if m.Readonly { - n += 2 - } - l = m.Timestamp.Size() - n += 1 + l + sovState(uint64(l)) - if len(m.Prereqs) > 0 { - l = 0 - for _, e := range m.Prereqs { - l += sovState(uint64(e)) - } - n += 1 + sovState(uint64(l)) + l + if m.WriteCount != 0 { + n += 1 + sovState(uint64(m.WriteCount)) } return n } @@ -1182,7 +987,7 @@ func (m *RangeInfo) Unmarshal(dAtA []byte) error { } return nil } -func (m *CommandQueuesSnapshot) Unmarshal(dAtA []byte) error { +func (m *LatchManagerInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1205,321 +1010,17 @@ func (m *CommandQueuesSnapshot) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: CommandQueuesSnapshot: wiretype end group for non-group") + return fmt.Errorf("proto: LatchManagerInfo: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: CommandQueuesSnapshot: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Timestamp.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LocalScope", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.LocalScope == nil { - m.LocalScope = make(map[int64]CommandQueuesSnapshot_Command) - } - var mapkey int64 - mapvalue := &CommandQueuesSnapshot_Command{} - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - mapkey |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - } else if fieldNum == 2 { - var mapmsglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - mapmsglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if mapmsglen < 0 { - return ErrInvalidLengthState - } - postmsgIndex := iNdEx + mapmsglen - if mapmsglen < 0 { - return ErrInvalidLengthState - } - if postmsgIndex > l { - return io.ErrUnexpectedEOF - } - mapvalue = &CommandQueuesSnapshot_Command{} - if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { - return err - } - iNdEx = postmsgIndex - } else { - iNdEx = entryPreIndex - skippy, err := skipState(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthState - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - m.LocalScope[mapkey] = *mapvalue - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field GlobalScope", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.GlobalScope == nil { - m.GlobalScope = make(map[int64]CommandQueuesSnapshot_Command) - } - var mapkey int64 - mapvalue := &CommandQueuesSnapshot_Command{} - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - mapkey |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - } else if fieldNum == 2 { - var mapmsglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - mapmsglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if mapmsglen < 0 { - return ErrInvalidLengthState - } - postmsgIndex := iNdEx + mapmsglen - if mapmsglen < 0 { - return ErrInvalidLengthState - } - if postmsgIndex > l { - return io.ErrUnexpectedEOF - } - mapvalue = &CommandQueuesSnapshot_Command{} - if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { - return err - } - iNdEx = postmsgIndex - } else { - iNdEx = entryPreIndex - skippy, err := skipState(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthState - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - m.GlobalScope[mapkey] = *mapvalue - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipState(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthState - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CommandQueuesSnapshot_Command) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Command: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Command: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: LatchManagerInfo: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ReadCount", wireType) } - m.Id = 0 + m.ReadCount = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowState @@ -1529,74 +1030,16 @@ func (m *CommandQueuesSnapshot_Command) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Id |= (int64(b) & 0x7F) << shift + m.ReadCount |= (int64(b) & 0x7F) << shift if b < 0x80 { break } } case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Key = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EndKey", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.EndKey = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Readonly", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field WriteCount", wireType) } - var v int + m.WriteCount = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowState @@ -1606,104 +1049,11 @@ func (m *CommandQueuesSnapshot_Command) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + m.WriteCount |= (int64(b) & 0x7F) << shift if b < 0x80 { break } } - m.Readonly = bool(v != 0) - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Timestamp.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType == 0 { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - m.Prereqs = append(m.Prereqs, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthState - } - postIndex := iNdEx + packedLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - for iNdEx < postIndex { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowState - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - m.Prereqs = append(m.Prereqs, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Prereqs", wireType) - } default: iNdEx = preIndex skippy, err := skipState(dAtA[iNdEx:]) @@ -1833,64 +1183,53 @@ var ( func init() { proto.RegisterFile("storage/storagepb/state.proto", fileDescriptorState) } var fileDescriptorState = []byte{ - // 931 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcd, 0x6e, 0xdb, 0x46, - 0x17, 0x35, 0x45, 0xca, 0x96, 0x86, 0x49, 0xac, 0x6f, 0xbe, 0xa4, 0x21, 0x14, 0x58, 0x12, 0x54, - 0xb4, 0x50, 0x81, 0x94, 0x02, 0xdc, 0x1f, 0x14, 0x46, 0x37, 0x91, 0x52, 0x04, 0x76, 0x9c, 0xc2, - 0xa1, 0x8c, 0x2e, 0xba, 0x21, 0x46, 0xe4, 0x98, 0x22, 0x3c, 0x9c, 0x99, 0x70, 0x86, 0x81, 0xe4, - 0x07, 0xe8, 0xba, 0x8f, 0xd0, 0x7d, 0x9f, 0xa1, 0x7b, 0x2f, 0x03, 0x74, 0xd3, 0x95, 0xd0, 0xaa, - 0x9b, 0xac, 0xfb, 0x04, 0xc5, 0x0c, 0x7f, 0x2c, 0xb9, 0x46, 0x1a, 0x78, 0xd1, 0x95, 0xc8, 0x73, - 0xcf, 0xb9, 0xf7, 0xce, 0xe1, 0x21, 0x05, 0xf6, 0x84, 0x64, 0x29, 0x8a, 0xf0, 0xb0, 0xf8, 0xe5, - 0xd3, 0xa1, 0x90, 0x48, 0x62, 0x97, 0xa7, 0x4c, 0x32, 0xf8, 0x28, 0x60, 0xc1, 0x79, 0xca, 0x50, - 0x30, 0x73, 0x0b, 0x82, 0x5b, 0x11, 0xdb, 0xfd, 0x52, 0x8b, 0x69, 0x14, 0xd3, 0xf2, 0x87, 0x4f, - 0x87, 0xc9, 0xeb, 0x20, 0xc8, 0x1b, 0xb4, 0x1f, 0x69, 0x31, 0x9f, 0x0e, 0x63, 0x2a, 0x71, 0x4a, - 0x11, 0xf1, 0x53, 0x74, 0x26, 0x8b, 0xe2, 0x07, 0x65, 0x31, 0xc1, 0x12, 0x85, 0x48, 0xa2, 0x02, - 0x87, 0x25, 0xbe, 0x86, 0x39, 0x99, 0x8c, 0xc9, 0x70, 0x46, 0x82, 0xa1, 0x8c, 0x13, 0x2c, 0x24, - 0x4a, 0x78, 0x51, 0xb9, 0x1f, 0xb1, 0x88, 0xe9, 0xcb, 0xa1, 0xba, 0xca, 0xd1, 0xfe, 0xcf, 0x75, - 0x70, 0xc7, 0xc3, 0x9c, 0xc4, 0x01, 0x9a, 0xa8, 0x03, 0xc1, 0xc7, 0x00, 0xaa, 0xd1, 0x3e, 0xe2, - 0x9c, 0xc4, 0x38, 0xf4, 0x63, 0x1a, 0xe2, 0xb9, 0x63, 0xf4, 0x8c, 0x81, 0xe5, 0xb5, 0x54, 0xe5, - 0x49, 0x5e, 0x38, 0x54, 0x38, 0x74, 0xc1, 0xff, 0x09, 0x46, 0x02, 0x5f, 0xa3, 0xd7, 0x34, 0xfd, - 0x7f, 0xba, 0xb4, 0xc1, 0xff, 0x12, 0x58, 0x21, 0x16, 0x81, 0x63, 0xf6, 0x8c, 0x81, 0xbd, 0xdf, - 0x77, 0xaf, 0x7c, 0x2b, 0xce, 0xe2, 0x7a, 0x88, 0x46, 0xf8, 0x29, 0x16, 0x41, 0x1a, 0x73, 0xc9, - 0x52, 0x4f, 0xf3, 0xa1, 0x0b, 0xea, 0xba, 0x99, 0x63, 0x69, 0xa1, 0x73, 0x83, 0xf0, 0x58, 0xd5, - 0xbd, 0x9c, 0x06, 0xbf, 0x05, 0xbb, 0x32, 0xcd, 0x68, 0x80, 0x24, 0x0e, 0x7d, 0xfd, 0xa4, 0x9c, - 0xba, 0x56, 0x7e, 0x74, 0xe3, 0xc8, 0x33, 0x79, 0x5a, 0xb2, 0xb5, 0x0b, 0xde, 0x3d, 0xb9, 0x71, - 0x0f, 0x19, 0xb8, 0x13, 0x05, 0xbe, 0x9c, 0xa5, 0x58, 0xcc, 0x18, 0x09, 0x9d, 0x6d, 0xdd, 0x6c, - 0x6f, 0xad, 0x99, 0xf2, 0xdd, 0x9d, 0x91, 0xc0, 0x3d, 0x2d, 0x7d, 0x1f, 0x7d, 0xba, 0x5a, 0x76, - 0xed, 0x67, 0xe3, 0xd3, 0x52, 0xf5, 0xd7, 0xb2, 0xdb, 0xae, 0x04, 0xe1, 0xf4, 0xa0, 0x9f, 0x22, - 0x1a, 0xd2, 0x8c, 0x10, 0x34, 0x25, 0xb8, 0xef, 0xd9, 0x51, 0x50, 0x51, 0xe1, 0x08, 0xd4, 0xd5, - 0xda, 0xc2, 0xd9, 0xd1, 0x93, 0x1e, 0xbb, 0xff, 0x4c, 0x58, 0x9e, 0x23, 0xb7, 0x8c, 0x93, 0xfb, - 0xe2, 0xbb, 0xf1, 0x58, 0x6d, 0x2b, 0xbc, 0x5c, 0x0a, 0x7f, 0x30, 0xc0, 0x03, 0x39, 0xa7, 0xbe, - 0xe0, 0x88, 0xfa, 0x1b, 0xeb, 0x37, 0xdf, 0x67, 0xfd, 0xcf, 0x57, 0xcb, 0x2e, 0x3c, 0x9d, 0xd3, - 0x09, 0x47, 0xf4, 0xfd, 0x4f, 0x01, 0x65, 0xa1, 0x58, 0x3b, 0xcc, 0x17, 0xe0, 0x61, 0x26, 0x62, - 0x1a, 0x55, 0x29, 0xd1, 0x4f, 0xc4, 0x3f, 0xc7, 0x0b, 0xc7, 0xee, 0x19, 0x83, 0x86, 0x77, 0x5f, - 0x97, 0x8b, 0xa4, 0x68, 0xc7, 0x9f, 0xe3, 0xc5, 0x81, 0xf5, 0xf6, 0xa7, 0xae, 0x71, 0x64, 0x35, - 0x1a, 0xad, 0xe6, 0x91, 0xd5, 0x00, 0x2d, 0xbb, 0xff, 0x6b, 0x0d, 0x34, 0x75, 0x40, 0x0e, 0xe9, - 0x19, 0x83, 0x87, 0xb9, 0x47, 0x58, 0xa7, 0xd3, 0xde, 0xff, 0xc4, 0x7d, 0xc7, 0x5b, 0xe8, 0xae, - 0x87, 0x7c, 0xd4, 0xb8, 0x5c, 0x76, 0xb7, 0xde, 0x2c, 0xbb, 0x46, 0x6e, 0x15, 0x86, 0x7b, 0x00, - 0x10, 0x24, 0xe4, 0x46, 0x7c, 0x9b, 0x0a, 0xc9, 0x63, 0xdb, 0x05, 0x36, 0xcd, 0x12, 0x9f, 0x63, - 0x1a, 0xc6, 0x34, 0xd2, 0xe9, 0xb5, 0x3c, 0x40, 0xb3, 0xe4, 0x24, 0x47, 0x4a, 0x42, 0x98, 0x32, - 0xce, 0x71, 0xa8, 0xb3, 0x96, 0x13, 0x9e, 0xe6, 0x08, 0xec, 0x83, 0xbb, 0xfa, 0xb5, 0x22, 0x2c, - 0xf2, 0x45, 0x7c, 0x81, 0x75, 0x82, 0x4c, 0xcf, 0x56, 0xe0, 0x31, 0x8b, 0x26, 0xf1, 0x05, 0x86, - 0x5f, 0x83, 0x36, 0xe2, 0x3c, 0x65, 0xf3, 0x38, 0x51, 0xf6, 0xf0, 0x94, 0x71, 0x26, 0x10, 0xf1, - 0x5f, 0x65, 0x4c, 0x22, 0x1d, 0x04, 0xd3, 0x73, 0xd6, 0x18, 0x27, 0x05, 0xe1, 0xa5, 0xaa, 0xc3, - 0x8f, 0xc1, 0x6e, 0xaa, 0xac, 0xf1, 0x13, 0x34, 0xf7, 0xa7, 0x0b, 0x89, 0x85, 0xd3, 0xd0, 0x92, - 0xbb, 0x1a, 0x7e, 0x81, 0xe6, 0x23, 0x05, 0x56, 0xae, 0x5a, 0xad, 0xfa, 0x91, 0xd5, 0x68, 0xb6, - 0x40, 0xff, 0x6d, 0x1d, 0x3c, 0x18, 0xb3, 0x24, 0x41, 0x34, 0x7c, 0x99, 0xe1, 0x0c, 0x8b, 0x09, - 0x45, 0x5c, 0xcc, 0x98, 0x84, 0x4f, 0x40, 0xb3, 0xfa, 0x8c, 0x14, 0x2e, 0xff, 0x4b, 0x68, 0x2c, - 0xe5, 0xac, 0x77, 0xa5, 0x82, 0x33, 0x00, 0x08, 0x0b, 0x10, 0x99, 0x04, 0x8c, 0x63, 0xa7, 0xd6, - 0x33, 0x07, 0xf6, 0xfe, 0xe8, 0x9d, 0x4f, 0xea, 0xc6, 0x55, 0xdc, 0xe3, 0xaa, 0xc9, 0x37, 0x54, - 0xa6, 0x8b, 0x62, 0xd0, 0x5a, 0x6f, 0x78, 0x0e, 0xec, 0x88, 0xb0, 0x69, 0x39, 0xca, 0xd4, 0xa3, - 0xc6, 0xb7, 0x18, 0xf5, 0xec, 0xaa, 0xcb, 0xfa, 0xac, 0xf5, 0xee, 0xed, 0x5f, 0x0c, 0xb0, 0x53, - 0xa8, 0xe1, 0x3d, 0x50, 0x8b, 0x43, 0x6d, 0x8f, 0xe9, 0xd5, 0xe2, 0x10, 0xb6, 0x80, 0xa9, 0xa2, - 0xad, 0x52, 0xd4, 0xf4, 0xd4, 0x25, 0x7c, 0x08, 0x76, 0x30, 0x0d, 0x75, 0xe0, 0x4d, 0x8d, 0x6e, - 0x63, 0x1a, 0x3e, 0xc7, 0x0b, 0xd8, 0x06, 0x8d, 0x14, 0xa3, 0x90, 0x51, 0xb2, 0xd0, 0x9f, 0xb6, - 0x86, 0x57, 0xdd, 0x6f, 0x9a, 0x5f, 0xbf, 0x95, 0xf9, 0x0e, 0xd8, 0xe1, 0x29, 0x4e, 0xf1, 0x2b, - 0xe1, 0x6c, 0xf7, 0xcc, 0x81, 0xe9, 0x95, 0xb7, 0xed, 0x05, 0xd8, 0xbd, 0xe6, 0x68, 0xb9, 0x76, - 0x7e, 0x0e, 0xbd, 0xf6, 0x09, 0xa8, 0xbf, 0x46, 0x24, 0xc3, 0xfa, 0x28, 0xf6, 0xfe, 0xc1, 0x2d, - 0xbc, 0x2c, 0x50, 0x2f, 0x6f, 0x74, 0x50, 0xfb, 0xca, 0x68, 0x5f, 0x80, 0xd6, 0x75, 0x87, 0xff, - 0xab, 0xd9, 0xa3, 0x0f, 0x2f, 0xff, 0xe8, 0x6c, 0x5d, 0xae, 0x3a, 0xc6, 0x9b, 0x55, 0xc7, 0xf8, - 0x6d, 0xd5, 0x31, 0x7e, 0x5f, 0x75, 0x8c, 0x1f, 0xff, 0xec, 0x6c, 0x7d, 0xdf, 0xac, 0xba, 0x4d, - 0xb7, 0xf5, 0x5f, 0xe3, 0x67, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x24, 0x81, 0x28, 0xbf, 0xf5, - 0x07, 0x00, 0x00, + // 756 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcf, 0x6e, 0xdb, 0x36, + 0x1c, 0x8e, 0x62, 0x39, 0xb3, 0xa9, 0x64, 0xf1, 0xb8, 0x6c, 0x13, 0x1c, 0xd8, 0x0e, 0x34, 0x6c, + 0xc8, 0x80, 0x4c, 0x06, 0xb2, 0xb5, 0x87, 0xa0, 0x97, 0xda, 0x01, 0x8a, 0xa4, 0x49, 0x91, 0x2a, + 0x46, 0x0f, 0xbd, 0x08, 0xb4, 0xc4, 0xc8, 0x42, 0x24, 0x92, 0x25, 0xa9, 0xd6, 0xc9, 0x03, 0xf4, + 0xdc, 0x47, 0xe8, 0xbd, 0x2f, 0x92, 0x63, 0x80, 0x5e, 0x7a, 0x32, 0x5a, 0xf7, 0xd2, 0x73, 0x9f, + 0xa0, 0x20, 0x25, 0xb9, 0x76, 0x1b, 0x14, 0x39, 0x49, 0xfe, 0xfe, 0x90, 0xfc, 0x7d, 0xfc, 0x64, + 0xd0, 0x12, 0x92, 0x72, 0x14, 0xe1, 0x6e, 0xf1, 0x64, 0xc3, 0xae, 0x90, 0x48, 0x62, 0x97, 0x71, + 0x2a, 0x29, 0xdc, 0x0c, 0x68, 0x70, 0xce, 0x29, 0x0a, 0x46, 0x6e, 0x21, 0x70, 0x67, 0xc2, 0xa6, + 0x53, 0x7a, 0x31, 0x89, 0x62, 0x52, 0x3e, 0xd8, 0xb0, 0x9b, 0x3e, 0x0f, 0x82, 0x7c, 0x81, 0xe6, + 0xa6, 0x36, 0xb3, 0x61, 0x37, 0x26, 0x12, 0x73, 0x82, 0x12, 0x9f, 0xa3, 0x33, 0x59, 0x90, 0xbf, + 0x97, 0x64, 0x8a, 0x25, 0x0a, 0x91, 0x44, 0x05, 0x0e, 0x4b, 0x7c, 0x0e, 0xb3, 0x33, 0x19, 0x27, + 0xdd, 0x51, 0x12, 0x74, 0x65, 0x9c, 0x62, 0x21, 0x51, 0xca, 0x0a, 0x66, 0x23, 0xa2, 0x11, 0xd5, + 0xaf, 0x5d, 0xf5, 0x96, 0xa3, 0xce, 0x9b, 0x2a, 0x58, 0xf5, 0x30, 0x4b, 0xe2, 0x00, 0x9d, 0xaa, + 0x81, 0xe0, 0x0e, 0x80, 0x6a, 0x6b, 0x1f, 0x31, 0x96, 0xc4, 0x38, 0xf4, 0x63, 0x12, 0xe2, 0xb1, + 0x6d, 0x6c, 0x19, 0xdb, 0xa6, 0xd7, 0x50, 0xcc, 0xfd, 0x9c, 0x38, 0x50, 0x38, 0x74, 0xc1, 0xaf, + 0x09, 0x46, 0x02, 0x7f, 0x23, 0x5f, 0xd6, 0xf2, 0x5f, 0x34, 0xb5, 0xa0, 0xbf, 0x0b, 0xcc, 0x10, + 0x8b, 0xc0, 0xae, 0x6c, 0x19, 0xdb, 0xd6, 0xae, 0xe3, 0x7e, 0xcd, 0xad, 0x98, 0xc5, 0xf5, 0x10, + 0x89, 0xf0, 0x3e, 0x16, 0x01, 0x8f, 0x99, 0xa4, 0xdc, 0xd3, 0x7a, 0xe8, 0x82, 0xaa, 0x5e, 0xcc, + 0x36, 0xb5, 0xd1, 0xbe, 0xc1, 0x78, 0xa4, 0x78, 0x2f, 0x97, 0xc1, 0x47, 0x60, 0x5d, 0xf2, 0x8c, + 0x04, 0x48, 0xe2, 0xd0, 0xd7, 0x37, 0x65, 0x57, 0xb5, 0xf3, 0xaf, 0x1b, 0xb7, 0x3c, 0x93, 0x83, + 0x52, 0xad, 0x53, 0xf0, 0x7e, 0x96, 0x0b, 0xbf, 0x21, 0x05, 0xab, 0x51, 0xe0, 0xcb, 0x11, 0xc7, + 0x62, 0x44, 0x93, 0xd0, 0x5e, 0xd1, 0x8b, 0xb5, 0xe6, 0x16, 0x53, 0xb9, 0xbb, 0xa3, 0x24, 0x70, + 0x07, 0x65, 0xee, 0xbd, 0x7f, 0xa7, 0x93, 0x8e, 0xf5, 0xa0, 0x3f, 0x28, 0x5d, 0x9f, 0x27, 0x9d, + 0xe6, 0xcc, 0x10, 0x0e, 0xf7, 0x1c, 0x8e, 0x48, 0x48, 0xb2, 0x24, 0x41, 0xc3, 0x04, 0x3b, 0x9e, + 0x15, 0x05, 0x33, 0x29, 0xec, 0x81, 0xaa, 0x3a, 0xb6, 0xb0, 0x7f, 0xd2, 0x3b, 0xed, 0xb8, 0xdf, + 0x37, 0x2c, 0xef, 0x91, 0x5b, 0xd6, 0xc9, 0x3d, 0x7e, 0xd2, 0xef, 0xab, 0xd3, 0x0a, 0x2f, 0xb7, + 0xc2, 0x97, 0x06, 0xf8, 0x4d, 0x8e, 0x89, 0x2f, 0x18, 0x22, 0xfe, 0xc2, 0xf1, 0xeb, 0xb7, 0x39, + 0xfe, 0xff, 0xd3, 0x49, 0x07, 0x0e, 0xc6, 0xe4, 0x94, 0x21, 0x72, 0xfb, 0x29, 0xa0, 0x2c, 0x1c, + 0x73, 0xc3, 0xdc, 0x01, 0x7f, 0x64, 0x22, 0x26, 0xd1, 0xac, 0x25, 0xfa, 0x46, 0xfc, 0x73, 0x7c, + 0x61, 0x5b, 0x5b, 0xc6, 0x76, 0xcd, 0xdb, 0xd0, 0x74, 0xd1, 0x14, 0x9d, 0xf8, 0x43, 0x7c, 0xb1, + 0x67, 0x7e, 0x7a, 0xdd, 0x31, 0x0e, 0xcd, 0x5a, 0xad, 0x51, 0x3f, 0x34, 0x6b, 0xa0, 0x61, 0x39, + 0x6f, 0x97, 0x41, 0x5d, 0x17, 0xe4, 0x80, 0x9c, 0x51, 0x78, 0x90, 0x67, 0x84, 0x75, 0x3b, 0xad, + 0xdd, 0x7f, 0xdc, 0x1f, 0x7c, 0x85, 0xee, 0x7c, 0xc9, 0x7b, 0xb5, 0xab, 0x49, 0x67, 0xe9, 0x7a, + 0xd2, 0x31, 0xf2, 0xa8, 0x30, 0x6c, 0x01, 0x90, 0x20, 0x21, 0x17, 0xea, 0x5b, 0x57, 0x48, 0x5e, + 0xdb, 0x0e, 0xb0, 0x48, 0x96, 0xfa, 0x0c, 0x93, 0x30, 0x26, 0x91, 0x6e, 0xaf, 0xe9, 0x01, 0x92, + 0xa5, 0x27, 0x39, 0x52, 0x0a, 0x42, 0x4e, 0x19, 0xc3, 0xa1, 0xee, 0x5a, 0x2e, 0xd8, 0xcf, 0x11, + 0xe8, 0x80, 0x35, 0xfd, 0x59, 0x25, 0x34, 0xf2, 0x45, 0x7c, 0x89, 0x75, 0x83, 0x2a, 0x9e, 0xa5, + 0xc0, 0x23, 0x1a, 0x9d, 0xc6, 0x97, 0x18, 0xde, 0x03, 0x4d, 0xc4, 0x18, 0xa7, 0xe3, 0x38, 0x55, + 0xf1, 0x30, 0x4e, 0x19, 0x15, 0x28, 0xf1, 0x9f, 0x65, 0x54, 0x22, 0x5d, 0x84, 0x8a, 0x67, 0xcf, + 0x29, 0x4e, 0x0a, 0xc1, 0x63, 0xc5, 0xc3, 0xbf, 0xc1, 0x3a, 0x57, 0xd1, 0xf8, 0x29, 0x1a, 0xfb, + 0xc3, 0x0b, 0x89, 0x85, 0x5d, 0xd3, 0x96, 0x35, 0x0d, 0x1f, 0xa3, 0x71, 0x4f, 0x81, 0xb3, 0x54, + 0xcd, 0x46, 0xf5, 0xd0, 0xac, 0xd5, 0x1b, 0xc0, 0xf1, 0x40, 0xe3, 0x08, 0xc9, 0x60, 0x74, 0x8c, + 0x08, 0x8a, 0x30, 0xd7, 0xd9, 0xb6, 0x00, 0xe0, 0x18, 0x85, 0x7e, 0x40, 0x33, 0x22, 0x75, 0xc0, + 0x15, 0xaf, 0xae, 0x90, 0xbe, 0x02, 0xd4, 0xbc, 0x2f, 0x78, 0x2c, 0x71, 0xc1, 0x2f, 0x6b, 0x1e, + 0x68, 0x48, 0x0b, 0x7a, 0x7f, 0x5e, 0x7d, 0x68, 0x2f, 0x5d, 0x4d, 0xdb, 0xc6, 0xf5, 0xb4, 0x6d, + 0xbc, 0x9b, 0xb6, 0x8d, 0xf7, 0xd3, 0xb6, 0xf1, 0xea, 0x63, 0x7b, 0xe9, 0x69, 0x7d, 0x76, 0x27, + 0xc3, 0x15, 0xfd, 0x1f, 0xf4, 0xdf, 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0x26, 0xb3, 0x16, 0x00, + 0x5e, 0x05, 0x00, 0x00, } diff --git a/pkg/storage/storagepb/state.proto b/pkg/storage/storagepb/state.proto index 326c1270195d..d0937021be7a 100644 --- a/pkg/storage/storagepb/state.proto +++ b/pkg/storage/storagepb/state.proto @@ -102,22 +102,9 @@ message RangeInfo { reserved 9; } -// CommandQueueSnapshot is a snapshot of the command queue graph for rendering -// on an admin UI debug page. While the actual CommandQueue uses interval trees -// for fast mutation and lookups, all the UI needs is a simple map of commands. -message CommandQueuesSnapshot { - message Command { - int64 id = 1; - string key = 2; - string end_key = 3; - bool readonly = 4; - util.hlc.Timestamp timestamp = 5 [(gogoproto.nullable) = false]; - repeated int64 prereqs = 6; - } - - // Timestamp in nanoseconds when this snapshot was taken. - util.hlc.Timestamp timestamp = 1 [(gogoproto.nullable) = false]; - // localScope and globalScope are maps from command ids to commands. - map localScope = 2 [(gogoproto.nullable) = false]; - map globalScope = 3 [(gogoproto.nullable) = false]; +// LatchManagerInfo is used for reporting status information about a spanlatch +// manager out through the status server. +message LatchManagerInfo { + int64 read_count = 1; + int64 write_count = 2; } diff --git a/pkg/storage/store.go b/pkg/storage/store.go index 7ee51700062a..d2551a381db9 100644 --- a/pkg/storage/store.go +++ b/pkg/storage/store.go @@ -46,7 +46,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/storage/engine/enginepb" "github.com/cockroachdb/cockroach/pkg/storage/idalloc" "github.com/cockroachdb/cockroach/pkg/storage/raftentry" - "github.com/cockroachdb/cockroach/pkg/storage/spanset" "github.com/cockroachdb/cockroach/pkg/storage/stateloader" "github.com/cockroachdb/cockroach/pkg/storage/tscache" "github.com/cockroachdb/cockroach/pkg/storage/txnwait" @@ -4210,74 +4209,6 @@ func (s *Store) updateReplicationGauges(ctx context.Context) error { return nil } -// updateCommandQueueGauges updates a number of simple statistics for -// the CommandQueues of each replica in this store. -func (s *Store) updateCommandQueueGauges() error { - var ( - maxCommandQueueSize int64 - maxCommandQueueWriteCount int64 - maxCommandQueueReadCount int64 - maxCommandQueueTreeSize int64 - maxCommandQueueOverlaps int64 - combinedCommandQueueSize int64 - combinedCommandWriteCount int64 - combinedCommandReadCount int64 - ) - newStoreReplicaVisitor(s).Visit(func(rep *Replica) bool { - rep.cmdQMu.Lock() - - writes := rep.cmdQMu.queues[spanset.SpanGlobal].localMetrics.writeCommands - writes += rep.cmdQMu.queues[spanset.SpanLocal].localMetrics.writeCommands - - reads := rep.cmdQMu.queues[spanset.SpanGlobal].localMetrics.readCommands - reads += rep.cmdQMu.queues[spanset.SpanLocal].localMetrics.readCommands - - treeSize := int64(rep.cmdQMu.queues[spanset.SpanGlobal].treeSize()) - treeSize += int64(rep.cmdQMu.queues[spanset.SpanLocal].treeSize()) - - maxOverlaps := rep.cmdQMu.queues[spanset.SpanGlobal].localMetrics.maxOverlapsSeen - if locMax := rep.cmdQMu.queues[spanset.SpanLocal].localMetrics.maxOverlapsSeen; locMax > maxOverlaps { - maxOverlaps = locMax - } - rep.cmdQMu.queues[spanset.SpanGlobal].localMetrics.maxOverlapsSeen = 0 - rep.cmdQMu.queues[spanset.SpanLocal].localMetrics.maxOverlapsSeen = 0 - rep.cmdQMu.Unlock() - - cqSize := writes + reads - if cqSize > maxCommandQueueSize { - maxCommandQueueSize = cqSize - } - if writes > maxCommandQueueWriteCount { - maxCommandQueueWriteCount = writes - } - if reads > maxCommandQueueReadCount { - maxCommandQueueReadCount = reads - } - if treeSize > maxCommandQueueTreeSize { - maxCommandQueueTreeSize = treeSize - } - if maxOverlaps > maxCommandQueueOverlaps { - maxCommandQueueOverlaps = maxOverlaps - } - - combinedCommandQueueSize += cqSize - combinedCommandWriteCount += writes - combinedCommandReadCount += reads - return true // more - }) - - s.metrics.MaxCommandQueueSize.Update(maxCommandQueueSize) - s.metrics.MaxCommandQueueWriteCount.Update(maxCommandQueueWriteCount) - s.metrics.MaxCommandQueueReadCount.Update(maxCommandQueueReadCount) - s.metrics.MaxCommandQueueTreeSize.Update(maxCommandQueueTreeSize) - s.metrics.MaxCommandQueueOverlaps.Update(maxCommandQueueOverlaps) - s.metrics.CombinedCommandQueueSize.Update(combinedCommandQueueSize) - s.metrics.CombinedCommandWriteCount.Update(combinedCommandWriteCount) - s.metrics.CombinedCommandReadCount.Update(combinedCommandReadCount) - - return nil -} - // ComputeMetrics immediately computes the current value of store metrics which // cannot be computed incrementally. This method should be invoked periodically // by a higher-level system which records store metrics. @@ -4289,9 +4220,6 @@ func (s *Store) ComputeMetrics(ctx context.Context, tick int) error { if err := s.updateReplicationGauges(ctx); err != nil { return err } - if err := s.updateCommandQueueGauges(); err != nil { - return err - } // Get the latest RocksDB stats. stats, err := s.engine.GetStats() diff --git a/pkg/storage/testing_knobs.go b/pkg/storage/testing_knobs.go index 9c2541e1bdd3..74f74929838c 100644 --- a/pkg/storage/testing_knobs.go +++ b/pkg/storage/testing_knobs.go @@ -34,11 +34,17 @@ type StoreTestingKnobs struct { EvalKnobs storagebase.BatchEvalTestingKnobs // TestingRequestFilter is called before evaluating each command on a - // replica. The filter is run before the request is added to the - // CommandQueue, so blocking in the filter will not block interfering - // requests. If it returns an error, the command will not be evaluated. + // replica. The filter is run before the request acquires latches, so + // blocking in the filter will not block interfering requests. If it + // returns an error, the command will not be evaluated. TestingRequestFilter storagebase.ReplicaRequestFilter + // TestingLatchFilter is called before evaluating each command on a replica + // but after acquiring latches for the command. Blocking in the filter will + // block interfering requests. If it returns an error, the command will not + // be evaluated. + TestingLatchFilter storagebase.ReplicaRequestFilter + // TestingProposalFilter is called before proposing each command. TestingProposalFilter storagebase.ReplicaProposalFilter @@ -67,9 +73,6 @@ type StoreTestingKnobs struct { // TODO(kaneda): This hook is not encouraged to use. Get rid of it once // we make TestServer take a ManualClock. ClockBeforeSend func(*hlc.Clock, roachpb.BatchRequest) - // OnCommandQueueAction is called when the BatchRequest performs an action - // on the CommandQueue. - OnCommandQueueAction func(*roachpb.BatchRequest, storagebase.CommandQueueAction) // MaxOffset, if set, overrides the server clock's MaxOffset at server // creation time. // See also DisableMaxOffsetCheck. diff --git a/pkg/ui/package.json b/pkg/ui/package.json index 144cd3d00778..7e9de19838e7 100644 --- a/pkg/ui/package.json +++ b/pkg/ui/package.json @@ -44,7 +44,6 @@ "@types/d3-dispatch": "^1.0.4", "@types/d3-drag": "^1.1.0", "@types/d3-timer": "^1.0.5", - "@types/dagre-layout": "^0.8.0", "@types/enzyme": "^3.1.9", "@types/enzyme-adapter-react-16": "^1.0.2", "@types/fetch-mock": "^5.8.1", @@ -75,7 +74,6 @@ "css-loader": "^0.28.0", "d3": "<4.0.0", "d3-geo-projection": "^2.5.0", - "dagre-layout": "^0.8.0", "enzyme": "^3.3.0", "enzyme-adapter-react-16": "^1.1.1", "express": "^4.15.2", diff --git a/pkg/ui/src/index.tsx b/pkg/ui/src/index.tsx index 230a85f94ee1..98ebe7aa0449 100644 --- a/pkg/ui/src/index.tsx +++ b/pkg/ui/src/index.tsx @@ -49,7 +49,6 @@ import NodeOverview from "src/views/cluster/containers/nodeOverview"; import NodeLogs from "src/views/cluster/containers/nodeLogs"; import JobsPage from "src/views/jobs"; import Certificates from "src/views/reports/containers/certificates"; -import CommandQueue from "src/views/reports/containers/commandQueue"; import CustomChart from "src/views/reports/containers/customChart"; import Debug from "src/views/reports/containers/debug"; import EnqueueRange from "src/views/reports/containers/enqueueRange"; @@ -169,7 +168,6 @@ ReactDOM.render( - diff --git a/pkg/ui/src/redux/apiReducers.ts b/pkg/ui/src/redux/apiReducers.ts index 7c263a70d24a..917ee82f2d27 100644 --- a/pkg/ui/src/redux/apiReducers.ts +++ b/pkg/ui/src/redux/apiReducers.ts @@ -222,18 +222,6 @@ const rangeLogReducerObj = new KeyedCachedDataReducer( ); export const refreshRangeLog = rangeLogReducerObj.refresh; -export const commandQueueRequestKey = (req: api.CommandQueueRequestMessage): string => - _.isNil(req.range_id) ? "none" : req.range_id.toString(); - -const commandQueueReducerObj = new KeyedCachedDataReducer( - api.getCommandQueue, - "commandQueue", - commandQueueRequestKey, - moment.duration(0), - moment.duration(1, "m"), -); -export const refreshCommandQueue = commandQueueReducerObj.refresh; - export const settingsReducerObj = new CachedDataReducer( api.getSettings, "settings", @@ -291,7 +279,6 @@ export interface APIReducersState { range: KeyedCachedDataReducerState; allocatorRange: KeyedCachedDataReducerState; rangeLog: KeyedCachedDataReducerState; - commandQueue: KeyedCachedDataReducerState; settings: CachedDataReducerState; stores: KeyedCachedDataReducerState; statements: CachedDataReducerState; @@ -320,7 +307,6 @@ export const apiReducersReducer = combineReducers({ [rangeReducerObj.actionNamespace]: rangeReducerObj.reducer, [allocatorRangeReducerObj.actionNamespace]: allocatorRangeReducerObj.reducer, [rangeLogReducerObj.actionNamespace]: rangeLogReducerObj.reducer, - [commandQueueReducerObj.actionNamespace]: commandQueueReducerObj.reducer, [settingsReducerObj.actionNamespace]: settingsReducerObj.reducer, [storesReducerObj.actionNamespace]: storesReducerObj.reducer, [queriesReducerObj.actionNamespace]: queriesReducerObj.reducer, diff --git a/pkg/ui/src/util/api.ts b/pkg/ui/src/util/api.ts index e92f314f0b32..61b51c22b5ba 100644 --- a/pkg/ui/src/util/api.ts +++ b/pkg/ui/src/util/api.ts @@ -93,9 +93,6 @@ export type RangeLogRequestMessage = export type RangeLogResponseMessage = protos.cockroach.server.serverpb.RangeLogResponse; -export type CommandQueueRequestMessage = protos.cockroach.server.serverpb.CommandQueueRequest; -export type CommandQueueResponseMessage = protos.cockroach.server.serverpb.CommandQueueResponse; - export type SettingsRequestMessage = protos.cockroach.server.serverpb.SettingsRequest; export type SettingsResponseMessage = protos.cockroach.server.serverpb.SettingsResponse; @@ -328,11 +325,6 @@ export function getRangeLog( ); } -// getCommandQueue returns a representation of the command queue for a given range id -export function getCommandQueue(req: CommandQueueRequestMessage, timeout?: moment.Duration): Promise { - return timeoutFetch(serverpb.CommandQueueResponse, `${STATUS_PREFIX}/range/${req.range_id}/cmdqueue`, null, timeout); -} - // getSettings gets all cluster settings export function getSettings(_req: SettingsRequestMessage, timeout?: moment.Duration): Promise { return timeoutFetch(serverpb.SettingsResponse, `${API_PREFIX}/settings`, null, timeout); diff --git a/pkg/ui/src/views/cluster/containers/nodeGraphs/dashboards/requests.tsx b/pkg/ui/src/views/cluster/containers/nodeGraphs/dashboards/requests.tsx index 88038106e799..669128ed1e53 100644 --- a/pkg/ui/src/views/cluster/containers/nodeGraphs/dashboards/requests.tsx +++ b/pkg/ui/src/views/cluster/containers/nodeGraphs/dashboards/requests.tsx @@ -35,9 +35,9 @@ export default function (props: GraphDashboardProps) { , - - - + + + , ]; diff --git a/pkg/ui/src/views/reports/containers/commandQueue/commandQueueViz.tsx b/pkg/ui/src/views/reports/containers/commandQueue/commandQueueViz.tsx deleted file mode 100644 index 0d587ad7fcc2..000000000000 --- a/pkg/ui/src/views/reports/containers/commandQueue/commandQueueViz.tsx +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2018 The Cockroach Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. - -import _ from "lodash"; -import React from "react"; -import Long from "long"; -import classNames from "classnames"; -import * as dagre from "dagre-layout"; - -import * as protos from "src/js/protos"; -import Print from "src/views/reports/containers/range/print"; - -interface QueueVizProps { - queue: { - [ID: string]: protos.cockroach.storage.storagepb.CommandQueuesSnapshot.ICommand, - }; -} - -interface QueueVizState { - selectedNodeID: Long; -} - -const COMMAND_RADIUS = 10; -const COMMAND_DIAMETER = COMMAND_RADIUS * 2; - -export default class CommandQueueViz extends React.Component { - - constructor(props: QueueVizProps) { - super(props); - this.state = { - selectedNodeID: null, - }; - } - - computeLayout() { - const g = new dagre.graphlib.Graph(); - - g.setGraph({ - marginx: 20, - marginy: 20, - nodesep: 10, - }); - g.setDefaultEdgeLabel(() => ({})); - - _.forEach(this.props.queue, (command) => { - g.setNode(command.id.toString(), { - width: COMMAND_DIAMETER, - height: COMMAND_DIAMETER, - command: command, - }); - command.prereqs.forEach((prereq) => { - g.setEdge(prereq.toString(), command.id.toString()); - }); - }); - - dagre.layout(g); - - return g; - } - - renderDetailsTable(graph: dagre.graphlib.Graph) { - if (this.state.selectedNodeID === null) { - return (

Click on a node to see details.

); - } - - const command = graph.node(this.state.selectedNodeID.toString()).command; - return ( - - - - - - - - - - - - - - - - - - - -
ID{command.id.toString()}
Read Only{(!!command.readonly).toString()}
Key Range{command.key} to {command.end_key}
Timestamp - {command.timestamp.wall_time.toString()} - . - {command.timestamp.logical} - {" "}({Print.Timestamp(command.timestamp)}) -
- ); - } - - nodeIsSelected(nodeID: Long) { - return this.state.selectedNodeID !== null && this.state.selectedNodeID.equals(nodeID); - } - - render() { - const g = this.computeLayout(); - - const nodes = g.nodes().map((nodeId) => g.node(nodeId)); - const edges = g.edges().map((edgeId) => g.edge(edgeId)); - - if (nodes.length === 0) { - return ( -

No commands in queue

- ); - } - - return ( -
- - {nodes.map((node) => { - return ( - { this.setState({ selectedNodeID: node.command.id }); }} - className={classNames( - "command-queue__node", - node.command.readonly ? "read" : "write", - { selected: this.nodeIsSelected(node.command.id) }, - )} /> - ); - })} - {edges.map((edge: { points: Array<{x: number, y: number}> }, idx: number) => { - return ( - (`${x},${y}`)).join(" ")} - style={{stroke: "black", fill: "none"}} /> - ); - })} - - {this.renderDetailsTable(g)} -
- ); - } - -} diff --git a/pkg/ui/src/views/reports/containers/commandQueue/command_queue.styl b/pkg/ui/src/views/reports/containers/commandQueue/command_queue.styl deleted file mode 100644 index 29e307647374..000000000000 --- a/pkg/ui/src/views/reports/containers/commandQueue/command_queue.styl +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 The Cockroach Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. - -$read-color = lightgreen -$write-color = pink - -.command-queue svg - background-color white - -.command-queue__timestamp - margin-top 20px - -.command-queue__key - margin-top 10px - -.command-queue__key div - display inline-block - padding 5px - -.command-queue__key__read - background-color $read-color - margin-left 5px - margin-right 5px - -.command-queue__key__write - background-color $write-color - -.command-queue - table - border-collapse collapse - - table, th, td - border 1px solid black - - td - padding 5px - -.command-queue__node - stroke black - cursor pointer - - &.selected - stroke red - - &.read - fill $read-color - - &.write - fill $write-color diff --git a/pkg/ui/src/views/reports/containers/commandQueue/index.tsx b/pkg/ui/src/views/reports/containers/commandQueue/index.tsx deleted file mode 100644 index e46ea3da6d0a..000000000000 --- a/pkg/ui/src/views/reports/containers/commandQueue/index.tsx +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2018 The Cockroach Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. - -import _ from "lodash"; -import Long from "long"; -import { Link, RouterState } from "react-router"; -import React from "react"; -import { Helmet } from "react-helmet"; -import { connect } from "react-redux"; - -import * as protos from "src/js/protos"; -import { commandQueueRequestKey, refreshCommandQueue } from "src/redux/apiReducers"; -import { CachedDataReducerState } from "src/redux/cachedDataReducer"; -import { AdminUIState } from "src/redux/state"; -import { rangeIDAttr } from "src/util/constants"; -import Print from "src/views/reports/containers/range/print"; -import Loading from "src/views/shared/components/loading"; -import CommandQueueViz from "src/views/reports/containers/commandQueue/commandQueueViz"; - -import "./command_queue.styl"; - -interface CommandQueueOwnProps { - commandQueue: CachedDataReducerState; - refreshCommandQueue: typeof refreshCommandQueue; -} - -type CommandQueueProps = CommandQueueOwnProps & RouterState; - -function commandQueueRequestFromProps(props: CommandQueueProps) { - return new protos.cockroach.server.serverpb.CommandQueueRequest({ - range_id: Long.fromString(props.params[rangeIDAttr]), - }); -} - -/** - * Renders the Command Queue Report page. - */ -class CommandQueue extends React.Component { - - refresh(props = this.props) { - props.refreshCommandQueue(commandQueueRequestFromProps(props)); - } - - componentWillMount() { - this.refresh(); - } - - renderReportBody = () => { - const commandQueue = this.props.commandQueue; - if (_.isNil(commandQueue)) { - return null; - } - if (commandQueue && !_.isNil(commandQueue.lastError)) { - return ( -
-

Error loading the command queue:

- {commandQueue.lastError.toString()} -
- ); - } - - if (_.isNil(commandQueue.data) || _.isNil(commandQueue.data.snapshot)) { - return ( -
-

Error

- "No command queue data was returned." -
- ); - } - - const snapshot = commandQueue.data.snapshot; - - return ( -
-
- - Snapshot taken at - {" "}{Print.Timestamp(snapshot.timestamp)} - -
-
- Key: -
Read
-
Write
-
- -

Local Scope

- - -

Global Scope

- -
- ); - } - - render() { - const rangeID = this.props.params[rangeIDAttr]; - return ( -
- - { `Command Queue | r${rangeID.toString()} Range | Debug` } - -

- - r{rangeID.toString()} - - {" > "} - Command queue -

- -
- ); - } -} - -function mapStateToProps(state: AdminUIState, props: CommandQueueProps) { - const commandQueueKey = commandQueueRequestKey(commandQueueRequestFromProps(props)); - return { - commandQueue: state.cachedData.commandQueue[commandQueueKey], - }; -} - -const actions = { - refreshCommandQueue, -}; - -export default connect(mapStateToProps, actions)(CommandQueue); diff --git a/pkg/ui/src/views/reports/containers/range/rangeTable.tsx b/pkg/ui/src/views/reports/containers/range/rangeTable.tsx index 7f205e38c6f2..9c68ce422d1c 100644 --- a/pkg/ui/src/views/reports/containers/range/rangeTable.tsx +++ b/pkg/ui/src/views/reports/containers/range/rangeTable.tsx @@ -16,7 +16,6 @@ import classNames from "classnames"; import _ from "lodash"; import Long from "long"; import moment from "moment"; -import { Link } from "react-router"; import React from "react"; import * as protos from "src/js/protos"; @@ -87,10 +86,8 @@ const rangeTableDisplayList: RangeTableRow[] = [ { variable: "mvccIntentBytesCount", display: "MVCC Intent Bytes/Count", compareToLeader: true }, { variable: "mvccSystemBytesCount", display: "MVCC System Bytes/Count", compareToLeader: true }, { variable: "rangeMaxBytes", display: "Max Range Size Before Split", compareToLeader: true }, - { variable: "cmdQWrites", display: "CmdQ Writes Local/Global", compareToLeader: false }, - { variable: "cmdQReads", display: "CmdQ Reads Local/Global", compareToLeader: false }, - { variable: "cmdQMaxOverlapsSeen", display: "CmdQ Max Overlaps Local/Global", compareToLeader: false }, - { variable: "cmdQTreeSize", display: "CmdQ Tree Size Local/Global", compareToLeader: false }, + { variable: "writeLatches", display: "Write Latches Local/Global", compareToLeader: false }, + { variable: "readLatches", display: "Read Latches Local/Global", compareToLeader: false }, ]; const rangeTableEmptyContent: RangeTableCellContent = { @@ -152,7 +149,7 @@ export default class RangeTable extends React.Component { return { value: [`${humanizedBytes} / ${count.toString()} count`], title: [`${humanizedBytes} / ${count.toString()} count`, - `${bytes.toString()} bytes / ${count.toString()} count`], + `${bytes.toString()} bytes / ${count.toString()} count`], }; } @@ -176,7 +173,7 @@ export default class RangeTable extends React.Component { }; } - contentCommandQueue( + contentLatchInfo( local: Long | number, global: Long | number, isRaftLeader: boolean, ): RangeTableCellContent { if (isRaftLeader) { @@ -398,33 +395,6 @@ export default class RangeTable extends React.Component { ); } - renderCommandQueueVizRow( - sortedStoreIDs: number[], - rangeID: Long, - leader: protos.cockroach.server.serverpb.IRangeInfo, - ) { - const vizLink = ( - - Visualize - - ); - - return ( - - - CmdQ State - - {sortedStoreIDs.map((storeId) => ( - - {storeId === leader.source_store_id ? vizLink : "-"} - - ))} - - ); - } - render() { const { infos, replicas } = this.props; const leader = _.head(infos); @@ -520,24 +490,14 @@ export default class RangeTable extends React.Component { mvccIntentBytesCount: this.contentMVCC(FixLong(mvcc.intent_bytes), FixLong(mvcc.intent_count)), mvccSystemBytesCount: this.contentMVCC(FixLong(mvcc.sys_bytes), FixLong(mvcc.sys_count)), rangeMaxBytes: this.contentBytes(FixLong(info.state.range_max_bytes)), - cmdQWrites: this.contentCommandQueue( - FixLong(info.cmd_q_local.write_commands), - FixLong(info.cmd_q_global.write_commands), - raftLeader, - ), - cmdQReads: this.contentCommandQueue( - FixLong(info.cmd_q_local.read_commands), - FixLong(info.cmd_q_global.read_commands), - raftLeader, - ), - cmdQMaxOverlapsSeen: this.contentCommandQueue( - FixLong(info.cmd_q_local.max_overlaps_seen), - FixLong(info.cmd_q_global.max_overlaps_seen), + writeLatches: this.contentLatchInfo( + FixLong(info.latches_local.write_count), + FixLong(info.latches_global.write_count), raftLeader, ), - cmdQTreeSize: this.contentCommandQueue( - info.cmd_q_local.tree_size, - info.cmd_q_global.tree_size, + readLatches: this.contentLatchInfo( + FixLong(info.latches_local.read_count), + FixLong(info.latches_global.read_count), raftLeader, ), }); @@ -572,7 +532,6 @@ export default class RangeTable extends React.Component { ) )) } - {this.renderCommandQueueVizRow(sortedStoreIDs, rangeID, leader)} { _.map(replicas, (replica, key) => ( this.renderRangeReplicaRow( diff --git a/pkg/ui/yarn.lock b/pkg/ui/yarn.lock index 469682887bfa..868c78618e54 100644 --- a/pkg/ui/yarn.lock +++ b/pkg/ui/yarn.lock @@ -108,10 +108,6 @@ version "3.5.38" resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.38.tgz#76f8f2e9159ae562965b2fa0e6fbee1aa643a1bc" -"@types/dagre-layout@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@types/dagre-layout/-/dagre-layout-0.8.0.tgz#79fb118253b84ee908f7666b41f1e4d342c4db91" - "@types/enzyme-adapter-react-16@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz#15ae37c64d6221a6f4b3a4aacc357cf773859de4" @@ -2130,13 +2126,6 @@ d@1: dependencies: es5-ext "^0.10.9" -dagre-layout@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/dagre-layout/-/dagre-layout-0.8.0.tgz#7147b6afb655602f855158dfea171db9aa98d4ff" - dependencies: - graphlib "^2.1.1" - lodash "^4.17.4" - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -3362,12 +3351,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" -graphlib@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.1.tgz#42352c52ba2f4d035cb566eb91f7395f76ebc951" - dependencies: - lodash "^4.11.1" - growl@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" @@ -4387,7 +4370,7 @@ lodash@^3.8.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.11.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.5.0: +lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.5.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"