Ejemplo n.º 1
0
	int Ardb::FlushScripts()
	{
		KeyObject start(Slice(), SCRIPT, ARDB_GLOBAL_DB);
		Iterator* iter = FindValue(start, false);
		BatchWriteGuard guard(GetEngine());
		while (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, NULL);
			if (NULL != kk)
			{
				if (kk->type == SCRIPT)
				{
					DelValue(*kk);
				} else
				{
					break;
				}
			}
			DELETE(kk);
			iter->Next();
		}
		DELETE(iter);
		return 0;
	}
Ejemplo n.º 2
0
	void Ardb::PrintDB(const DBID& db)
	{
		Slice empty;
		KeyObject start(empty, KV, db);
		Iterator* iter = FindValue(start);
		while (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, NULL);
			if (kk->db != db)
			{
				DELETE(kk);
				break;
			}
			ValueObject v;
			Buffer readbuf(const_cast<char*>(iter->Value().data()), 0, iter->Value().size());
			decode_value(readbuf, v, false);
			if (NULL != kk)
			{
				std::string str;
				DEBUG_LOG("[%d]Key=%s, Value=%s", kk->type, kk->key.data(), v.ToString(str).c_str());
			}
			DELETE(kk);
			iter->Next();
		}
		DELETE(iter);
	}
Ejemplo n.º 3
0
	bool Ardb::DBExist(const DBID& db, DBID& nextdb)
	{
		KeyObject start(Slice(), KV, db);
		Iterator* iter = FindValue(start, false);
		bool found = false;
		nextdb = db;
		if (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, NULL);
			if (NULL != kk)
			{
				if (kk->db == db)
				{
					found = true;
				} else
				{
					nextdb = kk->db;
				}
			}
			DELETE(kk);
		}
		DELETE(iter);
		return found;
	}
Ejemplo n.º 4
0
	void Ardb::Walk(WalkHandler* handler)
	{
		KeyObject start(Slice(), KV, 0);
		Iterator* iter = FindValue(start);
		uint32 cursor = 0;
		while (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, NULL);
			if (NULL == kk)
			{
				break;
			}
			ValueObject v;
			Buffer readbuf(const_cast<char*>(iter->Value().data()), 0, iter->Value().size());
			decode_value(readbuf, v, false);
			int ret = handler->OnKeyValue(kk, &v, cursor++);
			DELETE(kk);
			if (ret < 0)
			{
				break;
			}
			iter->Next();
		}
		DELETE(iter);
	}
Ejemplo n.º 5
0
static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
{
	struct fake_input *fake = data;
	const char *ok = "\r\nOK\r\n";
	char buf[BUF_SIZE];
	ssize_t bread = 0, bwritten;
	uint16_t key;
	int fd;

	if (cond & G_IO_NVAL)
		return FALSE;

	if (cond & (G_IO_HUP | G_IO_ERR)) {
		error("Hangup or error on rfcomm server socket");
		goto failed;
	}

	fd = g_io_channel_unix_get_fd(chan);

	memset(buf, 0, BUF_SIZE);
	bread = read(fd, buf, sizeof(buf) - 1);
	if (bread < 0) {
		error("IO Channel read error");
		goto failed;
	}

	DBG("Received: %s", buf);

	bwritten = write(fd, ok, 6);
	if (bwritten < 0) {
		error("IO Channel write error");
		goto failed;
	}

	key = decode_key(buf);
	if (key != KEY_RESERVED)
		send_key(fake->uinput, key);

	return TRUE;

failed:
	ioctl(fake->uinput, UI_DEV_DESTROY);
	close(fake->uinput);
	fake->uinput = -1;
	g_io_channel_unref(fake->io);

	return FALSE;
}
Ejemplo n.º 6
0
	void Ardb::Walk(KeyObject& key, bool reverse, WalkHandler* handler)
	{
		bool isFirstElement = true;
		Iterator* iter = FindValue(key);
		if (NULL != iter && !iter->Valid() && reverse)
		{
			iter->SeekToLast();
			isFirstElement = false;
		}
		uint32 cursor = 0;
		while (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, &key);
			if (NULL == kk || kk->type != key.type
			        || kk->key.compare(key.key) != 0)
			{
				DELETE(kk);
				if (reverse && isFirstElement)
				{
					iter->Prev();
					isFirstElement = false;
					continue;
				}
				break;
			}
			ValueObject v;
			Buffer readbuf(const_cast<char*>(iter->Value().data()), 0,
			        iter->Value().size());
			decode_value(readbuf, v, false);
			int ret = handler->OnKeyValue(kk, &v, cursor++);
			DELETE(kk);
			if (ret < 0)
			{
				break;
			}
			if (reverse)
			{
				iter->Prev();
			}
			else
			{
				iter->Next();
			}
		}
		DELETE(iter);
	}
