Drupal - In a general sense, what is the purpose of the Drupal DB Semaphore Table

The semaphore table is used from the locking mechanism implemented by default from Drupal. It is not different from the usual mechanism of locking seen in programming: A value is used to verify an operation is already in progress, to avoid conflicts or race conditions. The difference is that, normally, the lock is a file, while Drupal uses the row in a database.

In fact, the locking mechanism has functions to acquire a lock (lock_acquire()), or wait a lock is released (lock_wait()). In both the cases, the semaphore database is used.

// lock_acquire()
// Optimistically try to acquire the lock, then retry once if it fails.
// The first time through the loop cannot be a retry.
$retry = FALSE;
// We always want to do this code at least once.
do {
  try {
    db_insert('semaphore')
      ->fields(array(
        'name' => $name,
        'value' => _lock_id(),
        'expire' => $expire,
      ))
      ->execute();
    // We track all acquired locks in the global variable.
    $locks[$name] = TRUE;
    // We never need to try again.
    $retry = FALSE;
  }
  catch (PDOException $e) {
    // Suppress the error. If this is our first pass through the loop,
    // then $retry is FALSE. In this case, the insert must have failed
    // meaning some other request acquired the lock but did not release it.
    // We decide whether to retry by checking lock_may_be_available()
    // Since this will break the lock in case it is expired.
    $retry = $retry ? FALSE : lock_may_be_available($name);
  }
  //lock_may_be_available()
  $lock = db_query('SELECT expire, value FROM {semaphore} WHERE name = :name', array(':name' => $name))->fetchAssoc();
  if (!$lock) {
    return TRUE;
  }
  $expire = (float) $lock['expire'];
  $now = microtime(TRUE);
  if ($now > $expire) {
    // We check two conditions to prevent a race condition where another
    // request acquired the lock and set a new expire time. We add a small
    // number to $expire to avoid errors with float to string conversion.
    return (bool) db_delete('semaphore')
      ->condition('name', $name)
      ->condition('value', $lock['value'])
      ->condition('expire', 0.0001 + $expire, '<=')
      ->execute();
  }
  return FALSE;

In Drupal, different users can requests the same page, which means different threads or processes could execute the same code at the same time. This could cause problems when the code is, for example, updating a database table. Using locks is a way to avoid this could cause problems.

The reason a database table is used is simply that Drupal requires a database engine to work; using a database table also for the locking mechanism is a way to reduce the requirements. The locking mechanism could be implemented using the APCu extension too, and if I recall correctly, there is a module doing that.


The answer from @kiamlaluno is complete and perfect. But, I think it focuses on explaining (brilliantly) the concept/use of db locking using drupal's semaphores.

I would in turn venture getting closer to the OP:

The purpose of the semaphore table is (as described in the semaphore table creation description):

Table for holding semaphores, locks, flags, etc. that cannot be stored as Drupal variables since they must not be cached.

So, the purpose of that table is more than just db locking mechanisms (so far I can understand from that comment), and it also addresses the technical requirement of avoiding caching of variables.

N.B.: Will be happy to be corrected by someone with more expertise on this topic if I got this wrong. Cheers!

Tags:

Database