Ejemplo n.º 1
0
static BOOL SaveState(FILE *fp, QDPLUS_DIGITIZER *digitizer)
{
QDP_LC *lc;
LNKLST_NODE *crnt;

/* write out digitizer serial number */

    if (fwrite(&digitizer->serialno, sizeof(UINT64), 1, fp) != 1) return FALSE;

/* write out each active HLP */
    
    crnt = listFirstNode(digitizer->lcq.lc);
    while (crnt != NULL) {
        lc = (QDP_LC *) crnt->payload;
        if (lc->hlp != NULL && lc->hlp->nsamp != 0) {
            if (!isiWriteSeqno(fp, &lc->hlp->seqno)) return FALSE;
            if (fwrite(lc->hlp->chn, QDP_CNAME_LEN+1, 1, fp) != 1) return FALSE;
            if (fwrite(lc->hlp->loc, QDP_LNAME_LEN+1, 1, fp) != 1) return FALSE;
            if (fwrite(&lc->hlp->offset, sizeof(INT32), 1, fp) != 1) return FALSE;
        }
        crnt = listNextNode(crnt);
    }

/* flag end of list with undefined sequence number */

    if (!isiWriteSeqno(fp, &ISI_UNDEFINED_SEQNO)) return FALSE;

    return TRUE;
}
Ejemplo n.º 2
0
BOOL qdplusSaveState(QDPLUS *handle)
{
FILE *fp;
LNKLST_NODE *crnt;
UINT16 dirty = QDPLUS_FLAG_DIRTY;
UINT16 clean = QDPLUS_FLAG_CLEAN;
QDPLUS_DIGITIZER *digitizer;

    if ((fp = OpenStateFile(handle, "wb", NULL)) == NULL) return FALSE;

    if (fwrite(&dirty, sizeof(UINT16), 1, fp) != 1) {
        fclose(fp);
        return FALSE;
    }

    fflush(fp);

    crnt = listFirstNode(handle->list.digitizer);
    while (crnt != NULL) {
        if (!SaveState(fp, (QDPLUS_DIGITIZER *) crnt->payload)) {
            fclose(fp);
            return FALSE;
        }
        crnt = listNextNode(crnt);
    }

    rewind(fp);
    if (fwrite(&clean, sizeof(UINT16), 1, fp) != 1) {
        fclose(fp);
        return FALSE;
    }

    fclose(fp);
    return TRUE;
}
Ejemplo n.º 3
0
void qdplusPrintState(FILE *fp, QDPLUS *handle)
{
LNKLST_NODE *crnt;
QDPLUS_DIGITIZER *digitizer;

    if (fp == NULL || handle == NULL) return;

    if (handle->par.path.state != NULL) {
        fprintf(fp, "%s\n", handle->par.path.state);
    } else {
        fprintf(fp, "qdplusPrintState called with NULL par.path.state!\n");
    }

    if ((crnt = listFirstNode(handle->list.digitizer)) == NULL) {
        fprintf(fp, "empty file\n");
        return;
    }

    while (crnt != NULL) {
        digitizer = (QDPLUS_DIGITIZER *) crnt->payload;
        fprintf(fp, "S/N %016llX\n", digitizer->serialno);
        PrintState(fp, digitizer->state);
        crnt = listNextNode(crnt);
    }

    fflush(fp);
}
Ejemplo n.º 4
0
void printttglist()
    {
    char msg[101];
    LNKLST_NODE *node; 

    printf("\nDATA GAP INFO\n");

    node = listFirstNode(messageList);

    if(node==NULL)
        {
        printf("\nNo gaps found\n");
        }
    else
        {
        memset(msg,' ', 101);msg[99]='\n';msg[100]=0;
        memcpy(msg,"Stream",6);
        memcpy(&msg[40],"Gap",3);
        memcpy(&msg[80],"Length",6);
        printf(msg);
        }
    while (node != NULL) 
        {
        printf((char *)node->payload);
        node = listNextNode(node);
        }

    DeleteLists();
    }
