Постоянное хранилище учетных записей

Набор учетных записей представляет собой текущее вычисленное состояние всех транзакций, которые были обработаны валидатором. Каждый валидатор должен поддерживать весь этот набор. Каждый блок, предлагаемый сетью, представляет собой изменение в этом наборе, а поскольку каждый блок является потенциальной точкой отката, изменения должны быть обратимыми.

Постоянные хранилища, такие как NVME, в 20–40 раз дешевле, чем DDR. Проблема с постоянным хранилищем заключается в том, что производительность записи и чтения намного ниже, чем у DDR. Необходимо соблюдать осторожность при чтении или записи данных. И чтение, и запись могут быть разделены между несколькими накопителями и доступны параллельно. Этот проект предлагает структуру данных, которая допускает одновременное чтение и запись в хранилище. Записи оптимизируются с помощью структуры данных AppendVec, которая позволяет одному писателю выполнять добавление, предоставляя доступ многим одновременным считывателям. Индекс учетных записей поддерживает указатель на точку, в которой учетная запись была добавлена ​​к каждой вилке, что устраняет необходимость в явной проверке состояния.

AppendVec

AppendVec — это структура данных, которая допускает произвольное чтение одновременно с одной записью только для добавления. Увеличение или изменение емкости AppendVec требует монопольного доступа. Это реализовано с помощью атомарного смещения, которое обновляется в конце завершенного добавления.

Базовая память для AppendVec — это отображаемый в память файл. Файлы, отображаемые в памяти, обеспечивают быстрый произвольный доступ, а подкачка выполняется операционной системой.

Индекс учетной записи

Индекс учетной записи предназначен для поддержки единого индекса для всех учетных записей, разветвленных в настоящее время.

type AppendVecId = usize;

type Fork = u64;

struct AccountMap(Hashmap<Fork, (AppendVecId, u64)>);

type AccountIndex = HashMap<Pubkey, AccountMap>;

Индекс представляет собой сопоставление открытых ключей учетной записи с картой вилок и расположением данных учетной записи в AppendVec. Чтобы получить версию учетной записи для определенного форка:

/// Load the account for the pubkey.
/// This function will load the account from the specified fork, falling back to the fork's parents
/// * fork - a virtual Accounts instance, keyed by Fork.  Accounts keep track of their parents with Forks,
///       the persistent store
/// * pubkey - The Account's public key.
pub fn load_slow(&self, id: Fork, pubkey: &Pubkey) -> Option<&Account>

Чтение выполняется путем указания на отображаемое в памяти местоположение в AppendVecId с сохраненным смещением. Справку можно вернуть без копии.

Корневые форки

Tower BFT в конечном итоге выбирает вилку в качестве корневой вилки, и вилка сжимается. Раздавленную/корневую вилку нельзя откатить.

Когда вилка раздавлена, все учетные записи ее родителей, еще не присутствующие в вилке, переносятся в вилку путем обновления индексов. Учетные записи с нулевым балансом в раздавленном форке удаляются из форка путем обновления индексов.

Аккаунт может быть собран мусором, когда раздавливание делает его недоступным.

Возможны три варианта:

Вывоз мусора

По мере обновления учетных записей они перемещаются в конец AppendVec. После исчерпания емкости можно создать новый AppendVec и хранить в нем обновления. Со временем ссылки на старый AppendVec исчезнут, потому что все учетные записи были обновлены, а старый AppendVec можно удалить.

Чтобы ускорить этот процесс, можно переместить Аккаунты, которые недавно не обновлялись, в начало нового AppendVec. Эта форма сборки мусора может быть реализована без эксклюзивных блокировок каких-либо структур данных, за исключением обновления индекса.

Первоначальная реализация сборки мусора заключается в том, что когда все учетные записи в AppendVec становятся устаревшими, она используется повторно. Учетные записи не обновляются и не перемещаются после добавления.

Восстановление индекса

Каждый поток банка имеет эксклюзивный доступ к учетным записям во время добавления, поскольку блокировки учетных записей не могут быть сняты до тех пор, пока данные не будут зафиксированы. Но нет явного порядка записи между отдельными файлами AppendVec. Чтобы создать порядок, индекс поддерживает атомарный счетчик версии записи. Каждое добавление к AppendVec записывает номер версии записи индекса для этого добавления в записи для Пользователя в AppendVec.

Чтобы восстановить индекс, все файлы AppendVec можно читать в любом порядке, а последняя версия записи для каждой вилки должна храниться в индексе.

Снимки

Для моментального снимка базовые отображаемые в память файлы в AppendVec должны быть сброшены на диск. Индекс также может быть записан на диск.

Представление