|
51 | 51 | typedef enum { DEFRAG_NOT_DONE = 0,
|
52 | 52 | DEFRAG_DONE = 1 } doneStatus;
|
53 | 53 |
|
54 |
| - |
55 | 54 | /*
|
56 | 55 | * Defragmentation is performed in stages. Each stage is serviced by a stage function
|
57 | 56 | * (defragStageFn). The stage function is passed a target (void*) to defrag. The contents of that
|
@@ -135,7 +134,7 @@ typedef struct {
|
135 | 134 | static_assert(offsetof(defragKeysCtx, kvstate) == 0, "defragStageKvstoreHelper requires this");
|
136 | 135 |
|
137 | 136 | // Private data for pubsub kvstores
|
138 |
| -typedef dict *(*getClientChannelsFn)(client *); |
| 137 | +typedef hashtable *(*getClientChannelsFn)(client *); |
139 | 138 | typedef struct {
|
140 | 139 | getClientChannelsFn fn;
|
141 | 140 | } getClientChannelsFnWrapper;
|
@@ -243,30 +242,6 @@ robj *activeDefragStringOb(robj *ob) {
|
243 | 242 | return new_robj;
|
244 | 243 | }
|
245 | 244 |
|
246 |
| -/* Defrag helper for dict main allocations (dict struct, and hash tables). |
247 |
| - * Receives a pointer to the dict* and return a new dict* when the dict |
248 |
| - * struct itself was moved. |
249 |
| - * |
250 |
| - * Returns NULL in case the allocation wasn't moved. |
251 |
| - * When it returns a non-null value, the old pointer was already released |
252 |
| - * and should NOT be accessed. */ |
253 |
| -static dict *dictDefragTables(dict *d) { |
254 |
| - dict *ret = NULL; |
255 |
| - dictEntry **newtable; |
256 |
| - /* handle the dict struct */ |
257 |
| - if ((ret = activeDefragAlloc(d))) d = ret; |
258 |
| - /* handle the first hash table */ |
259 |
| - if (!d->ht_table[0]) return ret; /* created but unused */ |
260 |
| - newtable = activeDefragAlloc(d->ht_table[0]); |
261 |
| - if (newtable) d->ht_table[0] = newtable; |
262 |
| - /* handle the second hash table */ |
263 |
| - if (d->ht_table[1]) { |
264 |
| - newtable = activeDefragAlloc(d->ht_table[1]); |
265 |
| - if (newtable) d->ht_table[1] = newtable; |
266 |
| - } |
267 |
| - return ret; |
268 |
| -} |
269 |
| - |
270 | 245 | /* Internal function used by zslDefrag */
|
271 | 246 | static void zslUpdateNode(zskiplist *zsl, zskiplistNode *oldnode, zskiplistNode *newnode, zskiplistNode **update) {
|
272 | 247 | int i;
|
@@ -786,37 +761,33 @@ static void dbKeysScanCallback(void *privdata, void *elemref) {
|
786 | 761 | /* Defrag scan callback for a pubsub channels hashtable. */
|
787 | 762 | static void defragPubsubScanCallback(void *privdata, void *elemref) {
|
788 | 763 | defragPubSubCtx *ctx = privdata;
|
789 |
| - void **channel_dict_ref = (void **)elemref; |
790 |
| - dict *newclients, *clients = *channel_dict_ref; |
791 |
| - robj *newchannel, *channel = *(robj **)dictMetadata(clients); |
792 |
| - size_t allocation_size; |
| 764 | + void **clients_ref = (void **)elemref; |
| 765 | + hashtable *newclients, *clients = *clients_ref; |
| 766 | + robj *newchannel, *channel = *(robj **)hashtableMetadata(clients); |
793 | 767 |
|
794 | 768 | /* Try to defrag the channel name. */
|
795 |
| - serverAssert(channel->refcount == (int)dictSize(clients) + 1); |
796 |
| - newchannel = activeDefragStringObWithoutFree(channel, &allocation_size); |
| 769 | + serverAssert(channel->refcount == (int)hashtableSize(clients) + 1); |
| 770 | + newchannel = activeDefragStringOb(channel); |
797 | 771 | if (newchannel) {
|
798 |
| - *(robj **)dictMetadata(clients) = newchannel; |
| 772 | + *(robj **)hashtableMetadata(clients) = newchannel; |
799 | 773 |
|
800 | 774 | /* The channel name is shared by the client's pubsub(shard) and server's
|
801 | 775 | * pubsub(shard), after defraging the channel name, we need to update
|
802 | 776 | * the reference in the clients' dictionary. */
|
803 |
| - dictIterator *di = dictGetIterator(clients); |
804 |
| - dictEntry *clientde; |
805 |
| - while ((clientde = dictNext(di)) != NULL) { |
806 |
| - client *c = dictGetKey(clientde); |
807 |
| - dict *client_channels = ctx->getPubSubChannels(c); |
808 |
| - dictEntry *pubsub_channel = dictFind(client_channels, newchannel); |
809 |
| - serverAssert(pubsub_channel); |
810 |
| - dictSetKey(ctx->getPubSubChannels(c), pubsub_channel, newchannel); |
| 777 | + hashtableIterator iter; |
| 778 | + hashtableInitIterator(&iter, clients, 0); |
| 779 | + void *c; |
| 780 | + while (hashtableNext(&iter, &c)) { |
| 781 | + hashtable *client_channels = ctx->getPubSubChannels(c); |
| 782 | + int replaced = hashtableReplaceReallocatedEntry(client_channels, channel, newchannel); |
| 783 | + serverAssert(replaced); |
811 | 784 | }
|
812 |
| - dictReleaseIterator(di); |
813 |
| - // Now that we're done correcting the references, we can safely free the old channel robj |
814 |
| - allocatorDefragFree(channel, allocation_size); |
| 785 | + hashtableResetIterator(&iter); |
815 | 786 | }
|
816 | 787 |
|
817 | 788 | /* Try to defrag the dictionary of clients that is stored as the value part. */
|
818 |
| - if ((newclients = dictDefragTables(clients))) |
819 |
| - *channel_dict_ref = newclients; |
| 789 | + if ((newclients = hashtableDefragTables(clients, activeDefragAlloc))) |
| 790 | + *clients_ref = newclients; |
820 | 791 |
|
821 | 792 | server.stat_active_defrag_scanned++;
|
822 | 793 | }
|
|
0 commit comments