// 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 }
// 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 }
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) } } } }