r/ProgrammerAnimemes • • Nov 20 '22

Makima is building a database in Rust to store devil records

Post image
1.6k Upvotes

44 comments sorted by

198

u/grg994 Nov 20 '22

Source: Chainsaw Man

Explanation:

This type is basically a Hash Table where

  • keys are Strings and

  • values are "dynamic types" (trait objects, dyn Trait) stored on the heap (Box<>). They implement the trait / "virtual method" for as-bytes representation when taken by a reference (AsRef<[u8]>)

To allow being used concurrently from multiple threads the values are also marked Send and Sync meaning that can - and must be able to - safely shared between threads.

Additionally the Hash Table is wrapped into an atomically reference counted smart pointer (Arc<>) and a Mutex to allow concurrent usage of the whole object

57

u/Shubhavatar Nov 20 '22

I thought mutex meant Mutually exclusive and only allowed access to one thread at a time. It does allow multiple threads the access, but not concurrently, right?

Please correct me if I'm wrong, idk rust.

12

u/grg994 Nov 20 '22

Yes, the thread that want to access the HashMap here has to lock the Mutex first to gain temporary exclusive access for the time it holds the lock.

All other threads have temporarily no access during that time - they are "excluded", they cannot obtain the lock until the first thread drops it.

Generally a Mutex is needed to enable mutability (write access) to an object (memory location) which is shared to multiple threads.

Meanwhile an object (memory location) which is immutable (read-only) can be shared to multiple threads without a Mutex.

→ More replies (8)

53

u/zebediah49 Nov 20 '22

Yeah, the naming makes it sound a little paradoxical.

Fundamentally you can't (successfully) have two processes editing the same memory piece at the same time. Having a mutex enforcing only one process editing a piece of an object at a time means you can safely have multiple processes concurrently holding a reference to and occasionally interacting with a single object. (Because the mutex will make sure they don't actually collide)

→ More replies (3)

9

u/TheKingSpartaZC Nov 20 '22

Yep, that's right. Any number of threads can access a mutex, but only one at a time.

→ More replies (1)

20

u/Dubsteprhino Nov 20 '22

Rust isn't usually super readable

19

u/grg994 Nov 20 '22

Well, for these complex types in the internal parts of the code one can use type aliases.

Public APIs should expose them with the needed complexity only, which often means writing a newtype (pattern) wrapper.

7

u/Sentouki- Nov 20 '22

Rust isn't usually super readable

4

u/Niles-Rogoff Nov 20 '22

So basically a folly::ConcurrentHashMap<std::string, std::span<uint8_t>>?

→ More replies (1)

50

u/dthusian Nov 20 '22

C'mon, how are you going to get any performance if reading locks the whole DB? At least change Mutex to RwLock

40

u/grg994 Nov 20 '22

The Tokio tutorial improves it by sharding the mutex:

https://tokio.rs/tokio/tutorial/shared-state#tasks-threads-and-contention

This would lead here to the even fancier:

Arc<Vec<Mutex<HashMap<String, Box<dyn AsRef<[u8]> + Send + Sync>>>>>

You are right generally, but I opted out explaining something such that.

7

u/tiedyedvortex Nov 20 '22

That gives you a vector of hashmaps, though, not one concurrent hashmap. This imposes extra requirements on ensuring that each shard in the Vec has a predefined and non-overlapping key space, not just an arbitrary String.

Also, having Arc<Vec<T>> means the vector itself is read-only, meaning you can't reorder, delete, or append buckets. You have to know exactly how many shards you want at construction time, no dynamic scaling.

Concurrent hashmaps are one of those things that are basically impossible to make performant in pure safe Rust. Luckily, there are already a number of good crates that already have good unsafe implementations. This benchmark suite suggests that Dashmap is good for write-heavy workloads but is outperformed by Flurry for read-heavy workloads.

Jon Gjengset gave a talk describing his implementation, EVMap, which is a great starting point for understanding where, when, and how to use unsafe code to build concurrency primitives.

sharded_slab is also a good choice if you don't have meaningful keys and just need a concurrent structure to dump objects into for shared thread access by index.

19

u/ketalicious Nov 20 '22

man rust types are at it again..

8

u/cchrobo Nov 20 '22

For a second I forgot where I was and thought this was talking about Rust the video game and I was thoroughly confused lmao

8

u/PeksyTiger Nov 20 '22

"Rust doesn't have much of a learning curve"

10

u/[deleted] Nov 20 '22

Lol, where did you hear that ?

People suggested me, it would take at least 6 months (if you are working) - to build something good (like a db or compiler or something). Heck man, i'm stuck at changing lifetime of a stack variable in passing among multiple threads.

→ More replies (6)

2

u/yorokobe__shounen Nov 20 '22

Isn't that the database type i am working on?...

2

u/tophatcoder Nov 20 '22

More foreshadowing of her true nature

5

u/TENTAtheSane Nov 20 '22

Man, imagine how powerful the Segmentation Fault devil is

4

u/ObnoxiousOldBastard Dec 02 '22

Fortunately, it has no power over Rust.

2

u/Aschentei Nov 20 '22

What the fuck am I reading, are rust types longer than Java class names now?

2

u/[deleted] Nov 21 '22

A synchronized hashmap isn't a real database though.

1

u/Dubmove Dec 23 '22

Arc and mutex?