Tutorial - connecting

Server component ie. scached daemon can be installed both locally with web server, or on a separate server so that it can be queried by multiple frontend servers. For communication between php code and backend scache supports local unix sockets, ipv4 and ipv6 thought ipv6 is largely untested.

Most serious bottlenecks in scache's performance are network latencies. As a rule of thumb, if scached is installed on same server with web server and is communicating through unix socket, performance with single-op queries results some ten to tens of thousands requests per second. If queried over network, because of network latencies, maximum query rate between backend and single client drops at least to some 20% from locally achieved speed at its best. Of course these 20% can be achieved by multiple clients simultaneously.

Network latencies can be abundantly overcome by using multi-op command scache_iov() that is capable of posting multiple operations on single network packet thus reducing round trip latencies. However internal design of your application might limit possibilities for using multi-op queries.

When querying multiple small requests with scache_iov on local installation communicating through unix socket, you can easily break one million operations per second barrier even with not so current hardware.

Server can be connected by either scache_open(), scache_reset() or scache_connect(). These differ from whether they query server and what they do if given session id already exists.

Both scache_reset and scache_open actually queries server and returns false if some problems occurs with session. Scache_connect instead does not query server thus omitting one costly and latencyful round trip to server, but as an drawback existence and validity of session is not reported until on first actual query. Scache_connect exists purely for speed.

$c = scache_reset($id); // resets previous session ie. create always new 
                        // empty session
$c = scache_open($id);  // opens previous session or initialize as new 
                        // if given session id doesn't previously exist
$c = scache_connect($id); // just prepares connection for given session id

By default all connect functions connect to built-in or php.ini specified path. If destination is specified, it is considered as unix socket path, ip address or hostname depending whether it begins with slash or is resolvable to address. All missing values are regarded as default built-in values. The unconfigured php extension defaults to connect through local unix socket.

$c = scache_open($sessid); // default path, built-in or from php.ini
$c = scache_open($sessid, '/var/run/scached.sock'); // connect to unix socket
$c = scache_open($sessid, '127.0.0.1'); // ipv4 + builtin (or php.ini) port
$c = scache_open($sessid, '127.0.0.1', false, 50659); // ipv4 and port
$c = scache_open($sessid, '::1', false, 50659); // ipv6 + port
$c = scache_open($sessid, 'scached.example.com'); // with dns name

It is possible to give extra secret as an third parameter. If session is initialized with secret, it must match on further connection attempts or connection will fail. This might give some extra security when same scached backend is used by multiple separate web applications where exists possibility for session id collision.

$c = scache_reset("$sessid", 'localhost', "MyHiddenSecret");
$c = scache_reset("$sessid", 'localhost'); // fails, secret mismatch

Notes I

If you scache_open session, there is no builtin way to detect whether it opened already existing session or initialized new one. Example scenario is that client has had an used valid session, but exited for long period (enough to stored session to expire) and returned back with same session id (cookie). Scache_open opens all the time without any indication of errors, but after returning back it opens expired session as new one.

To detect this, it must be done programmatically by expecting valid initialized session to always have some attribute and assume lack of it as an indication of new uninitialized session.

Notes II

Whether to open, reset or connect is subject to application design. One example is to :

function require_login() {
  include('show-my-login-page.html');
  die();
}

function login($user, $pass) {

  if (($info = get_user_info($user, $pass))) {

    $cookie = md5(uniqid()) . md5(uniqid());
    if (($conn = scache_reset($cookie))) {

      setcookie('MySecId', $cookie);
      scache_iov($conn, 
		 Array(Array(SCIOP_SET, 'user/login', $info['login']),
		       Array(SCIOP_SET, 'user/fname', $info['fname']),
		       Array(SCIOP_SET, 'user/sname', $info['sname']),
		       Array(SCIOP_SET, 'user/uid', $info['uid'])));
    }
  }
}

function bootstrap($cookie) {

  $conn = scache_connect($cookie); /* no round-trip */
  list($login,
       $fname,
       $sname,
       $uid) = scache_iov($conn, /* everything in one query */
			  Array(Array(SCIOP_GET, 'user/login'),
				Array(SCIOP_GET, 'user/fname'),
				Array(SCIOP_GET, 'user/sname'),
				Array(SCIOP_GET, 'user/uid')));

  if (!$uid) {

    /* failed, session got rewritten or invalid */
    require_login();

  } else {

    /* define to globals */
    $vars = Array('login', 'fname', 'sname', 'uid');
    foreach($vars as $v) define('__' . strtoupper($v), $$v);
  }
}

if (($cookie = trim($_COOKIES['MySecId')))) {
  bootstrap();
} else if (($user = trim($_POST['username'])) && 
	    ($pass = trim($_POST['password']))) {
  login($user, $pass);
} else {
  require_login();
}

...

By this way there is only one round-trip to server generated versus using scache_open and querying expected parameters with separate command.