/** Moves the given handle to the head of the handle cache.
  If it doesn't exist, it allocates the tail, and moves it to head.
  Returns the index in the cache, or HANDLE_CACHE_ENTRY_INVALID if the cache
  is full of persistent handles */
static uint16_t handle_entry_to_head(rbc_mesh_value_handle_t handle)
{
    uint16_t i = handle_entry_get(handle, true);
    if (i == HANDLE_CACHE_ENTRY_INVALID)
    {
        i = m_handle_cache_tail;
        while (m_handle_cache[i].persistent)
        {
            HANDLE_CACHE_ITERATE_BACK(i);
            if (i == HANDLE_CACHE_ENTRY_INVALID)
            {
                return i; /* reached the head without hitting a non-persistent handle */
            }
        }
        /* clean up old data */
        m_handle_cache[i].handle = handle;
        m_handle_cache[i].tx_event = 0;
        m_handle_cache[i].version = 0;
        if (m_handle_cache[i].data_entry != DATA_CACHE_ENTRY_INVALID)
        {
            data_entry_free(&m_data_cache[m_handle_cache[i].data_entry]);
            m_handle_cache[i].data_entry = DATA_CACHE_ENTRY_INVALID;
        }
    }
    /* detach and move to head */
    if (i != m_handle_cache_tail)
    {
        if (i != m_handle_cache_head)
        {
            m_handle_cache[m_handle_cache[i].index_next].index_prev = m_handle_cache[i].index_prev;
        }
    }
    else
    {
        m_handle_cache_tail = m_handle_cache[i].index_prev;
        m_handle_cache[i].index_next = HANDLE_CACHE_ENTRY_INVALID;
    }

    if (i != m_handle_cache_head)
    {
        if (m_handle_cache[i].index_prev != HANDLE_CACHE_ENTRY_INVALID)
        {
            m_handle_cache[m_handle_cache[i].index_prev].index_next = m_handle_cache[i].index_next;
        }

        m_handle_cache[i].index_prev = HANDLE_CACHE_ENTRY_INVALID;
        m_handle_cache[i].index_next = m_handle_cache_head;
        m_handle_cache[m_handle_cache_head].index_prev = i;
        m_handle_cache_head = i;
    }

    m_handle_cache[m_handle_cache_head].index_prev = HANDLE_CACHE_ENTRY_INVALID;
    m_handle_cache[m_handle_cache_tail].index_next = HANDLE_CACHE_ENTRY_INVALID;

    return i;
}
TEST_F(TairClientRDBTest, test_lrange) {
  VDE* vde = vector_data_entry_rand(100, 10);
  data_entry key("lindex_normal");

  tairClient.remove(10, key);

  long successlen = 0;
  int resultcode = tairClient.rpush(10, key, *vde, NOT_CARE_EXPIRE, NOT_CARE_VERSION, successlen);
  ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
  ASSERT_EQ(10, successlen);

  for (size_t i = 0; i < vde->size(); i++) {
    std::vector<data_entry *> v;
    resultcode = tairClient.lrange(10, key, i, vde->size() - 1, v);
    ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
    ASSERT_EQ(vde->size() - i, v.size());
    for (size_t j = i; j < vde->size(); j++) {
      ASSERT_EQ(1, data_entry_cmp((*vde)[j], v[j - i]));
    }
  }

  std::vector<data_entry *> v;
  resultcode = tairClient.lrange(10, key, -1000, 1000, v);
  ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
  ASSERT_EQ(vde->size(), v.size());
  ASSERT_EQ(1, vector_data_entry_cmp(vde, &v));
  for (size_t i = 0; i < v.size(); i++) {
    data_entry_free(v[i]);
  }

  v.clear();
  resultcode = tairClient.lrange(10, key, 1000, 2000, v);
  ASSERT_EQ(TAIR_RETURN_OUT_OF_RANGE, resultcode);
  ASSERT_EQ(v.size(), 0);

  v.clear();
  resultcode = tairClient.lrange(10, key, -1000, -2000, v);
  ASSERT_EQ(TAIR_RETURN_OUT_OF_RANGE, resultcode);
  ASSERT_EQ(v.size(), 0);

  vector_data_entry_free(vde);
}
/** Allocate a new data entry. Will take the least recently updated entry if all are allocated.
  Returns the index of the resulting entry. */
