1
0
mirror of https://github.com/fluencelabs/redis synced 2025-03-31 14:51:04 +00:00

Lazyfree: Sorted sets convereted to plain SDS. (several commits squashed)

This commit is contained in:
antirez 2015-08-04 09:20:55 +02:00
parent 86d48efbfd
commit a7c5be18a8
10 changed files with 306 additions and 266 deletions

@ -826,7 +826,7 @@ int rewriteSetObject(rio *r, robj *key, robj *o) {
dictEntry *de; dictEntry *de;
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
robj *eleobj = dictGetKey(de); sds ele = dictGetKey(de);
if (count == 0) { if (count == 0) {
int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ? int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ?
AOF_REWRITE_ITEMS_PER_CMD : items; AOF_REWRITE_ITEMS_PER_CMD : items;
@ -835,7 +835,7 @@ int rewriteSetObject(rio *r, robj *key, robj *o) {
if (rioWriteBulkString(r,"SADD",4) == 0) return 0; if (rioWriteBulkString(r,"SADD",4) == 0) return 0;
if (rioWriteBulkObject(r,key) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0;
} }
if (rioWriteBulkObject(r,eleobj) == 0) return 0; if (rioWriteBulkString(r,ele,sdslen(ele)) == 0) return 0;
if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0; if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0;
items--; items--;
} }
@ -892,7 +892,7 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
dictEntry *de; dictEntry *de;
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
robj *eleobj = dictGetKey(de); sds ele = dictGetKey(de);
double *score = dictGetVal(de); double *score = dictGetVal(de);
if (count == 0) { if (count == 0) {
@ -904,7 +904,7 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
if (rioWriteBulkObject(r,key) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0;
} }
if (rioWriteBulkDouble(r,*score) == 0) return 0; if (rioWriteBulkDouble(r,*score) == 0) return 0;
if (rioWriteBulkObject(r,eleobj) == 0) return 0; if (rioWriteBulkString(r,ele,sdslen(ele)) == 0) return 0;
if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0; if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0;
items--; items--;
} }

