аналог тайммашины для проекта нужен прямо сейчас. может, для nvim что-то такое есть — что бы были снапшоты с таймстемпами и можно было между ними быстро переключаться
Пока в соседнем чате идут споры (ну как — споры, просто появляются люди, которые абсолютно всё уже знают заранее, куда другим идти и что там делать и как) — и планируется построение глобальной распределенной системы в которой всё будет хорошо — корпорации и AI будут унижены и вообще общее благолепие — примерно скажу, как я всё это вижу.
А вижу я это как на этапе 0 — просто соглашение о структурах данных, и не так важно, как эти именно структуры доедут до конечного потребителя.
Идея, в общем, не нова — есть тот же nostr, на него любопытно посмотреть в плане того, во что можно превратить изначально вроде бы разумную идею.
В web в своё время появились гиперссылки — но по факту, ссылка же ничего физически не адресует и нет никакой гарантии, что для разных пользователей одна и та же ссылка будет указывать на одно и то же (что?). Сейчас ни домены, ни ip адреса, ни строчки после имени домена в URL (да и до него тоже) не имеют никакого смысла.
Сейчас — это когда мы вступаем в эпоху глобального мультичебурнета.
Хэш ссылка — напротив, адресует нечто конкретное, но тоже вопрос — а что именно?
Ну и нет какого-то всеобщего способа хэширования. Последняя проблема выглядит решаемой.
Но если мы сможем хотя бы договориться о ссылках и форматах — то при наличии некоей системы, которая по хэш-ссылке сможет отдать её содержимое — уже можно строить самые занятные системы.
Система это, в общем-то некий глобальный CAS и основное, что он должен уметь делать — это отдавать контент по хэш-ссылке.
Второе, что он должен уметь делать — это поддерживать мутабельные переменные, и эта самая мутабельность в распределенных системах — целая отдельная большая тема.
Углубляться дальше пока незачем, т.е на фазе 0 — нужно хотя бы согласовать виды хэш-ссылок и подумать, как будут добавляться новые алгоритмы хэширования. Что-то мне подсказывает, что даже здесь нас ожидают проблемы, достаточно посмотреть на git, например.
А вижу я это как на этапе 0 — просто соглашение о структурах данных, и не так важно, как эти именно структуры доедут до конечного потребителя.
Идея, в общем, не нова — есть тот же nostr, на него любопытно посмотреть в плане того, во что можно превратить изначально вроде бы разумную идею.
В web в своё время появились гиперссылки — но по факту, ссылка же ничего физически не адресует и нет никакой гарантии, что для разных пользователей одна и та же ссылка будет указывать на одно и то же (что?). Сейчас ни домены, ни ip адреса, ни строчки после имени домена в URL (да и до него тоже) не имеют никакого смысла.
Сейчас — это когда мы вступаем в эпоху глобального мультичебурнета.
Хэш ссылка — напротив, адресует нечто конкретное, но тоже вопрос — а что именно?
Ну и нет какого-то всеобщего способа хэширования. Последняя проблема выглядит решаемой.
Но если мы сможем хотя бы договориться о ссылках и форматах — то при наличии некоей системы, которая по хэш-ссылке сможет отдать её содержимое — уже можно строить самые занятные системы.
Система это, в общем-то некий глобальный CAS и основное, что он должен уметь делать — это отдавать контент по хэш-ссылке.
Второе, что он должен уметь делать — это поддерживать мутабельные переменные, и эта самая мутабельность в распределенных системах — целая отдельная большая тема.
Углубляться дальше пока незачем, т.е на фазе 0 — нужно хотя бы согласовать виды хэш-ссылок и подумать, как будут добавляться новые алгоритмы хэширования. Что-то мне подсказывает, что даже здесь нас ожидают проблемы, достаточно посмотреть на git, например.
Неловкий момент, когда высосал из пальца фильтр тупо на TVar + unboxed vector и он работает примерно так (первый тест — библиотечный блум фильтр bloomfilter)
Но потом говорящие собаки говорят, что ты высосал из пальца то, что уже используется в
- RocksDB (filter block)
- Parquet
- LSM-based системах
и вообще Твой подход — это blocked Bloom filter + multi-bit hashing
См. статью: "Blocked Bloom Filters"
ну... пусть будет тогда, что ли. Так-то мне всего лишь надо было что бы фильтр в STM работал
Но потом говорящие собаки говорят, что ты высосал из пальца то, что уже используется в
- RocksDB (filter block)
- Parquet
- LSM-based системах
и вообще Твой подход — это blocked Bloom filter + multi-bit hashing
См. статью: "Blocked Bloom Filters"
ну... пусть будет тогда, что ли. Так-то мне всего лишь надо было что бы фильтр в STM работал
Еще к фильтрам. Как и было изначально, .cq индексы сами по себе фильтры. Надо просто снижать их количество при помощи merge и/или делать поиск по ним параллельным, что и попробую сейчас запилить. Фильтры это хорошо, но с ними очень много проблем - и с масштабированием, и отсутствием готовых, и непонятно что с инкрементальностью. Иерархический блум например по сложности как весь ncq, + были придумки насчёт инкрементального куку-индекса, но он по сложности тоже больше самого ncq. Ладно...
Вот еще загадка века — зачем нужен PAXOS если есть PBFT. Гугл говорит нам, что
https://ieeexplore.ieee.org/document/9975938
Самое интересное в этом то, что PBFT это типа 2001-ый год, что ли. 1999!!
И он простой как тапок, там 20kloc это потому, что на C++, на х-ле сам алгоритм (минус gossip минус сеть минус сторейдж, чисто FSM) — строк триста. И главное его умом понять можно, а не как PAXOS.
Т.е оно проще даже Raft, кажется. Если же к согласуемому стейту применимы некоторыe принципы CRDT — то становится еще проще.
Finally, based on the evaluation results, it was found that the PBFT algorithm has a speed five times faster than Raft and six times faster than Paxos to reach consensus. So we consider the PBFT algorithm to have the best speed and scalability.
https://ieeexplore.ieee.org/document/9975938
Самое интересное в этом то, что PBFT это типа 2001-ый год, что ли. 1999!!
И он простой как тапок, там 20kloc это потому, что на C++, на х-ле сам алгоритм (минус gossip минус сеть минус сторейдж, чисто FSM) — строк триста. И главное его умом понять можно, а не как PAXOS.
Т.е оно проще даже Raft, кажется. Если же к согласуемому стейту применимы некоторыe принципы CRDT — то становится еще проще.
А как чисто технически СРКНы собираются мониторить "экстремисткие запросы" в гугл или duckduckgo ? TLS-то вроде еще работает, а логи гугл им не выдаёт. История браузера? Но кто в здравом уме будет такое делать не в incognito режиме? Он конечно так себе инкогнито, но историю точно не хранит. Опять же, LLM-ы охотно общаются на любые темы экстремисткие темы, это ж не про секс.
в 0.25.2 есть скрытый критичный баг в сторейдже. у кого не выстрелил — повезло. остальным не рекомендую 0.25.2, придется его пропустить и переходить сразу на 0.25.3
Desperation Driven Development всегда работает. Единственная проблема, что отчаяние должно быть неподдельным. Т.е заранее (что бы сэкономить время) не получится.
Ну и день. Когда тесты проваливаются, и ты патчишь код, но ничего не помогает, потому что ошибки в тестах. Ладно, эта пилорама — график пропускной способности NCQ2 от числа потоков.
Красным пунктиром — baseline, то есть просто берёт N блоков и пишем в файл через appendFile.
Это с пересчётом хэшей. Учитывая то, что лог реально пишется в один поток в один момент времени — и всё остальное это мои ухищрения с fsynс и батчингом.
Т.е клиент-то зовётся из N потоков, но в итоге реально на диск пишет один. То, что это быстрее, чем просто в файл записать, я считаю, победа. Ведь тут еще построение индексов идёт параллельно — и всё равно быстрее просто записи в файл
Красным пунктиром — baseline, то есть просто берёт N блоков и пишем в файл через appendFile.
Это с пересчётом хэшей. Учитывая то, что лог реально пишется в один поток в один момент времени — и всё остальное это мои ухищрения с fsynс и батчингом.
Т.е клиент-то зовётся из N потоков, но в итоге реально на диск пишет один. То, что это быстрее, чем просто в файл записать, я считаю, победа. Ведь тут еще построение индексов идёт параллельно — и всё равно быстрее просто записи в файл
"Говорящая собака" пошло из интервью, кажись, с Марковым (?), который сравнил LLM с собакой, которая притаскивает хозяину всякие ништяки и ждёт, пока хозяин похвалит. LLM перебирает реплики, пока мясного не устроит результат и он не отвяжется
Хотел сделать бенчмарков относительно rocksdb, но по славной традиции ни один никсовый флейк не собирается, а в никсовом пакете нет db_bench. Я уже и забыл, что основной причиной не использовать rocksdb было то, что какой-то с ним вечно гемор. Софт на плюсах -> скорее всего не соберётся. ни сам, ни то, что с ним линкуется. Закон!
Сделал тест напротив rocksb, пока результаты приблизительные, т.к. в rocksdb черт ногу сломит, но вроде бы я попытался записать 100K значений размером 96K (среднее 64..256), потом для них lookup на холодную. ncq2:
rocksdb:
тестовая обвязка для rocksdb http://hbs2.net/tree/En5Fy2s3RKJcc924wseYtwQ88M3sBLnz4UmHKx4Zz1Tj
заметим, что в тесте скорости ncq2 считает хэши, чего rocksdb не делает - и скорость в районе 900Mb/s,
ну... хрен знает. но вроде бы перспективно.
UPD: rocksdb - 1.4Gb/s, если ncq2 отключить генерацию рандомных строк и подсчёт хэшей - то 1.9 .. 2.2 Gb/s. Не, ну это норм, получается
median 0.171 0.171 секунд на 100K чтений.rocksdb:
readrandom : 7.041 micros/op 142013 ops/sec 0.704 seconds 100000 operations; 8 - 0.704тестовая обвязка для rocksdb http://hbs2.net/tree/En5Fy2s3RKJcc924wseYtwQ88M3sBLnz4UmHKx4Zz1Tj
заметим, что в тесте скорости ncq2 считает хэши, чего rocksdb не делает - и скорость в районе 900Mb/s,
ну... хрен знает. но вроде бы перспективно.
UPD: rocksdb - 1.4Gb/s, если ncq2 отключить генерацию рандомных строк и подсчёт хэшей - то 1.9 .. 2.2 Gb/s. Не, ну это норм, получается
JHC ожил. Какой-то чувак его форкнул и что-то туда поддерживает. Это я реддит почитал от прокрастинации. Ничего себе! Вообще нам бы не помешал еще один компилятор хаскелла. Даже у плюсов больше одного компилятора есть. Но так-то смотришь на список расширений языка в проекте и понимаешь, что безнадёжно
Интересно, если какие-то общепринятые/готовые/достаточно хорошие эвристики для сборки мусора в lsm-подобных иммутабельных файлах? Т.е с одной стороны их лучше держать размером поменьше. т.к. любая трансформация -> полное переписывание. С другой стороны их лучше бы держать размером побольше => т.к. меньше файлов -- быстрее лукап, а лукап тут O(n) от количества файлов. С третьей стороны, а что если файлы будут ОГРОМНЫЕ? С четвёртой тут можно эвристики придумывать бесконечно, надо с чем-то достаточно хорошим закрыть этот вопрос и дальше двигаться
Я был внутри двух мощных волн хайпа - SDN и БЧ. Если взять соотношение сигнал/шум оттуда и применить для анализа заявлений в рамках текущего хайпа - можно почти на все наплевать и игнорировать. Т.е делить надо где-то на два-три порядка, а настоящее начнется, когда волна схлынет. Если, конечно, подход применим. Помню, какой-то тётке в Стэнфорде дали (или заявили, что дали) 30 миллионов на БЧ, который решает все проблемы БЧ - когда надо быстрый, когда надо медленный. Где ее стартап? Где-где. Именно там, да.
Короче, сборка мусора. Придется всё переделывать. В новой модели:
Алгоритм мержа индекса: I, J ∣ T(I) > T(J) ⟹ K = I ∪ (J ∖ I), T(K) = T(I)
I,J - подряд идущие по таймстемпу файлы, K - новый файл. В стейте заменяем I, J на K, потом отложенно "актуализируем" стейт, т.е удаляем всё, что не в нём, если
refcount = 0.
Стейты пишутся срезами, один срез - один файл, в нём все адресуемые элементы — файлы данных, индексы, счётчик, и связи файлов с индексами, которые приходится ввести, т.к. больше индексы не соответствуют файлами по именам.
Удаление мусора: из индекса удаляются дублирующие (по ключу) данные. Если затираются томбом — ну, значит, остаётся томб.
Для любого томба — его можно удалить отдельным проходом, если больше нигде нет на него ссылок.
Сборка мусора для файлов данных: удаляем блоки, если их нет в индексе или они томбы.
Целостность обеспечивается стейтом. Т.е пишем файлы, добавляем в состояние. Источник правды — файл(ы) стейта, дамп стейта = коммит транзакции. Лишнее (отсутствующее в текущем стейте) удаляем отложенно и когда оно точно не используется.
Из плюсов — файлы индекса маленькие, их быстро мержить. Файлы данных можно мержить, можно нет, на скорости чтения особо сказываться не должно.
Такие дела
индекс (n) -> (k) данные т.е файл индекса индексирует множество данных. Связь не по соответствию индекса файлу, как в гите, а в каждой записи индекса - ссылка на ключ файла. Ключ - 32 битное целое, монотонный счётчик. Файлы данных мержатся редко и до определенного размера, индексы — (неограниченно? до какого-то лимита?). Данные не трогаем. Индексы мержим. Время доступа остаётся близким к O(1), мерж индекса - O(m+n), память O(1). Индекс где-то на два порядка меньше данных, 48 байт на запись. при населённости около 0.6 — 16Gb индекс может адресовать ~ 48 терабайт данныхАлгоритм мержа индекса: I, J ∣ T(I) > T(J) ⟹ K = I ∪ (J ∖ I), T(K) = T(I)
I,J - подряд идущие по таймстемпу файлы, K - новый файл. В стейте заменяем I, J на K, потом отложенно "актуализируем" стейт, т.е удаляем всё, что не в нём, если
refcount = 0.
Стейты пишутся срезами, один срез - один файл, в нём все адресуемые элементы — файлы данных, индексы, счётчик, и связи файлов с индексами, которые приходится ввести, т.к. больше индексы не соответствуют файлами по именам.
Удаление мусора: из индекса удаляются дублирующие (по ключу) данные. Если затираются томбом — ну, значит, остаётся томб.
Для любого томба — его можно удалить отдельным проходом, если больше нигде нет на него ссылок.
Сборка мусора для файлов данных: удаляем блоки, если их нет в индексе или они томбы.
Целостность обеспечивается стейтом. Т.е пишем файлы, добавляем в состояние. Источник правды — файл(ы) стейта, дамп стейта = коммит транзакции. Лишнее (отсутствующее в текущем стейте) удаляем отложенно и когда оно точно не используется.
Из плюсов — файлы индекса маленькие, их быстро мержить. Файлы данных можно мержить, можно нет, на скорости чтения особо сказываться не должно.
Такие дела
Что-то в нашем этом хаскелле не хватает гарантий хвостовой рекурсии. Я бы написал что-то такое
tailrec (what ...) и что бы компилятор если не может гарантировать, что хвостовое — шоб ошибку генерил. А то палево прямо. Интересно, можно такое сделать? Это мне как в сишке не хватало гарантий экстента.По мере надобности подпиливаю bf6 (aka suckless-script), добавил по мелочи file:size, median, avg. Теперь например посчитать медианный размер файла в каталоге:
bf6 median [map file:size [dir:list:files .]]
Пошёл посмотреть чо как поживают Nim, Zig и D, выяснил, что существует язык Odin. Получается так, что теперь отдельно язык Жопа Одина, отдельно Один. Одни тесты в язык встраивают — т.е получается, что в языке нет более общих конструкций, на которых можно было бы выразить тест, например (функция с аннотацией). Причем, конечно же, весь этот лес adhoc конструкций еще и более всрат, чем то, что тут уже с 59-го года есть. Ну, как обычно. Я бы выпускникам факультетов компьютер сайнсов дарил бы книжку, что бы хоть одну книжку прочитали. В идеале бы две, конечно
Помнится, был во времена оны такой мем, что если высадить рандомного человека на необитаемый остров и выдать ему некий компьютер, то единственное разумное, что можно сделать — это в машинных кодах сделать некий форт, а потом на нём напилить интерпретатор лиспа, а на нём уже все остальное (нормальный интерпретатор лиспа, нормальнй интерпретатор лиспа и так далее). Пока что я нашёл единственную реализацию лиспа на форте. Но там gnu fort, что неспортивно. Спортивно было бы написать форт на чём-то, минимальный форт вроде бы что-то должно быть наподобие
ну умножить где-то еще в десять раз. но типа того, не больше. конечно, пока что заруливает sectorlisp , https://github.com/jart/sectorlisp/blob/main/sectorlisp.S который делает lisp в 512 байт машинных кодов, что наводит на мысль, что форт здесь лишнее звено и скорее уж форт писать на лиспе, чем наоборот.
Когда нибудь, когда будет время можно было бы попробовать. Например, в каком-то месте, где нет связи.
put "#define DEFSTACK(n, t, l) t n[(l)], *n##top = n"
put "#define RESET(a) (a##top) = a"
put "#define PTOP(a) (a##top)"
put "#define TOP(a) (*(a##top))"
put "#define POP(a) (*(a##top)--)"
put "#define PUSH(a,v) (*(++(a##top)) = v)"
put "#define NEXT(x) continue"
put "#define JUMP(x, b, o) ((x) = (b) + (o)); continue"
put "#define SKIP(x, n) (x += n)"
put "#define PC(x, b) ((unsigned int)(x - b))"
ну умножить где-то еще в десять раз. но типа того, не больше. конечно, пока что заруливает sectorlisp , https://github.com/jart/sectorlisp/blob/main/sectorlisp.S который делает lisp в 512 байт машинных кодов, что наводит на мысль, что форт здесь лишнее звено и скорее уж форт писать на лиспе, чем наоборот.
Когда нибудь, когда будет время можно было бы попробовать. Например, в каком-то месте, где нет связи.
GitHub
sectorlisp/sectorlisp.S at main · jart/sectorlisp
Bootstrapping LISP in a Boot Sector. Contribute to jart/sectorlisp development by creating an account on GitHub.
Шутка про сделать простой сторейдж на хаскелле используя только простые иммутабельные дисковые структуры несколько затянулась, конечно. Но тем не менее — подход рабочий. 850 - 880 mb/s при записи (с индексацией и fsync), 820K лукапов в секунду по 32-байтовому ключу при 1 индексе (скорость заметно падает с ростом числа сегментов, так что надо мержить), фоновой сборкой мусора и компакцией. Сегодня допилил тесты на устойчивость к kill -9, всё работает как должно — теряется только в пределах fsyncBytes данных и ничего не корраптится. Несколько Пару тысяч тестов сегодня прогнал. Начал чистить код и готовить к внедрению в hbs2-peer. Теперь уже после 10-го числа только.