Ejemplo n.º 1
0
// A faster version of MsgForMsgBlock
// Similar to http://blog.golang.org/go-concurrency-patterns-timing-out-and
// try more and get the fastest one
func ParalMsgForMsg(m btcmsg.Message, f peer.MsgFilter, paral int) btcmsg.Message {
	ch := make(chan struct {
		btcmsg.Message
		Error error
	}, paral)
	for i := 0; i < paral; i++ {
		h := Peers().Borrow()
		go func() {
			select {
			case ch <- h.MsgForMsg(m, f):
				Peers().Return(h)
			default:
			}
		}()
	}
	for i := 0; i < paral; i++ {
		me := <-ch
		if me.Error == nil {
			return me.Message
		} else {
			log.Debugf("ParalMsgForMsg error : %s", me.Error)
		}
	}
	return nil
}
Ejemplo n.º 2
0
// Add a record
func (db *KDB) Add(key []byte, value []byte) error {
	if len(value) > int(math.MaxInt16) {
		return errors.New("KDB:Add data too long!")
	}
	kdata := toInternal(key)
	db.mutex.Lock()
	defer db.mutex.Unlock()
	db.smutex.RLock()
	defer db.smutex.RUnlock()
	collision := false
	n, err := db.slotScan(kdata, nil,
		func(val []byte, mv bool) error {
			collision = true // We hit an internal key collision
			log.Debugf("Internal key collision happened")
			var cd collisionData
			if mv {
				cd.fromBytes(val)
			} else {
				cd.firstVal = val
			}
			cd.add(key, value)
			value = cd.toBytes()
			return nil
		})
	if err != nil {
		return err
	}
	c := make([]byte, SlotSize, SlotSize)
	ul := (len(value) == ValLenUnit)
	kdata.setFlags(ul)
	copy(c[:InternalKeySize], kdata[:])
	binary.LittleEndian.PutUint32(c[InternalKeySize:], db.dataLoc())
	db.writeKey(c, n)
	db.writeValue(value, ul, collision)
	return nil
}
Ejemplo n.º 3
0
func (sw *swdl) schedule(msgs map[int]interface{}) {
	// 1. Fill blanks with downloaded blocks
	got := 0
	for k, v := range msgs {
		i := k - sw.cursor
		if _, ok := v.(*btcmsg.Message_block); ok {
			got++
		}
		sw.window[i] = v
	}
	// 2. Congestion control
	if len(msgs) > 0 && sw.ca.update(got, len(msgs)) {
		// Send nil for a "NOP" download
		sw.sendWork(nil)
		return
	}
	// 3. Slide window and process blocks
	dist := len(sw.window) // Slide distance
	for i, elem := range sw.window {
		if bm, ok := elem.(*btcmsg.Message_block); ok {
			//log.Infoln("save block", i + sw.cursor, i, sw.cursor, bm.Header.Hash())
			sw.chblock <- struct {
				btcmsg.Message
				I int
			}{bm, i + sw.cursor}
		} else {
			dist = i
			break
		}
	}
	if dist > 0 {
		log.Infof("swdl: window slided %d", dist)
	}
	sw.window = sw.window[dist:]
	sw.cursor += dist
	l := len(sw.window)
	for i := l; i < sw.size; i++ {
		p := sw.cursor + i
		if p >= sw.end {
			break
		}
		ie := blockchain.GetInvElem(p)
		sw.window = append(sw.window, ie)
	}
	if len(sw.window) == 0 {
		close(sw.done) // All blocks downloaded
	}
	// 4. Handle unfinished work
	unfinished := make(map[int]*blockchain.InvElement)
	for i, elem := range sw.window {
		if ie, ok := elem.(*blockchain.InvElement); ok {
			unfinished[sw.cursor+i] = ie
		}
	}
	l = len(unfinished)
	if len(msgs) > 0 {
		log.Debugf("winsize %d left %d got %d cursor %d health %f", len(sw.window), l, got, sw.cursor, sw.ca.health)
	}
	if l == 0 { // No blocks left, do nothing
	} else if l <= sw.load {
		sw.sendWork(unfinished)
	} else {
		work := make(map[int]*blockchain.InvElement)
		for k, v := range unfinished {
			work[k] = v
			if len(work) >= sw.load {
				if !sw.sendWork(work) { // channel is full
					break
				}
				work = make(map[int]*blockchain.InvElement)
			}
		}
	}
}