@ -4087,7 +4087,10 @@ void clusterCommand(client *c) {
keys = zmalloc(sizeof(robj*)*maxkeys); keys = zmalloc(sizeof(robj*)*maxkeys);
numkeys = getKeysInSlot(slot, keys, maxkeys); numkeys = getKeysInSlot(slot, keys, maxkeys);
addReplyMultiBulkLen(c,numkeys); addReplyMultiBulkLen(c,numkeys);
for (j = 0; j < numkeys; j++) addReplyBulk(c,keys[j]); for (j = 0; j < numkeys; j++) {
addReplyBulk(c,keys[j]);
decrRefCount(keys[j]);
}
zfree(keys); zfree(keys);
} else if (!strcasecmp(c->argv[1]->ptr,"forget") && c->argc == 3) { } else if (!strcasecmp(c->argv[1]->ptr,"forget") && c->argc == 3) {
/* CLUSTER FORGET <NODE ID> */ /* CLUSTER FORGET <NODE ID> */

@ -423,8 +423,8 @@ void scanCallback(void *privdata, const dictEntry *de) {
val = dictGetVal(de); val = dictGetVal(de);
incrRefCount(val); incrRefCount(val);
} else if (o->type == OBJ_ZSET) { } else if (o->type == OBJ_ZSET) {
key = dictGetKey(de); sds keysds = dictGetKey(de);
incrRefCount(key); key = createStringObject(keysds,sdslen(keysds));
val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0); val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0);
} else { } else {
serverPanic("Type not handled in SCAN callback."); serverPanic("Type not handled in SCAN callback.");
@ -1181,14 +1181,13 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
void slotToKeyAdd(robj *key) { void slotToKeyAdd(robj *key) {
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr)); unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
zslInsert(server.cluster->slots_to_keys,hashslot,key); sds sdskey = sdsdup(key->ptr);
incrRefCount(key); zslInsert(server.cluster->slots_to_keys,hashslot,sdskey);
} }
void slotToKeyDel(robj *key) { void slotToKeyDel(robj *key) {
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr)); unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
zslDelete(server.cluster->slots_to_keys,hashslot,key->ptr,NULL);
zslDelete(server.cluster->slots_to_keys,hashslot,key);
} }
void slotToKeyFlush(void) { void slotToKeyFlush(void) {
@ -1196,6 +1195,9 @@ void slotToKeyFlush(void) {
server.cluster->slots_to_keys = zslCreate(); server.cluster->slots_to_keys = zslCreate();
} }
/* Pupulate the specified array of objects with keys in the specified slot.
* New objects are returned to represent keys, it's up to the caller to
* decrement the reference count to release the keys names. */
unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) { unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) {
zskiplistNode *n; zskiplistNode *n;
zrangespec range; zrangespec range;
@ -1206,7 +1208,7 @@ unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int coun
n = zslFirstInRange(server.cluster->slots_to_keys, &range); n = zslFirstInRange(server.cluster->slots_to_keys, &range);
while(n && n->score == hashslot && count--) { while(n && n->score == hashslot && count--) {
keys[j++] = n->obj; keys[j++] = createStringObject(n->ele,sdslen(n->ele));
n = n->level[0].forward; n = n->level[0].forward;
} }
return j; return j;
@ -1224,9 +1226,9 @@ unsigned int delKeysInSlot(unsigned int hashslot) {
n = zslFirstInRange(server.cluster->slots_to_keys, &range); n = zslFirstInRange(server.cluster->slots_to_keys, &range);
while(n && n->score == hashslot) { while(n && n->score == hashslot) {
robj *key = n->obj; sds sdskey = n->ele;
robj *key = createStringObject(sdskey,sdslen(sdskey));
n = n->level[0].forward; /* Go to the next item before freeing it. */ n = n->level[0].forward; /* Go to the next item before freeing it. */
incrRefCount(key); /* Protect the object while freeing it. */
dbDelete(&server.db[0],key); dbDelete(&server.db[0],key);
decrRefCount(key); decrRefCount(key);
j++; j++;
@ -1248,7 +1250,7 @@ unsigned int countKeysInSlot(unsigned int hashslot) {
/* Use rank of first element, if any, to determine preliminary count */ /* Use rank of first element, if any, to determine preliminary count */
if (zn != NULL) { if (zn != NULL) {
rank = zslGetRank(zsl, zn->score, zn->obj); rank = zslGetRank(zsl, zn->score, zn->ele);
count = (zsl->length - (rank - 1)); count = (zsl->length - (rank - 1));
/* Find last element in range */ /* Find last element in range */
@ -1256,7 +1258,7 @@ unsigned int countKeysInSlot(unsigned int hashslot) {
/* Use rank of last element, if any, to determine the actual count */ /* Use rank of last element, if any, to determine the actual count */
if (zn != NULL) { if (zn != NULL) {
rank = zslGetRank(zsl, zn->score, zn->obj); rank = zslGetRank(zsl, zn->score, zn->ele);
count -= (zsl->length - rank); count -= (zsl->length - rank);
} }
} }

@ -163,12 +163,9 @@ void computeDatasetDigest(unsigned char *final) {
listTypeReleaseIterator(li); listTypeReleaseIterator(li);
} else if (o->type == OBJ_SET) { } else if (o->type == OBJ_SET) {
setTypeIterator *si = setTypeInitIterator(o); setTypeIterator *si = setTypeInitIterator(o);
robj *ele;
sds sdsele; sds sdsele;
while((sdsele = setTypeNextObject(si)) != NULL) { while((sdsele = setTypeNextObject(si)) != NULL) {
ele = createObject(OBJ_STRING,sdsele); xorDigest(digest,sdsele,sdslen(sdsele));
xorObjectDigest(digest,ele);
decrRefCount(ele);
} }
setTypeReleaseIterator(si); setTypeReleaseIterator(si);
} else if (o->type == OBJ_ZSET) { } else if (o->type == OBJ_ZSET) {
@ -210,12 +207,12 @@ void computeDatasetDigest(unsigned char *final) {
dictEntry *de; dictEntry *de;
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
robj *eleobj = dictGetKey(de); sds sdsele = dictGetKey(de);
double *score = dictGetVal(de); double *score = dictGetVal(de);
snprintf(buf,sizeof(buf),"%.17g",*score); snprintf(buf,sizeof(buf),"%.17g",*score);
memset(eledigest,0,20); memset(eledigest,0,20);
mixObjectDigest(eledigest,eleobj); mixDigest(eledigest,sdsele,sdslen(sdsele));
mixDigest(eledigest,buf,strlen(buf)); mixDigest(eledigest,buf,strlen(buf));
xorDigest(digest,eledigest,20); xorDigest(digest,eledigest,20);
} }

@ -112,7 +112,7 @@ int extractLongLatOrReply(client *c, robj **argv,
int longLatFromMember(robj *zobj, robj *member, double *xy) { int longLatFromMember(robj *zobj, robj *member, double *xy) {
double score = 0; double score = 0;
if (zsetScore(zobj, member, &score) == C_ERR) return C_ERR; if (zsetScore(zobj, member->ptr, &score) == C_ERR) return C_ERR;
if (!decodeGeohash(score, xy)) return C_ERR; if (!decodeGeohash(score, xy)) return C_ERR;
return C_OK; return C_OK;
} }
@ -261,16 +261,14 @@ int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double l
} }
while (ln) { while (ln) {
robj *o = ln->obj; sds ele = ln->ele;
/* Abort when the node is no longer in range. */ /* Abort when the node is no longer in range. */
if (!zslValueLteMax(ln->score, &range)) if (!zslValueLteMax(ln->score, &range))
break; break;
member = (o->encoding == OBJ_ENCODING_INT) ? ele = sdsdup(ele);
sdsfromlonglong((long)o->ptr) : if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,ele)
sdsdup(o->ptr); == C_ERR) sdsfree(ele);
if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,member)
== C_ERR) sdsfree(member);
ln = ln->level[0].forward; ln = ln->level[0].forward;
} }
} }
@ -606,7 +604,7 @@ void geohashCommand(client *c) {
addReplyMultiBulkLen(c,c->argc-2); addReplyMultiBulkLen(c,c->argc-2);
for (j = 2; j < c->argc; j++) { for (j = 2; j < c->argc; j++) {
double score; double score;
if (zsetScore(zobj, c->argv[j], &score) == C_ERR) { if (zsetScore(zobj, c->argv[j]->ptr, &score) == C_ERR) {
addReply(c,shared.nullbulk); addReply(c,shared.nullbulk);
} else { } else {
/* The internal format we use for geocoding is a bit different /* The internal format we use for geocoding is a bit different
@ -660,7 +658,7 @@ void geoposCommand(client *c) {
addReplyMultiBulkLen(c,c->argc-2); addReplyMultiBulkLen(c,c->argc-2);
for (j = 2; j < c->argc; j++) { for (j = 2; j < c->argc; j++) {
double score; double score;
if (zsetScore(zobj, c->argv[j], &score) == C_ERR) { if (zsetScore(zobj, c->argv[j]->ptr, &score) == C_ERR) {
addReply(c,shared.nullmultibulk); addReply(c,shared.nullmultibulk);
} else { } else {
/* Decode... */ /* Decode... */
@ -700,8 +698,8 @@ void geodistCommand(client *c) {
/* Get the scores. We need both otherwise NULL is returned. */ /* Get the scores. We need both otherwise NULL is returned. */
double score1, score2, xyxy[4]; double score1, score2, xyxy[4];
if (zsetScore(zobj, c->argv[2], &score1) == C_ERR || if (zsetScore(zobj, c->argv[2]->ptr, &score1) == C_ERR ||
zsetScore(zobj, c->argv[3], &score2) == C_ERR) zsetScore(zobj, c->argv[3]->ptr, &score2) == C_ERR)
{ {
addReply(c,shared.nullbulk); addReply(c,shared.nullbulk);
return; return;

@ -622,10 +622,11 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
nwritten += n; nwritten += n;
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
robj *eleobj = dictGetKey(de); sds ele = dictGetKey(de);
double *score = dictGetVal(de); double *score = dictGetVal(de);
if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1; if ((n = rdbSaveRawString(rdb,(unsigned char*)ele,sdslen(ele)))
== -1) return -1;
nwritten += n; nwritten += n;
if ((n = rdbSaveDoubleValue(rdb,*score)) == -1) return -1; if ((n = rdbSaveDoubleValue(rdb,*score)) == -1) return -1;
nwritten += n; nwritten += n;
@ -992,7 +993,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
return NULL; return NULL;
if (o->encoding == OBJ_ENCODING_INTSET) { if (o->encoding == OBJ_ENCODING_INTSET) {
/* Fetch integer value from element */ /* Fetch integer value from element. */
if (isSdsRepresentableAsLongLong(sdsele,&llval) == C_OK) { if (isSdsRepresentableAsLongLong(sdsele,&llval) == C_OK) {
o->ptr = intsetAdd(o->ptr,llval,NULL); o->ptr = intsetAdd(o->ptr,llval,NULL);
} else { } else {
@ -1002,7 +1003,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
} }
/* This will also be called when the set was just converted /* This will also be called when the set was just converted
* to a regular hash table encoded set */ * to a regular hash table encoded set. */
if (o->encoding == OBJ_ENCODING_HT) { if (o->encoding == OBJ_ENCODING_HT) {
dictAdd((dict*)o->ptr,sdsele,NULL); dictAdd((dict*)o->ptr,sdsele,NULL);
} else { } else {
@ -1010,7 +1011,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
} }
} }
} else if (rdbtype == RDB_TYPE_ZSET) { } else if (rdbtype == RDB_TYPE_ZSET) {
/* Read list/set value */ /* Read list/set value. */
size_t zsetlen; size_t zsetlen;
size_t maxelelen = 0; size_t maxelelen = 0;
zset *zs; zset *zs;
@ -1019,23 +1020,21 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
o = createZsetObject(); o = createZsetObject();
zs = o->ptr; zs = o->ptr;
/* Load every single element of the list/set */ /* Load every single element of the sorted set. */
while(zsetlen--) { while(zsetlen--) {
robj *ele; sds sdsele;
double score; double score;
zskiplistNode *znode; zskiplistNode *znode;
if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; if ((sdsele = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS)) == NULL)
ele = tryObjectEncoding(ele); return NULL;
if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL; if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL;
/* Don't care about integer-encoded strings. */ /* Don't care about integer-encoded strings. */
if (sdsEncodedObject(ele) && sdslen(ele->ptr) > maxelelen) if (sdslen(sdsele) > maxelelen) maxelelen = sdslen(sdsele);
maxelelen = sdslen(ele->ptr);
znode = zslInsert(zs->zsl,score,ele); znode = zslInsert(zs->zsl,score,sdsele);
dictAdd(zs->dict,ele,&znode->score); dictAdd(zs->dict,sdsele,&znode->score);
incrRefCount(ele); /* added to skiplist */
} }
/* Convert *after* loading, since sorted sets are not stored ordered. */ /* Convert *after* loading, since sorted sets are not stored ordered. */

@ -554,11 +554,11 @@ dictType setDictType = {
/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */ /* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
dictType zsetDictType = { dictType zsetDictType = {
dictEncObjHash, /* hash function */ dictSdsHash, /* hash function */
NULL, /* key dup */ NULL, /* key dup */
NULL, /* val dup */ NULL, /* val dup */
dictEncObjKeyCompare, /* key compare */ dictSdsKeyCompare, /* key compare */
dictObjectDestructor, /* key destructor */ NULL, /* Note: SDS string shared & freed by skiplist */
NULL /* val destructor */ NULL /* val destructor */
}; };
@ -1428,8 +1428,8 @@ void createSharedObjects(void) {
* actually used for their value but as a special object meaning * actually used for their value but as a special object meaning
* respectively the minimum possible string and the maximum possible * respectively the minimum possible string and the maximum possible
* string in string comparisons for the ZRANGEBYLEX command. */ * string in string comparisons for the ZRANGEBYLEX command. */
shared.minstring = createStringObject("minstring",9); shared.minstring = sdsnew("minstring");
shared.maxstring = createStringObject("maxstring",9); shared.maxstring = sdsnew("maxstring");
} }
void initServerConfig(void) { void initServerConfig(void) {

@ -612,16 +612,17 @@ struct sharedObjectsStruct {
*masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr, *masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr,
*busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk, *busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk,
*unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop, *unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop,
*lpush, *emptyscan, *minstring, *maxstring, *lpush, *emptyscan,
*select[PROTO_SHARED_SELECT_CMDS], *select[PROTO_SHARED_SELECT_CMDS],
*integers[OBJ_SHARED_INTEGERS], *integers[OBJ_SHARED_INTEGERS],
*mbulkhdr[OBJ_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */ *mbulkhdr[OBJ_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */
*bulkhdr[OBJ_SHARED_BULKHDR_LEN]; /* "$<value>\r\n" */ *bulkhdr[OBJ_SHARED_BULKHDR_LEN]; /* "$<value>\r\n" */
sds minstring, maxstring;
}; };
/* ZSETs use a specialized version of Skiplists */ /* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode { typedef struct zskiplistNode {
robj *obj; sds ele;
double score; double score;
struct zskiplistNode *backward; struct zskiplistNode *backward;
struct zskiplistLevel { struct zskiplistLevel {
@ -1261,15 +1262,15 @@ typedef struct {
/* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */ /* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */
typedef struct { typedef struct {
robj *min, *max; /* May be set to shared.(minstring|maxstring) */ sds min, max; /* May be set to shared.(minstring|maxstring) */
int minex, maxex; /* are min or max exclusive? */ int minex, maxex; /* are min or max exclusive? */
} zlexrangespec; } zlexrangespec;
zskiplist *zslCreate(void); zskiplist *zslCreate(void);
void zslFree(zskiplist *zsl); void zslFree(zskiplist *zsl);
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj); zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele);
unsigned char *zzlInsert(unsigned char *zl, robj *ele, double score); unsigned char *zzlInsert(unsigned char *zl, sds ele, double score);
int zslDelete(zskiplist *zsl, double score, robj *obj); int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node);
zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range); zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range);
zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range); zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range);
double zzlGetScore(unsigned char *sptr); double zzlGetScore(unsigned char *sptr);
@ -1277,8 +1278,8 @@ void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr); void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
unsigned int zsetLength(robj *zobj); unsigned int zsetLength(robj *zobj);
void zsetConvert(robj *zobj, int encoding); void zsetConvert(robj *zobj, int encoding);
int zsetScore(robj *zobj, robj *member, double *score); int zsetScore(robj *zobj, sds member, double *score);
unsigned long zslGetRank(zskiplist *zsl, double score, robj *o); unsigned long zslGetRank(zskiplist *zsl, double score, sds o);
/* Core functions */ /* Core functions */
int freeMemoryIfNeeded(void); int freeMemoryIfNeeded(void);

