|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* Кольцо проверенных блоков одного запуска: общий бюджет данных для всех субпотоков.
|
|
|
|
/* Кольцо структурно проверенных частей одного запуска; подпись проверяется после восстановления.
|
|
|
|
* Пустые субпотоки не резервируют блоки: 32 МБ занимают реально сохранённые кодограммы. |
|
|
|
* Слоты резервируются по максимальному размеру, stored_bytes учитывает фактические длины. |
|
|
|
* Вытеснение целой старейшей пачки не закрепляет данные для медленного получателя. |
|
|
|
* Вытеснение целой старейшей пачки не закрепляет данные для медленного получателя. |
|
|
|
* Все вызовы — один uasync-поток. read возвращает память до следующего put/destroy. |
|
|
|
* Все вызовы — один uasync-поток. read возвращает память до следующего put/destroy. |
|
|
|
* public_key должен происходить из проверенной записи источника в группе. */ |
|
|
|
* public_key должен происходить из проверенной записи источника в группе. */ |
|
|
|
@ -17,8 +17,10 @@ struct stream_buffer; |
|
|
|
/* Observer не выполняет I/O и не меняет кольцо; wire действует лишь внутри callback. Destroy observer не вызывает. */ |
|
|
|
/* Observer не выполняет I/O и не меняет кольцо; wire действует лишь внутри callback. Destroy observer не вызывает. */ |
|
|
|
typedef void (*stream_buffer_event_fn)(void *arg, const uint8_t *wire, size_t length, int added); |
|
|
|
typedef void (*stream_buffer_event_fn)(void *arg, const uint8_t *wire, size_t length, int added); |
|
|
|
void stream_buffer_set_observer(struct stream_buffer *buffer, stream_buffer_event_fn observer, void *arg); |
|
|
|
void stream_buffer_set_observer(struct stream_buffer *buffer, stream_buffer_event_fn observer, void *arg); |
|
|
|
/* Точные ожидающие блоки >= seq и время старейшего принятия. count=NULL ищет только старейший, без полного обхода. */ |
|
|
|
/* Точное число/сумма байтов частей >= seq и время старейшего принятия.
|
|
|
|
int stream_buffer_pending(struct stream_buffer *buffer, uint64_t seq, uint8_t subblock, uint64_t *count, uint64_t *oldest_ms); |
|
|
|
* count=bytes=NULL ищет только старейший, без полного обхода. */ |
|
|
|
|
|
|
|
int stream_buffer_pending(struct stream_buffer *buffer, uint64_t seq, uint8_t subblock, |
|
|
|
|
|
|
|
uint64_t *count, uint64_t *bytes, uint64_t *oldest_ms); |
|
|
|
|
|
|
|
|
|
|
|
struct stream_buffer_stats { |
|
|
|
struct stream_buffer_stats { |
|
|
|
size_t capacity_bytes; |
|
|
|
size_t capacity_bytes; |
|
|
|
@ -29,6 +31,7 @@ struct stream_buffer_stats { |
|
|
|
uint64_t highest_seq; |
|
|
|
uint64_t highest_seq; |
|
|
|
uint64_t evicted_batches; |
|
|
|
uint64_t evicted_batches; |
|
|
|
uint64_t duplicates; |
|
|
|
uint64_t duplicates; |
|
|
|
|
|
|
|
uint64_t rejected_batches; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/* out заранее NULL; bytes=0 выбирает 32 МБ, меньший бюджет допускается для стенда.
|
|
|
|
/* out заранее NULL; bytes=0 выбирает 32 МБ, меньший бюджет допускается для стенда.
|
|
|
|
@ -37,8 +40,9 @@ int stream_buffer_create(struct stream_buffer **out, const struct stream_descrip |
|
|
|
const uint8_t public_key[SC_PUBKEY_SIZE], size_t bytes); |
|
|
|
const uint8_t public_key[SC_PUBKEY_SIZE], size_t bytes); |
|
|
|
void stream_buffer_destroy(struct stream_buffer *buffer); |
|
|
|
void stream_buffer_destroy(struct stream_buffer *buffer); |
|
|
|
|
|
|
|
|
|
|
|
/* Новый блок проверяется до изменения кольца. Повтор неизменного блока: STREAM_DUPLICATE.
|
|
|
|
/* Формат новой части проверяется до изменения кольца. Повтор неизменной части: STREAM_DUPLICATE.
|
|
|
|
* STREAM_EXPIRED не меняет более свежие данные; неверная подпись/конфликт возвращает отрицательный код. */ |
|
|
|
* STREAM_EXPIRED не меняет более свежие данные; конфликт возвращает отрицательный код. |
|
|
|
|
|
|
|
* Части ещё не подтверждены подписью источника и могут пересылаться до локального decode. */ |
|
|
|
int stream_buffer_put(struct stream_buffer *buffer, const uint8_t *wire, size_t length); |
|
|
|
int stream_buffer_put(struct stream_buffer *buffer, const uint8_t *wire, size_t length); |
|
|
|
/* Сохранённая история содержит текущего владельца кольца; первый путь повтора остаётся неизменным. */ |
|
|
|
/* Сохранённая история содержит текущего владельца кольца; первый путь повтора остаётся неизменным. */ |
|
|
|
int stream_buffer_put_path(struct stream_buffer *buffer, const uint8_t *wire, size_t length, const struct stream_path *path); |
|
|
|
int stream_buffer_put_path(struct stream_buffer *buffer, const uint8_t *wire, size_t length, const struct stream_path *path); |
|
|
|
@ -54,8 +58,9 @@ int stream_buffer_read(struct stream_buffer *buffer, uint64_t seq, uint8_t subbl |
|
|
|
const uint8_t **wire, size_t *length, uint64_t *actual_seq); |
|
|
|
const uint8_t **wire, size_t *length, uint64_t *actual_seq); |
|
|
|
int stream_buffer_range(struct stream_buffer *buffer, uint8_t subblock, uint64_t *first, uint64_t *last); |
|
|
|
int stream_buffer_range(struct stream_buffer *buffer, uint8_t subblock, uint64_t *first, uint64_t *last); |
|
|
|
|
|
|
|
|
|
|
|
/* Восстановить пачку из проверенных блоков; достаточно capacity >= действительной длины.
|
|
|
|
/* Восстановить пачку и проверить одну подпись; достаточно capacity >= действительной длины.
|
|
|
|
* Выход не меняется при WAIT/GAP/EXPIRED/ошибке; восстановленные отсутствующие блоки в кольцо не добавляются. */ |
|
|
|
* STREAM_REJECTED означает неверную подпись/подписанные метаданные; такая пачка повторно не декодируется. |
|
|
|
|
|
|
|
* Выход не меняется при WAIT/GAP/EXPIRED/REJECTED/ошибке; отсутствующие части в кольцо не добавляются. */ |
|
|
|
int stream_buffer_decode(struct stream_buffer *buffer, uint64_t seq, uint8_t *output, size_t capacity, size_t *length); |
|
|
|
int stream_buffer_decode(struct stream_buffer *buffer, uint64_t seq, uint8_t *output, size_t capacity, size_t *length); |
|
|
|
int stream_buffer_get_stats(const struct stream_buffer *buffer, struct stream_buffer_stats *stats); |
|
|
|
int stream_buffer_get_stats(const struct stream_buffer *buffer, struct stream_buffer_stats *stats); |
|
|
|
|
|
|
|
|
|
|
|
|