/* The following is only needed if VM is active, but since the conditional
* is probably more costly than initializing the field it's better to
* have every field properly initialized anyway. */
- o->storage = REDIS_DS_MEMORY;
return o;
}
robj *createStringObjectFromLongLong(long long value) {
robj *o;
if (value >= 0 && value < REDIS_SHARED_INTEGERS &&
+ !server.ds_enabled &&
pthread_equal(pthread_self(),server.mainthread)) {
incrRefCount(shared.integers[value]);
o = shared.integers[value];
robj *createZsetObject(void) {
zset *zs = zmalloc(sizeof(*zs));
+ robj *o;
zs->dict = dictCreate(&zsetDictType,NULL);
zs->zsl = zslCreate();
- return createObject(REDIS_ZSET,zs);
+ o = createObject(REDIS_ZSET,zs);
+ o->encoding = REDIS_ENCODING_SKIPLIST;
+ return o;
+}
+
+robj *createZsetZiplistObject(void) {
+ unsigned char *zl = ziplistNew();
+ robj *o = createObject(REDIS_ZSET,zl);
+ o->encoding = REDIS_ENCODING_ZIPLIST;
+ return o;
}
void freeStringObject(robj *o) {
}
void freeZsetObject(robj *o) {
- zset *zs = o->ptr;
-
- dictRelease(zs->dict);
- zslFree(zs->zsl);
- zfree(zs);
+ zset *zs;
+ switch (o->encoding) {
+ case REDIS_ENCODING_SKIPLIST:
+ zs = o->ptr;
+ dictRelease(zs->dict);
+ zslFree(zs->zsl);
+ zfree(zs);
+ break;
+ case REDIS_ENCODING_ZIPLIST:
+ zfree(o->ptr);
+ break;
+ default:
+ redisPanic("Unknown sorted set encoding");
+ }
}
void freeHashObject(robj *o) {
robj *o = obj;
if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
- if (--(o->refcount) == 0) {
- /* DS_SAVING objects should always have a reference in the
- * IO Job structure. So we should never reach this state. */
- redisAssert(o->storage != REDIS_DS_SAVING);
+ if (o->refcount == 1) {
switch(o->type) {
case REDIS_STRING: freeStringObject(o); break;
case REDIS_LIST: freeListObject(o); break;
case REDIS_HASH: freeHashObject(o); break;
default: redisPanic("Unknown object type"); break;
}
- o->ptr = NULL; /* defensive programming. We'll see NULL in traces. */
zfree(o);
+ } else {
+ o->refcount--;
}
}
return 0;
}
+int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
+ redisAssert(o->type == REDIS_STRING);
+ if (o->encoding == REDIS_ENCODING_INT) {
+ if (llval) *llval = (long) o->ptr;
+ return REDIS_OK;
+ } else {
+ return string2ll(o->ptr,sdslen(o->ptr),llval) ? REDIS_OK : REDIS_ERR;
+ }
+}
+
/* Try to encode a string object in order to save space */
robj *tryObjectEncoding(robj *o) {
long value;
redisAssert(o->type == REDIS_STRING);
/* Check if we can represent this string as a long integer */
- if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return o;
+ if (!string2l(s,sdslen(s),&value)) return o;
/* Ok, this object can be encoded...
*
* Note that we also avoid using shared integers when maxmemory is used
* because every object needs to have a private LRU field for the LRU
* algorithm to work well. */
- if (server.ds_enabled == 0 &&
+ if (!server.ds_enabled &&
server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS &&
pthread_equal(pthread_self(),server.mainthread))
{
case REDIS_ENCODING_LINKEDLIST: return "linkedlist";
case REDIS_ENCODING_ZIPLIST: return "ziplist";
case REDIS_ENCODING_INTSET: return "intset";
+ case REDIS_ENCODING_SKIPLIST: return "skiplist";
default: return "unknown";
}
}
REDIS_LRU_CLOCK_RESOLUTION;
}
}
+
+/* This is an helper function for the DEBUG command. We need to lookup keys
+ * without any modification of LRU or other parameters. */
+robj *objectCommandLookup(redisClient *c, robj *key) {
+ dictEntry *de;
+
+ if ((de = dictFind(c->db->dict,key->ptr)) == NULL) return NULL;
+ return (robj*) dictGetEntryVal(de);
+}
+
+robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply) {
+ robj *o = objectCommandLookup(c,key);
+
+ if (!o) addReply(c, reply);
+ return o;
+}
+
+/* Object command allows to inspect the internals of an Redis Object.
+ * Usage: OBJECT <verb> ... arguments ... */
+void objectCommand(redisClient *c) {
+ robj *o;
+
+ if (!strcasecmp(c->argv[1]->ptr,"refcount") && c->argc == 3) {
+ if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
+ == NULL) return;
+ addReplyLongLong(c,o->refcount);
+ } else if (!strcasecmp(c->argv[1]->ptr,"encoding") && c->argc == 3) {
+ if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
+ == NULL) return;
+ addReplyBulkCString(c,strEncoding(o->encoding));
+ } else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) {
+ if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
+ == NULL) return;
+ addReplyLongLong(c,estimateObjectIdleTime(o));
+ } else {
+ addReplyError(c,"Syntax error. Try OBJECT (refcount|encoding|idletime)");
+ }
+}
+