static int ReadTick (TRI_json_t const* json,
                     char const* attributeName,
                     TRI_voc_tick_t* dst) {
  TRI_json_t* tick;

  assert(json != NULL);
  assert(json->_type == TRI_JSON_ARRAY);
                                     
  tick = TRI_LookupArrayJson(json, attributeName);

  if (! TRI_IsStringJson(tick)) {
    return TRI_ERROR_REPLICATION_INVALID_APPLIER_STATE;
  }

  *dst = (TRI_voc_tick_t) TRI_UInt64String2(tick->_value._string.data, tick->_value._string.length -1);

  return TRI_ERROR_NO_ERROR;
}
int TRI_LoadStateReplicationApplier (TRI_vocbase_t* vocbase,
                                     TRI_replication_applier_state_t* state) {
  TRI_json_t* json;
  TRI_json_t* serverId;
  char* filename;
  int res;
  
  TRI_InitStateReplicationApplier(state);
  filename = GetStateFilename(vocbase);

  if (filename == NULL) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

  LOG_TRACE("looking for replication state file '%s'", filename);

  if (! TRI_ExistsFile(filename)) {
    TRI_FreeString(TRI_CORE_MEM_ZONE, filename);

    return TRI_ERROR_FILE_NOT_FOUND;
  }
  
  LOG_TRACE("replication state file '%s' found", filename);

  json  = TRI_JsonFile(TRI_CORE_MEM_ZONE, filename, NULL);
  TRI_FreeString(TRI_CORE_MEM_ZONE, filename);

  if (! TRI_IsArrayJson(json)) {
    if (json != NULL) {
      TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
    }

    return TRI_ERROR_REPLICATION_INVALID_APPLIER_STATE;
  }

  res = TRI_ERROR_NO_ERROR;

  // read the server id
  serverId = TRI_LookupArrayJson(json, "serverId");

  if (! TRI_IsStringJson(serverId)) {
    res = TRI_ERROR_REPLICATION_INVALID_APPLIER_STATE;
  }
  else {
    state->_serverId = TRI_UInt64String2(serverId->_value._string.data, 
                                         serverId->_value._string.length - 1);
  }

  if (res == TRI_ERROR_NO_ERROR) {
    // read the ticks
    res |= ReadTick(json, "lastAppliedContinuousTick", &state->_lastAppliedContinuousTick); 

    // set processed = applied
    state->_lastProcessedContinuousTick = state->_lastAppliedContinuousTick;
  }

  TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
  
  LOG_TRACE("replication state file read successfully");

  return res;
}
static int AutoIncrementGenerate (TRI_key_generator_t* const generator,
                                  const size_t maxLength,
                                  const TRI_voc_tick_t tick,
                                  const char* const userKey,
                                  char* const outBuffer,
                                  size_t* const outLength,
                                  bool isRestore) {
  autoincrement_keygen_t* data;
  char* current;

  data = (autoincrement_keygen_t*) generator->_data;
  assert(data != NULL);

  current = outBuffer;

  if (userKey != NULL) {
    uint64_t userKeyValue;
    size_t userKeyLength;

    // user has specified a key
    if (! data->_allowUserKeys && ! isRestore) {
      // we do not allow user-generated keys
      return TRI_ERROR_ARANGO_DOCUMENT_KEY_UNEXPECTED;
    }

    userKeyLength = strlen(userKey);
    if (userKeyLength > maxLength) {
      // user key is too long
      return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
    }

    // validate user-supplied key
    if (! ValidateNumericKey(userKey)) {
      return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
    }

    memcpy(outBuffer, userKey, userKeyLength);
    current += userKeyLength;

    userKeyValue = TRI_UInt64String2(userKey, userKeyLength);
    if (userKeyValue > data->_lastValue) {
      // update our last value
      data->_lastValue = userKeyValue;
    }
  }
  else {
    // user has not specified a key, generate one based on algorithm
    uint64_t keyValue = AutoIncrementNext(data->_lastValue, data->_increment, data->_offset);

    // bounds and sanity checks
    if (keyValue == UINT64_MAX || keyValue < data->_lastValue) {
      return TRI_ERROR_ARANGO_OUT_OF_KEYS;
    }

    assert(keyValue > data->_lastValue);
    // update our last value
    data->_lastValue = keyValue;

    current += TRI_StringUInt64InPlace(keyValue, outBuffer);
  }

  // add 0 byte
  *current = '\0';

  if (current - outBuffer > (int) maxLength) {
    return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
  }

  *outLength = (current - outBuffer);

  return TRI_ERROR_NO_ERROR;
}