Ejemplo n.º 7
0
static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
{
	struct fake_input *fake = data;
	const char *ok = "\r\nOK\r\n";
	char buf[BUF_SIZE];
	gsize bread = 0, bwritten;
	uint16_t key;

	if (cond & G_IO_NVAL)
		return FALSE;

	if (cond & (G_IO_HUP | G_IO_ERR)) {
		error("Hangup or error on rfcomm server socket");
		goto failed;
	}

	memset(buf, 0, BUF_SIZE);
	if (g_io_channel_read(chan, buf, sizeof(buf) - 1,
				&bread) != G_IO_ERROR_NONE) {
		error("IO Channel read error");
		goto failed;
	}

	debug("Received: %s", buf);

	if (g_io_channel_write(chan, ok, 6, &bwritten) != G_IO_ERROR_NONE) {
		error("IO Channel write error");
		goto failed;
	}

	key = decode_key(buf);
	if (key != KEY_RESERVED)
		send_key(fake->uinput, key);

	return TRUE;

failed:
	ioctl(fake->uinput, UI_DEV_DESTROY);
	close(fake->uinput);
	fake->uinput = -1;
	g_io_channel_unref(fake->io);

	return FALSE;
}
Ejemplo n.º 8
0
Archivo: ardb.cpp Proyecto: Ivasek/ardb
	int Ardb::FirstDB(DBID& db)
	{
		int ret = -1;
		Iterator* iter = NewIterator();
		iter->SeekToFirst();
		if (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, NULL);
			if (NULL != kk)
			{
				db = kk->db;
				ret = 0;
			}
			DELETE(kk);
		}
		DELETE(iter);
		return ret;
	}
Ejemplo n.º 9
0
void Key_Scan()
{
	uchar k;
	if(KEYBJ2 == 0){
		if(kbit == 0)
		{
			KEYBJ2 = 1;
			keycount = 0;
		}
		return;
	}

		k = keykeep;
		keykeep = KEY_INVALID;
		decode_key(); //decode the key
		if(keycount == 0) //initial decode
		{
			if(keykeep == KEY_INVALID) //invalid key
			{
				KEYBJ2 = 0;
				P1 = 0x0f;l9=0;	 
				return;
			}
		}
		if(keykeep == KEY_INVALID) //key up event found
		{
			KEYBJ2 = 0;
 			P1 = 0x0f;l9=0;

			if(keycount >= KEYTIMEOUT)
				key = k;
			return;
		}
		keycount++;
		if(keycount > 128)
			keycount = 1;
	return;

}
Ejemplo n.º 10
0
Archivo: ardb.cpp Proyecto: Ivasek/ardb
	int Ardb::LastDB(DBID& db)
	{
		int ret = -1;
		Iterator* iter = NewIterator(ARDB_GLOBAL_DB);
		if (NULL != iter && iter->Valid())
		{
			//Skip last KEY_END entry
			iter->Prev();
		}
		if (NULL != iter && iter->Valid())
		{
			Slice tmpkey = iter->Key();
			KeyObject* kk = decode_key(tmpkey, NULL);
			if (NULL != kk)
			{
				db = kk->db;
				ret = 0;
			}
			DELETE(kk);
		}
		DELETE(iter);
		return ret;
	}
