static void
stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
{
int stat_id = -1;
ENTRY search, *result = NULL;
static __thread struct hsearch_data stat_cache;
static __thread bool hash_init = false;

if (unlikely(!hash_init)) {
    hcreate_r(TS_MAX_API_STATS << 1, &stat_cache);
    hash_init = true;
    TSDebug(DEBUG_TAG, "stat cache hash init");
}

search.key  = name;
search.data = 0;
hsearch_r(search, FIND, &result, &stat_cache);

if (unlikely(result == NULL)) {
    // This is an unlikely path because we most likely have the stat cached
    // so this mutex won't be much overhead and it fixes a race condition
    // in the RecCore. Hopefully this can be removed in the future.
    TSMutexLock(create_mutex);
    if (TS_ERROR == TSStatFindName((const char *)name, &stat_id)) {
        stat_id = TSStatCreate((const char *)name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
        if (stat_id == TS_ERROR) {
            TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
        } else {
            TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
        }
    }
    TSMutexUnlock(create_mutex);

    if (stat_id >= 0) {
        search.key  = TSstrdup(name);
        search.data = (void *)((intptr_t)stat_id);
        hsearch_r(search, ENTER, &result, &stat_cache);
        TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
    }
} else {
    stat_id = (int)((intptr_t)result->data);
}

if (likely(stat_id >= 0)) {
    TSStatIntIncrement(stat_id, amount);
} else {
    TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
}
}
void
init_stats(void)
{
  /* noncoupled: */
  redirect_count_connect =
    TSStatCreate(STAT_PREFIX "count.connect", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_delete = TSStatCreate(STAT_PREFIX "count.delete", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_get    = TSStatCreate(STAT_PREFIX "count.get", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_head   = TSStatCreate(STAT_PREFIX "count.head", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_options =
    TSStatCreate(STAT_PREFIX "count.options", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_post  = TSStatCreate(STAT_PREFIX "count.post", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_purge = TSStatCreate(STAT_PREFIX "count.purge", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_put   = TSStatCreate(STAT_PREFIX "count.put", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_trace = TSStatCreate(STAT_PREFIX "count.trace", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  redirect_count_unknown =
    TSStatCreate(STAT_PREFIX "count.unknown", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);

  requests_redirects = TSStatCreate(STAT_PREFIX "total.redirects", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
  requests_unchanged = TSStatCreate(STAT_PREFIX "total.unchanged", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
}