static uint16_t data_entry_allocate(void)
{
    static uint16_t allocated = 0;
    TICK_PIN(7);

    for (uint32_t i = allocated; i < RBC_MESH_DATA_CACHE_ENTRIES; ++i)
    {
        if (m_data_cache[i].p_packet == NULL)
        {
            trickle_timer_reset(&m_data_cache[i].trickle, 0);
            allocated++;
            return i;
        }
    }

    /* no unused entries, take the least recently updated (and disregard persistent handles) */
    uint32_t handle_index = m_handle_cache_tail;
    while (m_handle_cache[handle_index].data_entry == DATA_CACHE_ENTRY_INVALID ||
           m_handle_cache[handle_index].persistent)
    {
        HANDLE_CACHE_ITERATE_BACK(handle_index);

        if (handle_index == HANDLE_CACHE_ENTRY_INVALID)
        {
            return DATA_CACHE_ENTRY_INVALID;
        }
    }

    uint32_t data_index = m_handle_cache[handle_index].data_entry;
    APP_ERROR_CHECK_BOOL(data_index < RBC_MESH_DATA_CACHE_ENTRIES);

    /* cleanup */
    m_handle_cache[handle_index].data_entry = DATA_CACHE_ENTRY_INVALID;

    data_entry_free(&m_data_cache[data_index]);
    trickle_timer_reset(&m_data_cache[data_index].trickle, 0);
    return data_index;
}
TEST_F(TairClientRDBTest, test_lpush_rpop_llen_no_expire_no_version) {
  VDE* vde = vector_data_entry_rand(100, 10);
  data_entry key("lpush_rpop_llen_no_expire_no_version");

  tairClient.remove(10, key);

  int length = 0;
  int resultcode = tairClient.llen(10, key, length);
  ASSERT_EQ(TAIR_RETURN_DATA_NOT_EXIST, resultcode);
  ASSERT_EQ(0, length);

  long successlen = 0;
  resultcode = tairClient.lpush(10, key, *vde, NOT_CARE_EXPIRE, (const int)NOT_CARE_VERSION, successlen);
  ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
  ASSERT_EQ(10, successlen);

  VDE* vde1 = vector_data_entry_rand(10, 8182);
  for (size_t i = 0; i < vde1->size(); i++) {
    data_entry* de = (*vde1)[i];
    resultcode = tairClient.lpush(10, key, de, NOT_CARE_EXPIRE, (int)NOT_CARE_VERSION);
    ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);

    resultcode = tairClient.llen(10, key, length);
    ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
    ASSERT_EQ(i + 11, length);
  }

  data_entry* dentry = data_entry_rand(100);
  resultcode = tairClient.lpush(10, key, dentry, NOT_CARE_EXPIRE, NOT_CARE_VERSION);
  ASSERT_EQ(TAIR_RETURN_DATA_LEN_LIMITED, resultcode);
  data_entry_free(dentry);

  resultcode = tairClient.llen(10, key, length);
  ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
  ASSERT_EQ(8192, length);

  std::vector<data_entry *> ret_values;
  resultcode = tairClient.rpop(10, key, 10, ret_values, NOT_CARE_EXPIRE, NOT_CARE_VERSION);
  ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);

  ASSERT_EQ(1, vector_data_entry_cmp(vde, &ret_values));

  for (size_t i = 0; i < vde1->size(); i++) {
    data_entry* value = NULL;
    resultcode = tairClient.rpop(10, key, &value, NOT_CARE_EXPIRE, NOT_CARE_VERSION);
    ASSERT_EQ(TAIR_RETURN_SUCCESS, resultcode);
    ASSERT_EQ(1, data_entry_cmp((*vde1)[i], value));
    data_entry_free(value);
  }

  data_entry* value = NULL;
  resultcode = tairClient.rpop(10, key, &value, NOT_CARE_EXPIRE, NOT_CARE_VERSION);
  ASSERT_EQ(TAIR_RETURN_DATA_NOT_EXIST, resultcode);
  ASSERT_EQ(NULL, value);

  vector_data_entry_free(vde);
  vector_data_entry_free(vde1);

  resultcode = tairClient.remove(10, key);
  ASSERT_EQ(TAIR_RETURN_DATA_NOT_EXIST, resultcode);
}