tags:

views:

76

answers:

2

I use the file system to create a application wide persistent singleton (application does not use a database). Occasionally a page will take 1-2 minutes to load and I have narrowed the problem down to the use of flock in the function that gets an instance of the singleton. Here is a simplified version of the code: (edit: left out the most important part of the code in my original post)

public static final function getInstance() {
  if (is_null(self::$instance) {
    $fh = fopen($filename, 'ab+');
    if (flock($fh, LOCK_EX)) {
      $N = filesize($filename); 
      if ($N > 0) {
        rewind($fh);
        $s = stream_get_contents($fh);
        $obj = unserialize($s);
      } else {
        $obj = new MyClass();
      }
      self::$instance = $obj;
      return $obj;
    } else {
      fclose($fh);
      trigger_error("could not create lock", E_USER_WARNING);
    }
  } else {
    return self::$instance;
  }
}

The code is currently being run my development machine which uses XP and NTFS.
The lock is always created (i.e. trigger_error is not called).
The delay is random but seems to happen more often when refresh is hit.
Getting rid of flock completely eliminates the problem but it also makes the code unsafe.

Any advice?

Does anyone know a better way of creating an application wide persistent singleton?

+1  A: 

Who closes the $fh in the if {} clause? Isn't it left open? in that case it might take a long time to unlock. Otherwise it will hang open for at least the duration of the script.

EFraim
Its closed after the object is serialized back to the file in the destructor.
Lawrence Barsanti
That's unlikely correct. According to the code snippet the file descriptor $fh is only valid within getInstance(). It's "only" a local variable, no global, no code storing another reference that "survives" getInstancde(). I.e. it's (supposed to be) destroyed when php leaves the method's scope. In that case php_stdiop_close($fh, ...) is called. It will close the file handle and also release any file lock associated with this stream resource. Did you show us the real code?
VolkerK
A: 

You could try locking with the LOCK_SH parameter instead of LOCK_EX. You can still lock for writing if you find that you need to at a later time. I would further release the lock as soon as possible or other processes will block unnecessarily.

soulmerge