Transactions in multi threaded environment in SQLite WP 8.1 - multithreading

I am facing an issue using SQLite with following scenario.
There are two threads working on database.
Both threads have to insert messages in transactions.
So if say one thread commits after inserting 20k rows and other thread has not committed yet.
In output I see all the data has been committed which was inserted by thread 2 till the moment data was committed by thread 1.
Sample function:
/// <summary>
/// Inserts list of messages in message table
/// </summary>
/// <param name="listMessages"></param>
/// <returns></returns>
public bool InsertMessages(IList<MessageBase> listMessages, bool commitTransaction)
{
bool success = false;
if (listMessages == null || listMessages.Count == 0)
return success;
DatabaseHelper.BeginTransaction(_sqlLiteConnection);
foreach (MessageBase message in listMessages)
{
using (var statement = _sqlLiteConnection.Prepare(_insertMessageQuery))
{
BindMessageData(message, statement);
SQLiteResult result = statement.Step();
success = result == SQLiteResult.DONE;
if (success)
{
Debug.WriteLine("Message inserted suucessfully,messageId:{0}, message:{1}", message.Id, message.Message);
}
else
{
Debug.WriteLine("Message failed,Result:{0}, message:{1}", result, message.Message);
}
}
}
if (commitTransaction)
{
Debug.WriteLine("Data committed");
DatabaseHelper.CommitTransaction(_sqlLiteConnection);
}
else
{
Debug.WriteLine("Data not committed");
}
return success;
}
Is there any way to prevent commit transaction of thread 2 inserts?

In short, it's not possible on a single database.
A single sqlite database cannot have multiple simultaneous writers with separate transaction contexts. sqlite databases also do not have separate contexts per connection; to get a context, you would need to make a new connection. However, as soon as you start the initial write using insert (or update/delete), the transaction needs a RESERVED lock on the database (readers allowed, no other writers), which means parallel writes are impossible. I thought you might be able to fake it with SAVEPOINT and RELEASE, but these are also serialized on the connection and do not generate a separate context.
With that in mind, you may be able to use separate databases connected using ATTACH DATABASE, as long as both threads are not writing to the same table. To do so, you would attach the additional database at runtime which contains the other tables. However, you still need a separate connection for each parallel writer because commits to the connection still apply to all open transactions.
Otherwise, you can get separate transactions by opening an additional connection and the later connection & transaction will just have to wait until the RESERVED lock is released.
References:
SQLite Transactions
SQLite Locking
SQLite ATTACH DATABASE

Related

How can I run atomic read/write operations or transactions in Azure CosmosDB with MongoDB API

I'm trying to execute 2 reads and 1 write in a collection atomically, making sure that there are no writes between the reads and the write.
I tried following several docs and tutorials but every one of them uses batches and containers instead of mongoDB collections.
I also tried to use transactions in mongoDB client sessions but the transactions are still not atomic.
MongoClient mongoClient = new MongoClient(new MongoClientURI(System.getenv("mongodb")));
ClientSession clientSession = mongoClient.startSession();
clientSession.startTransaction();
try{
if (!auctionRepository.checkAuctionStatusAtomic(auctionID, mongoClient)){
return Response.status(Response.Status.METHOD_NOT_ALLOWED).entity("Auction is not open").build();
}
if(!auctionRepository.checkAuctionPriceAtomic(auctionID, bid.value, mongoClient)){
return Response.status(Response.Status.METHOD_NOT_ALLOWED).entity("Bid value is too low").build();
}
auctionRepository.updateCurrentPriceAtomic(auctionID, bid.value, mongoClient);
}
catch (Exception e){
clientSession.abortTransaction();
}
clientSession.commitTransaction();
Is there any way of executing these operations atomically?
In a transaction or batch for example.

How does Cassandra serialise concurrent requests?

I am reading about Cassandra and how other databases maintain the wal and memtable.
WAL - As name suggests, cassandra writes all mutations sequentially in this file
My question is - if there are thousands of parallel requests coming to the same node of cassandra, how does it maintain sequential writes to WAL.
I check cassandra code base and I could not find any thread lock or anything mutex operation.
Cassandra write code
private CommitLogPosition addToCommitLog(Mutation mutation)
{
// Usually one of these will be true, so first check if that's the case.
boolean allSkipCommitlog = true;
boolean noneSkipCommitlog = true;
for (PartitionUpdate update : mutation.getPartitionUpdates())
{
if (update.metadata().params.memtable.factory().writesShouldSkipCommitLog())
noneSkipCommitlog = false;
else
allSkipCommitlog = false;
}
if (!noneSkipCommitlog)
{
if (allSkipCommitlog)
return null;
else
{
Set<TableId> ids = new HashSet<>();
for (PartitionUpdate update : mutation.getPartitionUpdates())
{
if (update.metadata().params.memtable.factory().writesShouldSkipCommitLog())
ids.add(update.metadata().id);
}
mutation = mutation.without(ids);
}
}
// Note: It may be a good idea to precalculate none/all for the set of all tables in the keyspace,
// or memoize the mutation.getTableIds()->ids map (needs invalidation on schema version change).
Tracing.trace("Appending to commitlog");
return CommitLog.instance.add(mutation); --- ** Actual commit log write ***
}
Any help would be appreciated.
All mutations are immediately appended to the end of the commitlog -- in whatever order they arrived on the replica.
The writes come in through a request queue that Cassandra processes first-in-first-out. There isn't any additional ordering that occurs.
Since all mutations are simply appended to the commit log, this makes writes in Cassandra very, very fast. Cheers!

