Курс основ программирования на МКН СПбГУ

Проект 2: key-value база данных

Это проект первого курса СПбГУ факультета МКН "Современное программирование" — консольный интерфейс к базе данных, хранящей текстовые значения с доступом по текстовым ключам. Утилита работает с базами данных кастомного формата (с расширением .db). Она может осуществлять поиск, вставку, удаление записей, а также копирование и создание новых баз данных. Оригинальная постановка задачи: TASK.md.

Концепция неизменяемых баз данных

При операциях, меняющих базу данных (вставка, удаление, слияние, ...), по умолчанию изменение не происходит на месте: все данные вместе с изменениями записываются в новый файл базы данных. Такое поведение программы задано из соображений неизменяемости (по аналогии с immutable структурами данных в языках программирования). По умолчанию, для пользователя база данных должна выглядеть неизменяемой (подобно тому, что в Kotlin многие структуры данных по умолчанию неизменяемые) для того, чтобы риск потерять или испортить данные был минимален.

Если же вам всё-таки удобно изменять базу данных на месте, и вы не видите смысл в неизменяемости, то достаточно просто дописать символ !, указывающий, что изменения надо записывать обратно в тот же файл (примеры использования восклицательного знака см. в разделе "Опции и аргументы").

Запуск

В релизах можно найти скомпилированный jar файл kvdb.jar. Запуск производится следующей командой:

java -jar kvdb.jar [OPTION] [ARGS...]

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

Опции и аргументы

  • -h или --help: вызвать справку.
  • -r или --read: найти значения в базе данных по заданным ключам. Число ключей может быть нулевым. Ключи могут повторяться. Значения выводятся по одному в строке. При первом ключе, отсутствующем в базе, программа завершается с ошибкой. Аргументы:
-r [DATABASE] [KEY1] [KEY2] ...
  • -rf или --readf или --readFound: вывести все найденные записи в базе данных по заданным ключам. Число ключей может быть нулевым. Ключи могут повторяться. Каждая запись выводится в двух строках: в первой строке выводится ключ, а во второй - значение. Если ключ отсутствует в базе, то он пропускается. Аргументы такие же, как и у -r.
  • -c или --create: создать новую базу данных с заданными записями. Файл базы данных не должен существовать до вызова команды. Указываемые записи не должны противоречить друг другу. Аргументы:
-c [DATABASE] [KEY1] [VALUE1] [KEY2] [VALUE2] ...
  • -co или --createo или --createOverwrite: создать новую базу данных с заданными записями, при необходимости перезаписав уже существующий файл. Указываемые записи не должны противоречить друг другу. Аргументы такие же, как и у -c.
  • -a или --add: добавить записи в первую базу данных и сохранить результат во вторую базу данных. Если ключ у добавляемой записи уже присутствовал в базе данных, то эта запись не записывается. Указываемые записи не должны противоречить друг другу. Аргументы:
-a [DATABASE1] [DATABASE2] [KEY1] [VALUE1] [KEY2] [VALUE2] ...

Здесь и в последующих командах [DATABASE2] можно заменить на !, после чего результат будет записываться в исходную базу данных (иными словами, вторая база данных совпадёт с первой):

-a [DATABASE1] ! [KEY1] [VALUE1] [KEY2] [VALUE2] ...
  • -ao или --addo или --addOverwrite: добавить записи в первую базу данных и сохранить результат во вторую базу данных, при этом перезаписывая значения уже существующих ключей. Указываемые записи не должны противоречить друг другу. Аргументы такие же, как и у -a.
  • -d или --delete: удалить записи с заданными ключами из первой базы данных и сохранить результат во вторую базу данных. Ключи могут повторяться. Если какого-то ключа не было в базе данных, то для него ничего не удаляется. Аргументы:
-d [DATABASE1] [DATABASE2] [KEY1] [KEY2] [KEY3] ...
-d [DATABASE1] ! [KEY1] [KEY2] [KEY3] ...
  • -cp или --copy: скопировать базу данных из первого файла во второй. Аргументы:
-cp [DATABASE1] [DATABASE2]
  • -m или --merge: слить две базы данных, и записать результат в третью базу данных. Две базы данных не должны противоречить друг другу. Аргументы:
-m [DATABASE1] [DATABASE2] [DATABASE_OUT]

Как и ранее, [DATABASE_OUT] можно заменить на ! (тогда результат запишется в [DATABASE1]), а теперь также и на !! (тогда результат запишется в [DATABASE2]):

-m [DATABASE1] [DATABASE2] !
-m [DATABASE1] [DATABASE2] !!
  • -mo или --mergeo или --mergeOverwrite: слить две базы данных, и записать результат в третью базу данных. Если в двух базах есть противоречия, то приоритет отдаётся второй базе данных (противоречащие записи перезаписываются). Аргументы такие же, как и у -m.

Коды возврата

  • 0 — программа выполнилась успешно
  • 1 — программа выполнилась с ошибками (некорректные опции/аргументы, базы данных не найдены, недоступны, некорректны и т.п.)

Примеры использования

Проверить программу вручную можно на примерах из папки samples.

Тестирование

Исходный код сопровождён unit тестами, покрывающими все компоненты проекта.

Стресс-тестирование

В классе src/test/kotlin/stressTests/StressTests.kt содержится ряд функций, позволяющих произвести замер времени работы на больших данных некоторых компонентов, таких, как запись базы данных в файл, чтение базы данных из файла, операций поиска и добавления. Функции следует запускать в качестве unit теста.