@ -399,7 +399,7 @@ void sortCommand(client *c) {
zset *zs = sortval->ptr; zset *zs = sortval->ptr;
zskiplist *zsl = zs->zsl; zskiplist *zsl = zs->zsl;
zskiplistNode *ln; zskiplistNode *ln;
robj *ele; sds sdsele;
int rangelen = vectorlen; int rangelen = vectorlen;
/* Check if starting point is trivial, before doing log(N) lookup. */ /* Check if starting point is trivial, before doing log(N) lookup. */
@ -417,8 +417,8 @@ void sortCommand(client *c) {
while(rangelen--) { while(rangelen--) {
serverAssertWithInfo(c,sortval,ln != NULL); serverAssertWithInfo(c,sortval,ln != NULL);
ele = ln->obj; sdsele = ln->ele;
vector[j].obj = ele; vector[j].obj = createStringObject(sdsele,sdslen(sdsele));
vector[j].u.score = 0; vector[j].u.score = 0;
vector[j].u.cmpobj = NULL; vector[j].u.cmpobj = NULL;
j++; j++;
@ -431,9 +431,11 @@ void sortCommand(client *c) {
dict *set = ((zset*)sortval->ptr)->dict; dict *set = ((zset*)sortval->ptr)->dict;
dictIterator *di; dictIterator *di;
dictEntry *setele; dictEntry *setele;
sds sdsele;
di = dictGetIterator(set); di = dictGetIterator(set);
while((setele = dictNext(di)) != NULL) { while((setele = dictNext(di)) != NULL) {
vector[j].obj = dictGetKey(setele); sdsele = dictGetKey(setele);
vector[j].obj = createStringObject(sdsele,sdslen(sdsele));
vector[j].u.score = 0; vector[j].u.score = 0;
vector[j].u.cmpobj = NULL; vector[j].u.cmpobj = NULL;
j++; j++;

File diff suppressed because it is too large Load Diff