示例#1
0
static void
xdirfixdotdot(
	struct xmemnode	*fromxp,	/* child directory */
	struct xmemnode	*fromparent,	/* old parent directory */
	struct xmemnode	*toparent)	/* new parent directory */
{
	struct xdirent	*dotdot;

	ASSERT(RW_LOCK_HELD(&toparent->xn_rwlock));

	/*
	 * Increment the link count in the new parent xmemnode
	 */
	INCR_COUNT(&toparent->xn_nlink, &toparent->xn_tlock);
	gethrestime(&toparent->xn_ctime);

	dotdot = xmemfs_hash_lookup("..", fromxp, 0, NULL);

	ASSERT(dotdot->xd_xmemnode == fromparent);
	dotdot->xd_xmemnode = toparent;

	/*
	 * Decrement the link count of the old parent xmemnode.
	 * If fromparent is NULL, then this is a new directory link;
	 * it has no parent, so we need not do anything.
	 */
	if (fromparent != NULL) {
		mutex_enter(&fromparent->xn_tlock);
		if (fromparent->xn_nlink != 0) {
			fromparent->xn_nlink--;
			gethrestime(&fromparent->xn_ctime);
		}
		mutex_exit(&fromparent->xn_tlock);
	}
}
示例#2
0
/*
 * Allocate and initialize an Address/Length List cursor.
 */
alenlist_cursor_t
alenlist_cursor_create(alenlist_t alenlist, unsigned flags)
{
	alenlist_cursor_t cursorp;

	ASSERT(alenlist != NULL);
	cursorp = snia_kmem_zone_alloc(alenlist_cursor_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0);
	if (cursorp) {
		INCR_COUNT(&alenlist_cursor_count);
		alenlist_cursor_init(alenlist, 0, cursorp);
	}
	return(cursorp);
}
示例#3
0
/*
 * xdirinit is used internally to initialize a directory (dir)
 * with '.' and '..' entries without checking permissions and locking
 */
void
xdirinit(
	struct xmemnode *parent,	/* parent of directory to initialize */
	struct xmemnode *dir)		/* the new directory */
{
	struct xdirent *dot, *dotdot;
	timestruc_t now;

	ASSERT(RW_WRITE_HELD(&parent->xn_rwlock));
	ASSERT(dir->xn_type == VDIR);

	dot = xmem_memalloc(sizeof (struct xdirent) + 2, 1);
	dotdot = xmem_memalloc(sizeof (struct xdirent) + 3, 1);

	/*
	 * Initialize the entries
	 */
	dot->xd_xmemnode = dir;
	dot->xd_offset = 0;
	dot->xd_name = (char *)dot + sizeof (struct xdirent);
	dot->xd_name[0] = '.';
	dot->xd_parent = dir;
	xmemfs_hash_in(dot);

	dotdot->xd_xmemnode = parent;
	dotdot->xd_offset = 1;
	dotdot->xd_name = (char *)dotdot + sizeof (struct xdirent);
	dotdot->xd_name[0] = '.';
	dotdot->xd_name[1] = '.';
	dotdot->xd_parent = dir;
	xmemfs_hash_in(dotdot);

	/*
	 * Initialize directory entry list.
	 */
	dot->xd_next = dotdot;
	dot->xd_prev = dotdot;	/* dot's xd_prev holds roving slot pointer */
	dotdot->xd_next = NULL;
	dotdot->xd_prev = dot;
	INCR_COUNT(&parent->xn_nlink, &parent->xn_tlock);

	dir->xn_dir = dot;
	dir->xn_size = 2 * sizeof (struct xdirent) + 5;	/* dot and dotdot */
	dir->xn_dirents = 2;
	dir->xn_nlink = 2;	/* one for daddy, and one just for being me */

	gethrestime(&now);
	dir->xn_mtime = now;
	dir->xn_ctime = now;
	parent->xn_ctime = now;
}
示例#4
0
/*
 * Create an Address/Length List, and clear it.
 * Set the cursor to the beginning.
 */
alenlist_t 
alenlist_create(unsigned flags)
{
	alenlist_t alenlist;

	alenlist = snia_kmem_zone_alloc(alenlist_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0);
	if (alenlist) {
		INCR_COUNT(&alenlist_count);

		alenlist->al_flags = 0;
		alenlist->al_logical_size = 0;
		alenlist->al_actual_size = ALEN_CHUNK_SZ;
		alenlist->al_last_chunk = &alenlist->al_chunk;
		alenlist->al_chunk.alc_next = NULL;
		do_cursor_init(alenlist, &alenlist->al_cursor);
	}

	return(alenlist);
}
示例#5
0
/*
 * ----------------------------------------------------------
 * Fast path setpiece when delimiter is one (lit) char replacing
 * a single piece (last is same as first).
 *
 * Arguments:
 *	src	- source mval
 *	delim	- delimiter char
 *	expr	- expression string mval
 *	ind	- index in source mval to be set
 *	dst	- destination mval where the result is saved.
 *
 * Return:
 *	none
 * ----------------------------------------------------------
 */
