Korni3
Технология личного информационного суверенитета.
korni3
это файловая система хранения данных, управления данными с SQL возможностями.- ваши данные всегда есть как минимум у Вас, и доступ к ним вам никто не может запретить, перекрыть итд.
korni3
работает как быстрый “дописываемый журнал”, сделанный так, чтобы его частями удобно было обмениваться (а ля KAfka)korni3
проверяет и создает “Цифровые Подписи”, которые есть у каждой записи, ясно кто и когда её создал и изменил.Ретроспектива:
korni3
может хранить историю всех изменений.korni3
это утилита командной строки.korni3
можно использовать как более быструю нативную (с++) замену для python утилитыsqlite-utils
с некоторыми улучшениями.korni3
работает как замена kafka-sql , но не требует разворачивания серверов , их доступности итд,korni3
работает с файлами и больше поход наgit
при использовании.korni3
идеально подойдет как основа хранилища данных децентрализованных сервисов , как система управления научными данными, тем , кто парсит и обрабатывает данные, анализирует… и хочет добиться порядка в своих данных.korni3
это “транспорт агностик” система - в ней нет сетевых функций и не должно их быть. Это Unix way файловый способ взаимодействия с системой. Пользователяkorni3
юридически невозможно обвинить в “распространении чего-либо” т.к. в ней нет никаких транспортных функций.korni3
сделан так, чтобы быть много-пользовательским хранилищем для децентрализованных систем , при этом не имея транспорта - это сеть , без сети.для
korni3
существует 100500 множество “сторонних” способов обмена данными. Перекрыть их все совершенно. невозможно. Сkorni3
можно работать даже без интернета - через флешки, через радио, через mesh сети, факс, “лапшу”, модемы и конечно десятки способов с разной идеологией через белый и тёмный интернет…korni3
использует “Цифровые подписи”, но может использовать опционально и любое шифрование, внутри обучающих материалов будет для Вас курс по крипто-безопасности.
Короче! я грамотно совместил :
- идею
kafka storage
, выкинув, громоздкое, и добавивgzip
сжатие И- концепт
kafka-sql
(из журнала в индексы, доступные через sql, пишем в журнал, читаем sql) И- файловую
slite3
субд базу + удобные расширения для ГЕО индексов И- цифровые подписи для проверки подлинности (в кафка такого не было)
ipfs
+torrent
+sha
… кодирование файлов для хранения, для дедубликации и удобства обмена файламичтобы не зависеть от сетей и протоколов - это реализуется отдельными системами.
Планы
переделать интернет, так, чтобы пользователь там полноправным хозяином всех своих данных.
- для
korni3
создается такой состав графических приложений:- Интернет магазин / “маркетплейс”, типа Avito, Kufar, Яндекс.Маркет, и многих подобных… Там будет гораздо больше категорий, в том числе спрос.
- статьи с обсуждением, как , например, на Я.Дзене
- Огромная база знаний, с медиа материалами (как @youtube) и с текстами, резервные копии ценных сайтов итд.
- Мощная система управления знаниями (спрашивайте) и обучения.
- система управления предприятием, ERP, MES, PDM, планирование, склад, … всё нужные модули.
SYNOPSYS
1 | # genkey <nickname> [<bits; 4096 by default>] |
TUTORIAL
genkey ; generate keypairs ; Генерируем пары ключей с человеко-читаемым “прозвищем” (только вы его будете знать)
Содержимое папки
/home/mp/.config/korni/MY-KEYS/
никому нельзя показывать! Лучше хранить это на личной “флешке”, а путь пробрасывать через символьную ссылку.
1 | # genkey <nickname> [<bits; 4096 by default>] |
keys ; Просмотр списка пар ключей
read “special directory” with keys
print to stdout available keys (basicaly key nicknames) in format // TODO публичные ключи
1 | # print to stdout keys nicknames |
печатает доступные для login
псевдонимы
login ; выбрать рабочий ключ
если успех: Печатает в stdout tsv строку из двух полей псевдоним и идентификатор в виде публичного ключа. Этот длинный публичный ключ и есть внутренний идентификатор пользователя.
если ошибка: печатает в stderr сообщение ошибки
1 | # korni3 login <nickname> |
insert/create ; добавление данных
Данные можно только добавлять. Менять данные и удалять данные - нельзя , by design
Опции:
--skip-db-update
создаются только подписанные записи на диске, но не добавляются в sql базу данных. Это удобно при быстром пакетном добавлении данных, или когда записи поступают наSTDIN
чтобы быстро их просто добавить и потом уже сделатьkorni3 scan <db>
… чтобы данные из файлов попали в бд. без указания этой опции - записи попадают и в базу тоже
1 | # create|insert <dbName> <tableName> [<jsonRecord>] [--skip-db-update] |
В результате получим данные в БД (поле zU
условно не показано),
1 | $ korni3 rows test testTable --csv --table -c id -c zT -c name --where 'id = 1' |
или графически
Первичным ключом является пара (id
, zT
), где zT
- epoch UTC timestamp, т.е. момент времени когда создана данныя запись.
В записи, так же, всегда присутствует публичный ключ (pubkey) пользователя, который создал запись.
Прикладное приложение может выбирать для каждого id объекта только одну версию с наиболее поздним моментом времени создания.
То, что данные автоматически появились в таблице - это результат опtрации scan автоматической операции scan, которая вызвалась автоматичеcки при вставке записей в “журнал”.
На самом деле главная функция операции insert - создание записей в журнале.
/home/mp/.config/korni/
- файлы системы korni3/home/mp/.config/korni/test
- данные контейнера с именем test (это имя фигурирует в командах выше)
посмотрим файлы записей таблицы testTable, которые были созданы командой insert:
1 | $ find ~/.config/korni/test -type f | grep T--testTable-- |
Итак, имеем файл с причудливым названием T--testTable--D-2022-9-24-GH-uf7d5zbvz7qt.jsonnl.gz
в папке с причудливым названием tables/2022/2022-9-24/U-646/60e/e5431584f0fd0cf0f86b7fa04ff23bf3d0a554c5930786ffd7155cd29c7c/
- Каждое изменение данных, продуцирует новые записи в этом и подобных файлах,
- записи добавляются автоматически предсказуемо в нужные файлы.
- система дописывает файлы “сегодняшнего дня”, файлы предыдущих дат - не трогает.
- файлы сжаты gzip алгоритмом, внутри частичные подписанные ЦП записи в формате jsonnl, которые еще соответствуют определенным требованиям (созданы разными пользователями)
- каждый файл дописывается только одним пользователем , разные пользователи пишут “дополнения к таблицам файлы с разными именами
Имя самого файла содержит :
T--testTable--
имя таблицы, “дополнения” к которой, содержатся в файлеD-2022-9-24-
- дата создания (UTC) дополнений в этом файлеGH-uf7d5zbvz7qt
- geoHash ; гео позиция точки , к которой относятся записи, которую пользователь мог указать, если желает. (чтобы сразу по листингу быстрее получать обновления только интересующего региона, например для приложений с объявлениями)
Имя папки содержит:
- Год, дату,
sha256(user public key)
, разбитый на три части (три подпапки) по три значащих символа в первых двух частях.
Это важно, чтобы файловая система быстро могла работать с миллиардами пользователей, и при этом можно было бы продолжать получать обновления инкрементально, начиная с нужной даты, и интересоваться обновлениями по приоритетным пользователям (подписки, каналы, друзья, команда … ).
Ещё это важно, чтобы файлы не пересекались конфликтами по пользователям, и можно было бы безболезненно мержить папки разных пользователей, объединяя их наборы изменений.
Пример содержимого файлов обновлений таблиц (распакуем только две записи):
1 | $ zcat /home/mp/.config/korni/test/tables/2022/2022-9-24/U-646/60e/e5431584f0fd0cf0f86b7fa04ff23bf3d0a554c5930786ffd7155cd29c7c/T--testTable--D-2022-9-24-GH-uf7d5zbvz7qt.jsonnl.gz | head -n 2 |
Здесь записи громоздкие.
В каждой записи есть одинаковое поле zU
(пользователь), которое очень хорошо жмётся gzip и не влияет на размер.
В каждой записи есть поле zS
(цифровая подпись) она есть только в сырых записях, после проверки это поле не попадает в базу данных.
Записи не обязательно формируются вами, их может формировать стороннее ПО, и при подписывании могут быть ошибки… “Битые записи” могут лежать в журналах, но ни одна запись с не правильной подписью не попадает в базу данных из журнала через scan
.
Выход из примера выше можно легко обработать, например, jq
утилитой. Но у нас есть вариант получше : korni3 verify
, например, является фильтром, который пропускает сквозь себя только записи для которых пройдена проверка ЦП.
repack ; пересжатие
При формировании файлов “дополнений для таблиц” , для бОльшей скорости, используется “дописывание gzip блоков в файл”, а уже вчерашние и более старые файлы не нужно дописывать - для них можно применить наилучшее сжатие с предварительным вычислением общего словаря.
!!! Аккуратно, этой командой можно попортить данные, если с ними работает другой процесс - перестаньте менять данные во время этой операции, остановите синхронизации, не делайте операций вставки записей.
1 | $ korni3 repack |
эта команда сжимает все таблицы заново
Пример вывода команды (ratio %, old size, new size, filename; в конце - экономия места на диске):
1 | mp@mp-strela:/media/mp/ac22fd5c-3daf-4f5a-a4bf-65b346984f64/BACKUP/KORNI-DATA/yt-korni-WfoAvg6ooB$ korni3 repack yt comments |
file ; сохранение файлов
главный способ
- Файлы не правильно хранить в базе данных
- хотя, в ряде случаев это разумно и я позже покажу как это можно удобно делать в korni3
- Кроме того, удобнее и правильнее делать, используя ХЕШ по контенту.
Korni3 transport agnistic ! - это значит, что
korni3
не имеет и не будет иметь сетевых функций, однако предоставляет все удобства для всех систем обмена файлами.
Пример добавления файлов в систему korni3
: (добавлять можно и один файл и папку рекурсивно)
1 | # korni3 file <dbName> <fileOrDirPath> [--skipmeta] [--ignore] [--rm] [--empty] |
Ключи не обязательны, порядок любой :
--skipmeta
- добавить сам файл в контейнер, но не писать в таблицуfiles
метаинформацию--skip-db-update
метаинформацию писать на диск, но бд не обновлять для скорости обработки (можно будет сделать обновить “пачкой” позжеkorni3 scan
)--ignore
- проверить id файла и если он есть в контейнере - не добавлять ни его ни метаинформацию.--rm
после успешной обработки файлов - исходные файлы удалить с диска. Используется для экономии места на диске - произойдет перенос файлов в контейнер, это выгодно для скриптов, которые скачивают, чтобы добавить, больших файлов видео и фото, устранения дубликатов…--empty
- после успешной обработки исходный файл усекается по размеру до нуля. Это выгодно для скриптов, которые скачивают контент для добавления, чтобы они знали с какого места продолжить работу в случае разрыва связи, и не скачивали уже скачанные файлы (они по наличию на диске часто проверяют)
Утилита печатает в STDOUT и в STDERR каналы в разных форматах, чтобы удобнее было использоать korni3 в bash конвейерах.
- в stdout - json (nl new line ended) в котором
- korni3 file id , о нём подробнее ниже
- путь к файлу
- размер в байтах
- даты создания и последней модификации
- вывод диагностики test утилитой file - информация о типе файле и его полях.
- в будущем список тестов будет дополнятся.
- в stderr - только korni3 file id (состоит из хешей) И путь
- Сам файл добавляется в систему (так что с исходного места его уже можно удалить для экономии места)
- в контейнер в таблицу “files” добавляется запись о нём. (тот самый json record)
вот сам файл :
1 | $ find ~/.config/korni/test -type f | grep Qme6DcxwC2SABnttae5ndAPzNyk4G2KHmxFas7NqFHPFhy |
структура пути файлов
- korni/test/files - место для файлов в контейнере test
e6/Dc/xw/GFS-Qme6DcxwC2S...
Qme6DcxwC2S разбивка файлов по папкам , имена папок образуются как части ipfs идентификатора файла, ipfs по умолчанию для хешей по умолчанию использует base58 кодирование, т.е. максимальное число папок в каждой папке на каждом уровне не превышает 58^2=3364 при таком числе папок в папке файловая система обычно не тормозит , а вот при большем числе символов это уже 58^3=195_112 уже многовато и ФС будет тормозить при “ручной навигации”, на трёх уровнях это 3364^3=38_068_692_544 файлов если в каждой конечной папке будет только по одному файлу, что более чем достаточно для одного контейнера, (и ничего не мешает в будущем заложить больше уровней.)
сам идентификатор файла (его имя в папке korni3) содержит такие хеши, в качестве частей
GFS-Qme6DcxwC2SABnttae5ndAPzNyk4G2KHmxFas7NqFHPFhy-
ipfs хеш по умолчанию, это всё таки “global file system”T-bd3541672cd9a9c83d7ac8c6f74a7f6fe272f734-
torrent hashM-8a5ff4aeb511b1cfae11787da6e28a99-
md5S256-7b3a3f93a63341651d7ef129ddca235f33cf061e434cd866e3d1695cb4cee402
sha256
korni3
дополняет лог /tmp/TORRENT-error.log/
выводом программы transmission-create (это возможные ошибки создания торрент файлов)
Сторонние программы, которые будут управлять содержимым легко смогут по этим хешам ориентироваться.
Вы, например, можете смело добавить вашу папку files в torrent раздачу и по hash находить файлы для скачивания (подобные “синхронизаторы” я предложу в рамках другого проекта).
другой способ -TODO пока он не реализован
Добавление base64 файла в “дополнения таблиц” - в сами таблицы попадает в итоге BLOB поле.
1 | $ korni3 insert-files images *.gif |
По умолчанию схема полей будет такой
1 | CREATE TABLE [images] ( |
Если добавить файл снова - будет другая запись! т.к. path
- НЕ PRIMARY KEY. Будьте аккуратны.
Можно добавить опциями команды , например -c path -c md5 -c mtime
…
Доступные опции :
1 | name |
setgeo ; указать местоположение пользователя
- Команда получает координаты пользователя, кодирует их в формате geohash и запоминает для следующих операций (вставка записей, scan, …)
- не имеет отношение к контейнеру/базе, а только к пользователю.
- может быть использовано приложениями, которым нужна гео функциональность “из коробки”
- помогает просто получать обновления данных из “своего региона базирования”
1 | # setgeo <lat like 58.05139>,<lat like 38.83802> |
verify ; проверить записи ; helper utility ; служебная утилита
- Команда читает jsonnl записи с STDOUT
- проверяет цифровую подпись
- если ок - удаляет поле подпись из записи и выводит запись на STDOUT
- если ошибка - печатает их на STDERR
1 | # korni3 verify |
scan ; обновить БД sqlite3 из проверенных по подписи “дополнений” в журналах.
- Команда получает ограничения (filter - подстрока коорая должна рисутствовать в именах файлов на диске (смотри кодирование структуры файлов)), иначе обрабатывается всё
- по ним проверяет дополнения (change set)
- импортирует их в БД.
на псевдокоде работу команды можно выразить так:
1 | # pseudocode replace : |
Фильтровать изменения можно
- по дате начиная с которой до текущего момента изменения применяются (всё, если не указана)
- по конкретному списку аккаунтов, или по всем, если не указано
- по гео локации, с указанием радиуса от гео точки, или по всей планете, если не указано иное
1 | // scan <containerName> [ filter condition options ] |
под user1
, user2
, user3
тут понимается не pubkey
юзера , а sha1(pubkey of user)
который встречается в пути файлов от него
Зачем эти ключи:
Эти ключи предусмотрены для приложений , которые ориентированы на быструю синхронизацию баз данных юзеров, для случаев частичной синхронизации таких баз, чтобы после частичной синхронизации файлов обновить бд по смерженым наборам данных.
могут интересовать
- обновления от друзей - фильтр по юзерам.
- обновления объектов в радиусе от вас… - например объявления и заявки или заказы или аварии или отчеты. перед scan для этого установите текущее местоположение
setgeo
- и обновления не старше заданной даты т.к. вы можете знать, что в ту дату уже проводили скан и ничего нового с той даты с данными не делали.
- в будущем добавлю фильтр по отдельным таблицам по имени
Важно:
- запись не вставляется заново если такая уже есть. проверка идет по первичному ключу, который составной
(id, zT)
т.е. разные версии будут вставлены, но не повторно версия. - если столбец в таблице не существует - он будет создан, т.е. над таблицей будет проведен
SQL ALTER TABLE
. тип столбца будет такой, какое значение вставляется в него первый раз.
db ; путь к базе для прямой работы
Утилита печатает на std out путь к файлу БД для прямой работы с базой
Надо для запросов чтения через sqlite3
Используется например так:
1 | # db <containerName> |
Для обработки (фильтрации, преобразования итд) данных тут есть все возможности.