return REDIS_OK;
fmterr:
- redisLog(REDIS_WARNING,"Unrecovarable error: corrupted cluster.conf file.");
+ redisLog(REDIS_WARNING,"Unrecovarable error: corrupted cluster config file.");
fclose(fp);
exit(1);
}
*
* This function writes the node config and returns 0, on error -1
* is returned. */
-int clusterSaveConfig(char *filename) {
+int clusterSaveConfig(void) {
sds ci = clusterGenNodesDescription();
int fd;
- if ((fd = open(filename,O_WRONLY|O_CREAT,0644)) == -1) goto err;
+ if ((fd = open(server.cluster.configfile,O_WRONLY|O_CREAT,0644)) == -1)
+ goto err;
if (write(fd,ci,sdslen(ci)) != (ssize_t)sdslen(ci)) goto err;
close(fd);
sdsfree(ci);
return -1;
}
+void clusterSaveConfigOrDie(void) {
+ if (clusterSaveConfig() == -1) {
+ redisLog(REDIS_WARNING,"Fatal: can't update cluster config file.");
+ exit(1);
+ }
+}
+
void clusterInit(void) {
+ int saveconf = 0;
+
server.cluster.myself = createClusterNode(NULL,REDIS_NODE_MYSELF);
server.cluster.state = REDIS_CLUSTER_FAIL;
server.cluster.nodes = dictCreate(&clusterNodesDictType,NULL);
sizeof(server.cluster.importing_slots_from));
memset(server.cluster.slots,0,
sizeof(server.cluster.slots));
- if (clusterLoadConfig("cluster.conf") == REDIS_ERR) {
+ if (clusterLoadConfig(server.cluster.configfile) == REDIS_ERR) {
/* No configuration found. We will just use the random name provided
* by the createClusterNode() function. */
redisLog(REDIS_NOTICE,"No cluster configuration found, I'm %.40s",
server.cluster.myself->name);
- if (clusterSaveConfig("cluster.conf") == -1) {
- redisLog(REDIS_WARNING,"Fatal: can't update cluster config file.");
- exit(1);
- }
+ clusterAddNode(server.cluster.myself);
+ saveconf = 1;
}
- clusterAddNode(server.cluster.myself);
+ if (saveconf) clusterSaveConfigOrDie();
/* We need a listening TCP port for our cluster messaging needs */
server.cfd = anetTcpServer(server.neterr,
server.port+REDIS_CLUSTER_PORT_INCR, server.bindaddr);
sds ci = sdsempty();
dictIterator *di;
dictEntry *de;
+ int j, start;
di = dictGetIterator(server.cluster.nodes);
while((de = dictNext(di)) != NULL) {
ci = sdscatprintf(ci,"- ");
/* Latency from the POV of this node, link status */
- ci = sdscatprintf(ci,"%ld %ld %s\n",
+ ci = sdscatprintf(ci,"%ld %ld %s",
(long) node->ping_sent,
(long) node->pong_received,
node->link ? "connected" : "disconnected");
+
+ /* Slots served by this instance */
+ start = -1;
+ for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) {
+ int bit;
+
+ if ((bit = clusterNodeGetSlotBit(node,j)) != 0) {
+ if (start == -1) start = j;
+ }
+ if (start != -1 && (!bit || j == REDIS_CLUSTER_SLOTS-1)) {
+ if (j == REDIS_CLUSTER_SLOTS-1) j++;
+
+ if (start == j-1) {
+ ci = sdscatprintf(ci," %d",start);
+ } else {
+ ci = sdscatprintf(ci," %d-%d",start,j-1);
+ }
+ start = -1;
+ }
+ }
}
+ ci = sdscatlen(ci,"\n",1);
dictReleaseIterator(di);
return ci;
}
/* Finally create the object from the serialized dump and
* store it at the specified key. */
- o = rdbLoadObject(data[0],fp);
- if (o == NULL) {
+ if ((data[0] > 4 && data[0] < 9) ||
+ data[0] > 11 ||
+ (o = rdbLoadObject(data[0],fp)) == NULL)
+ {
addReplyError(c,"Bad data format.");
fclose(fp);
return;
strerror(errno));
fclose(fp);
close(fd);
+ return;
file_rd_err:
redisLog(REDIS_WARNING,"Can't read from tmp file for MIGRATE: %s",
strerror(errno));
fclose(fp);
close(fd);
+ return;
socket_wr_err:
redisLog(REDIS_NOTICE,"Can't write to target node for MIGRATE: %s",
strerror(errno));
fclose(fp);
close(fd);
+ return;
socket_rd_err:
redisLog(REDIS_NOTICE,"Can't read from target node for MIGRATE: %s",
strerror(errno));
fclose(fp);
close(fd);
+ return;
+}
+
+/* DUMP keyname
+ * DUMP is actually not used by Redis Cluster but it is the obvious
+ * complement of RESTORE and can be useful for different applications. */
+void dumpCommand(redisClient *c) {
+ char buf[64];
+ FILE *fp;
+ robj *o, *dumpobj;
+ sds dump = NULL;
+ off_t payload_len;
+ unsigned int type;
+
+ /* Check if the key is here. */
+ if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) {
+ addReply(c,shared.nullbulk);
+ return;
+ }
+
+ /* Create temp file */
+ snprintf(buf,sizeof(buf),"redis-dump-%d.tmp",getpid());
+ fp = fopen(buf,"w+");
+ if (!fp) {
+ redisLog(REDIS_WARNING,"Can't open tmp file for MIGRATE: %s",
+ strerror(errno));
+ addReplyErrorFormat(c,"DUMP failed, tmp file creation error: %s.",
+ strerror(errno));
+ return;
+ }
+ unlink(buf);
+
+ /* Dump the serailized object and read it back in memory.
+ * We prefix it with a one byte containing the type ID.
+ * This is the serialization format understood by RESTORE. */
+ if (rdbSaveObject(fp,o) == -1) goto file_wr_err;
+ payload_len = ftello(fp);
+ if (fseeko(fp,0,SEEK_SET) == -1) goto file_rd_err;
+ dump = sdsnewlen(NULL,payload_len+1);
+ if (payload_len && fread(dump+1,payload_len,1,fp) != 1) goto file_rd_err;
+ fclose(fp);
+ type = o->type;
+ if (type == REDIS_LIST && o->encoding == REDIS_ENCODING_ZIPLIST)
+ type = REDIS_LIST_ZIPLIST;
+ else if (type == REDIS_HASH && o->encoding == REDIS_ENCODING_ZIPMAP)
+ type = REDIS_HASH_ZIPMAP;
+ else if (type == REDIS_SET && o->encoding == REDIS_ENCODING_INTSET)
+ type = REDIS_SET_INTSET;
+ else
+ type = o->type;
+ dump[0] = type;
+
+ /* Transfer to the client */
+ dumpobj = createObject(REDIS_STRING,dump);
+ addReplyBulk(c,dumpobj);
+ decrRefCount(dumpobj);
+ return;
+
+file_wr_err:
+ redisLog(REDIS_WARNING,"Can't write on tmp file for DUMP: %s",
+ strerror(errno));
+ addReplyErrorFormat(c,"DUMP failed, tmp file write error: %s.",
+ strerror(errno));
+ sdsfree(dump);
+ fclose(fp);
+ return;
+
+file_rd_err:
+ redisLog(REDIS_WARNING,"Can't read from tmp file for DUMP: %s",
+ strerror(errno));
+ addReplyErrorFormat(c,"DUMP failed, tmp file read error: %s.",
+ strerror(errno));
+ sdsfree(dump);
+ fclose(fp);
+ return;
}
/* -----------------------------------------------------------------------------