void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst)
{
    int		len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, str_len, delim_cnt, pfx_scan_offset;
    int		cpy_cache_lines;
    unsigned char	ldelim, lc, *start_sfx, *str_addr, *end_pfx, *end_src, *start_pfx;
    boolean_t	do_scan;
    mval		dummymval;	/* It's value is not used but is part of the call to op_fnp1() */
    fnpc		*cfnpc, *pfnpc;

    error_def(ERR_MAXSTRLEN);

    ldelim = delim;		/* Local copy (in unsigned char format) */
    do_scan = FALSE;
    cpy_cache_lines = -1;

    MV_FORCE_STR(expr);	/* Expression to put into piece place */
    if (MV_DEFINED(src))
    {
        /* We have 3 possible scenarios:

           1) If length of src is too small to cause cacheing by op_fnp1, then just do
           the work ourselves with no cacheing.
           2) If the requested piece is larger than can be cached by op_fnp1, call fnp1
           for the maximum piece possible, use the cache info to "prime the pump" and
           then process the rest of the string ourselves.
           3) If the requested piece can be obtained from the cache, call op_fnp1 to validate
           and rebuild the cache if necessary and then retrieve the necessary info from
           the fnpc cache.
        */
        MV_FORCE_STR(src);	/* Make sure is string prior to length check */
        if (FNPC_STRLEN_MIN < src->str.len && FNPC_ELEM_MAX >= ind)
        {   /* 3) Best of all possible cases. The op_fnp1 can do most of our work for us
               and we can preload the cache on the new string to help its subsequent
               uses along as well.
            */
            SETWON;
            op_fnp1(src, delim, ind, &dummymval, FALSE);
            SETWOFF;
            cfnpc = &fnpca.fnpcs[src->fnpc_indx - 1];
            assert(cfnpc->last_str.addr == src->str.addr);
            assert(cfnpc->last_str.len == src->str.len);
            assert(cfnpc->delim == delim);
            assert(0 < cfnpc->npcs);
            /* Three more scenarios: #1 piece all in cache, #2 piece would be in cache but ran
               out of text or #3 piece is beyond what can be cached
            */
            if (cfnpc->npcs >= ind)
            {   /* #1 The piece we want is totally within the cache which is good news */
                pfx_str_len = cfnpc->pstart[ind - 1];
                delim_cnt = 0;
                sfx_start_offset = cfnpc->pstart[ind] - 1;			/* Include delimiter */
                rep_str_len = cfnpc->pstart[ind] - cfnpc->pstart[ind - 1] - 1;	/* Replace string length */
                sfx_str_len = src->str.len - pfx_str_len - rep_str_len;
                cpy_cache_lines = ind - 1;
            } else
            {   /* #2 The string was too short so the cache does not contain our string. This means
                   that the prefix becomes any text that IS in the cache and we set the delim_cnt
                   to be the number of missing pieces so the delimiters can be put in as part of the
                   prefix when we build the new string.
                */
                pfx_str_len = cfnpc->pstart[cfnpc->npcs] - 1;
                delim_cnt = ind - cfnpc->npcs;
                sfx_start_offset = 0;
                sfx_str_len = 0;
                cpy_cache_lines = cfnpc->npcs;
            }
        } else if (FNPC_STRLEN_MIN < src->str.len)
        {   /* 2) We have a element that would not be able to be in the fnpc cache. Go ahead
               and call op_fnp1 to get cache info up to the maximum and then we will continue
               the scan on our own.
            */
            SETWON;
            op_fnp1(src, delim, FNPC_ELEM_MAX, &dummymval, FALSE);
            SETWOFF;
            cfnpc = &fnpca.fnpcs[src->fnpc_indx - 1];
            assert(cfnpc->last_str.addr == src->str.addr);
            assert(cfnpc->last_str.len == src->str.len);
            assert(cfnpc->delim == delim);
            assert(0 < cfnpc->npcs);
            if (FNPC_ELEM_MAX > cfnpc->npcs)
            {   /* We ran out of text so the scan is complete. This is basically the same
                   as case #2 above.
                */
                pfx_str_len = cfnpc->pstart[cfnpc->npcs] - 1;
                delim_cnt = ind - cfnpc->npcs;
                sfx_start_offset = 0;
                sfx_str_len = 0;
                cpy_cache_lines = cfnpc->npcs;
            } else
            {   /* We have a case where the piece we want cannot be kept in cache. In the special
                   case where there is no more text to handle, we don't need to scan further. Otherwise
                   we prime the pump and continue the scan where the cache left off.
                */
                if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len)
                {   /* Normal case where we prime the pump */
                    do_scan = TRUE;
                } else
                {   /* Special case -- no more text to scan */
                    pfx_str_len = cfnpc->pstart[FNPC_ELEM_MAX] - 1;
                    sfx_start_offset = 0;
                    sfx_str_len = 0;
                }
                delim_cnt = ind - FNPC_ELEM_MAX;
                cpy_cache_lines = FNPC_ELEM_MAX;
            }

        } else
        {   /* 1) We have a short string where no cacheing happens. Do the scanning work ourselves */
            MV_FORCE_STR(src);
            do_scan = TRUE;
            pfx_scan_offset = 0;
            delim_cnt = ind;
        }
    } else
    {   /* Source is not defined -- treat as a null string */
        pfx_str_len = sfx_str_len = sfx_start_offset = 0;
        delim_cnt = ind - 1;
    }

    /* If we have been forced to do our own scan, do that here. Note the variable pfx_scan_offset has been
       set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters
       still need to be processed.
    */
    if (do_scan)
    {   /* Scan the line isolating prefix piece, and end of the
           piece being replaced
        */
        COUNT_EVENT(cs_small);
        end_pfx = start_sfx = (unsigned char *)src->str.addr + pfx_scan_offset;
        end_src = (unsigned char *)src->str.addr + src->str.len;

        /* The compiler would unroll this loop this way anyway but we want to
           adjust the start_sfx pointer after the loop but only if we have gone
           into it at least once.
        */
        if (0 < delim_cnt && start_sfx < end_src)
        {
            do
            {
                end_pfx = start_sfx;
                while (start_sfx < end_src && (lc = *start_sfx) != ldelim) start_sfx++;
                start_sfx++;
                delim_cnt--;
            } while (0 < delim_cnt && start_sfx < end_src);

            /* We have to backup up the suffix start pointer except under the condition
               that the last character in the buffer is the last delimiter we were looking
               for.
            */
            if (0 == delim_cnt || start_sfx < end_src || lc != ldelim)
                --start_sfx;				/* Back up suffix to include delimiter char */

            /* If we scanned to the end (no text left) and still have delimiters to
               find, the entire src text should be part of the prefix */
            if (start_sfx >= end_src && 0 < delim_cnt)
            {
                end_pfx = start_sfx;
                if (lc == ldelim)			/* if last char was delim, reduce delim cnt */
                    --delim_cnt;
            }

        } else
        {
            /* If not doing any token finding, then this count becomes the number
               of tokens to output. Adjust accordingly.
            */
            if (0 > --delim_cnt)
                delim_cnt = 0;
        }
        INCR_COUNT(cs_small_pcs, ind - delim_cnt);

        /* Now having the following situation:
           end_pfx	-> end of the prefix piece including delimiter
           start_sfx	-> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none
        */
        pfx_str_len = end_pfx - (unsigned char *)src->str.addr;
        if (0 > pfx_str_len)
            pfx_str_len = 0;
        sfx_start_offset = start_sfx - (unsigned char *)src->str.addr;
        sfx_str_len = src->str.len - sfx_start_offset;
        if (0 > sfx_str_len)
            sfx_str_len = 0;
    }

    /* Calculate total string len. delim_cnt has needed padding delimiters for null fields */
    str_len = expr->str.len + pfx_str_len + delim_cnt + sfx_str_len;
    if (str_len > MAX_STRLEN)
        rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
    if (str_len > (stringpool.top - stringpool.free))
        stp_gcol(str_len);
    str_addr = stringpool.free;
    start_pfx = (unsigned char *)src->str.addr;

    /* copy prefix */
    if (0 < pfx_str_len)
    {
        memcpy(str_addr, src->str.addr, pfx_str_len);
        str_addr += pfx_str_len;
    }

    /* copy delimiters */
    while (delim_cnt-- > 0)
        *str_addr++ = ldelim;

    /* copy expression */
    if (0 < expr->str.len)
    {
        memcpy(str_addr, expr->str.addr, expr->str.len);
        str_addr += expr->str.len;
    }

    /* copy suffix */
    if (0 < sfx_str_len)
    {
        memcpy(str_addr, start_pfx + sfx_start_offset, sfx_str_len);
        str_addr += sfx_str_len;
    }

    assert(str_addr - stringpool.free == str_len);
    dst->mvtype = MV_STR;
    dst->str.len = str_addr - stringpool.free;
    dst->str.addr = (char *)stringpool.free;
    stringpool.free = str_addr;

    /* If available, update the cache information for this newly created mval to hopefully
       give it a head start on its next usage. Note that we can only copy over the cache info
       for the prefix. We cannot include information for the 'expression' except where it starts
       because the expression could itself contain delimiters that would be found on a rescan.
    */
    if (0 < cpy_cache_lines)
    {
        pfnpc = cfnpc;				/* pointer for src mval's cache */
        do
        {
            cfnpc = fnpca.fnpcsteal;	/* Next cache element to steal */
            if (fnpca.fnpcmax < cfnpc)
                cfnpc = &fnpca.fnpcs[0];
            fnpca.fnpcsteal = cfnpc + 1;	/* -> next element to steal */
        } while (cfnpc == pfnpc);		/* Make sure we don't step on ourselves */

        cfnpc->last_str = dst->str;		/* Save validation info */
        cfnpc->delim = delim;
        cfnpc->npcs = cpy_cache_lines;
        dst->fnpc_indx = cfnpc->indx + 1;	/* Save where we are putting this element
							   (1 based index in mval so 0 isn't so common) */
        memcpy(&cfnpc->pstart[0], &pfnpc->pstart[0], (cfnpc->npcs + 1) * sizeof(unsigned int));
    } else
    {   /* No cache available -- just reset index pointer to get fastest cache validation failure */
        dst->fnpc_indx = -1;
    }
}
示例#6
0
void op_fnzp1(mval *src, int delim, int trgpcidx, mval *dst)
{
    unsigned char	*first, *last, *start, *end;
    unsigned char	dlmc;
    unsigned int	*pcoff, *pcoffmax, fnpc_indx, slen;
    int		trgpc, cpcidx, spcidx;
    mval		ldst;		/* Local copy since &dst == &src .. move to dst at return */
    fnpc   		*cfnpc;
    delimfmt	ldelim;
    DCL_THREADGBL_ACCESS;

    SETUP_THREADGBL_ACCESS;
    MV_FORCE_STR(src);
    ldst.mvtype = MV_STR;
    DEBUG_ONLY(ldst.str.len = -1);	/* Trigger assert at end if length not changed */
    ldelim.unichar_val = delim;
    dlmc = ldelim.unibytes_val[0];
    start = first = last = (unsigned char *)src->str.addr;
    slen = src->str.len;
    end = start + slen;

    /* Detect annoyance cases and deal with quickly so we don't muck up the
       logic below trying to handle it properly */
    if (0 >= trgpcidx || 0 == slen)
    {
        ldst.str.addr = (char *)start;
        ldst.str.len  = 0;
        *dst = ldst;
        return;
    }

    /* Test mval for valid cache: index ok, mval addr same, delim same. One additional test
     * is if byte_oriented is FALSE, then this cache entry was created by $PIECE (using
     * UTF8 chars) and since we cannot reuse it, we must ignore the cache and rebuild it for
     * this mval. */
    fnpc_indx = src->fnpc_indx - 1;
    cfnpc = &(TREF(fnpca)).fnpcs[fnpc_indx];
    if (FNPC_MAX > fnpc_indx && cfnpc->last_str.addr == (char *)first &&
            cfnpc->last_str.len == slen && cfnpc->delim == ldelim.unichar_val &&
            cfnpc->byte_oriented)
    {
        /* Have valid cache. See if piece we want already in cache */
        COUNT_EVENT(hit);
        INCR_COUNT(pskip, cfnpc->npcs);

        if (trgpcidx <= cfnpc->npcs)
        {
            /* Piece is totally in cache no scan needed */
            ldst.str.addr = (char *)first + cfnpc->pstart[trgpcidx - 1];
            ldst.str.len = cfnpc->pstart[trgpcidx] - cfnpc->pstart[trgpcidx - 1] - 1;
            assert(ldst.str.len >= 0 && ldst.str.len <= src->str.len);
            *dst = ldst;
            return;
        } else
        {
            /* Not in cache but pick up scan where we left off */
            cpcidx = cfnpc->npcs;
            first = last = start + cfnpc->pstart[cpcidx];	/* First char of next pc */
            pcoff = &cfnpc->pstart[cpcidx];
            if (pcoff == cfnpc->pcoffmax)
                ++pcoff; 		/* No further updates to pstart array */
            ++cpcidx;			/* Now past last piece and on to next one */
            COUNT_EVENT(parscan);
        }
    } else
    {
        /* The piece cache index or mval validation was incorrect.
           Start from the beginning */

        COUNT_EVENT(miss);

        /* Need to steal a new piece cache, get "least recently reused" */
        cfnpc = (TREF(fnpca)).fnpcsteal;	/* Get next element to steal */
        if ((TREF(fnpca)).fnpcmax < cfnpc)
            cfnpc = &(TREF(fnpca)).fnpcs[0];
        (TREF(fnpca)).fnpcsteal = cfnpc + 1;	/* -> next element to steal */

        cfnpc->last_str = src->str;		/* Save validation info */
        cfnpc->delim = ldelim.unichar_val;
        cfnpc->npcs = 0;
        cfnpc->byte_oriented = TRUE;
        src->fnpc_indx = cfnpc->indx + 1;	/* Save where we are putting this element
							   (1 based index in mval so 0 isn't so common) */
        pcoff = &cfnpc->pstart[0];
        cpcidx = 1;				/* current piece index */
    }

    /* Do scan filling in offsets of pieces if they fit in the cache */
    spcidx = cpcidx;				/* Starting value for search */
    pcoffmax = cfnpc->pcoffmax;			/* Local end of array value */
    while (cpcidx <= trgpcidx && last < end)
    {
        /* Once through for each piece we pass, last time through to find length of piece we want */
        first = last;				/* first char of current piece */
        while (last != end && *last != dlmc) last++;	/* Find delim signaling end of piece */
        last++;					/* Bump past delim to first char next piece,
							   or if hit last char, +2 past end of piece */
        ++cpcidx;				/* Next piece */
        if (pcoff < pcoffmax)
            *pcoff++ = (unsigned int)(first - start);	/* offset to this piece */
        if (pcoff == pcoffmax)
            *pcoff++ = (unsigned int)(last - start);	/* store start of first piece beyond what is in cache */
    }

    ldst.str.addr = (char *)first;

    /* If we scanned some chars, adjust end pointer and save end of final piece */
    if (spcidx != cpcidx)
    {
        if (pcoff < pcoffmax)
            *pcoff = (unsigned int)(last - start);		/* If not at end of cache, save start of "next" piece */

        --last;					/* Undo bump past last delim or +2 past end char
							   of piece for accurate string len */
        /* Update count of pieces in cache */
        cfnpc->npcs = MIN((cfnpc->npcs + cpcidx - spcidx), FNPC_ELEM_MAX);
        assert(cfnpc->npcs <= FNPC_ELEM_MAX);
        assert(cfnpc->npcs > 0);

        /* If the above loop ended prematurely because we ran out of text, we return null string */
        if (trgpcidx < cpcidx)
            ldst.str.len = INTCAST(last - first);	/* Length of piece we located */
        else
            ldst.str.len = 0;

        INCR_COUNT(pscan, cpcidx - spcidx);	/* Pieces scanned */
    } else
        ldst.str.len  = 0;

    assert(cfnpc->npcs > 0);
    assert(ldst.str.len >= 0 && ldst.str.len <= src->str.len);
    *dst = ldst;
    return;
}
示例#7
0
文件: op_setp1.c 项目: mihawk/fis-gtm
/*
 * ----------------------------------------------------------
 * Fast path setpiece when delimiter is one (lit) char replacing
 * a single piece (last is same as first). Unicode flavor.
 *
 * Arguments:
 *	src	- source mval
 *	delim	- delimiter char
 *	expr	- expression string mval
 *	ind	- index in source mval to be set
 *	dst	- destination mval where the result is saved.
 *
 * Return:
 *	none
 * ----------------------------------------------------------
 */