Ejemplo n.º 11
0
Archivo: keys.cpp Proyecto: boreys/ardb
    int Ardb::Scan(Context& ctx, RedisCommandFrame& cmd)
    {
        StringArray keys;
        std::string pattern;
        uint32 limit = 10000; //return max 10000 keys one time
        if (cmd.GetArguments().size() > 1)
        {
            for (uint32 i = 1; i < cmd.GetArguments().size(); i++)
            {
                if (!strcasecmp(cmd.GetArguments()[i].c_str(), "count"))
                {
                    if (i + 1 >= cmd.GetArguments().size() || !string_touint32(cmd.GetArguments()[i + 1], limit))
                    {
                        fill_error_reply(ctx.reply, "value is not an integer or out of range");
                        return 0;
                    }
                    i++;
                }
                else if (!strcasecmp(cmd.GetArguments()[i].c_str(), "match"))
                {
                    if (i + 1 >= cmd.GetArguments().size())
                    {
                        fill_error_reply(ctx.reply, "'MATCH' need one args followed");
                        return 0;
                    }
                    pattern = cmd.GetArguments()[i + 1];
                    i++;
                }
                else
                {
                    fill_error_reply(ctx.reply, "Syntax error, try scan 0 ");
                    return 0;
                }
            }
        }
        RedisReply& r1 = ctx.reply.AddMember();
        RedisReply& r2 = ctx.reply.AddMember();
        r2.type = REDIS_REPLY_ARRAY;

        KeyObject from;
        from.db = ctx.currentDB;
        from.type = KEY_META;
        const std::string& cursor = cmd.GetArguments()[0];
        std::string scan_start_cursor;
        if (cmd.GetArguments()[0] != "0")
        {
            if (m_cfg.scan_redis_compatible)
            {
                FindElementByRedisCursor(cursor, scan_start_cursor);
            }
            from.key = scan_start_cursor;
        }
        Iterator* iter = IteratorKeyValue(from, false);
        bool reachend = false;
        std::string tmpkey;
        while (NULL != iter && iter->Valid())
        {
            KeyObject kk;
            if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META)
            {
                reachend = true;
                break;
            }
            tmpkey.clear();
            tmpkey.assign(kk.key.data(), kk.key.size());
            if (r2.MemberSize() >= limit)
            {
                break;
            }
            if ((pattern.empty()
                    || stringmatchlen(pattern.c_str(), pattern.size(), tmpkey.c_str(), tmpkey.size(), 0) == 1))
            {
                RedisReply& rr1 = r2.AddMember();
                fill_str_reply(rr1, tmpkey);
            }
            iter->Next();
        }
        if (reachend || !iter->Valid())
        {
            fill_str_reply(r1, "0");
        }
        else
        {
            if (m_cfg.scan_redis_compatible)
            {
                uint64 newcursor = GetNewRedisCursor(tmpkey);
                fill_str_reply(r1, stringfromll(newcursor));
            }
            else
            {
                fill_str_reply(r1, tmpkey);
            }
        }
        DELETE(iter);
        return 0;
    }
Ejemplo n.º 12
0
Archivo: keys.cpp Proyecto: boreys/ardb
    int Ardb::KeysOperation(Context& ctx, const KeysOptions& options)
    {
        KeyObject from;
        from.db = ctx.currentDB;
        from.type = KEY_META;

        std::string::size_type cursor = options.pattern.find("*");
        if (cursor == std::string::npos)
        {
            from.key = options.pattern;
        }
        else
        {
            if (options.pattern != "*" && cursor > 0)
            {
                from.key = options.pattern.substr(0, cursor);
            }
        }
        Iterator* iter = IteratorKeyValue(from, false);
        std::string tmpkey;
        uint32 count = 0;
        while (NULL != iter && iter->Valid())
        {
            KeyObject kk;
            if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META)
            {
                break;
            }
            tmpkey.clear();
            tmpkey.assign(kk.key.data(), kk.key.size());
            if ((options.pattern == "*"
                    || stringmatchlen(options.pattern.c_str(), options.pattern.size(), tmpkey.data(), tmpkey.size(), 0)
                            == 1))
            {
                if (options.op == OP_GET)
                {
                    RedisReply& r = ctx.reply.AddMember();
                    fill_str_reply(r, tmpkey);
                }
                else
                {
                    count++;
                }
            }
            else
            {
                /*
                 * If the '*' is the last char, we can break iteration now
                 */
                if (cursor == options.pattern.size() - 1)
                {
                    break;
                }
            }
            iter->Next();
        }
        DELETE(iter);
        if (options.op == OP_GET)
        {
            ctx.reply.type = REDIS_REPLY_ARRAY;
        }
        else
        {
            fill_int_reply(ctx.reply, count);
        }
        return 0;
    }
