108 lines
7.1 KiB
Markdown
108 lines
7.1 KiB
Markdown
# distbuild
|
||
|
||
В этом задании вам нужно будет реализовать систему распределённой сборки.
|
||
|
||
Система сборки получает на вход граф сборки и файлы с исходным кодом. Результатом сборки
|
||
являются исполняемые файлы и stderr/stdout запущенных процессов.
|
||
|
||
## Граф сборки
|
||
|
||
Граф сборки состоит из джобов. Каждый джоб описывает команды, которые нужно запустить на одной машине,
|
||
вместе со всеми входными файлами, которые нужны этим командам для работы.
|
||
|
||
Джобы в графе сборки запускают произвольные команды. Например, вызывать компилятор, линкер или
|
||
запускать тесты.
|
||
|
||
Команды внутри джоба могут читать файлы с файловой системы. Мы будем различать два вида файлов:
|
||
- Файлы с исходным кодом с машины пользователя.
|
||
- Файлы, которые породили другие джобы.
|
||
|
||
Команды внутри джоба могут писать результаты своей работы в файлы на диске. Выходные файлы
|
||
обязаны находиться внутри его выходной директории. Директория с результатом работы джоба называется
|
||
артефактом.
|
||
|
||
```go
|
||
package build
|
||
|
||
import "crypto/sha1"
|
||
|
||
// ID задаёт уникальный идентификатор джоба.
|
||
//
|
||
// Мы будем использовать sha1 хеш, поэтому ID будет занимать 20 байт.
|
||
type ID [sha1.Size]byte
|
||
|
||
// Job описывает одну вершину графа сборки.
|
||
type Job struct {
|
||
// ID задаёт уникальный идентификатор джоба.
|
||
//
|
||
// ID вычисляется как хеш от всех входных файлов, команд запуска и хешей зависимых джобов.
|
||
//
|
||
// Выход джоба целиком опеределяется его ID. Это важное свойство позволяет кешировать
|
||
// результаты сборки.
|
||
ID ID
|
||
|
||
// Name задаёт человекочитаемое имя джоба.
|
||
//
|
||
// Например:
|
||
// build gitlab.com/slon/disbuild/pkg/b
|
||
// vet gitlab.com/slon/disbuild/pkg/a
|
||
// test gitlab.com/slon/disbuild/pkg/test
|
||
Name string
|
||
|
||
// Inputs задаёт список файлов из директории с исходным кодом,
|
||
// которые нужны для работы этого джоба.
|
||
//
|
||
// В типичном случае, тут будут перечислены все .go файлы одного пакета.
|
||
Inputs []string
|
||
|
||
// Deps задаёт список джобов, выходы которых нужны для работы этого джоба.
|
||
Deps []ID
|
||
|
||
// Cmds описывает список команд, которые нужно выполнить в рамках этого джоба.
|
||
Cmds []Cmd
|
||
}
|
||
```
|
||
|
||
## Архитектура системы
|
||
|
||
Наша система будет состоять из трех компонент.
|
||
* Клиент - процесс запускающий сборку.
|
||
* Воркер - процесс запускающий команды компиляции и тестирования.
|
||
* Координатор - центральный процесс в системе, общается с клиентами и воркерами. Раздаёт задачи
|
||
воркерам.
|
||
|
||
Типичная сборка выглядит так:
|
||
1. Клиент подключается к координатору, посылает ему граф сборки и входные файлы для графа сборки.
|
||
2. Кооринатор сохраняет граф сборки в памяти и начинает его исполнение.
|
||
3. Воркеры начинают выполнять вершины графа, пересылая друг другу выходные директории джобов.
|
||
4. Результаты работы джобов скачиваются на клиента.
|
||
|
||
# Как решать эту задачу
|
||
|
||
Задача разбита на шаги. В начале, вам нужно будет реализовать небольшой набор независимых пакетов,
|
||
которые реализует нужные примитивы. Код в этих пакетах покрыт юниттестами. В каждом пакете находится
|
||
файл README.md, объясняющий подзадачу.
|
||
|
||
Рекомендуемый порядок выполнения:
|
||
|
||
- [`distbuild/pkg/build`](./distbuild/pkg/build) - определение графа сборки. В этом пакете ничего писать не нужно,
|
||
нужно ознакомиться с существующим кодом.
|
||
- [`distbuild/pkg/tarstream`](./distbuild/pkg/tarstream) - передача директории через сокет.
|
||
- [`distbuild/pkg/api`](./distbuild/pkg/api) - протокол общения между компонентами.
|
||
- [`distbuild/pkg/artifact`](./distbuild/pkg/artifact) - кеш артефактов и протокол передачи артефактов между воркерами.
|
||
- [`distbuild/pkg/filecache`](./distbuild/pkg/filecache) - кеш файлов и протокол передачи файлов между компонентами.
|
||
- [`distbuild/pkg/scheduler`](./distbuild/pkg/filecache) - планировщик с экристикой локальности.
|
||
|
||
После того, как все кубики будут готовы, нужно будет соединить их вместе, реализовав `distbuild/pkg/worker`,
|
||
`distbuild/pkg/client` и `distbuild/pkg/coordinator`. Код в этих пакетах нужно отлаживать на
|
||
интеграционных тестах в [`distbuild/disttest`](./distbuild/disttest).
|
||
|
||
Код тестов в этом задании менять нельзя. Это значит, что вы не можете менять интерфейсы в тех местах, где
|
||
код покрыт тестами.
|
||
|
||
# Критерии оценки
|
||
|
||
Решение должно проходить все тесты, так же как в обычной задаче. После успешной попытки, в таблице gdoc
|
||
будет стоять 0. После этого, проверяющие должны будут просмотреть решение и заменить оценку в таблице на 1.
|
||
Это будет значить, что задача засчитана. Code Review не будет, проверка нужна только чтобы удостовериться что
|
||
посылка честно проходит все тесты.
|