void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst)
{
	size_t		str_len, delim_cnt;
	int		len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, pfx_scan_offset;
	int		dlmlen, cpy_cache_lines, mblen;
	unsigned char	*start_sfx, *str_addr, *end_pfx, *end_src, *start_pfx;
	boolean_t	do_scan, delim_last_scan, valid_char;
	mval		dummymval;	/* It's value is not used but is part of the call to op_fnp1() */
	fnpc		*cfnpc, *pfnpc;
	delimfmt	ldelim;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(gtm_utf8_mode);
	do_scan = FALSE;
	cpy_cache_lines = -1;
	ldelim.unichar_val = delim;
        if (!UTF8_VALID(ldelim.unibytes_val, (ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val)), dlmlen)
	    && !badchar_inhibit)
	{	/* The delimiter is a bad character so error out if badchar not inhibited */
		UTF8_BADCHAR(0, ldelim.unibytes_val, ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val), 0, NULL);
	}
	MV_FORCE_STR(expr);	/* Expression to put into piece place */
	if (MV_DEFINED(src))
	{
		/* We have 3 possible scenarios:
		 * 1) The source string is null. Nothing to do but proceed to building output.
		 * 2) If the requested piece is larger than can be cached by op_fnp1, call fnp1
		 *    for the maximum piece possible, use the cache info to "prime the pump" and
		 *    then process the rest of the string ourselves.
		 * 3) If the requested piece can be obtained from the cache, call op_fnp1 to validate
		 *    and rebuild the cache if necessary and then retrieve the necessary info from
		 *    the fnpc cache.
		 */
		MV_FORCE_STR(src);	/* Make sure is string prior to length check */
		if (0 == src->str.len)
		{	/* We have a null source string */
			pfx_str_len = sfx_str_len = sfx_start_offset = 0;
			delim_cnt = (0 < ind) ? (size_t)ind - 1 : 0;
		} else if (FNPC_ELEM_MAX >= ind)
		{	/* 3) Best of all possible cases. The op_fnp1 can do most of our work for us
			 *    and we can preload the cache on the new string to help its subsequent
			 *    uses along as well.
			 */
			SETWON;
			op_fnp1(src, delim, ind, &dummymval);
			SETWOFF;
			cfnpc = &(TREF(fnpca)).fnpcs[src->fnpc_indx - 1];
			assert(cfnpc->last_str.addr == src->str.addr);
			assert(cfnpc->last_str.len == src->str.len);
			assert(cfnpc->delim == delim);
			assert(0 < cfnpc->npcs);
			/* Three more scenarios: #1 piece all in cache, #2 piece would be in cache but ran
			 * out of text or #3 piece is beyond what can be cached
			 */
			if (cfnpc->npcs >= ind)
			{	/* #1 The piece we want is totally within the cache which is good news */
				pfx_str_len = cfnpc->pstart[ind - 1];
				delim_cnt = 0;
				sfx_start_offset = cfnpc->pstart[ind] - dlmlen;				/* Include delimiter */
				rep_str_len = cfnpc->pstart[ind] - cfnpc->pstart[ind - 1] - dlmlen;	/* Replace string length */
				sfx_str_len = src->str.len - pfx_str_len - rep_str_len;
				cpy_cache_lines = ind - 1;
			} else
			{	/* #2 The string was too short so the cache does not contain our string. This means
				 * that the prefix becomes any text that IS in the cache and we set the delim_cnt
				 * to be the number of missing pieces so the delimiters can be put in as part of the
				 * prefix when we build the new string.
				 */
				pfx_str_len = cfnpc->pstart[cfnpc->npcs] - dlmlen;
				delim_cnt = (size_t)(ind - cfnpc->npcs);
				sfx_start_offset = 0;
				sfx_str_len = 0;
				cpy_cache_lines = cfnpc->npcs;
			}
		} else
		{	/* 2) We have a element that would not be able to be in the fnpc cache. Go ahead
			 *    and call op_fnp1 to get cache info up to the maximum and then we will continue
			 *    the scan on our own.
			 */
			SETWON;
			op_fnp1(src, delim, FNPC_ELEM_MAX, &dummymval);
			SETWOFF;
			cfnpc = &(TREF(fnpca)).fnpcs[src->fnpc_indx - 1];
			assert(cfnpc->last_str.addr == src->str.addr);
			assert(cfnpc->last_str.len == src->str.len);
			assert(cfnpc->delim == delim);
			assert(0 < cfnpc->npcs);
			if (FNPC_ELEM_MAX > cfnpc->npcs)
			{	/* We ran out of text so the scan is complete. This is basically the same
				 * as case #2 above.
				 */
				pfx_str_len = cfnpc->pstart[cfnpc->npcs] - dlmlen;
				delim_cnt = (size_t)(ind - cfnpc->npcs);
				sfx_start_offset = 0;
				sfx_str_len = 0;
				cpy_cache_lines = cfnpc->npcs;
			} else
			{	/* We have a case where the piece we want cannot be kept in cache. In the special
				 * case where there is no more text to handle, we don't need to scan further. Otherwise
				 * we prime the pump and continue the scan where the cache left off.
				 */
				if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len)	/* Note assignment */
					/* Normal case where we prime the pump */
					do_scan = TRUE;
				else
				{	/* Special case -- no more text to scan */
					pfx_str_len = cfnpc->pstart[FNPC_ELEM_MAX] - dlmlen;
					sfx_start_offset = 0;
					sfx_str_len = 0;
				}
				delim_cnt = (size_t)ind - FNPC_ELEM_MAX;
				cpy_cache_lines = FNPC_ELEM_MAX;
			}
		}
	} else
	{	/* Source is not defined -- treat as a null string */
		pfx_str_len = sfx_str_len = sfx_start_offset = 0;
		delim_cnt = (size_t)ind - 1;
	}
	/* If we have been forced to do our own scan, do that here. Note the variable pfx_scan_offset has been
	 * set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters
	 * still need to be processed.
	 */
	if (do_scan)
	{	/* Scan the line isolating prefix piece, and end of the
		 * piece being replaced
		 */
		COUNT_EVENT(small);
		end_pfx = start_sfx = (unsigned char *)src->str.addr + pfx_scan_offset;
		end_src = (unsigned char *)src->str.addr + src->str.len;
		/* The compiler would unroll this loop this way anyway but we want to
		 * adjust the start_sfx pointer after the loop but only if we have gone
		 * into it at least once.
		 */
		if ((0 < delim_cnt) && (start_sfx < end_src))
		{
			do
			{
				end_pfx = start_sfx;
				delim_last_scan = FALSE;		/* Whether delimiter is last character scanned */
				while (start_sfx < end_src)
				{
					valid_char = UTF8_VALID(start_sfx, end_src, mblen); /* Length of next char */
					if (!valid_char)
					{	/* Next character is not valid unicode. If badchar error is not inhibited,
						 * signal it now. If it is inhibited, just treat the character as a single
						 * character and continue.
						 */
						if (!badchar_inhibit)
							utf8_badchar(0, start_sfx, end_src, 0, NULL);
						assert(1 == mblen);
					}
					/* Getting mblen first allows us to do quick length compare before the
					 * heavier weight memcmp call.
					 */
					assert(0 < mblen);
					if (mblen == dlmlen && 0 == memcmp(start_sfx, ldelim.unibytes_val, dlmlen))
					{
						delim_last_scan = TRUE;
						break;
					}
					/* Increment ptrs by size of found char */
					start_sfx += mblen;
				}
				start_sfx += dlmlen;
				delim_cnt--;
			} while ((0 < delim_cnt) && (start_sfx < end_src));
			/* We have to backup up the suffix start pointer except under the condition
			 * that the last character in the buffer is the last delimiter we were looking
			 * for.
			 */
			if ((0 == delim_cnt) || (start_sfx < end_src) || !delim_last_scan)
				start_sfx -= dlmlen;			/* Back up suffix to include delimiter char */
			/* If we scanned to the end (no text left) and still have delimiters to
			 * find, the entire src text should be part of the prefix
			 */
			if ((start_sfx >= end_src) && (0 < delim_cnt))
			{
				end_pfx = start_sfx;
				if (delim_last_scan)			/* if last char was delim, reduce delim cnt */
					--delim_cnt;
			}
		} else
		{
			/* If not doing any token finding, then this count becomes the number
			 * of tokens to output. Adjust accordingly.
			 */
			if (0 < delim_cnt)
				--delim_cnt;
		}
		INCR_COUNT(small_pcs, (int)((size_t)ind - delim_cnt));
		/* Now having the following situation:
		 * end_pfx	-> end of the prefix piece including delimiter
		 * start_sfx	-> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none
		 */
		pfx_str_len = (int)(end_pfx - (unsigned char *)src->str.addr);
		if (0 > pfx_str_len)
			pfx_str_len = 0;
		sfx_start_offset = (int)(start_sfx - (unsigned char *)src->str.addr);
		sfx_str_len = src->str.len - sfx_start_offset;
		if (0 > sfx_str_len)
			sfx_str_len = 0;
	}
	/* Calculate total string len. delim_cnt has needed padding delimiters for null fields */
	str_len = (size_t)expr->str.len + (size_t)pfx_str_len + (delim_cnt * (size_t)dlmlen) + (size_t)sfx_str_len;
	if (MAX_STRLEN < str_len)
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
	ENSURE_STP_FREE_SPACE((int)str_len);
	str_addr = stringpool.free;
	start_pfx = (unsigned char *)src->str.addr;
	/* copy prefix */
	if (0 < pfx_str_len)
	{
		memcpy(str_addr, src->str.addr, pfx_str_len);
		str_addr += pfx_str_len;
	}
	/* copy delimiters */
	while (0 < delim_cnt--)
	{
		memcpy(str_addr, ldelim.unibytes_val, dlmlen);
		str_addr += dlmlen;
	}
	/* copy expression */
	if (0 < expr->str.len)
	{
		memcpy(str_addr, expr->str.addr, expr->str.len);
		str_addr += expr->str.len;
	}
	/* copy suffix */
	if (0 < sfx_str_len)
	{
		memcpy(str_addr, start_pfx + sfx_start_offset, sfx_str_len);
		str_addr += sfx_str_len;
	}
	assert(IS_AT_END_OF_STRINGPOOL(str_addr, -str_len));
	dst->mvtype = MV_STR;
	dst->str.len = INTCAST(str_addr - stringpool.free);
	dst->str.addr = (char *)stringpool.free;
	stringpool.free = str_addr;
	/* If available, update the cache information for this newly created mval to hopefully
	 * give it a head start on its next usage. Note that we can only copy over the cache info
	 * for the prefix. We cannot include information for the 'expression' except where it starts
	 * because the expression could itself contain delimiters that would be found on a rescan.
	 */
	if (0 < cpy_cache_lines)
	{
		pfnpc = cfnpc;				/* pointer for src mval's cache */
		do
		{
			cfnpc = (TREF(fnpca)).fnpcsteal;	/* Next cache element to steal */
			if ((TREF(fnpca)).fnpcmax < cfnpc)
				cfnpc = &(TREF(fnpca)).fnpcs[0];
			(TREF(fnpca)).fnpcsteal = cfnpc + 1;	/* -> next element to steal */
		} while (cfnpc == pfnpc);		/* Make sure we don't step on ourselves */
		cfnpc->last_str = dst->str;		/* Save validation info */
		cfnpc->delim = delim;
		cfnpc->npcs = cpy_cache_lines;
		dst->fnpc_indx = cfnpc->indx + 1;	/* Save where we are putting this element
							 * (1 based index in mval so 0 isn't so common)
							 */
		memcpy(&cfnpc->pstart[0], &pfnpc->pstart[0], (cfnpc->npcs + 1) * SIZEOF(unsigned int));
	} else
