/**
   * Invoked after a non-sticky session is loaded from memcached, can be used to update some session
   * fields based on separately stored information (e.g. session validity info).
   *
   * @param lockStatus the {@link LockStatus} that was returned from {@link
   *     #onBeforeLoadFromMemcached(String)}.
   */
  protected void onAfterLoadFromMemcached(
      @Nonnull final MemcachedBackupSession session, @Nullable final LockStatus lockStatus) {
    session.setLockStatus(lockStatus);

    final long start = System.currentTimeMillis();
    final SessionValidityInfo info = loadSessionValidityInfo(session.getIdInternal());
    if (info != null) {
      _stats.registerSince(NON_STICKY_AFTER_LOAD_FROM_MEMCACHED, start);
      session.setLastAccessedTimeInternal(info.getLastAccessedTime());
      session.setThisAccessedTimeInternal(info.getThisAccessedTime());
    } else {
      _log.warn("No validity info available for session " + session.getIdInternal());
    }
  }
  static DeserializationResult deserializeSessionFields(
      final byte[] data, final SessionManager manager) throws InvalidVersionException {
    final MemcachedBackupSession result = manager.newMemcachedBackupSession();

    final short version = (short) decodeNum(data, 0, 2);

    if (version != CURRENT_VERSION) {
      throw new InvalidVersionException(
          "The version " + version + " does not match the current version " + CURRENT_VERSION,
          version);
    }

    final short sessionFieldsDataLength = (short) decodeNum(data, 2, 2);

    result.setCreationTimeInternal(decodeNum(data, 4, 8));
    result.setLastAccessedTimeInternal(decodeNum(data, 12, 8));
    result.setMaxInactiveInterval((int) decodeNum(data, 20, 4));
    result.setIsNewInternal(decodeBoolean(data, 24));
    result.setIsValidInternal(decodeBoolean(data, 25));
    result.setThisAccessedTimeInternal(decodeNum(data, 26, 8));
    result.setLastBackupTime(decodeNum(data, 34, 8));

    final short idLength = (short) decodeNum(data, 42, 2);
    result.setIdInternal(decodeString(data, 44, idLength));

    final short authTypeId = (short) decodeNum(data, 44 + idLength, 2);
    result.setAuthTypeInternal(AuthType.valueOfId(authTypeId).getValue());

    final int currentIdx = 44 + idLength + 2;
    final short principalDataLength = (short) decodeNum(data, currentIdx, 2);
    if (principalDataLength > 0) {
      final byte[] principalData = new byte[principalDataLength];
      System.arraycopy(data, currentIdx + 2, principalData, 0, principalDataLength);
      result.setPrincipalInternal(deserializePrincipal(principalData, manager));
    }

    final byte[] attributesData = new byte[data.length - sessionFieldsDataLength];
    System.arraycopy(
        data, sessionFieldsDataLength, attributesData, 0, data.length - sessionFieldsDataLength);

    return new DeserializationResult(result, attributesData);
  }