Ejemplo n.º 5
0
/* get data for socket / fd being monitored. Create if not found*/
aeSockState *aeGetSockState(void *apistate, int fd) {
    int sindex;
    listNode *node;
    list *socklist;
    aeSockState *sockState;
    if (apistate == NULL) return NULL;

    sindex = aeSocketIndex(fd);
    socklist = &(((aeApiState *)apistate)->lookup[sindex]);
    node = listFirst(socklist);
    while (node != NULL) {
        sockState = (aeSockState *)listNodeValue(node);
        if (sockState->fd == fd) {
            return sockState;
        }
        node = listNextNode(node);
    }
    // not found. Do lazy create of sockState.
    sockState = (aeSockState *) zmalloc(sizeof(aeSockState));
    if (sockState != NULL) {
        sockState->fd = fd;
        sockState->masks = 0;
        sockState->wreqs = 0;
        sockState->reqs = NULL;
        memset(&sockState->wreqlist, 0, sizeof(sockState->wreqlist));
        memset(&sockState->remoteAddress, 0, sizeof(sockState->remoteAddress));

        if (listAddNodeHead(socklist, sockState) != NULL) {
            return sockState;
        } else {
            zfree(sockState);
        }
    }
    return NULL;
}
Ejemplo n.º 6
0
static void WalkData(QDP_LCQ *lcq)
{
QDP_LC *lc;
LNKLST_NODE *crnt;

    crnt = listFirstNode(lcq->lc);
    while (crnt != NULL) {
        lc = (QDP_LC *) crnt->payload;
        PrintLC(lcq, lc);
        crnt = listNextNode(crnt);
    }
}
Ejemplo n.º 7
0
static void trigger_thread(void *args)
{
	SetThreadName("JSRT Trigger");
	for(;;) {
		list_node_t *node;
		pthread_mutex_lock(&jsrt_mutex);
		for(node=listFirstNode(&rt_list); node; node=listNextNode(node))
			JS_TriggerAllOperationCallbacks(node->data);
		pthread_mutex_unlock(&jsrt_mutex);
		SLEEP(100);
	}
}
Ejemplo n.º 8
0
// find matching value in list and remove. If found return 1
int removeMatchFromList(list *socklist, void *value) {
    listNode *node;
    if (socklist == NULL) return 0;
    node = listFirst(socklist);
    while (node != NULL) {
        if (listNodeValue(node) == value) {
            listDelNode(socklist, node);
            return 1;
        }
        node = listNextNode(node);
    }
    return 0;
}
Ejemplo n.º 9
0
/* Find matching value in list and remove. If found return TRUE */
BOOL removeMatchFromList(list *requestlist, void *value) {
    listNode *node;
    if (requestlist == NULL) {
        return FALSE;
    }
    node = listFirst(requestlist);
    while (node != NULL) {
        if (listNodeValue(node) == value) {
            listDelNode(requestlist, node);
            return TRUE;
        }
        node = listNextNode(node);
    }
    return FALSE;
}
int utilFlushAllBufferedStream()
	{
	UINT32 count = 0;
	LNKLST_NODE *crnt;
	BufferedStream  *p;

    crnt = listFirstNode(&list);
    while (crnt != NULL) 
		{
		p = (BufferedStream  *)crnt->payload;
		utilFlushBuffer(p);
        crnt = listNextNode(crnt);
		}
	return 0;
	}
