I have the case where multiple Linux processes need to link with RocksDB library and concurently read (high load) the same database.
The only one process updates database several times a day.
Is it possible to concurrently read from within multiple processes from RocksDB?
Unfortunately can't find this information over the Internet.
Seems that Rocksdb supports multiple read-only or secondary instances (two variations of read-only mode):
Read-only Instance - Opens the database in read-only mode. When the Read-only instance is created, it gets a static read-only view of
the Primary Instance’s database contents
Secondary Instance – Opens the database in read-only mode. Supports extra ability to dynamically catch-up with the Primary
instance (through a manual call by the user – based on their
delay/frequency requirements)
But only one read-write instance:
The Primary Instance is a regular RocksDB instance capable of read,
write, flush and compaction. The Read-only and Secondary Instances
supports read operations alone.
Only single instance of Primary is allowed; but many concurrent
Read-only and Secondary Instances are allowed.
https://github.com/facebook/rocksdb/wiki/Basic-Operations#concurrency indicates that:
A database may only be opened by one process at a time. The rocksdb
implementation acquires a lock from the operating system to prevent
misuse. Within a single process, the same rocksdb::DB object may be
safely shared by multiple concurrent threads. I.e., different threads
may write into or fetch iterators or call Get on the same database
without any external synchronization (the rocksdb implementation will
automatically do the required synchronization).
Related
During the webinar I heard that there are three ways to access a database for a number of users:
Using process per user
Thread per user
And pool of processes
The lecturer said that process per user avoid the need to take care of parallelization/locking/etc but is too heavy and complex. Thread per user is lightweight, but requires a lot of locking overhead. Pool of processes have shared data structure when accessing DB.
What is not clear to me is - arent users always access the same datastructure and regardless whether we have process or thread or poll - we still need to implement locking? Why would processes not require locking? What is the diff between process per user and pool of processes? As lecturer said - shared data structures. But what does it mean if processes dont share DB? Is DB replicated for each user assuming we are in process per user situation?
I really want this to get clarified, but I could not ask this during the webinar.
Thank you!
Locking is required only if you have some shared resource. When connecting to DB you first create a connection object and then through that object you connect and send your queries. In MySQL innoDb the database performs row level locking and not the entire table is locked. So if multiple process are trying to access different rows no locking will be required.
Coming to Threads, what people mostly do is they create a connection pool where multiple threads access that pool. Let say you have 50 threads and connection pool of 5 objects. Now all 50 thread cannot access these 5 connection objects they need to wait for the connection object to be free and once it is free they can use the connection object to fire query . Threads share same memory space so mostly all shared resources must be thread safe
Since creation of a process is quite heavy, you would want to keep it less max 10-20 processes on 4gb machine. But threads are less costly to create you can have them in large numbers (~50). So if there nothing to be shared Threads will give more parallelism.
Again everything boils down to how good is your design and that is very problem specific.
I'm running SQLite v3.7.17 from my program in in-memory mode and using shared cache (as specified in Shared Cache And In-Memory Databases). My program is multi-threaded and all these threads access the same in-memory database.
Is there any way I can configure or use my SQLite database such that, when two threads run update query on same table (but different rows), one doesn't wait on another? That is, how can I achieve row-level locking on this in-memory db?
This should theoretically be possible as my SQLite data is not in a file (therefore filesystem writes do not apply).
It's not the filesystem that determines whether SQLite can lock rows. It's SQLite's architecture.
Even using write-ahead logging, you can only have one writer at a time.
Writers merely append new content to the end of the WAL file. Because
writers do nothing that would interfere with the actions of readers,
writers and readers can run at the same time. However, since there is
only one WAL file, there can only be one writer at a time.
SQLite3 has a kind of table locking now, but not row locking.
Sqlite does not support row lock feature. And i’ve just seen sqlumdash, which is based on Sqlite has row lock feature.
Please check it at:
https://github.com/sqlumdash/sqlumdash/
As I know, it’s developed by toshiba
Is this in a larger transnational scenario? Because if the situation is as simple as you describe, then there is no advantage to row-locking vs. table locking.
An in-memory DB isn't subject to I/O latency; it is CPU bound and the CPU can process the two writes sequentially faster than it could process them concurrently because the latter has all the same memory operations plus thread-swapping and row-locking overhead. Sure, in a multi-CPU system one could, theoretically, write to different rows simultaneously, but the necessary logic to support row-locking would actually take longer than the (trivial) operation of writing the record into memory.
In an IMDB of any size, table-locks on individual tables can be retained for efficiency while multiple CPUs can be employed simultaneously on multiple independent queries against multiple independent tables.
sqlite3 doesn't support row level lock. if you can guarantee item is unique or don't need to be unique then you can works with multiple files.
just make multiple sqlite3 database(files) and open it. if you make 50 db, then you can works with 50 rows in same time.
More specifically, are there any databases that don't require secondary storage (e.g. HDD) to provide durability?
Note:This is a follow up of my earlier question.
If you want persistence of transations writing to persistent storage is only real option (you perhaps do not want to build many clusters with independent power supplies in independent data centers and still pray that they never fail simultaneously). On the other hand it depends on how valuable your data is. If it is dispensable then pure in-memory DB with sufficient replication may be appropriate. BTW even HDD may fail after you stored your data on it so here is no ideal solution. You may look at http://www.julianbrowne.com/article/viewer/brewers-cap-theorem to choose replication tradeoffs.
Prevayler http://prevayler.org/ is an example of in-memory system backed up with persistent storage (and the code is extremely simple BTW). Durability is provided via transaction logs that are persisted on appropriate device (e.g. HDD or SSD). Each transaction that modifies data is written into log and the log is used to restore DB state after power failure or database/system restart. Aside from Prevayler I have seen similar scheme used to persist message queues.
This is indeed similar to how "classic" RDBMS works except that logs are only data written to underlying storage. The logs can be used for replication also so you may send one copy of log to a live replica other one to HDD. Various combinations are possible of course.
All databases require non-volatile storage to ensure durability. The memory image does not provide a durable storage medium. Very shortly after you loose power your memory image becomes invalid. Likewise, as soon as the database process terminates, the operating system will release the memory containing the in-memory image. In either case, you loose your database contents.
Until any changes have been written to non-volatile memory, they are not truely durable. This may consist of either writing all the data changes to disk, or writing a journal of the change being done.
In space or size critical instances non-volatile memory such as flash could be substituted for a HDD. However, flash is reported to have issues with the number of write cycles that can be written.
Having reviewed your previous post, multi-server replication would work as long as you can keep that last server running. As soon as it goes down, you loose your queue. However, there are a number of alternatives to Oracle which could be considered.
PDAs often use battery backed up memory to store their databases. These databases are non-durable once the battery runs down. Backups are important.
In-memory means all the data is stored in memory for it to be accessed. When data is read, it can either be read from the disk or from memory. In case of in-memory databases, it's always retrieved from memory. However, if the server is turned off suddenly, the data will be lost. Hence, in-memory databases are said to lack support for the durability part of ACID. However, many databases implement different techniques to achieve durability. This techniques are listed below.
Snapshotting - Record the state of the database at a given moment in time. In case of Redis the data is persisted to the disk after every two seconds for durability.
Transaction Logging - Changes to the database are recorded in a journal file, which facilitates automatic recovery.
Use of NVRAM usually in the form of static RAM backed up by battery power. In this case data can be recovered after reboot from its last consistent state.
classic in memory database can't provide classic durability, but depending on what your requirements are you can:
use memcached (or similar) to storing in memory across enough nodes that it's unlikely that the data is lost
store your oracle database on a SAN based filesystem, you can give it enough RAM (say 3GB) that the whole database is in RAM, and so disk seek access never stores your application down. The SAN then takes care of delayed writeback of the cache contents to disk. This is a very expensive option, but it is common in places where high performance and high availability are needed and they can afford it.
if you can't afford a SAN, mount a ram disk and install your database on there, then use DB level replication (like logshipping) to provide failover.
Any reason why you don't want to use persistent storage?
according to the Berkeley documentation the Transactional (TS) and the Concurrent Datastore version of the Database, multiple threads may access (and change) the database.
Does this also mean that I can have 2 programs linked to the berkely 'client' and have them access the same database file without any problems?
(I ask, since for a separate database server this would be no problem of course, but in the case of Berkeley the database engine is linked long with your program)
thanks!
R
Some documentation seems to think you can use the same database concurrently from multiple processes as well as from multiple threads. Specifically:
"Multiple processes, or multiple threads in a single process, can all use the database at the same time as each uses the Berkeley DB library. Low-level services like locking, transaction logging, shared buffer management, memory management, and so on are all handled transparently by the library."
A cursory read did not shed any light on what BDB uses to control access from multiple processes, but if filesystem locks are used, access from multiple processes on a network filesystems may well be problematic.
Chapter 16: The Locking Subsystem from the reference guide looks promising.
How should one ensure correctness when multiple processes access one single SQLite database file?
First, avoid concurrent access to sqlite database files. Concurrency is one of sqlite's weak points and if you have a highly concurrent application, consider using another database engine.
If you cannot avoid concurrency or drop sqlite, wrap your write transactions in BEGIN IMMEDIATE; ... END;. The default transaction mode in sqlite is DEFERRED which means that a lock is acquired only on first actual write attempt. With IMMEDIATE transactions, the lock is acquired immediately, or you get SQLITE_BUSY immediately. When someone holds a lock to the database, other locking attempts will result in SQLITE_BUSY.
Dealing with SQLITE_BUSY is something you have to decide for yourself. For many applications, waiting for a second or two and then retrying works quite all right, giving up after n failed attempts. There are sqlite3 API helpers that make this easy, e.g. sqlite3_busy_handler() and sqlite3_busy_timeout() but it can be done manually as well.
You could also use OS level synchronization to acquire a mutex lock to the database, or use OS level inter-thread/inter-process messaging to signal when one thread is done accessing the database.
Any SQLite primitive will return SQLITE_BUSY if it tries to access a database other process is accessing at the same time. You could check for that error code and just repeat the action.
Alternatively you could use OS synchronization - mutex on MS Windows or something similar on other OSes. The process will try to acquire the mutex and if someone else already holds it the process will be blocked until the other process finishes the operation and releases the mutex. Care should be taken to prevent cases when the process acquires the mutext and then never releases it.
The SQLite FAQ about exactly this
Basically you need to wrap your data access code with transactions. This will keep your data consistent. Nothing else is required.
In SQLite you are using
BEGIN TRANSACTION
COMMIT TRANSACTION
pairs to delimit your transactions. Put your SQL code in between in order to have it execute in a single transaction.
However, as previous people have commented before me - you need to pay close attention for concurrency issues. SQLite can work reasonably fast if it used for read access (multiple readers are not blocked and can run concurrently).
However - the picture changes considerably if your code interleaves write and read access. With SQLite - your entire database file will be locked if even a single writer is active.