示例#8
0
void op_fnp1(mval *src, int delim, int trgpcidx,  mval *dst)
{
	unsigned char	*first, *last, *start, *end;
	unsigned int	*pcoff, *pcoffmax, fnpc_indx, slen;
	int		trgpc, cpcidx, spcidx, mblen, dlmlen;
	boolean_t       valid_char;
	mval		ldst;		/* Local copy since &dst == &src .. move to dst at return */
	fnpc   		*cfnpc;
	delimfmt	ldelim;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(gtm_utf8_mode);
	MV_FORCE_STR(src);
	ldelim.unichar_val = delim;
	if (!UTF8_VALID(ldelim.unibytes_val, ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val), dlmlen) &&
			!badchar_inhibit)
	{ /* The delimiter is a bad character so error out if badchar not inhibited */
		UTF8_BADCHAR(0, ldelim.unibytes_val, ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val), 0, NULL);
	}

	ldst.mvtype = MV_STR;
	start = first = last = (unsigned char *)src->str.addr;
	slen = src->str.len;
	end = start + slen;

	/* Detect annoyance cases and deal with quickly so we don't muck up the
	   logic below trying to handle it properly */
	if (0 >= trgpcidx || 0 == slen)
	{
		ldst.str.addr = (char *)start;
		ldst.str.len  = 0;
		*dst = ldst;
		return;
	}

	/* Test mval for valid cache: index ok, mval addr same, delim same. One additional test
	 * is if the cache entry is byte_oriented, then this cache entry was created by $ZPIECE
	 * (using bytes) and since its results are not same as $PIECE(), we must ignore the cache
	 * and rebuild it for this mval. */
	fnpc_indx = src->fnpc_indx - 1;
	cfnpc = &(TREF(fnpca)).fnpcs[fnpc_indx];
	if (FNPC_MAX > fnpc_indx && cfnpc->last_str.addr == (char *)first &&
	    cfnpc->last_str.len == slen && cfnpc->delim == ldelim.unichar_val &&
	    !cfnpc->byte_oriented) /* cannot use the cache created by an earlier $ZPIECE() */
	{
		/* Have valid cache. See if piece we want already in cache */
		COUNT_EVENT(hit);
		INCR_COUNT(pskip, cfnpc->npcs);

		if (trgpcidx <= cfnpc->npcs)
		{
			/* Piece is totally in cache no scan needed */
			ldst.str.addr = (char *)first + cfnpc->pstart[trgpcidx - 1];
			ldst.str.len = cfnpc->pstart[trgpcidx] - cfnpc->pstart[trgpcidx - 1] - dlmlen;
			assert(ldst.str.len >= 0 && ldst.str.len <= src->str.len);
			*dst = ldst;
			return;
		} else
		{
			/* Not in cache but pick up scan where we left off */
			cpcidx = cfnpc->npcs;
			first = last = start + cfnpc->pstart[cpcidx];	/* First byte of next pc */
			pcoff = &cfnpc->pstart[cpcidx];
			if (pcoff == cfnpc->pcoffmax)
				++pcoff; 		/* No further updates to pstart array */
			++cpcidx;			/* Now past last piece and on to next one */
			COUNT_EVENT(parscan);
		}
	} else
	{
		/* The piece cache index or mval validation was incorrect.
		   Start from the beginning */

		COUNT_EVENT(miss);

		/* Need to steal a new piece cache, get "least recently reused" */
		cfnpc = (TREF(fnpca)).fnpcsteal;	/* Get next element to steal */
		if ((TREF(fnpca)).fnpcmax < cfnpc)
			cfnpc = &(TREF(fnpca)).fnpcs[0];
		(TREF(fnpca)).fnpcsteal = cfnpc + 1;	/* -> next element to steal */

		cfnpc->last_str = src->str;		/* Save validation info */
		cfnpc->delim = ldelim.unichar_val;
		cfnpc->npcs = 0;
		cfnpc->byte_oriented = FALSE;
		src->fnpc_indx = cfnpc->indx + 1;	/* Save where we are putting this element
							   (1 based index in mval so 0 isn't so common) */
		pcoff = &cfnpc->pstart[0];
		cpcidx = 1;				/* current piece index */
	}

	/* Do scan filling in offsets of pieces if they fit in the cache */
	spcidx = cpcidx;				/* Starting value for search */
	pcoffmax = cfnpc->pcoffmax;			/* Local end of array value */
	while (cpcidx <= trgpcidx && last < end)
	{
		/* Once through for each piece we pass, last time through to find length of piece we want */
		first = last;				/* first char of current piece */
		while (last < end)
		{
			valid_char = UTF8_VALID(last, end, mblen);	/* Length of next char */
			if (!valid_char)
			{	/* Next character is not valid unicode. If badchar error is not inhibited,
				   signal it now. If it is inhibited, just treat the character as a single
				   character and continue.
				*/
				if (!badchar_inhibit)
					utf8_badchar(0, last, end, 0, NULL);
				assert(1 == mblen);
			}
			/* Getting mblen first allows us to do quick length compare before the
			   heavier weight memcmp call.
			*/
			assert(0 < mblen);
			if (mblen == dlmlen)
			{
				if (1 == dlmlen)
				{
					if (*last == ldelim.unibytes_val[0])			/* Shortcut - test single byte */
						break;
				} else if (0 == memcmp(last, ldelim.unibytes_val, dlmlen))	/* Longcut - for multibyte chk */
					break;
			}
			last += mblen;  	/* Find delim signaling end of piece */
		}
		last += dlmlen;				/* Bump past delim to first byte of next piece. The length of
							   the delimiter is assumed in the pcoff array and is removed
							   when piece length is calculated so even if we hit the end of
							   the scanned source, we bump the pointer so this extra length
							   is reflected in the pcoff array consistently.
							*/
		++cpcidx;				/* Next piece */
		if (pcoff < pcoffmax)
			*pcoff++ =(unsigned int)(first - start);	/* offset to this piece */
		if (pcoff == pcoffmax)
			*pcoff++ = (unsigned int)(last - start);	/* store start of first piece beyond what is in cache */
	}

	ldst.str.addr = (char *)first;

	/* If we scanned some chars, adjust end pointer and save end of final piece */
	if (spcidx != cpcidx)
	{
		if (pcoff < pcoffmax)
			*pcoff = (unsigned int)(last - start);		/* If not at end of cache, save start of "next" piece */

		last -= dlmlen;				/* Undo bump past last delim (existing or not)
							   of piece for accurate string len */
		/* Update count of pieces in cache */
		cfnpc->npcs = MIN((cfnpc->npcs + cpcidx - spcidx), FNPC_ELEM_MAX);
		assert(cfnpc->npcs <= FNPC_ELEM_MAX);
		assert(cfnpc->npcs > 0);

		/* If we the above loop ended prematurely because we ran out of text, we return null string */
		if (trgpcidx < cpcidx)
			ldst.str.len = INTCAST(last - first);	/* Length of piece we located */
		else
			ldst.str.len = 0;

		INCR_COUNT(pscan, cpcidx - spcidx);	/* Pieces scanned */
	} else
		ldst.str.len  = 0;

	assert(cfnpc->npcs > 0);
	assert(ldst.str.len >= 0 && ldst.str.len <= src->str.len);
	*dst = ldst;
	return;
}
示例#9
0
/*
 * Append another address/length to the end of an Address/Length List,
 * growing the list if permitted and necessary.
 *
 * Returns: SUCCESS/FAILURE
 */
