static int smrCbClose (void *arg, long long seq, short nid, int sid) { redisClient *c; callbackInfo *cb; dlisth *node; if (nid != smr_get_nid (server.smr_conn) || !(server.smr_init_flags & SMR_INIT_DONE)) return REDIS_OK; /* query from this server. get client from global callback list */ assert (!dlisth_is_empty (&server.global_callbacks)); /* global callback list shouldn't be empty */ node = server.global_callbacks.next; cb = (callbackInfo *) node; dlisth_delete (&cb->global_head); dlisth_delete (&cb->client_head); c = cb->client; zfree (cb); if (c->fd == -1) return REDIS_OK; /* ignore if the client is already freed */ assert (c->fd == sid); addReplyError (c, c->smr.protocol_error_reply); c->flags |= REDIS_CLOSE_AFTER_REPLY; return REDIS_OK; }
/* * hash_destroy - destroy static hash table * return: void * ht(in): hash table * dtor(in): element destructor function */ void hash_destroy (hash_table * ht, ht_destroyf dtor) { int i; assert (ht != NULL); if (ht == NULL) return; for (i = 0; i < ht->bucket_sz; i++) { dlisth *h, *header; h = header = &ht->buckets[i].head; h = h->next; while (h != header) { ht_elem *hte = (ht_elem *) h; h = h->next; dlisth_delete ((dlisth *) hte); if (dtor) dtor (hte->elem); API_FREE (hte); } } API_FREE (ht); }
/* * li_api_delete - delete existing element at the given position * return: NO_ERROR if successful, error code otherwise * indexer(in): VALUE_INDEXER * index(in): index of the element * rva(out): pointer to VALUE_AREA * dbval(out): pointer to API_VALUE */ static int li_api_delete (VALUE_INDEXER * indexer, int index, VALUE_AREA ** rva, API_VALUE ** dbval) { LIST_INDEXER *li = (LIST_INDEXER *) indexer; LIST_INDEXER_ELEM *e; assert (li != NULL); assert (li->nelems > 0); assert (index >= 0 && index < li->nelems); assert (rva != NULL); assert (dbval != NULL); assert (li->cache_idx >= 0 && li->cache_elem != NULL); e = li_getf (li, index); assert (e != NULL); *rva = e->va; *dbval = e->value; li->nelems--; /* ajust cache */ if (li->nelems > 0) { if (index < li->cache_idx) { li->cache_idx--; } else if (index == li->cache_idx) { if (index > 0) { li->cache_idx = index - 1; li->cache_elem = (LIST_INDEXER_ELEM *) (((dlisth *) e)->prev); } else { li->cache_elem = (LIST_INDEXER_ELEM *) (((dlisth *) e)->next); } } } else { li->cache_idx = -1; li->cache_elem = NULL; } dlisth_delete ((dlisth *) e); API_FREE (e); return NO_ERROR; }
/* * li_api_destroy - destroy value indexer * return: void * indexer(in): VALUE_INDEXER * df(in): element destroy function */ static void li_api_destroy (VALUE_INDEXER * indexer, void (*df) (VALUE_AREA * va, API_VALUE * db)) { LIST_INDEXER *li = (LIST_INDEXER *) indexer; assert (li != NULL); while (!dlisth_is_empty (&li->elems)) { LIST_INDEXER_ELEM *e = (LIST_INDEXER_ELEM *) li->elems.next; if (df) df (e->va, e->value); dlisth_delete ((dlisth *) e); API_FREE (e); } API_FREE (li); }
/* * api_free - free() debug version * return: void * ptr(in): pointer to allcated memory via api_malloc(), api_calloc() * file(in): file name * line(in): line number */ void api_free (void *ptr, const char *file, int line) { char *p = NULL; if (api_malloc_dhook_flag_set == 0) return free (ptr); API_ONCE_FUNC (&once, once_function); if (ptr) { p = (char *) ptr - MALLOC_HEADER_SZ; API_LOCK (&mutex); dlisth_delete ((dlisth *) p); free_count++; API_UNLOCK (&mutex); } free (p); }
/* * hash_delete - delete hash entry from hash table and return element found * return: NO_ERROR if successful, error_code otherwise * ht(in): hash table * key(in): pointer to the key * relem(out): element found, or set to NULL * * NOTE * When element is not found then NO_ERROR returned with NULL relem value */ int hash_delete (hash_table * ht, void *key, void **relem) { int rc; unsigned int hcode; dlisth *h, *header; assert (ht != NULL); assert (relem != NULL); *relem = NULL; rc = ht->hashf (key, &hcode); if (rc != NO_ERROR) return rc; hcode = hcode % ht->bucket_sz; header = &ht->buckets[(size_t) hcode].head; for (h = header->next; h != header; h = h->next) { int r; ht_elem *hte = (ht_elem *) h; void *ekey; if ((rc = ht->keyf (hte->elem, &ekey)) != NO_ERROR) return rc; if ((rc = ht->comparef (key, ekey, &r)) == NO_ERROR && r == 0) { *relem = hte->elem; dlisth_delete (h); API_FREE (hte); return NO_ERROR; } else if (rc != NO_ERROR) return rc; } return NO_ERROR; }
/* sid = |flags(4byte)|client fd(4byte)| */ static int smrCbData (void *arg, long long seq, long long timestamp, short nid, int sid, int hash, smrData * smr_data, int size) { char *data = smr_data_get_data (smr_data); redisClient *c; short cmdflags; dlisth *node; /* Special commands */ if (size == 1 && data[0] == REDIS_SMR_CMD_CATCHUP_CHECK) { if (nid == smr_get_nid (server.smr_conn) && (server.smr_init_flags & SMR_INIT_CATCHUP_PHASE2)) checkSmrCatchup (); goto release_seq; } else if (size == 1 && data[0] == REDIS_SMR_CMD_DELIVER_OOM) { server.smr_oom_until = timestamp + REDIS_OOM_DURATION_MS; goto release_seq; } /* Normal command */ server.smr_mstime = timestamp; cmdflags = (0xFFFF0000 & sid) >> 16; /* Because we fixed the bug that causes timestamp be 0, * this warning log is not necessary and just an assert statement is enough after all. * But currently, there are nbase-arc clusters which have the bug. * So, we don't assert for now. */ if (timestamp == 0) { redisLog (REDIS_WARNING, "Timestamp of SMR callback is 0," "seq:%lld, nid:%d, sid:%d, hash:%d, size:%d", seq, nid, sid, hash, size); } if ((server.smr_init_flags & SMR_INIT_DONE) && nid == smr_get_nid (server.smr_conn)) { callbackInfo *cb; /* query from this server. get client from global callback list */ assert (!dlisth_is_empty (&server.global_callbacks)); /* global callback list shouldn't be empty */ node = server.global_callbacks.next; cb = (callbackInfo *) node; dlisth_delete (&cb->global_head); dlisth_delete (&cb->client_head); c = cb->client; assert (cb->hash == hash); assert (c->fd == -1 || c->fd == (0X0000FFFF & sid)); /* We already parsed querybuf because the query is requested from this * server before smr callback*/ c->argc = cb->argc; c->argv = cb->argv; cb->argc = 0; cb->argv = NULL; zfree (cb); server.current_client = c; /* fake client doesn't need to execute non-write query(read-only or admin) */ if (c->fd != -1 || cmdflags & REDIS_CMD_WRITE) { assert (!(c->flags & REDIS_CLOSE_AFTER_REPLY)); processCommand (c); } } else { /* replicated query from other servers, or catchup query during initialize */ c = server.smrlog_client; server.current_client = c; /* fake client doesn't need to execute non-write query(read-only or admin) */ if (cmdflags & REDIS_CMD_WRITE) { /* We need to parse querybuf because the query is from different server * or we are recovering without client */ sdsclear (c->querybuf); c->querybuf = sdsMakeRoomFor (c->querybuf, size); memcpy (c->querybuf, data, size); sdsIncrLen (c->querybuf, size); if (c->querybuf_peak < size) c->querybuf_peak = size; processInputBuffer (c); } } resetClient (c); zfree (c->argv); c->argv = NULL; server.current_client = NULL; release_seq: if (smr_release_seq_upto (server.smr_conn, seq + size) == -1) { redisLog (REDIS_WARNING, "smr_release_seq_upto error"); redisAssert (0); return REDIS_ERR; } server.smr_seqnum = seq + size; return REDIS_OK; }