tikv-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tikv/_async/_pd.py ADDED
@@ -0,0 +1,167 @@
1
+ """Client for the Placement Driver (PD), TiKV's cluster metadata service."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+
7
+ import grpc
8
+ from google.protobuf.message import Message
9
+
10
+ from .._backoff import Backoff, Wait, describe, log
11
+ from .._errors import PDError
12
+ from .._proto import pdpb_pb2 as pdpb
13
+ from .._region import Region, RegionCache, make_region
14
+ from .._rpc import (
15
+ PD_GET_MEMBERS,
16
+ PD_GET_PREV_REGION,
17
+ PD_GET_REGION,
18
+ PD_GET_STORE,
19
+ PD_SCAN_REGIONS,
20
+ Method,
21
+ Response,
22
+ is_retryable,
23
+ strip_scheme,
24
+ )
25
+ from ._compat import Lock, sleep
26
+ from ._transport import Transport
27
+
28
+ CALLER_ID = "tikv-python"
29
+
30
+ # PD answers metadata queries quickly; a slower reply means a sick leader,
31
+ # so give up on it early and rediscover instead of burning the whole budget.
32
+ RPC_TIMEOUT = 3.0
33
+
34
+
35
+ class PDClient:
36
+ """Finds the PD leader and asks it where regions and stores are."""
37
+
38
+ def __init__(self, endpoints: Iterable[str], transport: Transport, cache: RegionCache) -> None:
39
+ self._endpoints = list(dict.fromkeys(map(strip_scheme, endpoints)))
40
+ self._transport = transport
41
+ self._cache = cache
42
+ self._lock = Lock()
43
+ self._leader: str | None = None
44
+ self.cluster_id = 0
45
+
46
+ async def region(self, key: bytes, backoff: Backoff) -> Region:
47
+ """The region containing *key*."""
48
+ while True:
49
+ region = await self._fetch_region(PD_GET_REGION, key, backoff)
50
+ if region is not None:
51
+ return region
52
+ # PD has no region for this key yet, e.g. right after bootstrap.
53
+ await sleep(backoff.delay(Wait.REGION_MISS, PDError(f"no region found for key {key!r}")))
54
+
55
+ async def region_by_end(self, key: bytes, backoff: Backoff) -> Region:
56
+ """The region in which *key* is a valid exclusive upper bound."""
57
+ while True:
58
+ region = await self.region(key, backoff)
59
+ if region.start != key or not key:
60
+ return region
61
+ # *key* opens this region, so the keys below it live in the one
62
+ # before. GetPrevRegion returns exactly that (like client-go).
63
+ previous = await self._fetch_region(PD_GET_PREV_REGION, key, backoff)
64
+ if previous is not None:
65
+ return previous
66
+ # The regions merged in between: start over.
67
+ await sleep(backoff.delay(Wait.REGION_MISS, PDError(f"no region found before key {key!r}")))
68
+
69
+ async def _fetch_region(
70
+ self, method: Method[pdpb.GetRegionResponse], key: bytes, backoff: Backoff
71
+ ) -> Region | None:
72
+ response = await self._call(method, pdpb.GetRegionRequest(region_key=key), backoff)
73
+ if not response.HasField("region"):
74
+ return None
75
+ region = make_region(response.region, response.leader)
76
+ self._cache.put(region)
77
+ return region
78
+
79
+ async def scan_regions(self, start: bytes, end: bytes, limit: int, backoff: Backoff) -> list[Region]:
80
+ """Up to *limit* consecutive regions overlapping ``[start, end)``."""
81
+ request = pdpb.ScanRegionsRequest(start_key=start, end_key=end, limit=limit)
82
+ response = await self._call(PD_SCAN_REGIONS, request, backoff)
83
+ if response.regions:
84
+ regions = [make_region(r.region, r.leader) for r in response.regions]
85
+ else: # older PD versions only fill the legacy fields
86
+ regions = [
87
+ make_region(m, leader)
88
+ for m, leader in zip(response.region_metas, response.leaders, strict=False)
89
+ ]
90
+ for region in regions:
91
+ self._cache.put(region)
92
+ return regions
93
+
94
+ async def store_address(self, store_id: int, backoff: Backoff) -> str:
95
+ """The client-facing address of TiKV store *store_id*."""
96
+ address = self._cache.store_address(store_id)
97
+ if address is None:
98
+ response = await self._call(PD_GET_STORE, pdpb.GetStoreRequest(store_id=store_id), backoff)
99
+ address = strip_scheme(response.store.address)
100
+ self._cache.set_store_address(store_id, address)
101
+ return address
102
+
103
+ async def _call(self, method: Method[Response], request: Message, backoff: Backoff) -> Response:
104
+ """Send *request* to the PD leader, following leader changes."""
105
+ while True:
106
+ leader = await self._leader_address(backoff)
107
+ request.header.cluster_id = self.cluster_id # type: ignore[attr-defined]
108
+ request.header.caller_id = CALLER_ID # type: ignore[attr-defined]
109
+ timeout = min(RPC_TIMEOUT, backoff.remaining())
110
+ try:
111
+ response = await self._transport.call(leader, method, request, timeout)
112
+ except grpc.RpcError as error:
113
+ if not is_retryable(error):
114
+ raise PDError(f"{method.path} failed: {describe(error)}") from error
115
+ self._leader = None # the leader may have moved; rediscover it
116
+ await sleep(backoff.delay(Wait.PD_RPC, error))
117
+ continue
118
+
119
+ header_error = response.header.error # type: ignore[attr-defined]
120
+ if header_error.type == pdpb.OK:
121
+ return response
122
+ failure = PDError(
123
+ f"{method.path} failed: {pdpb.ErrorType.Name(header_error.type)}: {header_error.message}"
124
+ )
125
+ if header_error.type != pdpb.REGION_NOT_FOUND:
126
+ raise failure
127
+ await sleep(backoff.delay(Wait.REGION_MISS, failure))
128
+
129
+ async def _leader_address(self, backoff: Backoff) -> str:
130
+ leader = self._leader
131
+ if leader is not None:
132
+ return leader
133
+ async with self._lock:
134
+ while self._leader is None:
135
+ await self._discover(backoff)
136
+ return self._leader
137
+
138
+ async def _discover(self, backoff: Backoff) -> None:
139
+ """Ask the known PD members who the leader is."""
140
+ cause: Exception = PDError("no PD endpoint answered")
141
+ rejected: list[str] = []
142
+ for endpoint in list(self._endpoints):
143
+ timeout = min(RPC_TIMEOUT, backoff.remaining())
144
+ try:
145
+ response = await self._transport.call(
146
+ endpoint, PD_GET_MEMBERS, pdpb.GetMembersRequest(), timeout
147
+ )
148
+ except grpc.RpcError as error:
149
+ if not is_retryable(error):
150
+ rejected.append(f"{endpoint} is not a PD server: {describe(error)}")
151
+ cause = error
152
+ continue
153
+ if not response.leader.client_urls:
154
+ cause = PDError(f"PD at {endpoint} reports no leader (election in progress?)")
155
+ continue
156
+ # Learn about every member so we survive losing the seed endpoints.
157
+ for member in response.members:
158
+ for url in member.client_urls:
159
+ if strip_scheme(url) not in self._endpoints:
160
+ self._endpoints.append(strip_scheme(url))
161
+ self.cluster_id = response.header.cluster_id
162
+ self._leader = strip_scheme(response.leader.client_urls[0])
163
+ log.debug("PD leader is %s (cluster %d)", self._leader, self.cluster_id)
164
+ return
165
+ if len(rejected) == len(self._endpoints): # retrying cannot help
166
+ raise PDError("; ".join(rejected)) from cause
167
+ await sleep(backoff.delay(Wait.PD_RPC, cause))
@@ -0,0 +1,52 @@
1
+ """A pool of gRPC channels, one per server address."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import threading
6
+ from typing import Any
7
+
8
+ import grpc
9
+ from google.protobuf.message import Message
10
+
11
+ from .._rpc import CHANNEL_OPTIONS, Method, Response
12
+ from ._compat import Channel, open_channel
13
+
14
+
15
+ class Transport:
16
+ """Sends unary requests to PD and TiKV servers over shared channels."""
17
+
18
+ def __init__(self, credentials: grpc.ChannelCredentials | None = None) -> None:
19
+ self._credentials = credentials
20
+ self._lock = threading.Lock() # never held across an await
21
+ self._channels: dict[str, Channel] = {}
22
+ self._stubs: dict[tuple[str, str], Any] = {}
23
+
24
+ async def call(
25
+ self, address: str, method: Method[Response], request: Message, timeout: float
26
+ ) -> Response:
27
+ stub = self._stubs.get((address, method.path))
28
+ if stub is None:
29
+ stub = self._channel(address).unary_unary(
30
+ method.path,
31
+ request_serializer=type(request).SerializeToString,
32
+ response_deserializer=method.response.FromString,
33
+ )
34
+ self._stubs[address, method.path] = stub
35
+ response: Response = await stub(request, timeout=timeout)
36
+ return response
37
+
38
+ def _channel(self, address: str) -> Channel:
39
+ with self._lock:
40
+ channel = self._channels.get(address)
41
+ if channel is None:
42
+ channel = open_channel(address, self._credentials, CHANNEL_OPTIONS)
43
+ self._channels[address] = channel
44
+ return channel
45
+
46
+ async def close(self) -> None:
47
+ with self._lock:
48
+ channels = list(self._channels.values())
49
+ self._channels.clear()
50
+ self._stubs.clear()
51
+ for channel in channels:
52
+ await channel.close()
tikv/_backoff.py ADDED
@@ -0,0 +1,78 @@
1
+ """Exponential backoff bounded by a per-operation deadline."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import enum
6
+ import logging
7
+ import random
8
+ import time
9
+
10
+ from ._errors import TimeoutError
11
+
12
+ log = logging.getLogger("tikv")
13
+
14
+
15
+ class Wait(enum.Enum):
16
+ """Why an operation is backing off; each reason has its own schedule.
17
+
18
+ Values are ``(base, cap)`` in seconds, following client-go's defaults.
19
+ """
20
+
21
+ REGION_MISS = (0.002, 0.5) # stale region cache: refresh and retry soon
22
+ REGION_SCHEDULING = (0.002, 0.5) # leader election, merge, split in progress
23
+ TIKV_RPC = (0.1, 2.0) # store unreachable
24
+ PD_RPC = (0.1, 3.0) # placement driver unreachable or electing a leader
25
+ SERVER_BUSY = (2.0, 10.0) # store is overloaded
26
+
27
+
28
+ class Backoff:
29
+ """Tracks retries of one logical operation against its deadline."""
30
+
31
+ __slots__ = ("_attempts", "deadline", "timeout")
32
+
33
+ def __init__(self, timeout: float, *, deadline: float | None = None) -> None:
34
+ self.timeout = timeout
35
+ self.deadline = time.monotonic() + timeout if deadline is None else deadline
36
+ self._attempts: dict[Wait, int] = {}
37
+
38
+ def remaining(self) -> float:
39
+ """Seconds left before the deadline, never negative."""
40
+ return max(0.0, self.deadline - time.monotonic())
41
+
42
+ def fork(self) -> Backoff:
43
+ """A backoff for a sub-request: same deadline and retry history.
44
+
45
+ The fork escalates independently from here on, so concurrent
46
+ sub-requests do not inflate each other's delays.
47
+ """
48
+ forked = Backoff(self.timeout, deadline=self.deadline)
49
+ forked._attempts = dict(self._attempts)
50
+ return forked
51
+
52
+ def delay(self, wait: Wait, cause: BaseException, *, hint: float = 0.0) -> float:
53
+ """Return how long to sleep before the next attempt.
54
+
55
+ Raises :class:`~tikv.TimeoutError` from *cause* when sleeping would
56
+ overrun the deadline, so callers never retry past their budget.
57
+ """
58
+ base, cap = wait.value
59
+ attempt = self._attempts.get(wait, 0)
60
+ self._attempts[wait] = attempt + 1
61
+ ceiling = min(cap, base * 2.0**attempt)
62
+ # "Equal jitter": at least half the ceiling, so retries stay spread out.
63
+ delay = max(hint, ceiling / 2 + random.uniform(0, ceiling / 2))
64
+ if delay >= self.remaining():
65
+ raise TimeoutError(
66
+ f"operation did not complete within {self.timeout:g}s: {describe(cause)}"
67
+ ) from cause
68
+ log.debug("retrying in %.3fs (%s): %s", delay, wait.name.lower(), describe(cause))
69
+ return delay
70
+
71
+
72
+ def describe(error: BaseException) -> str:
73
+ """A one-line description of *error*, including gRPC status details."""
74
+ details = getattr(error, "details", None)
75
+ code = getattr(error, "code", None)
76
+ if callable(details) and callable(code):
77
+ return f"gRPC {code().name}: {details()}"
78
+ return str(error) or type(error).__name__
tikv/_errors.py ADDED
@@ -0,0 +1,53 @@
1
+ """Exceptions raised by the TiKV client.
2
+
3
+ Every exception derives from :class:`TiKVError`, so ``except tikv.TiKVError``
4
+ catches anything the library raises on purpose. Transient failures (leader
5
+ changes, region splits, busy servers, unreachable stores) are retried
6
+ internally and only surface as :class:`TimeoutError` once the operation's time
7
+ budget runs out.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import builtins
13
+
14
+ __all__ = [
15
+ "PDError",
16
+ "RegionError",
17
+ "ServerError",
18
+ "TiKVError",
19
+ "TimeoutError",
20
+ "UndeterminedError",
21
+ ]
22
+
23
+
24
+ class TiKVError(Exception):
25
+ """Base class for all errors raised by this library."""
26
+
27
+
28
+ class TimeoutError(TiKVError, builtins.TimeoutError):
29
+ """The operation did not complete within the client's ``timeout``.
30
+
31
+ The last transient error, if any, is attached as ``__cause__``.
32
+ """
33
+
34
+
35
+ class PDError(TiKVError):
36
+ """The Placement Driver rejected a request."""
37
+
38
+
39
+ class ServerError(TiKVError):
40
+ """A TiKV server rejected a request, for example because a key is too large."""
41
+
42
+
43
+ class RegionError(TiKVError):
44
+ """A region error that retrying cannot resolve, such as an oversized write."""
45
+
46
+
47
+ class UndeterminedError(TiKVError):
48
+ """A non-idempotent request failed in flight; it may or may not have been applied.
49
+
50
+ Raised only by :meth:`RawClient.compare_and_swap`, which is never retried
51
+ blindly: replaying a swap that already succeeded would report a spurious
52
+ failure. Read the key to find out what happened.
53
+ """
tikv/_keys.py ADDED
@@ -0,0 +1,109 @@
1
+ """Argument validation and key-range arithmetic shared by both clients.
2
+
3
+ Internally an empty ``end`` key means "+inf", as on the wire. The public API
4
+ uses ``None`` for that instead, because ``b""`` is itself a valid key.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import math
10
+ from collections.abc import Callable, Iterator, Sequence
11
+ from datetime import timedelta
12
+ from typing import TypeVar
13
+
14
+ T = TypeVar("T")
15
+
16
+
17
+ def as_bytes(value: object, what: str) -> bytes:
18
+ if isinstance(value, bytes):
19
+ return value
20
+ if isinstance(value, (bytearray, memoryview)):
21
+ return bytes(value)
22
+ if isinstance(value, str):
23
+ raise TypeError(f"{what} must be bytes, not str; encode it first, e.g. {what}.encode()")
24
+ raise TypeError(f"{what} must be bytes, not {type(value).__name__}")
25
+
26
+
27
+ def as_key(key: object) -> bytes:
28
+ return as_bytes(key, "key")
29
+
30
+
31
+ def as_value(value: object) -> bytes:
32
+ return as_bytes(value, "value")
33
+
34
+
35
+ def ttl_seconds(ttl: float | timedelta | None) -> int:
36
+ """Convert a TTL to whole seconds, rounding up; 0 means "no expiry"."""
37
+ if ttl is None:
38
+ return 0
39
+ if isinstance(ttl, timedelta):
40
+ seconds = ttl.total_seconds()
41
+ elif isinstance(ttl, (int, float)) and not isinstance(ttl, bool):
42
+ seconds = float(ttl)
43
+ else:
44
+ raise TypeError(f"ttl must be a number of seconds or a timedelta, not {type(ttl).__name__}")
45
+ if not seconds > 0 or math.isinf(seconds):
46
+ raise ValueError(f"ttl must be a positive, finite duration, got {ttl!r}")
47
+ return math.ceil(seconds)
48
+
49
+
50
+ def prefix_end(prefix: bytes) -> bytes:
51
+ """The smallest key greater than every key starting with *prefix*.
52
+
53
+ Returns ``b""`` (+inf) when no such key exists, e.g. for ``b"\\xff\\xff"``.
54
+ """
55
+ stripped = prefix.rstrip(b"\xff")
56
+ if not stripped:
57
+ return b""
58
+ return stripped[:-1] + bytes([stripped[-1] + 1])
59
+
60
+
61
+ def key_range(start: object | None, end: object | None, prefix: object | None) -> tuple[bytes, bytes] | None:
62
+ """Resolve public ``start``/``end``/``prefix`` arguments to ``(start, end)``.
63
+
64
+ Returns ``None`` when the range is empty.
65
+ """
66
+ if prefix is not None:
67
+ if start is not None or end is not None:
68
+ raise ValueError("pass either prefix or start/end, not both")
69
+ lo = as_bytes(prefix, "prefix")
70
+ return lo, prefix_end(lo)
71
+ lo = b"" if start is None else as_bytes(start, "start")
72
+ if end is None:
73
+ return lo, b""
74
+ hi = as_bytes(end, "end")
75
+ return (lo, hi) if lo < hi else None
76
+
77
+
78
+ def min_end(a: bytes, b: bytes) -> bytes:
79
+ """The smaller of two exclusive upper bounds, where ``b""`` is +inf."""
80
+ if not a:
81
+ return b
82
+ if not b:
83
+ return a
84
+ return min(a, b)
85
+
86
+
87
+ def chunked(
88
+ items: Sequence[T],
89
+ *,
90
+ max_count: int,
91
+ max_bytes: int = 0,
92
+ size: Callable[[T], int] | None = None,
93
+ ) -> Iterator[list[T]]:
94
+ """Split *items* into runs of at most *max_count* items.
95
+
96
+ With a *size* function, runs also stay within *max_bytes*; a single item
97
+ larger than that still gets a run of its own.
98
+ """
99
+ chunk: list[T] = []
100
+ total = 0
101
+ for item in items:
102
+ item_size = size(item) if size is not None else 0
103
+ if chunk and (len(chunk) >= max_count or (size is not None and total + item_size > max_bytes)):
104
+ yield chunk
105
+ chunk, total = [], 0
106
+ chunk.append(item)
107
+ total += item_size
108
+ if chunk:
109
+ yield chunk
@@ -0,0 +1,2 @@
1
+ # Generated by scripts/generate_protos.py. DO NOT EDIT.
2
+ """Protobuf messages for the TiKV and PD wire protocols."""
@@ -0,0 +1,68 @@
1
+ # Generated by scripts/generate_protos.py. DO NOT EDIT.
2
+ # -*- coding: utf-8 -*-
3
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
4
+ # source: errorpb.proto
5
+ # Protobuf Python Version: 4.25.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import symbol_database as _symbol_database
10
+ from google.protobuf.internal import builder as _builder
11
+ # @@protoc_insertion_point(imports)
12
+
13
+ _sym_db = _symbol_database.Default()
14
+
15
+
16
+ from . import metapb_pb2 as metapb__pb2
17
+
18
+
19
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rerrorpb.proto\x12\x07\x65rrorpb\x1a\x0cmetapb.proto\"<\n\tNotLeader\x12\x11\n\tregion_id\x18\x01 \x01(\x04\x12\x1c\n\x06leader\x18\x02 \x01(\x0b\x32\x0c.metapb.Peer\"\x1e\n\tIsWitness\x12\x11\n\tregion_id\x18\x01 \x01(\x04\",\n\x08\x44iskFull\x12\x10\n\x08store_id\x18\x01 \x03(\x04\x12\x0e\n\x06reason\x18\x02 \x01(\t\"B\n\rStoreNotMatch\x12\x18\n\x10request_store_id\x18\x01 \x01(\x04\x12\x17\n\x0f\x61\x63tual_store_id\x18\x02 \x01(\x04\"#\n\x0eRegionNotFound\x12\x11\n\tregion_id\x18\x01 \x01(\x04\")\n\x14RegionNotInitialized\x12\x11\n\tregion_id\x18\x01 \x01(\x04\"T\n\x0eKeyNotInRegion\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\x11\n\tregion_id\x18\x02 \x01(\x04\x12\x11\n\tstart_key\x18\x03 \x01(\x0c\x12\x0f\n\x07\x65nd_key\x18\x04 \x01(\x0c\"8\n\rEpochNotMatch\x12\'\n\x0f\x63urrent_regions\x18\x01 \x03(\x0b\x32\x0e.metapb.Region\"d\n\x0cServerIsBusy\x12\x0e\n\x06reason\x18\x01 \x01(\t\x12\x12\n\nbackoff_ms\x18\x02 \x01(\x04\x12\x19\n\x11\x65stimated_wait_ms\x18\x03 \x01(\r\x12\x15\n\rapplied_index\x18\x04 \x01(\x04\"\x0e\n\x0cStaleCommand\":\n\x11RaftEntryTooLarge\x12\x11\n\tregion_id\x18\x01 \x01(\x04\x12\x12\n\nentry_size\x18\x02 \x01(\x04\"\x17\n\x15MaxTimestampNotSynced\"6\n\x11ReadIndexNotReady\x12\x0e\n\x06reason\x18\x01 \x01(\t\x12\x11\n\tregion_id\x18\x02 \x01(\x04\"*\n\x15ProposalInMergingMode\x12\x11\n\tregion_id\x18\x01 \x01(\x04\"E\n\x0e\x44\x61taIsNotReady\x12\x11\n\tregion_id\x18\x01 \x01(\x04\x12\x0f\n\x07peer_id\x18\x02 \x01(\x04\x12\x0f\n\x07safe_ts\x18\x03 \x01(\x04\"\'\n\x12RecoveryInProgress\x12\x11\n\tregion_id\x18\x01 \x01(\x04\"D\n\x13\x46lashbackInProgress\x12\x11\n\tregion_id\x18\x01 \x01(\x04\x12\x1a\n\x12\x66lashback_start_ts\x18\x02 \x01(\x04\")\n\x14\x46lashbackNotPrepared\x12\x11\n\tregion_id\x18\x01 \x01(\x04\"@\n\x0eMismatchPeerId\x12\x17\n\x0frequest_peer_id\x18\x01 \x01(\x04\x12\x15\n\rstore_peer_id\x18\x02 \x01(\x04\"%\n\x12UndeterminedResult\x12\x0f\n\x07message\x18\x01 \x01(\t\"\xbd\x08\n\x05\x45rror\x12\x0f\n\x07message\x18\x01 \x01(\t\x12&\n\nnot_leader\x18\x02 \x01(\x0b\x32\x12.errorpb.NotLeader\x12\x31\n\x10region_not_found\x18\x03 \x01(\x0b\x32\x17.errorpb.RegionNotFound\x12\x32\n\x11key_not_in_region\x18\x04 \x01(\x0b\x32\x17.errorpb.KeyNotInRegion\x12/\n\x0f\x65poch_not_match\x18\x05 \x01(\x0b\x32\x16.errorpb.EpochNotMatch\x12-\n\x0eserver_is_busy\x18\x06 \x01(\x0b\x32\x15.errorpb.ServerIsBusy\x12,\n\rstale_command\x18\x07 \x01(\x0b\x32\x15.errorpb.StaleCommand\x12/\n\x0fstore_not_match\x18\x08 \x01(\x0b\x32\x16.errorpb.StoreNotMatch\x12\x38\n\x14raft_entry_too_large\x18\t \x01(\x0b\x32\x1a.errorpb.RaftEntryTooLarge\x12@\n\x18max_timestamp_not_synced\x18\n \x01(\x0b\x32\x1e.errorpb.MaxTimestampNotSynced\x12\x38\n\x14read_index_not_ready\x18\x0b \x01(\x0b\x32\x1a.errorpb.ReadIndexNotReady\x12@\n\x18proposal_in_merging_mode\x18\x0c \x01(\x0b\x32\x1e.errorpb.ProposalInMergingMode\x12\x32\n\x11\x64\x61ta_is_not_ready\x18\r \x01(\x0b\x32\x17.errorpb.DataIsNotReady\x12=\n\x16region_not_initialized\x18\x0e \x01(\x0b\x32\x1d.errorpb.RegionNotInitialized\x12$\n\tdisk_full\x18\x0f \x01(\x0b\x32\x11.errorpb.DiskFull\x12\x37\n\x12RecoveryInProgress\x18\x10 \x01(\x0b\x32\x1b.errorpb.RecoveryInProgress\x12\x39\n\x13\x46lashbackInProgress\x18\x11 \x01(\x0b\x32\x1c.errorpb.FlashbackInProgress\x12;\n\x14\x46lashbackNotPrepared\x18\x12 \x01(\x0b\x32\x1d.errorpb.FlashbackNotPrepared\x12&\n\nis_witness\x18\x13 \x01(\x0b\x32\x12.errorpb.IsWitness\x12\x31\n\x10mismatch_peer_id\x18\x14 \x01(\x0b\x32\x17.errorpb.MismatchPeerId\x12\x38\n\x13undetermined_result\x18\x16 \x01(\x0b\x32\x1b.errorpb.UndeterminedResultb\x06proto3')
20
+
21
+ _globals = globals()
22
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
23
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'errorpb_pb2', _globals)
24
+ if _descriptor._USE_C_DESCRIPTORS == False:
25
+ DESCRIPTOR._options = None
26
+ _globals['_NOTLEADER']._serialized_start=40
27
+ _globals['_NOTLEADER']._serialized_end=100
28
+ _globals['_ISWITNESS']._serialized_start=102
29
+ _globals['_ISWITNESS']._serialized_end=132
30
+ _globals['_DISKFULL']._serialized_start=134
31
+ _globals['_DISKFULL']._serialized_end=178
32
+ _globals['_STORENOTMATCH']._serialized_start=180
33
+ _globals['_STORENOTMATCH']._serialized_end=246
34
+ _globals['_REGIONNOTFOUND']._serialized_start=248
35
+ _globals['_REGIONNOTFOUND']._serialized_end=283
36
+ _globals['_REGIONNOTINITIALIZED']._serialized_start=285
37
+ _globals['_REGIONNOTINITIALIZED']._serialized_end=326
38
+ _globals['_KEYNOTINREGION']._serialized_start=328
39
+ _globals['_KEYNOTINREGION']._serialized_end=412
40
+ _globals['_EPOCHNOTMATCH']._serialized_start=414
41
+ _globals['_EPOCHNOTMATCH']._serialized_end=470
42
+ _globals['_SERVERISBUSY']._serialized_start=472
43
+ _globals['_SERVERISBUSY']._serialized_end=572
44
+ _globals['_STALECOMMAND']._serialized_start=574
45
+ _globals['_STALECOMMAND']._serialized_end=588
46
+ _globals['_RAFTENTRYTOOLARGE']._serialized_start=590
47
+ _globals['_RAFTENTRYTOOLARGE']._serialized_end=648
48
+ _globals['_MAXTIMESTAMPNOTSYNCED']._serialized_start=650
49
+ _globals['_MAXTIMESTAMPNOTSYNCED']._serialized_end=673
50
+ _globals['_READINDEXNOTREADY']._serialized_start=675
51
+ _globals['_READINDEXNOTREADY']._serialized_end=729
52
+ _globals['_PROPOSALINMERGINGMODE']._serialized_start=731
53
+ _globals['_PROPOSALINMERGINGMODE']._serialized_end=773
54
+ _globals['_DATAISNOTREADY']._serialized_start=775
55
+ _globals['_DATAISNOTREADY']._serialized_end=844
56
+ _globals['_RECOVERYINPROGRESS']._serialized_start=846
57
+ _globals['_RECOVERYINPROGRESS']._serialized_end=885
58
+ _globals['_FLASHBACKINPROGRESS']._serialized_start=887
59
+ _globals['_FLASHBACKINPROGRESS']._serialized_end=955
60
+ _globals['_FLASHBACKNOTPREPARED']._serialized_start=957
61
+ _globals['_FLASHBACKNOTPREPARED']._serialized_end=998
62
+ _globals['_MISMATCHPEERID']._serialized_start=1000
63
+ _globals['_MISMATCHPEERID']._serialized_end=1064
64
+ _globals['_UNDETERMINEDRESULT']._serialized_start=1066
65
+ _globals['_UNDETERMINEDRESULT']._serialized_end=1103
66
+ _globals['_ERROR']._serialized_start=1106
67
+ _globals['_ERROR']._serialized_end=2191
68
+ # @@protoc_insertion_point(module_scope)