Ejemplo n.º 11
0
static void StateSeqnoLimits(QDPLUS_DIGITIZER *digitizer, ISI_SEQNO *beg, ISI_SEQNO *end)
{
LNKLST_NODE *crnt;
QDPLUS_STATE *state;

    crnt = listFirstNode(digitizer->state);
    while (crnt != NULL) {
        state = (QDPLUS_STATE *) crnt->payload;
        if (isiIsUndefinedSeqno(beg)) *beg = state->seqno;
        if (isiIsUndefinedSeqno(end)) *end = state->seqno;
        if (isiSeqnoLT(&state->seqno, beg)) *beg = state->seqno;
        if (isiSeqnoGT(&state->seqno, end)) *end = state->seqno;
        crnt = listNextNode(crnt);
    }
}
Ejemplo n.º 12
0
static void PrintState(FILE *fp, LNKLST *head)
{
LNKLST_NODE *crnt;
QDPLUS_STATE *state;

    if (fp == NULL || state == NULL) return;

    crnt = listFirstNode(head);
    while (crnt != NULL) {
        state = (QDPLUS_STATE *) crnt->payload;
        fprintf(fp, "%3s", state->chn);
        fprintf(fp, " %2s", state->loc);
        fprintf(fp, " %08lx%016llx", state->seqno.signature, state->seqno.counter);
        fprintf(fp, " %ld", state->offset);
        fprintf(fp, "\n");
        crnt = listNextNode(crnt);
    }
}
Ejemplo n.º 13
0
/* get data for socket / fd being monitored */
aeSockState *aeGetExistingSockState(void *apistate, int fd) {
    int sindex;
    listNode *node;
    list *socklist;
    aeSockState *sockState;
    if (apistate == NULL) return NULL;

    sindex = aeSocketIndex(fd);
    socklist = &(((aeApiState *)apistate)->lookup[sindex]);
    node = listFirst(socklist);
    while (node != NULL) {
        sockState = (aeSockState *)listNodeValue(node);
        if (sockState->fd == fd) {
            return sockState;
        }
        node = listNextNode(node);
    }

    return NULL;
}
BufferedStream  *utilOpenBufferedStream(char *pFileName)
	{
	int nLen;
	BufferedStream  *p;
	BufferedStream  obf;

	UINT32 count = 0;
	LNKLST_NODE *crnt;

    crnt = listFirstNode(&list);
    while (crnt != NULL) 
		{
		p = (BufferedStream  *)crnt->payload;
		if(strcmp(p->cFileName, pFileName)==0)
			{
			return p;
			}
        crnt = listNextNode(crnt);
		}
	
	nLen = strlen(pFileName);
	if(nLen<sizeof(obf.cFileName)-1)
		STRCPY(obf.cFileName, pFileName);
	else
		{
		strncpy(obf.cFileName, pFileName, sizeof(obf.cFileName)-1);
		obf.cFileName[sizeof(obf.cFileName)-1]=0;
		}

	obf.nBytes=0;
	obf.nTotalBytes=0;

	if(listAppend(&list, &obf, sizeof(obf)))
		{
		crnt = listLastNode(&list);
		p = (BufferedStream  *)crnt->payload;
		return p;
		}
	return NULL;
	}
Ejemplo n.º 15
0
int ispSendChnLocMap(int sd, char *buffer, IDA *ida, int to)
{
LNKLST_NODE *crnt;
IDA_CHNLOCMAP *entry;
int msglen, status;

    if (ida == NULL) return ISP_OK;
    if (ida->chnlocmap == NULL) return ISP_OK;
    msglen = EncodeChnLocMapName(buffer+4, ida);
    status = isp_send(sd, ISP_CHNMAP, buffer, msglen, to);
    if (status != ISP_OK) return status;

    crnt = listFirstNode(ida->chnlocmap);
    while (crnt != NULL) {
        entry = (IDA_CHNLOCMAP *) crnt->payload;
        status = SendChnLocMapEntry(sd, buffer, entry, to);
        if (status != ISP_OK) return status;
        crnt = listNextNode(crnt);
    }

    return ISP_OK;
}
Ejemplo n.º 16
0
BOOL qdplusStateSeqnoLimits(QDPLUS *handle, ISI_SEQNO *beg, ISI_SEQNO *end)
{
LNKLST_NODE *crnt;
QDPLUS_DIGITIZER *digitizer;

    if (handle == NULL || beg == NULL || end == NULL) {
        errno = EINVAL;
        return FALSE;
    }

    *beg = ISI_UNDEFINED_SEQNO;
    *end = ISI_UNDEFINED_SEQNO;

    if ((crnt = listFirstNode(handle->list.digitizer)) == NULL) return TRUE;

    while (crnt != NULL) {
        digitizer = (QDPLUS_DIGITIZER *) crnt->payload;
        StateSeqnoLimits(digitizer, beg, end);
        crnt = listNextNode(crnt);
    }

    return TRUE;
}
Ejemplo n.º 17
0
BOOL qdpBuildHLP(QDP_LCQ *lcq)
{
QDP_LC *lc;
LNKLST_NODE *crnt;
static char *fid = "qdpBuildHLP";

    if (!lcq->par.rules.valid) {
        qdpLcqWarn(lcq, "%s: WARNING: unexpected invalid rules!  Logic error? (sn=%016llX, addr=%08x)", fid, lcq->meta.combo.fix.sys_num, &lcq->par.rules);
        return TRUE;
    }

    crnt = listFirstNode(lcq->lc);
    while (crnt != NULL) {
        lc = (QDP_LC *) crnt->payload;
        if (lc->hlp == NULL) {
            qdpLcqError(lcq, "%s: ERROR: unexpected NULL hlp!\n", fid);
            return FALSE;
        }
        if (lc->state == QDP_LC_STATE_FULL && !BuildHLP(lcq, lc)) return FALSE;
        crnt = listNextNode(crnt);
    }

    return TRUE;
}
Ejemplo n.º 18
0
static stream_t *getStream(int nstream)
    {
    stream_t stt, *pstt;

    LNKLST_NODE *node; 
    node = listFirstNode(streamList);

    while (node != NULL) 
        {
        pstt = node->payload;
        if(pstt->nstream==nstream) break;
        node = listNextNode(node);
        }

    if(node==NULL)
        {
        stt.t       = 0.;
        stt.nstream = nstream;
        listAppend(streamList, &stt, sizeof(stt)); 
        node = listLastNode(streamList);
        }

    return (stream_t *)node->payload;
    }