Ejemplo n.º 13
0
    int Ardb::Randomkey(Context& ctx, RedisCommandFrame& cmd)
    {
        ctx.reply.type = REDIS_REPLY_NIL;
        KeyObject from;
        from.db = ctx.currentDB;
        from.type = KEY_META;

        std::string min_key, max_key, randkey;
        Iterator* iter = IteratorKeyValue(from, false);
        if (iter->Valid())
        {
            KeyObject kk;
            if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META)
            {
                goto _end;
            }
            min_key.assign(kk.key.data(), kk.key.size());
            max_key = min_key;
            from.type = SET_ELEMENT;    //Refer comparator.cpp

            from.encode_buf.Clear();
            IteratorSeek(iter, from);
            if (!iter->Valid())
            {
                iter->SeekToLast();
            }
            if (iter->Valid())
            {
                iter->Prev();
                if (iter->Valid())
                {
                    if (decode_key(iter->Key(), kk) && kk.db == ctx.currentDB && kk.type == KEY_META)
                    {
                        max_key.assign(kk.key.data(), kk.key.size());
                    }
                }
            }
            randkey = min_key;
            if (min_key < max_key)
            {
                randkey = random_between_string(min_key, max_key);
                from.type = KEY_META;
                from.db = ctx.currentDB;
                from.key = randkey;
                IteratorSeek(iter, from);
                if (iter->Valid())
                {
                    KeyObject kk;
                    if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META)
                    {
                        goto _end;
                    }
                    randkey.assign(kk.key.data(), kk.key.size());
                }
            }
        }
        if (!randkey.empty())
        {
            fill_str_reply(ctx.reply, randkey);
        }
        _end:
        DELETE(iter);
        return 0;
    }
