/* * reduce a subtree into a single leaf node */ static void _reduce(aguri_t *tp, anode_t *np, int depth) { if (depth > 0) { /* nodes to be deleted */ if (np->tn_left == NULL) { /* leaf node */ assert(np->tn_right == NULL); TAILQ_REMOVE(&tp->tr_lru, np, tn_chain); } else { /* internal node */ assert(np->tn_right != NULL); _reduce(tp, np->tn_left, depth + 1); _reduce(tp, np->tn_right, depth + 1); } np->tn_parent->tn_count += np->tn_count; if (np->tn_parent->tn_left == np) np->tn_parent->tn_left = NULL; else np->tn_parent->tn_right = NULL; np->tn_intree = 0; TAILQ_INSERT_TAIL(&tp->tr_lru, np, tn_chain); tp->tr_nfree++; return; } /* remaining node, converted from an internal node to a leaf */ assert(np->tn_left != NULL && np->tn_right != NULL); _reduce(tp, np->tn_left, depth + 1); _reduce(tp, np->tn_right, depth + 1); assert(np->tn_left == NULL && np->tn_right == NULL); TAILQ_INSERT_HEAD(&tp->tr_lru, np, tn_chain); }
/** * Reduces a list of tuple object (key, value) to a single tuple {_id: key, value: val} * Also applies a finalizer method if present. */ BSONObj JSReducer::finalReduce( const BSONList& tuples , Finalizer * finalizer ) { BSONObj res; BSONObj key; if (tuples.size() == 1) { // 1 obj, just use it key = tuples[0]; BSONObjBuilder b(key.objsize()); BSONObjIterator it(key); b.appendAs( it.next() , "_id" ); b.appendAs( it.next() , "value" ); res = b.obj(); } else { // need to reduce int endSizeEstimate = 16; _reduce( tuples , key , endSizeEstimate ); BSONObjBuilder b(endSizeEstimate); b.appendAs( key.firstElement() , "_id" ); _func.scope()->append( b , "value" , "return" ); res = b.obj(); } if ( finalizer ) { res = finalizer->finalize( res ); } return res; }
void __init() { const_0 = new str("*** ERROR! *** reduce() called with empty sequence and no initial value"); __name__ = new str("__main__"); acc = __lambda0__; score = (new list<__ss_int>(4,1,2,3,4)); print2(NULL,0,1, ___box(_reduce(acc, score, 0))); }
BSONObj JSReducer::reduce( const BSONList& tuples ) { BSONObj key; int endSizeEstimate = 16; _reduce( tuples , key , endSizeEstimate ); BSONObjBuilder b(endSizeEstimate); b.appendAs( key.firstElement() , "0" ); _func.scope()->append( b , "1" , "return" ); return b.obj(); }
BSONObj JSReducer::reduce( const BSONList& tuples , Finalizer * finalizer ) { BSONObj key; int endSizeEstimate = 16; _reduce( tuples , key , endSizeEstimate ); BSONObjBuilder b(endSizeEstimate); b.appendAs( key.firstElement() , "_id" ); _func.scope()->append( b , "value" , "return" ); BSONObj res = b.obj(); if ( finalizer ) { res = finalizer->finalize( res ); } return res; }
void aguri_release(aguri_t **tpp) { aguri_t *tp = *tpp; anode_t *np = NULL; *tpp = NULL; /* first, remove nodes from the tree */ if (tp->tr_top->tn_left != NULL) _reduce(tp, tp->tr_top, 0); /* * at this point, only top is remaining in the tree, * and all nodes are in the LRU list. */ assert(tp->tr_top->tn_left == NULL && tp->tr_top->tn_right == NULL); while ((np = TAILQ_FIRST(&tp->tr_lru)) != NULL) { TAILQ_REMOVE(&tp->tr_lru, np, tn_chain); free(np); } free(tp); }
/** * actually applies a reduce, to a list of tuples (key, value). * After the call, tuples will hold a single tuple {"0": key, "1": value} */ void JSReducer::_reduce( const BSONList& tuples , BSONObj& key , int& endSizeEstimate ) { uassert( 10074 , "need values" , tuples.size() ); int sizeEstimate = ( tuples.size() * tuples.begin()->getField( "value" ).size() ) + 128; // need to build the reduce args: ( key, [values] ) BSONObjBuilder reduceArgs( sizeEstimate ); boost::scoped_ptr<BSONArrayBuilder> valueBuilder; int sizeSoFar = 0; unsigned n = 0; for ( ; n<tuples.size(); n++ ) { BSONObjIterator j(tuples[n]); BSONElement keyE = j.next(); if ( n == 0 ) { reduceArgs.append( keyE ); key = keyE.wrap(); sizeSoFar = 5 + keyE.size(); valueBuilder.reset(new BSONArrayBuilder( reduceArgs.subarrayStart( "tuples" ) )); } BSONElement ee = j.next(); uassert( 13070 , "value too large to reduce" , ee.size() < ( BSONObjMaxUserSize / 2 ) ); if ( sizeSoFar + ee.size() > BSONObjMaxUserSize ) { assert( n > 1 ); // if not, inf. loop break; } valueBuilder->append( ee ); sizeSoFar += ee.size(); } assert(valueBuilder); valueBuilder->done(); BSONObj args = reduceArgs.obj(); Scope * s = _func.scope(); s->invokeSafe( _func.func() , args ); if ( s->type( "return" ) == Array ) { uasserted( 10075 , "reduce -> multiple not supported yet"); return; } endSizeEstimate = key.objsize() + ( args.objsize() / tuples.size() ); if ( n == tuples.size() ) return; // the input list was too large, add the rest of elmts to new tuples and reduce again // note: would be better to use loop instead of recursion to avoid stack overflow BSONList x; for ( ; n < tuples.size(); n++ ) { x.push_back( tuples[n] ); } BSONObjBuilder temp( endSizeEstimate ); temp.append( key.firstElement() ); s->append( temp , "1" , "return" ); x.push_back( temp.obj() ); _reduce( x , key , endSizeEstimate ); }
Purse(int p=0, int n=0, int d=0, int q=0) : _p(p), _n(n), _d(d), _q(q) { _reduce(); }
void remove(int n) { _p -= n; _reduce(); }
void insert(int n) { _p += n; _reduce(); }
inline void base_string<basic_allocate_size>::shrink() { _reduce(__len); }//_shrink()
/* * reclaim leaf nodes using the LRU replacement algorithm. * we don't select a node as a possible victim if the node is * - already reclaimed * - the counter value is larger than the threshold * - both of its parent and sibling's subtree are larger than the threshold * then, we compare parent's count with sibling's subtree sum. * - if parent is larger, reduce the subtree into parent. * - otherwise, reclaim this node and parent, and leave the sibling's subtree. */ static void _reclaim(aguri_t *tp, int n) { anode_t *np, *after, *parent, *sibling; u_int64_t thresh, sum, moved_to_head; thresh = tp->tr_count / 64; if (thresh == 0) thresh = 1; while (tp->tr_nfree < n) { /* * select a victim from the LRU list. * exclude nodes whose count is more than the threshold. */ moved_to_head = 0; np = TAILQ_LAST(&tp->tr_lru, _lru); while (np != NULL) { if (np->tn_intree == 0) { /* free node */ np = TAILQ_PREV(np, _lru, tn_chain); continue; } else if (np->tn_count > thresh) { /* if bigger than thresh, move it to head */ after = np; np = TAILQ_PREV(np, _lru, tn_chain); if (moved_to_head > 3) continue; TAILQ_REMOVE(&tp->tr_lru, after, tn_chain); TAILQ_INSERT_HEAD(&tp->tr_lru, after, tn_chain); moved_to_head++; continue; } /* * a possible victim found. * see if either its parent or sibling's subtree is * smaller than the threshold. * also check if parent is not the top node. */ parent = np->tn_parent; if (parent->tn_left == np) sibling = parent->tn_right; else sibling = parent->tn_left; sum = _subsum(sibling); if (sum > thresh && (parent->tn_count > thresh || parent == tp->tr_top)) { after = np; np = TAILQ_PREV(np, _lru, tn_chain); if (moved_to_head > 3) continue; TAILQ_REMOVE(&tp->tr_lru, after, tn_chain); TAILQ_INSERT_HEAD(&tp->tr_lru, after, tn_chain); moved_to_head++; continue; } /* * at this point, we are about to reclaim this victim. * compare parent's count with sibling's subtree sum. * if parent is larger, reduce the subtree into parent. * otherwise, reclaim this node and parent, and leave * sibling. */ if (parent->tn_count > sum || parent == tp->tr_top) _reduce(tp, np->tn_parent, 0); else _free(tp, np); break; } if (np == NULL) { thresh *= 2; #if 0 fprintf(stderr, "thresh increased to %llu\n", thresh); #endif } } }