Ejemplo n.º 19
0
/* return array of sockets that are ready for read or write 
   depending on the mask for each socket */
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
    aeApiState *state = (aeApiState *)eventLoop->apidata;
    aeSockState *sockstate;
    ULONG j;
    int numevents = 0;
    ULONG numComplete = 0;
    int rc;
	int mswait = (tvp == NULL) ? 100 : (tvp->tv_sec * 1000) + (tvp->tv_usec / 1000);

    if (pGetQueuedCompletionStatusEx != NULL) {
        /* first get an array of completion notifications */
        rc = pGetQueuedCompletionStatusEx(state->iocp,
                                        state->entries,
                                        MAX_COMPLETE_PER_POLL,
                                        &numComplete,
                                        mswait,
                                        FALSE);
    } else {
        /* need to get one at a time. Use first array element */
        rc = GetQueuedCompletionStatus(state->iocp,
                                        &state->entries[0].dwNumberOfBytesTransferred,
                                        &state->entries[0].lpCompletionKey,
                                        &state->entries[0].lpOverlapped,
                                        mswait);
        if (!rc && state->entries[0].lpOverlapped == NULL) {
            // timeout. Return.
            return 0;
        } else {
            // check if more completions are ready
            int lrc = 1;
            rc = 1;
            numComplete = 1;

            while (numComplete < MAX_COMPLETE_PER_POLL) {
                lrc = GetQueuedCompletionStatus(state->iocp,
                                                &state->entries[numComplete].dwNumberOfBytesTransferred,
                                                &state->entries[numComplete].lpCompletionKey,
                                                &state->entries[numComplete].lpOverlapped,
                                                0);
                if (lrc) {
                   numComplete++;
                } else {
                    if (state->entries[numComplete].lpOverlapped == NULL) break;
                }
            }
        }
    }

    if (rc && numComplete > 0) {
        LPOVERLAPPED_ENTRY entry = state->entries;
        for (j = 0; j < numComplete && numevents < state->setsize; j++, entry++) {
            /* the competion key is the socket */
            int rfd = (int)entry->lpCompletionKey;
            sockstate = aeGetExistingSockState(state, rfd);

            if (sockstate != NULL) {
                if ((sockstate->masks & LISTEN_SOCK) && entry->lpOverlapped != NULL) {
                    /* need to set event for listening */
                    aacceptreq *areq = (aacceptreq *)entry->lpOverlapped;
                    areq->next = sockstate->reqs;
                    sockstate->reqs = areq;
                    sockstate->masks &= ~ACCEPT_PENDING;
                    if (sockstate->masks & AE_READABLE) {
                        eventLoop->fired[numevents].fd = rfd;
                        eventLoop->fired[numevents].mask = AE_READABLE;
                        numevents++;
                    }
                } else if (sockstate->masks & CONNECT_PENDING) {
                    /* check if connect complete */
                    if (entry->lpOverlapped == &sockstate->ov_read) {
                        sockstate->masks &= ~CONNECT_PENDING;
                        /* enable read and write events for this connection */
                        aeApiAddEvent(eventLoop, rfd, sockstate->masks);
                    }
                } else {
                    int matched = 0;
                    /* check if event is read complete (may be 0 length read) */
                    if (entry->lpOverlapped == &sockstate->ov_read) {
                        matched = 1;
                        sockstate->masks &= ~READ_QUEUED;
                        if (sockstate->masks & AE_READABLE) {
                            eventLoop->fired[numevents].fd = rfd;
                            eventLoop->fired[numevents].mask = AE_READABLE;
                            numevents++;
                        }
                    } else if (sockstate->wreqs > 0 && entry->lpOverlapped != NULL) {
                        /* should be write complete. Get results */
                        asendreq *areq = (asendreq *)entry->lpOverlapped;
                        matched = removeMatchFromList(&sockstate->wreqlist, areq);
                        if (matched) {
                            /* call write complete callback so buffers can be freed */
                            if (areq->proc != NULL) {
                                DWORD written = 0;
                                DWORD flags;
                                WSAGetOverlappedResult(rfd, &areq->ov, &written, FALSE, &flags);
                                areq->proc(areq->eventLoop, rfd, &areq->req, (int)written);
                            }
                            sockstate->wreqs--;
                            zfree(areq);
                            /* if no active write requests, set ready to write */
                            if (sockstate->wreqs == 0 && sockstate->masks & AE_WRITABLE) {
                                eventLoop->fired[numevents].fd = rfd;
                                eventLoop->fired[numevents].mask = AE_WRITABLE;
                                numevents++;
                            }
                        }
                    }
                    if (matched == 0) {
                        /* redisLog */printf("Sec:%lld Unknown complete (closed) on %d\n", gettimeofdaysecs(NULL), rfd);
                        sockstate = NULL;
                    }
                }
            } else {
                // no match for active connection.
                // Try the closing list.
                list *socklist = &(state->closing);
                listNode *node;
                node = listFirst(socklist);
                while (node != NULL) {
                    sockstate = (aeSockState *)listNodeValue(node);
                    if (sockstate->fd == rfd) {
                        if (sockstate->masks & CONNECT_PENDING) {
                            /* check if connect complete */
                            if (entry->lpOverlapped == &sockstate->ov_read) {
                                sockstate->masks &= ~CONNECT_PENDING;
                            }
                        } else if (entry->lpOverlapped == &sockstate->ov_read) {
                            // read complete
                            sockstate->masks &= ~READ_QUEUED;
                        } else {
                            // check pending writes
                            asendreq *areq = (asendreq *)entry->lpOverlapped;
                            if (removeMatchFromList(&sockstate->wreqlist, areq)) {
                                sockstate->wreqs--;
                                zfree(areq);
                            }
                        }
                        if (sockstate->wreqs == 0 &&
                            (sockstate->masks & (CONNECT_PENDING | READ_QUEUED | SOCKET_ATTACHED)) == 0) {
                            if ((sockstate->masks & CLOSE_PENDING) != 0) {
                                close(rfd);
                                sockstate->masks &= ~(CLOSE_PENDING);
                            }
                            // safe to delete sockstate
                            aeDelSockState(state, sockstate);
                        }
                        break;
                    }
                    node = listNextNode(node);
                }
            }
        }
    }
    return numevents;
}
Ejemplo n.º 20
0
void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
{
    redisClient *c = privdata;
    int nwritten = 0, totwritten = 0, objlen, willwrite;
    robj *o;
    struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
    int offset, ion = 0;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(mask);

    listNode *node;
    while (listLength(c->reply)) {
        offset = c->sentlen;
        ion = 0;
        willwrite = 0;

        /* fill-in the iov[] array */
        for(node = listFirst(c->reply); node; node = listNextNode(node)) {
            o = listNodeValue(node);
            objlen = sdslen(o->ptr);

            if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
                break;

            if(ion == REDIS_WRITEV_IOVEC_COUNT)
                break; /* no more iovecs */

            iov[ion].iov_base = ((char*)o->ptr) + offset;
            iov[ion].iov_len = objlen - offset;
            willwrite += objlen - offset;
            offset = 0; /* just for the first item */
            ion++;
        }

        if(willwrite == 0)
            break;

        /* write all collected blocks at once */
        if((nwritten = writev(fd, iov, ion)) < 0) {
            if (errno != EAGAIN) {
                redisLog(REDIS_VERBOSE,
                         "Error writing to client: %s", strerror(errno));
                freeClient(c);
                return;
            }
            break;
        }

        totwritten += nwritten;
        offset = c->sentlen;

        /* remove written robjs from c->reply */
        while (nwritten && listLength(c->reply)) {
            o = listNodeValue(listFirst(c->reply));
            objlen = sdslen(o->ptr);

            if(nwritten >= objlen - offset) {
                listDelNode(c->reply, listFirst(c->reply));
                nwritten -= objlen - offset;
                c->sentlen = 0;
            } else {
                /* partial write */
                c->sentlen += nwritten;
                break;
            }
            offset = 0;
        }
    }

    if (totwritten > 0)
        c->lastinteraction = time(NULL);

    if (listLength(c->reply) == 0) {
        c->sentlen = 0;
        aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
    }
}
Ejemplo n.º 21
0
/* This command implements SCAN, HSCAN and SSCAN commands.
 * If object 'o' is passed, then it must be a Hash or Set object, otherwise
 * if 'o' is NULL the command will operate on the dictionary associated with
 * the current database.
 *
 * When 'o' is not NULL the function assumes that the first argument in
 * the client arguments vector is a key so it skips it before iterating
 * in order to parse options.
 *
 * In the case of a Hash object the function returns both the field and value
 * of every element on the Hash. */
