В этом задании вы реализуете алгоритм распределённого слияния N
отсортированных последовательностей.
В файлах DataHolder.kt
и Merger.kt
находятся описания интерфейсов, которые вам предстоит
реализовать.
Свой код вы должны писать на языке Kotlin в файлах DataHolderImpl.kt
и MergerImpl.kt
.
Допустима также реализация на Java. Для этого, как и в предыдущих заданиях, удалите файлы DataHolderImpl.kt
и MergerImpl.kt
и вместо них добавьте файлы с
Java-кодом, в которых реализуйте аналогичные классы.
DataHolder
-процесс хранит отсортированный список ключей и отдаёт ключи Merger
-процессам для слияния.
fun getBatch(): List<T>
— передаётMerger
-процессу пакет ключей размераbatchSize
. Если ключей осталось меньшеbatchSize
, то нужно вернуть все оставшиеся ключи (в частности, если ключей не осталось вообще, необходимо вернуть пустой список). Во всех остальных случаях необходимо вернуть пакет, размер которого в точности равенbatchSize
.
Производящий объединение Merger
-процесс может в любой момент отказать. В этом случае, объединение необходимо продолжить на новом Merger
-процессе. Объединение на новом процессе должно быть продолжено с того же самого места, с которого объединение началось на отказавшем процессе.
fun checkpoint()
— сохраняет текущее состояниеDataHolder
-процесса, чтобы его можно было восстановить в случае сбояMerger
-процесса.fun rollback()
— вызывается в случае сбояMerger
-процесса и загружает последнее сохранённое состояние.
Через ссылку на объект DataHolderEnvironment
DataHolder
-процесс может узнать batchSize
— требуемый размер пакета ключей.
Merger
-процесс выполняет операцию распределённого слияния, запрашивая пакеты ключей у DataHolder
-процессов.
- Конструктор класса
MergerImpl.kt
принимаетMap<Int, List<T>>?
— отображение из идентификатораDataHolder
-процесса в остаток пакета ключей, полученного от этогоDataHolder
-процесса. Эти пакеты были получены предыдущимMerger
-процессом, но не были использованы (так как у предыдущегоMerger
-процесса закончилось место на диске). Все списки в отображении непусты — если весь пакет ключей, полученных с определённогоDataHolder
-процесса, был израсходован ранее, то идентификатор этогоDataHolder
-процесса не будет присутствовать в отображении. Если текущийMerger
-процесс является первым, то вместо отображения ему в конструктор передаётсяnull
. fun mergeStep(): T?
— возвращает ключ, который должен быть следующим в сливаемой последовательности. Если ключей в сливаемой последовательности не осталось, процесс должен вернутьnull
.fun getRemainingBatches(): Map<Int, List<T>>
— возвращает отображение из идентификатораDataHolder
-процесса в остаток пакета ключей, полученного от этогоDataHolder
-процесса по описанным выше правилам. Заметьте, что в возвращаемом отображении не должно быть пустых списков: если некоторомуDataHolder
-процессу должен быть сопоставлен пустой список, идентификатор этогоDataHolder
-процесса не должен присутствовать в отображении.
Через ссылку на объект MergerEnvironment
Merger
-процесс может:
val dataHoldersCount: Int
— узнать, сколькоDataHolder
-процессов существует в системе.DataHolder
-процессы системы пронумерованы целыми числами в диапазоне[0; dataHoldersCount - 1]
.fun requestBatch(dataHolderId: Int): List<T>
— запросить пакет ключей уDataHolder
-процесса с идентификаторомdataHolderId
. Заметьте, что запрашивать ключи можно только если вы исчерпали весь запас ключей, полученных от этого процесса ранее.
Тестирования реализации происходит путем запуска теста SolutionTest
.
Из командной строки: ./gradlew test
.
- Выполняйте задание в этом репозитории.
- Код
DataHolder
-процесса должен быть реализован в одном файлеDataHolderImpl.kt
илиsrc/DataHolderImpl.java
. - Код
Merger
-процесса должен быть реализован в одном файлеMergerImpl.kt
илиsrc/MergerImpl.java
. - Не меняйте остальные файлы в репозитории.
Инструкции по сдаче заданий находятся в этом документе.