int 
alenlist_append(	alenlist_t alenlist, 		/* append to this list */
			alenaddr_t address, 		/* address to append */
			size_t length,			/* length to append */
			unsigned flags)
{
	alen_t *alenp;
	int index, last_index;

	index = alenlist->al_logical_size % ALEN_CHUNK_SZ;

	if ((alenlist->al_logical_size > 0)) {
		/*
		 * See if we can compact this new pair in with the previous entry.
		 * al_compaction_address holds that value that we'd need to see
		 * in order to compact.
		 */
		if (!(flags & AL_NOCOMPACT) &&
		    (alenlist->al_compaction_address == address)) {
			last_index = (alenlist->al_logical_size-1) % ALEN_CHUNK_SZ;
			alenp = &(alenlist->al_last_chunk->alc_pair[last_index]);
			alenp->al_length += length;
			alenlist->al_compaction_address += length;
			return(ALENLIST_SUCCESS);
		}

		/*
		 * If we're out of room in this chunk, move to a new chunk.
	 	 */
		if (index == 0) {
			if (alenlist->al_flags & AL_FIXED_SIZE) {
				alenlist->al_last_chunk = alenlist->al_last_chunk->alc_next;

				/* If we're out of space in a FIXED_SIZE List, quit. */
				if (alenlist->al_last_chunk == NULL) {
					ASSERT(alenlist->al_logical_size == alenlist->al_actual_size);
					return(ALENLIST_FAILURE);
				}
			} else {
				alenlist_chunk_t new_chunk;

				new_chunk = snia_kmem_zone_alloc(alenlist_chunk_zone, 
							flags & AL_NOSLEEP ? VM_NOSLEEP : 0);

				if (new_chunk == NULL)
					return(ALENLIST_FAILURE);

				alenlist->al_last_chunk->alc_next = new_chunk;
				new_chunk->alc_next = NULL;
				alenlist->al_last_chunk = new_chunk;
				alenlist->al_actual_size += ALEN_CHUNK_SZ;
				INCR_COUNT(&alenlist_chunk_count);
			}
		}
	}

	alenp = &(alenlist->al_last_chunk->alc_pair[index]);
	alenp->al_addr = address;
	alenp->al_length = length;
	
	alenlist->al_logical_size++;
	alenlist->al_compaction_address = address + length;

	return(ALENLIST_SUCCESS);
}