Ejemplo n.º 14
0
void
TTwaitForChar(void)
{
#if MEOPT_MOUSE
    union REGS rg ;

    if(meMouseCfg & meMOUSE_ENBLE)
    {
        meUShort mc ;
        meUInt arg ;
        /* If mouse state flags that the mouse should be visible then we
         * must make it visible. We had to make it invisible to get the
         * screen-updates correct
         */
        if(mouseState & MOUSE_STATE_SHOW)
        {
            mouseState |= MOUSE_STATE_VISIBLE ;
            rg.x.ax = 0x0001 ;
            int86(0x33, &rg, &rg) ;
        }
        
        /* If no keys left then if theres currently no mouse timer and
         * theres a button press (No mouse-time key) then check for a
         * time-mouse-? key, if found add a timer start a mouse checking
         */
        if(!isTimerActive(MOUSE_TIMER_ID) &&
           ((mc=(mouseState & MOUSE_STATE_BUTTONS)) != 0))
        {
            mc = ME_SPECIAL | TTmodif | (SKEY_mouse_time+mouseKeys[mc]) ;
            if((!TTallKeys && (decode_key(mc,&arg) != -1)) || (TTallKeys & 0x2))
            {
                /* Start a timer and move to timed state 1 */
                /* Start a new timer to clock in at 'delay' intervals */
                /* printf("Setting mouse timer for delay  %1x %1x %d\n",TTallKeys,meTimerState[MOUSE_TIMER_ID],delayTime) ;*/
                timerSet(MOUSE_TIMER_ID,-1,delayTime);
            }
        }
    }
#endif
#if MEOPT_CALLBACK
    /* IDLE TIME: Check the idle time events */        
    if(kbdmode == meIDLE)
        /* Check the idle event */
        doIdlePickEvent() ;
#endif
    
    for(;;)
    {
        handleTimerExpired() ;
        if(TTahead())
            break ;
#if MEOPT_MOUSE
        if(meMouseCfg & meMOUSE_ENBLE)
        {
            meShort row, col, but ;
            meUShort cc ;
            
            /* Get new mouse status. It appears that the fractional bits of
             * the mouse change across reads. ONLY Compare the non-fractional
             * components.
             */
            rg.x.ax = 0x0003 ;
            int86(0x33, &rg, &rg) ;
            but = rg.x.bx & MOUSE_STATE_BUTTONS ;
            col = rg.x.cx>>3 ;
            row = rg.x.dx>>3 ;
            
            /* Check for mouse state changes */
            if(((mouseState ^ but) & MOUSE_STATE_BUTTONS) || 
               (mouse_X != col) || (mouse_Y != row))
            {
                int ii ;
                
                /* Get shift status */
                rg.h.ah = 0x02;
                int86(0x16,&rg,&rg) ;
                TTmodif = ((rg.h.al & 0x01) << 8) | ((rg.h.al & 0x0E) << 7) ;
                
                /* Record the new mouse positions */
                mouse_X = col ;
                mouse_Y = row ;
                
                /* Check for button changes, these always create keys */
                if((mouseState ^ but) & MOUSE_STATE_BUTTONS)
                {
                    /* Iterate down the bit pattern looking for changes
                     * of state */
                    for (ii=1 ; ii<8 ; ii<<=1)
                    {
                        /* Test each key and add to the stack */
                        if((mouseState ^ but) & ii)
                        {
                            /* Up or down press ?? */
                            if(but & ii)
                                cc = ME_SPECIAL+SKEY_mouse_pick_1-1 ;     /* Down  */
                            else
                                cc = ME_SPECIAL+SKEY_mouse_drop_1-1 ;     /* Up !! */
                            cc = TTmodif | (cc + mouseKeys[ii]) ;
                            addKeyToBuffer(cc) ;
                        }
                    }
                    /* Correct the mouse state */
                    mouseState = (mouseState & ~MOUSE_STATE_BUTTONS) | but ;
                }
                else
                {
                    meUInt arg;                 /* Decode key argument */
                    /* Check for a mouse-move key */
                    cc = (ME_SPECIAL+SKEY_mouse_move+mouseKeys[but]) | TTmodif ;
                    /* Are we after all movements or mouse-move bound ?? */
                    if((!TTallKeys && (decode_key(cc,&arg) != -1)) || (TTallKeys & 0x1))
                        addKeyToBuffer(cc) ;        /* Add key to keyboard buffer */
                    else
                    {
                        /* Mouse has been moved so we must make it visible */
                        if(!(mouseState & MOUSE_STATE_VISIBLE))
                        {
                            mouseState |= MOUSE_STATE_VISIBLE ;
                            rg.x.ax = 0x0001 ;
                            int86(0x33, &rg, &rg) ;
                        }
                        continue ;
                    }
                }
                /* As we are adding a mouse key, the mouse is active
                 * so add the 'show' flag, so on entry next time
                 * the mouse will automatically become visible.
                 */
                mouseState |= MOUSE_STATE_SHOW ;
                break ;
            }
        }
#endif
    } /* ' for' */
Ejemplo n.º 15
0
int
decode_key(meUShort ocode, meUInt *arg)
{
    register meBind  *ktp;			/* Keyboard character array */
    register int      low;			/* Lowest index in table. */
    register int      hi;			/* Hightest index in table. */
    register int      mid;			/* Mid value. */
    register int      status;			/* Status of comparison. */
    register meUShort code=ocode;    
try_again:
#if MEOPT_LOCALBIND
    if(useMlBinds)
    {
        ktp = mlBinds ;
        mid = mlNoBinds ;
    }
    else
    {
        mid = frameCur->bufferCur->bindCount ;
        ktp = frameCur->bufferCur->bindList ;
    }
    while(mid>0)
        if(ktp[--mid].code == code)
        {
            *arg = ktp[mid].arg ;
            return ktp[mid].index ;
        }

#endif
    /* binary chop through the key table looking for the character code.  
    ** If found then return the index into the names table.
    */
    ktp = keytab ;
    hi  = keyTableSize-1;	/* Set hi water to end of table */
    low = 0;			/* Set low water to start of table */
    
    do
    {
        mid = (low + hi) >> 1;		/* Get mid value. */
        if ((status=code-ktp[mid].code) == 0)
        {
            /* Found - return index */
            *arg = ktp[mid].arg ;
            return ktp[mid].index ;
        }
        else if (status < 0)
            hi = mid - 1;		/* Discard bottom half */
        else
            low = mid + 1;		/* Discard top half */
    } while (low <= hi);		/* Until converges */
    /* If this is an Alt key without any prefix's (esc, C-x etc.) then
     * change the key to be the 1st prefix without the Alt, e.g.
     *     A-space -> esc space
     * and then look this up
     */
    if(code & ME_ALT)
    {
#if MEOPT_OSD
        if((meSystemCfg & meSYSTEM_ALTMENU) &&
           ((code & (ME_SPECIAL|ME_PREFIX_MASK)) == 0) &&
           ((status = osdMainMenuCheckKey(code & 0x0ff)) != 0))
        {
            /* Found - return index */
            *arg = (meUInt) (status+0x80000000) ;
            return CK_OSD ;
        }
#endif
        if((meSystemCfg & meSYSTEM_ALTPRFX1) &&
           ((code & ME_PREFIX_MASK) == 0))
        {
            code = (code & ~ME_ALT)|ME_PREFIX1 ;
            goto try_again ;
        }
    }
    if((charKeyboardMap != NULL) && ((code & ME_SPECIAL) == 0) &&
       (charKeyboardMap[code & 0x0ff] != 0))
    {
        meUByte *ckm=charKeyboardMap ;
        code = (ocode & 0xff00) | charKeyboardMap[code & 0x0ff] ;
        charKeyboardMap = NULL ;
        status = decode_key(code,arg) ;
        charKeyboardMap = ckm ;
        return status ;
    }
    *arg = 0 ;
    return -1 ;				/* Not found - return error */
}
Ejemplo n.º 16
0
int
setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) {

	TRUNCATE_CONFIG *trunc_cfg;
	TRUNCATE_QUEUE_ENTRY *truncate_item;
	WORKLOAD *workload;
	WT_CURSOR *cursor;
	char *key, *truncate_key;
	int ret;
	uint64_t end_point, final_stone_gap, i, start_point;

	end_point = final_stone_gap = start_point = 0;
	trunc_cfg = &thread->trunc_cfg;
	workload = thread->workload;

	/* We are limited to only one table when running truncate. */
	if ((ret = session->open_cursor(
	    session, cfg->uris[0], NULL, NULL, &cursor)) != 0)
		goto err;

	/* How many entries between each stone. */
	trunc_cfg->stone_gap =
	    (workload->truncate_count * workload->truncate_pct) / 100;
	/* How many stones we need. */
	trunc_cfg->needed_stones =
	    workload->truncate_count / trunc_cfg->stone_gap;

	final_stone_gap = trunc_cfg->stone_gap;

	/* Reset this value for use again. */
	trunc_cfg->stone_gap = 0;

	/*
	 * Here we check if there is data in the collection. If there is
	 * data available, then we need to setup some initial truncation
	 * stones.
	 */
	if ((ret = cursor->next(cursor)) != 0 ||
	    (ret = cursor->get_key(cursor, &key)) != 0) {
		lprintf(cfg, ret, 0, "truncate setup start: failed");
		goto err;
	}

	start_point = decode_key(key);
	if ((cursor->reset(cursor)) != 0 || (ret = cursor->prev(cursor)) != 0 ||
	    (ret = cursor->get_key(cursor, &key)) != 0) {
		lprintf(cfg, ret, 0, "truncate setup end: failed");
		goto err;
	}
	end_point = decode_key(key);

	/* Assign stones if there are enough documents. */
	if (start_point + trunc_cfg->needed_stones > end_point)
		trunc_cfg->stone_gap = 0;
	else
		trunc_cfg->stone_gap =
		    (end_point - start_point) / trunc_cfg->needed_stones;

	/* If we have enough data allocate some stones. */
	if (trunc_cfg->stone_gap != 0) {
		trunc_cfg->expected_total = (end_point - start_point);
		for (i = 1; i <= trunc_cfg->needed_stones; i++) {
			truncate_key = calloc(cfg->key_sz, 1);
			if (truncate_key == NULL) {
				ret = enomem(cfg);
				goto err;
			}
			truncate_item = calloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1);
			if (truncate_item == NULL) {
				free(truncate_key);
				ret = enomem(cfg);
				goto err;
			}
			generate_key(
			    cfg, truncate_key, trunc_cfg->stone_gap * i);
			truncate_item->key = truncate_key;
			truncate_item->diff =
			    (trunc_cfg->stone_gap * i) - trunc_cfg->last_key;
			TAILQ_INSERT_TAIL( &cfg->stone_head, truncate_item, q);
			trunc_cfg->last_key = trunc_cfg->stone_gap * i;
			trunc_cfg->num_stones++;
		}
	}
	trunc_cfg->stone_gap = final_stone_gap;

err:	if ((ret = cursor->close(cursor)) != 0) {
		lprintf(cfg, ret, 0, "truncate setup: cursor close failed");
	}
	return (ret);
}