void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
    int i, j;
    list *keys = listCreate();
    listNode *node, *nextnode;
    long count = 10;
    sds pat = NULL;
    int patlen = 0, use_pattern = 0;
    dict *ht;

    /* Object must be NULL (to iterate keys names), or the type of the object
     * must be Set, Sorted Set, or Hash. */
    serverAssert(o == NULL || o->type == OBJ_SET || o->type == OBJ_HASH ||
                o->type == OBJ_ZSET);

    /* Set i to the first option argument. The previous one is the cursor. */
    i = (o == NULL) ? 2 : 3; /* Skip the key argument if needed. */

    /* Step 1: Parse options. */
    while (i < c->argc) {
        j = c->argc - i;
        if (!strcasecmp(c->argv[i]->ptr, "count") && j >= 2) {
            if (getLongFromObjectOrReply(c, c->argv[i+1], &count, NULL)
                != C_OK)
            {
                goto cleanup;
            }

            if (count < 1) {
                addReply(c,shared.syntaxerr);
                goto cleanup;
            }

            i += 2;
        } else if (!strcasecmp(c->argv[i]->ptr, "match") && j >= 2) {
            pat = c->argv[i+1]->ptr;
            patlen = sdslen(pat);

            /* The pattern always matches if it is exactly "*", so it is
             * equivalent to disabling it. */
            use_pattern = !(pat[0] == '*' && patlen == 1);

            i += 2;
        } else {
            addReply(c,shared.syntaxerr);
            goto cleanup;
        }
    }

    /* Step 2: Iterate the collection.
     *
     * Note that if the object is encoded with a ziplist, intset, or any other
     * representation that is not a hash table, we are sure that it is also
     * composed of a small number of elements. So to avoid taking state we
     * just return everything inside the object in a single call, setting the
     * cursor to zero to signal the end of the iteration. */

    /* Handle the case of a hash table. */
    ht = NULL;
    if (o == NULL) {
        ht = c->db->dict;
    } else if (o->type == OBJ_SET && o->encoding == OBJ_ENCODING_HT) {
        ht = o->ptr;
    } else if (o->type == OBJ_HASH && o->encoding == OBJ_ENCODING_HT) {
        ht = o->ptr;
        count *= 2; /* We return key / value for this type. */
    } else if (o->type == OBJ_ZSET && o->encoding == OBJ_ENCODING_SKIPLIST) {
        zset *zs = o->ptr;
        ht = zs->dict;
        count *= 2; /* We return key / value for this type. */
    }

    if (ht) {
        void *privdata[2];
        /* We set the max number of iterations to ten times the specified
         * COUNT, so if the hash table is in a pathological state (very
         * sparsely populated) we avoid to block too much time at the cost
         * of returning no or very few elements. */
        long maxiterations = count*10;

        /* We pass two pointers to the callback: the list to which it will
         * add new elements, and the object containing the dictionary so that
         * it is possible to fetch more data in a type-dependent way. */
        privdata[0] = keys;
        privdata[1] = o;
        do {
            cursor = dictScan(ht, cursor, scanCallback, privdata);
        } while (cursor &&
              maxiterations-- &&
              listLength(keys) < (unsigned long)count);
    } else if (o->type == OBJ_SET) {
        int pos = 0;
        int64_t ll;

        while(intsetGet(o->ptr,pos++,&ll))
            listAddNodeTail(keys,createStringObjectFromLongLong(ll));
        cursor = 0;
    } else if (o->type == OBJ_HASH || o->type == OBJ_ZSET) {
        unsigned char *p = ziplistIndex(o->ptr,0);
        unsigned char *vstr;
        unsigned int vlen;
        long long vll;

        while(p) {
            ziplistGet(p,&vstr,&vlen,&vll);
            listAddNodeTail(keys,
                (vstr != NULL) ? createStringObject((char*)vstr,vlen) :
                                 createStringObjectFromLongLong(vll));
            p = ziplistNext(o->ptr,p);
        }
        cursor = 0;
    } else {
        serverPanic("Not handled encoding in SCAN.");
    }

    /* Step 3: Filter elements. */
    node = listFirst(keys);
    while (node) {
        robj *kobj = listNodeValue(node);
        nextnode = listNextNode(node);
        int filter = 0;

        /* Filter element if it does not match the pattern. */
        if (!filter && use_pattern) {
            if (sdsEncodedObject(kobj)) {
                if (!stringmatchlen(pat, patlen, kobj->ptr, sdslen(kobj->ptr), 0))
                    filter = 1;
            } else {
                char buf[LONG_STR_SIZE];
                int len;

                serverAssert(kobj->encoding == OBJ_ENCODING_INT);
                len = ll2string(buf,sizeof(buf),(long)kobj->ptr);
                if (!stringmatchlen(pat, patlen, buf, len, 0)) filter = 1;
            }
        }

        /* Filter element if it is an expired key. */
        if (!filter && o == NULL && expireIfNeeded(c->db, kobj)) filter = 1;

        /* Remove the element and its associted value if needed. */
        if (filter) {
            decrRefCount(kobj);
            listDelNode(keys, node);
        }

        /* If this is a hash or a sorted set, we have a flat list of
         * key-value elements, so if this element was filtered, remove the
         * value, or skip it if it was not filtered: we only match keys. */
        if (o && (o->type == OBJ_ZSET || o->type == OBJ_HASH)) {
            node = nextnode;
            nextnode = listNextNode(node);
            if (filter) {
                kobj = listNodeValue(node);
                decrRefCount(kobj);
                listDelNode(keys, node);
            }
        }
        node = nextnode;
    }

    /* Step 4: Reply to the client. */
    addReplyMultiBulkLen(c, 2);
    addReplyBulkLongLong(c,cursor);

    addReplyMultiBulkLen(c, listLength(keys));
    while ((node = listFirst(keys)) != NULL) {
        robj *kobj = listNodeValue(node);
        addReplyBulk(c, kobj);
        decrRefCount(kobj);
        listDelNode(keys, node);
    }

cleanup:
    listSetFreeMethod(keys,decrRefCountVoid);
    listRelease(keys);
}