Synchronize multiple requests to database in NestJS

in our NestJS application we are using TypeORM as ORM to work with db tables and typeorm-transactional-cls-hooked library.
now we have problem with synchronization of requests which are read and modifying database at same time.
Sample:
#Transactional()
async doMagicAndIncreaseCount (id) {
const await { currentCount } = this.fooRepository.findOne(id)
// do some stuff where I receive new count which I need add to current, for instance 10
const newCount = currentCount + 10
this.fooRepository.update(id, { currentCount: newCount })
}
When we executed this operation from the frontend multiple times at the same time, the final count is wrong. The first transaction read currentCount and then start computation, during computation started the second transaction, which read currentCount as well, and first transaction finish computation and save new currentCount, and then also second transaction finish and rewrite result of first transaction.
Our goal is to execute this operation on foo table only once at the time, and other requests should wait until.
I tried set SERIALIZABLE isolation level like this:
#Transactional({ isolationLevel: IsolationLevel.SERIALIZABLE })
which ensure that only one request is executed at time, but other requests failed with error. Can you please give me some advice how to solve that?
I never used TypeORM and moreover you are hiding the DB engine you are using.
Anyway to achieve this target you need write locks.
The doMagicAndIncreaseCount pseudocode should be something like
BEGIN TRANSACTION
ACQUIRE WRITE LOCK ON id
READ id RECORD
do computation
SAVE RECORD
CLOSE TRANSACTION
Alternatively you have to use some operation which is natively atomic on the DB engine; ex. the INCR operation on Redis.
Edit:
Reading on TypeORM find documentation, I can suggest something like:
this.fooRepository.findOne({
where: { id },
lock: { mode: "pessimistic_write", version: 1 },
})
P.S. Looking at the tags of the question I would guess the used DB engine is PostgreSQL.

what does the function incrementTransactionNumber() do in mongodb node driver?

I know the function's name seems to be self explanatory, however, after researching for quite a while I can't find a transaction number anywhere within a clientSession.
Is it an internal number ? is it possible to get it ?
Transaction numbers are used by mongodb to keep track of operations(read/writes) per transaction per session. Sessions can be started either explicitly by calling startSession() or implicity whenever you create a mongodb connection to db server.
How incrementTransactionNumber() works with sessions (explicit)
When you start a session, by calling client.startSession() method, it will create a new ClientSession. This takes in already created server session pool as one of its' constructor parameters. (See) These server sessions have a property called txnNumber which is initialized to be 0.(Init) So whenever you start a transaction by calling startTransaction(), client session object calls incrementTransactionNumber() internally to increment the txnNumber in server session. And all the successive operations will use the same txnNumber, until you call, commitTransaction() or abortTransaction() methods. Reason that you can't find it anywhere within clientSession is, it is a property of serverSession not clientSession.
ServerSession
class ServerSession {
constructor() {
this.id = { id: new Binary(uuidV4(), Binary.SUBTYPE_UUID) };
this.lastUse = now();
this.txnNumber = 0;
this.isDirty = false;
}
So whenever you try to send a command to database (read/write), this txnNumber would be sent along with it. (Assign transaction number to command)
This is to keep track of database operations that belong to a given transaction per session. (A transaction operation history that uniquely identify each transaction per session.)
How incrementTransactionNumber() works with sessions (implicit)
In this case it would be called every time a new command is issued to the database if that command does not belong to a transaction and it's a write operation where retryWrites are enabled. So each new write operation would have new transaction number as long as it does not belong to a explicitly started transaction with startTransaction(). But in this case as well a txnNumber would be sent along with each command.
execute_operation.
const willRetryWrite =
topology.s.options.retryWrites === true &&
session &&
!inTransaction &&
supportsRetryableWrites(server) &&
operation.canRetryWrite;
if (
operation.hasAspect(Aspect.RETRYABLE) &&
((operation.hasAspect(Aspect.READ_OPERATION) && willRetryRead) ||
(operation.hasAspect(Aspect.WRITE_OPERATION) && willRetryWrite))
) {
if (operation.hasAspect(Aspect.WRITE_OPERATION) && willRetryWrite) {
operation.options.willRetryWrite = true;
session.incrementTransactionNumber();
}
operation.execute(server, callbackWithRetry);
return;
}
operation.execute(server, callback);
Also read this article as well. And yes if you need you can get the transaction number for any session through txnNumber property, clientSession.serverSession.txnNumber.

Using Transaction scope to wrap Rhino ETL Processes

I'm using Rhino ETL for handling both SQL SERVER and Excel file Extraction/Load.
I've put more than one ETL processes (which insert data into sql server tables) in a transaction scope (c#) so that I can rollback the whole process in case of any errors or exceptions.
I'm not sure if C# transaction scope could be used along with ETL processes, but the way I did is as follows:
private void ELTProcessesInTransaction(string a, string b, int check)
{
using (var scope = new TransactionScope())
{
using (ETLProcess1 etlProcess1 = new ETLProcess1(a, b))
{
etlProcess1.Execute();
}
using (ETLProcess2 etlProcess2 = new ETLProcess2(a, b))
{
etlProcess2.Execute();
}
if (!_InSeverDB.HasError(check))
scope.Complete();//Commits based on a condition
}
}
This does not rollback the transaction at all. I tried removing the scope.Complete() line, still the process is getting committed.
Please let me know where I need to correct or if the whole approach is incorrect.

Resources