/// <summary>
        /// Update session items in the cache and release the exclusive lock.
        /// </summary>
        /// <param name="sessionId">Session key.</param>
        /// <param name="holder">Session holder.</param>
        /// <param name="newSession">
        /// Flag specifying whether this is a new session.
        /// </param>
        public virtual void SaveSession(SessionKey sessionId, SessionHolder holder, bool newSession)
        {
            long          lockId      = holder.LockId;
            bool          initialized = holder.Initialized;
            long          timeout     = (long)holder.Timeout.TotalMilliseconds;
            ISessionModel model       = holder.Model;
            Binary        binModel    = newSession || model.Dirty ? Serialize(model) : null;
            IDictionary   extAttr     = model.Dirty ? GetExternalAttributes(model) : null;
            IList         obsExtAttr  = model.Dirty ? GetObsoleteExternalAttributes(model) : null;

            SessionCache.Invoke(sessionId,
                                new SaveSessionProcessor(lockId, newSession, initialized, timeout, binModel, extAttr, obsExtAttr));

            if (newSession && m_sessionEndCallback != null)
            {
                SessionEndListener listener = new SessionEndListener(this, sessionId);
                SessionCache.AddCacheListener(listener, listener.EventFilter, false);
            }
        }