Locking DB records ("critical section" tools)

New features you'd like see on SIP Sorcery
Post Reply
MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Locking DB records ("critical section" tools)

Post by MikeTelis » Tue Sep 29, 2009 6:25 am

I wrote a dialplan for handling incoming calls, forwarded to SS account via several different routes simultaneosly. It works on most occasions but there is an obvious bug in it. For the dialplan to work correctly, it's important that it shouldn't be interrupted by the other instance of the same dialplan (initiated by the other incoming call) between DBRead and DBWrite calls.

In other words, I need some tool providing "critical section". The dialplan should enter critical section before DBRead and leave it after DBWrite.

One solution is something like DBLock(keyname) and DBUnlock(Keyname). If DB record is locked by one thread (instance of dialplan), DBRead and DBWrite initiated by the other instance must wait there until it's unlocked.

Aaron
Site Admin
Posts: 4652
Joined: Thu Jul 12, 2007 12:13 am

Post by Aaron » Tue Sep 29, 2009 9:22 am

Are you doing multiple database operations in your critical section? Sounds like you might be asking for a database transaction http://en.wikipedia.org/wiki/ACID.

Regards,

Aaron

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Post by MikeTelis » Tue Sep 29, 2009 1:33 pm

Dear Aaron,

please remove a dot (.) in the end of URL. Anyway, what I'm looking for is hardly called database transaction. It's not about consistency of my database, it contains only 1 record :)

What I do in that dialplan is best described as "Test and Set Flag" operation. That is, I test current flag status and if it's reset, I set it. I use DBRead to check status of the flag and DBWrite to set it. It is important that concurrently running instance of my dialplan can't read the flag before it's set.

Please follow the link in my original post and refer to the code (will take less than a minute to understand what I'm talking about). If the flag is reset, 1st instance will know it after DBRead and set it with DBWrite, then proceed with it's job. If flag is set, dialplan should exit. If 2nd instance of my dialplan reads the flag BEFORE the 1st issued DBWrite, both will proceed with the job (two calls will be initiated, which is wrong).

Isn't it possible to lock access to a database record? I think this is the best solution. As an alternative, you could provide with a generic "semaphore lock", something like mutex.synchronize in Ruby (I can't use it because the other instance of my dialplan spawned by SS code and I have no access to it).

Aaron
Site Admin
Posts: 4652
Joined: Thu Jul 12, 2007 12:13 am

Post by Aaron » Tue Sep 29, 2009 1:41 pm

Hmm seems to me your description is an exact fit for a database transaction. Transactions aren't necessarily about multiple records they are about multiple operations. While a transaction is in progress the database records being updated are locked.

Semaphores and other threading kung-fu is a bad idea to expose in the dialplans. There are already lots of threads flying around behind the scenes when a dialplan is processed and it would just be too easy to inadvertently break if available in a dialplan.

If a database transaction definitely doesn't solve your problem then hopefully there is some other solution that doesn't involve thread locks.

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Post by MikeTelis » Tue Sep 29, 2009 1:56 pm

Hmm seems to me your description is an exact fit for a database transaction. Transactions aren't necessarily about multiple records they are about multiple operations. While a transaction is in progress the database records being updated are locked.
It reminds me of a joke:

The LAPD, The FBI, and the CIA are all trying to prove that they are the best at apprehending criminals. The President decides to give them a test. He releases a rabbit into a forest and each of them has to catch it. The CIA goes in. They place animal informants throughout the forest. They question all plant and mineral witnesses. After three months of extensive investigations they conclude that rabbits do not exist.The FBI goes in. After two weeks with no leads they burn the forest, killing everything in it, including the rabbit, and they make no apologies. The rabbit had it coming.The LAPD goes in. They come out two hours later with a badly beaten bear.The bear is yelling: "Okay! Okay! I'm a rabbit! I'm a rabbit!

As long as it works, it doesn't matter what you call it :) I absolutely agree with you, playing with threads isn't the best solution and it's error-prone. I need something (let's call it a database transaction) that would make the other threads accessing the same database record wait until I'm done with it.

Aaron
Site Admin
Posts: 4652
Joined: Thu Jul 12, 2007 12:13 am

Post by Aaron » Wed Sep 30, 2009 12:11 am

How did you go with looking over the sipsorcery source code?

I'd be happy to do a joint effort on this feature. I can add a method that supports database transactions to the database layer in the sipsorcery code. That would leave the dialplan application to do, it should be pretty simple, 3 or 4 lines.

Regards,

Aaron

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Post by MikeTelis » Wed Sep 30, 2009 3:41 am

Aaron,

I downloaded the code several minutes after I saw your post in SS blog. I also downloaded a book on C# and reading it (as well as the code). Trying to understand both... I'm just not ready yet.

Post Reply