protected function lock_session($id) {
        $lockkey = $id.".lock";

        $haslock = isset($this->locks[$id]) && $this->time() < $this->locks[$id];
        $startlocktime = $this->time();

        /* To be able to ensure sessions don't write out of order we must obtain an exclusive lock
         * on the session for the entire time it is open.  If another AJAX call, or page is using
         * the session then we just wait until it finishes before we can open the session.
         */
        while (!$haslock) {
            $haslock = $this->connection->setnx($lockkey, '1');
            if (!$haslock) {
                usleep(rand(100000, 1000000));
                if ($this->time() > $startlocktime + $this->acquiretimeout) {
                    // This is a fatal error, better inform users.
                    // It should not happen very often - all pages that need long time to execute
                    // should close session immediately after access control checks.
                    error_log('Cannot obtain session lock for sid: '.$id.' within '.$this->acquiretimeout.
                            '. It is likely another page has a long session lock, or the session lock was never released.');
                    throw new exception("Unable to obtain session lock");
                }
            } else {
                $this->locks[$id] = $this->time() + $this->lockexpire;
                $this->connection->expire($lockkey, $this->lockexpire);
                return true;
            }
        }
    }