eliasdejong
Isn't type validation already in SQL with `CHECK` constraints? I don't see what the language is adding here exactly.
You might be interested in Datastar [1], which is like htmx but centered around Server-Sent Events. You don't have to do diffing yourself in application code because it's already handled by the framework under the hood through the "idiomorph" DOM morphing algorithm.
Show HN: Spsc-ring-threadsafe Python C ext. 100x faster as multiprocessing.Queue
Show HN: Plox – Lox compiler in ~600 LOC from the 'Crafting Interpreters' book
https://github.com/eliasdejong/plox
'Crafting Interpreters' is Bob Nystrom's book that teaches you how to build a compiler from scratch. It is an excellent resource and I can highly recommend it. Really light to read and walks you through all the concepts step-by-step.The first part of the book builds a compiler for the 'Lox' toy language in Java. While I have nothing against Java, personally I have never used it much so I...
For those interested:
- ZERO CLIENT-SIDE OR INLINE JAVASCRIPT except Datastar & Datastar attributes
- real-time multiplayer powered by CQRS
- 45x45 characters chunks stored in LMDB
- all characters are read & written through FULL ACID TRANSACTIONS. no shortcuts. no relaxations
- chunk-based viewport culling
- LZ4 compression on chunk-basis to remove white space and repeating chars
- runs on a 5,52 euro/mo VPS in Germany, cheapest tier in public cloud
Stack: Datastar, Python/FastAPI, LMDB
> but this doesn’t really work in mobile and it messes with the selection
I haven't tested it personally, but on the OverType they claim "excellect mobile support".
> The database is stored in memory. So it must be small enough to fit in RAM, and the full journal has to be replayed from scratch when opening a file.
For larger datasets, you really want disk support. Using something like SQLite or DuckDB as an append-only store is another way to achieve this effect.
Also lack of a proper query language will be a problem for long term serious use. A simple hand-rolled program API can only get you so far, until you need more advanced querying.
> Unlike XML or JSON, joedb is a binary file format that does not require any parsing. So, joedb files are much smaller, and processing data is much faster.
Some time ago I created a JSON-compatible serialization format that is zero-copy (no parsing required): https://github.com/fastserial/lite3
It doesn't do transactions or history versioning, but it is also very fast in memory. Something like jq or JSONPath on a disk-file version of this format could be interesting.
Conceptually similar to CAP, but with storage trade-offs. The idea is you can only pick 2 out of 3.
> With IOPOLL, completion events are polled directly from the NVMe device queue, either by the application or by the kernel SQPOLL thread (cf. Section 2), replacing interrupt-based signaling. This removes interrupt setup and handling overhead but disables non-polled I/O, such as sockets, within the same ring.
> Treating io_uring as a drop-in replacement in a traditional I/O-worker design is inadequate. Instead, io_uring requires a ring-per-thread design that overlaps computation and I/O within the same thread.
1) So does this mean that if you want to take advantage of IOPOLL, you should use two rings per thread: one for network and one for storage?
2) SQPoll is shown in the graph as outperforming IOPoll. I assume both polling options are mutually exclusive?
3) I'd be interested in what the considerations are (if any) for using IOPoll over SQPoll.
4) Additional question: I assume for a modern DBMS you would want to run this as thread-per core?
Doing this by definition requires processing an entire message which can be a little slow, so it is best done in C and exposed through CPython bindings / CFFI.
The ability to mutate serialized data allows for 2 things:
1) Services exchanging messages and making small changes each time e.g. adding a timestamp without full reserialization overhead.
2) A message producer can keep a message 'template' ready and only change the necessary fields each time before sending. As a result, serializing becomes practically free from a performance perspective.
One primary difference is that Rkyv does not support in-place mutation. So any modification of a message requires full reserialization, unlike Lite³.
Are those numbers also measured while skipping the CPU cache?
Btw: in my project README I have benchmarks against Cap'N Proto & Google Flatbuffers.
In the case of append, the old value still lives inside the buffer but is zeroed out. This means that if you keep replacing variable-sized elements, over time the buffer will fragment. You can vacuum a message by recursively writing it from the root to a new buffer. This will clear out the unused space. This operation can be delayed for as long as you like.
If you are only setting fixed-size values like integers or floats, then the buffer never grows as they are always updated in-place.
If you want schema, it must be done by the application through runtime type checking. All messages contain type information. Though I do see the value of adding pydantic-like schema checking in the future.
EDIT: Regarding message size, Lite³ does demand a message size penalty for being schemaless and fully indexed at the same time. Though if you are using it in an RPC / streaming setting, this can be negated through brotli/zstd/dict compression.
Yes, those numbers are real but only in very short bursts of strictly sequential reads, sustained speeds will be closer to 8-10 GB/s. And real workloads will be lower than that, because they contain random access.
Most NVMe drivers on Linux actually DMA the pages directly into host memory over the PCIe link, so it is not actually the CPU that is moving the data. Whenever the CPU is involved in any data movement, the 6 GB/s per core limit still applies.
When you see advertised numbers like '200 GB/s' that is total memory bandwidth, or all cores combined. For individual cores, the limit will still be around 6 GB/s.
This means even if you write a perfect parser, you cannot go faster. This limit also applies to (de)serializing data like JSON and Protobuf, because those formats must typically be fully parsed before a single field can be read.
If however you use a zero-copy format, the CPU can skip data that it doesn't care about, so you can 'exceed' the 6 GB/s limit.
The Lite³ serialization format I am working on aims to exploit exactly this, and is able to outperform simdjson by 120x in some benchmarks as a result: https://github.com/fastserial/lite3
You will be able to access the same data in different languages using APIs specific to your language.
Right now someone has already made a (private) Go port. And Rust is also in the works.
A serialization format does not care about versioning or rollbacks. It is simply trying to organize data such that it can be sent over a network. If updates can be made in-place without requiring re-serialization, then that is always a benefit.
Write amplification is still a fact however that I think deserves to be mentioned. To tackle this problem in the context of DBs/MVCC, you would have to use techniques other than in-place mutation like you mention: overlay/COW. Basically, LMDB-style.
And yes I think databases is where this technology will eventually have the greatest potential, so that is where I am also looking.
The documentation page is out of date, the format now resolves collisions through quadratic probing.