| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
| |
commit_hash:acb3e84437f5bdb125d7c1807847eb5edecbb11f
|
| |
|
|
|
|
|
|
|
|
| |
TMonService2 binds `this` into the HTTP handler stored in TMtHttpServer.
Stop() was only called from TImpl::~TImpl() — after TMonService2 members
(IndexMonPage, AuthProvider_) had already been destroyed. A concurrent
request could call ServeRequest() and crash on IndexMonPage->Output().
Fix: call Stop() in ~TMonService2() before member destruction.
commit_hash:f5b6aff5d9f85ae76d121a036bfd30094377c5ca
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Introduce AddPerCpu and StorePerCpu over an rseq-sharded per-CPU array.
On the x86-64 Linux fast path the update is committed by a hand-rolled
rseq critical section (non-atomic, migration-safe): addq for the 8-byte
accumulate, movq / movdqu for the 8- or 16-byte store. The kernel
restarts the sequence on preemption or migration, and only one thread
runs on a CPU at a time, so no atomic or lock is needed. Off the fast
path (other arches, no kernel rseq) the operation falls back to an
atomic on the slot indexed by sched_getcpu().
A naturally-aligned 8-byte store is single-copy atomic on x86-64, so it
is never observed torn; the 16-byte store may be, which is acceptable for
a last-writer-wins gauge.
commit_hash:6250f6e9e35cf3895ebafe0b534ec12cca50b03b
|
| |
|
|
| |
commit_hash:700366443410f399c1582f64da0f5efac01b725d
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
## 1. В чём была проблема
У сессии gRPC-клиента (`TClientSession`) несколько таймеров на базе **`TGrpcTimer`** используют один и тот же механизм: внутри лежит **`grpc::Alarm`**, привязанный к **одному** `CompletionQueue`, события с которого обрабатывает **отдельный поток** poller (в логах и стеках — `ua_grpc_cq`).
**Публичные методы** `TGrpcTimer::Set` и `Cancel` вызывались **и с этого потока** (после срабатывания alarm, из колбэков завершения gRPC-операций, из `Poll` и т.д.), **и с других потоков** — например, при старте сессии из потока пула (`DoStart` → первый `MakeGrpcCallTimer->Set`). В результате **один и тот же** `grpc::Alarm` и связанные с ним поля таймера менялись **конкурентно без синхронизации**. ThreadSanitizer фиксировал **data race** внутри реализации alarm в gRPC; с точки зрения контракта это **недопустимое параллельное использование** обёртки над alarm.
Типичный конфликт: на потоке приложения выполняется **`Set`** (первый запуск таймера переподключения), параллельно на **`ua_grpc_cq`** обрабатывается завершение вызова и снова вызывается **`Set`** для отложенного переподключения — оба попадают в **`Alarm::Set`** для одного объекта.
---
## 2. Изменение архитектуры (как починили)
Инвариант: **любое изменение состояния `TGrpcTimer`, которое трогает `grpc::Alarm` и служебные поля таймера, выполняется только на потоке, который крутит `CompletionQueue::Next` для этого клиента** (тот же поток, что обрабатывает срабатывания alarm).
Для этого:
- Введены внутренние **`ApplySet` / `ApplyCancel`** — в них перенесена прежняя логика работы с alarm; вызывать их разрешено **только** в контексте poller.
- Публичные **`Set` / `Cancel`**: если вызов уже идёт **из** poller (определяется **thread-local** флагом на время обработки события из CQ), сразу вызываются **`Apply*`**; иначе работа **ставится в ту же** `CompletionQueue` через **искусственное завершение** (`grpc_cq_begin_op` / `grpc_cq_end_op`), а колбэк на стороне poller выполняет **`Apply*`**.
- Чтобы отложенная операция не обращалась к уже уничтоженной сессии, перед постановкой в очередь делается **`TryRef`** на **`TAsyncJoiner`** сессии; после выполнения **`Apply*`** — **`UnRef`**. Если сессия уже уходит в закрытие и joiner недоступен, отложенный **`Set`/`Cancel`** тихо отбрасывается.
С точки зрения **`client_impl`**, вызовы **`MakeGrpcCallTimer->Set`**, **`ForceCloseTimer->Set`**, **`PollTimer->Set`**, **`->Cancel`** **не менялись** — меняется только реализация внутри **`TGrpcTimer`** и конструктор (передаётся ссылка на **`AsyncJoiner`** сессии).
---
## 3. Новая архитектура: sequence diagram и пример
{% cut "Таблица потоков, примеры A/B и диаграммы Mermaid" %}
Ниже — **два типичных сценария** для одного таймера, например **`MakeGrpcCallTimer`** (переподключение после завершения gRPC-вызова).
### Где именно теперь «живёт» работа с таймером
| Действие | Поток |
| :--- | :--- |
| Публичный **`Set` / `Cancel`** с **стороны приложения** (не poller) | Постановка задачи в **CQ**; реальное **`Apply*`** — на **`ua_grpc_cq`**. |
| Публичный **`Set` / `Cancel`** уже **внутри** обработчика события CQ (вложенный вызов) | Сразу **`Apply*`** на том же потоке (**без** повторной постановки). |
| Срабатывание **`grpc::Alarm`** | Доставка в poller → **`TGrpcTimer::OnIOCompleted`** → при необходимости снова **`Alarm.Set`** / вызов пользовательского колбэка — **всё на `ua_grpc_cq`**. |
### Пример A: первый `Set` при старте сессии (поток приложения)
Сессия стартует в **`DoStart`** на **рабочем** потоке; **`MakeGrpcCallTimer->Set(Now())`** не трогает alarm напрямую — **ставит** в CQ задачу «выполнить **`ApplySet`**»; poller **выполняет** её и выставляет alarm.
```mermaid
sequenceDiagram
participant App as AppThread
participant Timer as TGrpcTimer
participant CQ as CompletionQueue
participant Poller as ua_grpc_cq
App->>Timer: Set(now)
Timer->>Timer: not poller thread
Timer->>Timer: TryRef(AsyncJoiner)
Timer->>CQ: enqueue synthetic op
CQ-->>Poller: Next delivers op
Poller->>Timer: deferred callback
Timer->>Timer: ApplySet(now)
Timer->>Timer: Alarm.Set + schedule
Timer->>Timer: UnRef(AsyncJoiner)
```
### Пример B: перепланирование после завершения вызова (уже на poller)
**`OnGrpcCallFinished`** вызывается с **CQ** после обработки тега gRPC; **`MakeGrpcCallTimer->Set(reconnectTime)`** попадает в **fast path** и сразу вызывает **`ApplySet`** на **`ua_grpc_cq`** — без очереди.
```mermaid
sequenceDiagram
participant Poller as ua_grpc_cq
participant Session as TClientSession
participant Timer as TGrpcTimer
Poller->>Session: OnGrpcCallFinished
Session->>Timer: Set(reconnectTime)
Timer->>Timer: poller thread (TLS)
Timer->>Timer: ApplySet(reconnectTime)
```
### Срабатывание alarm (напоминание)
Когда срабатывает **внутренний** alarm gRPC, poller получает тег **`TGrpcTimer`**, вызывает **`OnIOCompleted`**: там снова возможны **`Alarm.Set`** (перенос по **`NextTriggerTime`**) или переход к **пользовательскому** колбэку (**`MakeGrpcCall`**, **`Poll`**, **`BeginClose`** и т.д.) — **всё на том же потоке `ua_grpc_cq`**.
{% endcut %}
---
{% cut "Технические детали (файлы, API gRPC, TSAN, lifetime)" %}
### Файлы в Arcadia
| Файл | Роль |
| :--- | :--- |
| `library/cpp/unified_agent_client/grpc_io.h`, `grpc_io.cpp` | `TGrpcTimer`, `TPostedCompletion` / `TPostedBridge`, `PostIIOCallbackToCompletionQueue`, `TlsInUaGrpcCompletionQueuePoller` в цикле poller. |
| `library/cpp/unified_agent_client/client_impl.cpp` | Создание трёх `TGrpcTimer` с передачей `AsyncJoiner` сессии. |
### Низкоуровневая постановка в CQ
Паттерн тот же, что у **`TGrpcNotification::Trigger`**: **`grpc_core::ApplicationCallbackExecCtx`**, **`grpc_core::ExecCtx`**, **`grpc_cq_begin_op`**, **`grpc_cq_end_op`**. Тег **`CompletionQueueTag`** — отдельный объект; в **`FinalizeResult`** в poller передаётся **`IIOCallback`** (мост), который выполняет отложенную лямбду и освобождает себя после **`OnIOCompleted`**.
### TSAN ()
В отчёте TSAN конкурирующие записи шли в **`grpc::internal::AlarmImpl::Set`** из потока **`ua_grpc_cq`** (цепочка **`OnGrpcCallFinished` → `MakeGrpcCallTimer->Set`**) и из потока приложения (**`DoStart` → `MakeGrpcCallTimer->Set(Now())`**). После фикса оба пути сериализуют **`ApplySet`** на poller.
### Поведение при закрытии сессии
Если **`TryRef(AsyncJoiner)`** не удался, отложенный **`Set`/`Cancel`** не ставится — сессия уже в фазе **`Join`**. Уже стоящие в CQ задачи удерживают ref до выполнения **`Apply*`** и **`UnRef`**.
### Заглушка счётчика для `MakeIOCallback`
Для отложенной лямбды используется **`TNoOpRefStub`**: **`Ref`/`UnRef`** пустые; удержание сессии обеспечивается парой **`TryRef`/`UnRef`** на **`TAsyncJoiner`**, а не счётчиком **`TIOCallback`**.
{% endcut %}
commit_hash:ba05e9c98e41bcf748270a48a818cc7d233a161b
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
TTscp::GetApproximate takes the processor id from the rseq fast path
(GetCurrentCpuId) and the instant from a non-serializing rdtsc, instead of the
single serializing rdtscp of TTscp::Get.
TPerCpuGauge::Update switches to it: the per-shard timestamp only orders writes
across shards to pick the freshest value, so the lower precision is fine. Update
is virtual and now YT_PREVENT_TLS_CACHING -- the fiber-TLS boundary the inlined
rseq read needs.
#### Benchmark
sas2-2769 (glibc 2.31 + tcmalloc, rseq fast path), median of 5:
| primitive | time |
|---|---|
| TTscp::Get() (rdtscp) | 14.1 ns |
| TTscp::GetApproximate() (rseq + rdtsc) | 10.6 ns (-25%) |
commit_hash:b277b6551accd6d0b879f8ffb168bcbe8d9fbb74
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Optimize timezone-aware query functions (timestamp_floor\_\*\_tz, format_timestamp_tz)
Problem: queries using timezone functions on a non-Moscow/non-UTC zone (e.g.
Europe/Bucharest) ran 10-20x slower than their non-timezone equivalents. For
Moscow/UTC a lookup table handles the conversion; for any other zone the code
falls back to live cctz calls.
Cause, confirmed by flamegraph and code:
1. NDatetime::ToCivilTime performed two independent timezone lookups per call.
cctz::convert(tp, tz) is defined as tz.lookup(tp).cs, and the function then
called tz.lookup(tp) again for the offset/is_dst fields. Both pieces of data
are already present in a single absolute_lookup result.
2. TimestampFloorDayTZInternal (and Month/Quarter/Year variants) located the
start of the period via a binary search that called ToCivilTime on every
iteration — \~18 iterations for the day case. Combined with (1) that is \~38
cctz lookups per call, and timestamp_floor_day_tz appears twice per row in a
typical WHERE clause.
* Changelog entry
Type: fix
1. ToCivilTime now does a single tz.lookup(tp) and reuses both cs and the
offset/is_dst fields. Behavior is identical; affects all callers.
2. TimestampFloor\{Day,Month,Quarter,Year\}TZ compute the period start directly
(subtract the civil time-of-day, or build the first second of the period and
convert it back), then verify the result. The binary search is kept as a
fallback for the rare days that do not start at midnight (DST transitions at
00:00, historical offset shifts), so results are unchanged.
commit_hash:295ee82832ab2a4a35920067e7c063d6992bb083
|
| |
|
|
| |
commit_hash:12a46325d5cf858c816e573782759a1cf0580070
|
| |
|
|
| |
commit_hash:35d60580ca855d25f47b96ec20edccdae29d3bf5
|
| |
|
|
|
| |
Make library/cpp/yt/rseq a Linux-only dependency of library/cpp/yt/system
commit_hash:7d6f5e738658447529440425b55b2891f6664d81
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add a macro for defining `TSentinelOptional` type aliases when the value type is not structural (e.g. has protected members) and therefore cannot use `TValueSentinel<V>`. The macro collapses the boilerplate sentinel struct plus `using` declaration into a single line:
```cpp
// before
struct TInstantSentinel
{
static constexpr auto Sentinel = TInstant::Zero();
};
using TSentinelOptionalInstant = TSentinelOptional<TInstant, TInstantSentinel>;
// after
YT_DEFINE_SENTINEL_OPTIONAL(TSentinelOptionalInstant, TInstant, TInstant::Zero());
```
Also convert the existing call sites in `service_detail.cpp` and `inferrum/block_cache.cpp`.
commit_hash:5dcdeb8db215736b0ce5a5b71f30aead91c7b8e8
|
| |
|
|
| |
commit_hash:33721d8fd9919cec2c217db529145c881baf144b
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The own-area approach did not deliver the fast path on glibc 2.31 (YT's current
runtime). There tcmalloc registers the conventional `__rseq_abi` area for every
thread; our attempt to register a separate area was rejected by the kernel with
EINVAL (a thread may have only one rseq area), so `cpu_id` stayed -1 and every
`GetCurrentCpuId()` fell back to `sched_getcpu()` (~17-20 ns, slower than the
rdtscp it replaced).
Read the shared `__rseq_abi` symbol instead -- the area tcmalloc, librseq and
pre-2.35 glibc all register. Our definition is weak, so it coalesces with theirs
when present (the common case -- tcmalloc owns it) and stands alone otherwise
(e.g. musl), with us registering it. We register with the conventional signature
`0x53053053` and size 32, so re-registering an already-registered area returns
EBUSY (treated as success) rather than EINVAL -- coexisting cleanly with tcmalloc.
glibc >= 2.35 still takes the `__rseq_offset` path unchanged.
Measured on sas2-2769 (glibc 2.31 + tcmalloc): `GetCurrentCpuId()` 20.0 ns -> 0.60 ns,
verified via strace that our registration now returns EBUSY against tcmalloc's
`__rseq_abi` (was EINVAL against a separate area).
commit_hash:509809deeb5f7c671817fcd9ebcc8499eabf096e
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
GetMinValue()/GetMaxValue() are constexpr, but when called from a runtime
context for a large-domain enum, clang does not fold the min/max_element and
emits a runtime scan over the whole domain on every call. This is hot on the
master replay path: TEnumIndexedArray::operator[] bounds-checks against these
(e.g. TCypressManager::FindHandler), and TCompositeAutomaton::RememberReign
hits GetCurrentReign() = GetMaxValue() over the ~3300-entry EMasterReign domain
per mutation.
Bind the result to a constexpr local to force compile-time evaluation. Verified
by disasm on a 240-value sample enum: getmin() goes from a ~44-instruction
runtime scan to a single 'mov $const'. No behavior change.
Part of YT-28453 (master replay-speed optimizations).
commit_hash:7cdb969e00ba219415d80c5c8c984aa8bbde99d2
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Self-contained current-CPU-id reader backed by Linux **rseq** (restartable
sequences), with **no third-party dependency** (no librseq):
* The rseq ABI is hand-defined; the calling thread is registered lazily via the
rseq syscall.
* Fast path is a single inlined, **branch-free** thread-local read. The offset
always points at a readable `cpu_id` -- the glibc-owned area when glibc registers
rseq (>= 2.35, via the weak `__rseq_offset`/`__rseq_size`), otherwise our own
area -- so an unregistered thread reads `-1` and routes to the slow path.
* Falls back to `sched_getcpu()` (Linux) or `0` (darwin/windows). Works on glibc
**and musl** alike (librseq does not build on musl).
Fiber-TLS contract: the inlined read must be reached only via a non-inlinable,
fiber-switch-free frame (a virtual call or `YT_PREVENT_TLS_CACHING`).
#### Benchmark -- cost of one cpu-id read
| source | time / call |
|---|---|
| `GetCurrentCpuId()` (rseq) | **0.34 ns** |
| `sched_getcpu()` (vDSO) | 3.5 ns |
| `rdtscp` (what `TTscp::Get()` does) | 23 ns |
This is an alternative to the librseq-based review/13886037 -- same speed, but no
contrib dependency and it also covers musl. The unit test pins to each allowed CPU
and asserts the reported id matches.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
commit_hash:09d282c2f48755836b1cd68cedbffc3c6a662eed
|
| |
|
|
|
|
|
|
|
|
| |
YT_LOG_TRACE is gated on YT_ENABLE_TRACE_LOGGING, defined in
library/cpp/yt/misc/port.h. logger.h relies on that macro but does not
include port.h, so in a TU that does not pull in port.h before logger.h,
YT_LOG_TRACE silently compiles to a no-op regardless of the configured
log level. Make logger.h self-contained by including the header that
defines the macro it depends on.
commit_hash:c53f26a7dff9d3f9c5a9d9aab8ea7fa31d11ec49
|
| |
|
|
| |
commit_hash:b892a307cba4ad3c500398eaaf34669ba3f76b00
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Profile-driven optimizations of the `Format` hot path, benchmarked against a representative master debug log (structured `"Key: %v"` messages dominated by GUIDs, strings, integers, bools and durations). Median improvements of ~15-20% across the workload, measured on a dedicated host.
Changes:
- `string_builder`: use `resize_uninitialized` in `DoReserve` to avoid zero-filling the buffer on every `Format` call.
- `format`: replace the per-argument `memchr` (`spec.Contains('n')`) with an inline scan, force-inline `RunFormatterAt`, and add a `FormatString` fast path for the common plain `%v` / empty spec.
- `guid`: rewrite `WriteGuidToBuffer` using a `clz`-derived digit count and a back-to-front fill instead of the per-magnitude branch cascade (cut from ~26% to ~12% of a GUID-heavy line). Validated against an `%x` reference over 2M random GUIDs plus edge cases.
Also adds `library/cpp/yt/string/benchmark` to track `Format` performance.
### Benchmarks
Median ns/op (lower is better), pinned core on a dedicated Xeon E5-2650 v2, 9x1s repetitions. See `library/cpp/yt/string/benchmark`.
| Benchmark | What it formats | Before | After | Speedup |
| --- | --- | ---: | ---: | ---: |
| `ManyMixedArgs` | ~18 args: GUIDs, strings, duration, ints | 1030 | 833 | -19% |
| `StringAndTwoGuids` | literal prefix + two GUIDs | 233 | 185 | -21% |
| `IntAndGuid` | one int + one GUID | 205 | 179 | -13% |
| `ManyInts` | six integers | 389 | 340 | -13% |
| `Guid` | a single GUID | 156 | 131 | -16% |
| `String` | a single string | 139 | 104 | -25% |
| `Int` | a single integer | 142 | 120 | -15% |
| `NoArgs` | a literal with no arguments | 88.8 | 85.7 | -3% |
commit_hash:ce9957a06c3ff28b2889aa65fbbddf4ca444f9fe
|
| |
|
|
| |
commit_hash:1666d5c27b2dfe54460efdc686d98ad955b0c4f1
|
| |
|
|
| |
commit_hash:41bdf36203cd75db0aa209d4867da7ca434cef78
|
| |
|
|
|
| |
add gzip alias
commit_hash:4543da4a84ec380ede1e06385ff85a7fa8d6bcec
|
| |
|
|
| |
commit_hash:4a07699e482566e3338ad4a92dcef209f57c2742
|
| |
|
|
| |
commit_hash:de3a49d188850e6ff1eee30d3f25ff5726a9f415
|
| |
|
|
|
|
|
|
|
|
| |
Make generic local values more safe and usable:
- instead of factory, register fiber/coroutine-aware "GLS (general local storage) contexts";
- put up to 4 (normally no more than 2 -- threads and one coroutine implementation) different "tls" variables into one generic, choose correct one from current execution context;
- suitable version of variable will be constructed on demand (no dependency from first usage);
- improve unit test too.
commit_hash:8586846a6a775bd66dffcdf58263f78042be2480
|
| |
|
|
|
| |
Replace google::protobuf::util::JsonStringToMessage with NProtobufJson::Json2Proto in incut_search request parsing and helpers/proto.h::ConvertFromString.
commit_hash:ccd17f46188ef0fd0253e146d9df2e6a8e7ba1b0
|
| |
|
|
| |
commit_hash:91a2de31f763fca2eb5b8595deb369458d889731
|
| |
|
|
| |
commit_hash:0f92ee40eb5e4a80c59a5cbdcac895ff7acd22e9
|
| |
|
|
| |
commit_hash:ba8c42476d6274212745348071682042e780037f
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
## Motivation
Profiling the YT master Automaton thread showed TOriginAttributes::Capture (run on every non-OK TError) spending ~60% of its time in a getpid() syscall — uncached on glibc >= 2.25. NYT::GetCurrentThreadId() (gettid) feeds hot thread-affinity / log-manager checks on the same thread.
## Changes
- New library/cpp/yt/system/process_id.* with cached GetProcessId(); GetSystemThreadId() now caches the kernel tid in TLS. Both caches reset in the child after fork.
- Moved thread_name.{h,cpp} from misc to system.
- Removed GetCurrentProcessId/GetCurrentThreadId shims from yt/yt/core/misc/proc.{h,cpp}; migrated all callers to NYT::GetProcessId / NYT::GetSystemThreadId.
- TOriginAttributes::Capture uses the cached getters; recorded Tid is now the real kernel tid (matches perf/ps).
- Added microbenchmarks (library/cpp/yt/system/benchmarks, yt/yt/core/benchmarks/error.cpp).
## Microbenchmarks (release)
| | before | after |
|---|---|---|
| getpid | 101 ns | 0.33 ns |
| gettid | 102 ns | 1.64 ns |
| Capture | 161 ns | 50 ns |
| failed TError | 221 ns | 74 ns |
commit_hash:ee37ae57d61a5a2dd33daee935270f4bb93b7ff9
|
| |
|
|
|
| |
`YA_COVERAGE_DUMP_PROFILE_AND_EXIT` is not used anymore
commit_hash:c7158fb4e201d522e6e2c31c91fa9361af4bf50c
|
| |
|
|
| |
commit_hash:5cd17c6fa69e4f6a18eb72ebb05a874491ae8ac7
|
| |
|
|
|
| |
Add a templated GetEnvValueOrThrow<T> that parses the environment variable value via FromString, next to the existing std::string overload.
commit_hash:0421b0463c473c8c7f88c0b1619484e52b002897
|
| |
|
|
| |
commit_hash:1156b3325b874f25124c2e535b63ae714d348818
|
| |
|
|
| |
commit_hash:58bf07dcff4aac728a67e0607d2c3b49ad1feef1
|
| |
|
|
|
| |
Added the ability to explicitly specify parsing options.
commit_hash:1bd7947cfc298f0c3edc895a77c64f70504b78d5
|
| |
|
|
| |
commit_hash:0db96562c160786c274a724485357e45753113e0
|
| |
|
|
| |
commit_hash:cdddd6e34a004a2942a80c4f94bcc8f80481d93a
|
| |
|
|
|
|
|
|
|
|
|
| |
Fix typos in docstrings
---
Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1733
Co-authored-by: ilyaibraev <[email protected]>
commit_hash:33a12aeaeeaec2f93ef9f465a3d5cdff95b62757
|
| |
|
|
| |
commit_hash:1023e8e70ded788fb37e7af6e0fa6cb508011aea
|
| |
|
|
| |
commit_hash:e8b2304f773f981dd79203f68a204671954ee399
|
| |
|
|
| |
commit_hash:ca6efe06865fe9fc9ebfd5ca8bbd79c2acbb4ff3
|
| |
|
|
| |
commit_hash:87f1242f4d944457ae5f4d7f22860ffb516b5b97
|
| |
|
|
| |
commit_hash:dbf6bb806bcac71fd67d65ec209838e5f5133710
|
| |
|
|
| |
commit_hash:3edd8e05acaa66bfc742eb137f73474783c91bc3
|
| |
|
|
| |
commit_hash:699e7e9a27bcf1220bbe3e408349a36a50408644
|
| |
|
|
| |
commit_hash:521dab2ac8a1582612ccc7734797e8bab9180714
|
| |
|
|
| |
commit_hash:776cd37ba05fd4d206ebf47b2a3bb2323bb32c51
|
| |
|
|
| |
commit_hash:b9f1c87173a18fb59f8cf684191efd4436dd6012
|
| |
|
|
| |
commit_hash:de6fd3d7115c7d34934e129720805c6a096292a2
|
| |
|
|
| |
commit_hash:fff41cdbc1400a312067a6517c334440404c662b
|