// StoreBlock is blocking if the blockbuffer is full func (c *Client) StoreBlock(block *HashboxBlock) Byte128 { // Add the block to the io queue for full := true; full; { // c.dispatchMutex.Lock() if c.closing { c.dispatchMutex.Unlock() panic(errors.New("Connection closed")) } else if c.blockqueuesize+bytearray.ChunkQuantize(int64(block.UncompressedSize))*2 < c.QueueMax { if c.blockbuffer[block.BlockID] == nil { c.blockbuffer[block.BlockID] = block c.blockqueuesize += bytearray.ChunkQuantize(int64(block.UncompressedSize)) } else { block.Release() c.dispatchMutex.Unlock() return block.BlockID } full = false } c.dispatchMutex.Unlock() if full { time.Sleep(25 * time.Millisecond) } } // Put an allocate block on the line c.dispatchMessage(MsgTypeAllocateBlock, &MsgClientAllocateBlock{BlockID: block.BlockID}, nil) return block.BlockID }
func (c *Client) singleExchange(outgoing *messageDispatch) *ProtocolMessage { // Send an outgoing message WriteMessage(c.conn, outgoing.msg) // Wait for the reply incoming := ReadMessage(c.conn) if incoming.Num != outgoing.msg.Num { panic(errors.New("ASSERT! Jag kan inte programmera")) } if outgoing.returnChannel != nil { outgoing.returnChannel <- incoming close(outgoing.returnChannel) } // Handle block queue switch d := incoming.Data.(type) { case *MsgServerError: panic(errors.New("Received error from server: " + string(d.ErrorMessage))) case *MsgServerAcknowledgeBlock: var skipped bool = false c.dispatchMutex.Lock() block := c.blockbuffer[d.BlockID] if block != nil { if block.CompressedSize < 0 { // no encoded data = never sent skipped = true c.blockqueuesize -= bytearray.ChunkQuantize(int64(block.UncompressedSize)) } else { c.blockqueuesize -= bytearray.ChunkQuantize(int64(block.CompressedSize)) } block.Release() delete(c.blockbuffer, d.BlockID) } c.dispatchMutex.Unlock() if skipped { atomic.AddInt32(&c.skippedBlocks, 1) //c.skippedBlocks++ c.Paint("-") } case *MsgServerReadBlock: c.sendQueue(d.BlockID) case *MsgServerWriteBlock: } return incoming }
func (c *Client) sendQueue(what Byte128) { c.dispatchMutex.Lock() defer c.dispatchMutex.Unlock() block := c.blockbuffer[what] if block != nil { c.sendqueue = append(c.sendqueue, &sendQueueEntry{0, block}) // fmt.Printf("+q=%d;", len(c.sendqueue)) if c.sendworkers < int32(runtime.NumCPU()) { atomic.AddInt32(&c.sendworkers, 1) go func() { defer func() { // a panic was raised inside the goroutine (most likely the channel was closed) if r := recover(); !c.closing && r != nil { err, _ := <-c.handlerErrorSignal if err != nil { panic(err) } else { panic(r) } } }() for done := false; !done; { var workItem *sendQueueEntry c.dispatchMutex.Lock() if len(c.sendqueue) > 0 { if c.sendqueue[0].state == 2 { // compressed c.blockqueuesize -= bytearray.ChunkQuantize(int64(c.sendqueue[0].block.UncompressedSize)) c.blockqueuesize += bytearray.ChunkQuantize(int64(c.sendqueue[0].block.CompressedSize)) workItem = c.sendqueue[0] // send it } else if c.sendqueue[0].state == 4 { // sent c.sendqueue = c.sendqueue[1:] // remove it // fmt.Printf("-q=%d;", len(c.sendqueue)) } else { for i := 0; i < len(c.sendqueue); i++ { if c.sendqueue[i].state == 0 { // new workItem = c.sendqueue[i] // compress it break } } } if workItem != nil { atomic.AddInt32(&workItem.state, 1) } } else { done = true atomic.AddInt32(&c.sendworkers, -1) // fmt.Println("worker stopping") } c.dispatchMutex.Unlock() if workItem != nil { switch workItem.state { case 0: panic("ASSERT!") case 1: workItem.block.CompressData() atomic.AddInt32(&workItem.state, 1) case 2: panic("ASSERT!") case 3: atomic.AddInt64(&c.WriteData, int64(workItem.block.UncompressedSize)) atomic.AddInt64(&c.WriteDataCompressed, int64(workItem.block.CompressedSize)) atomic.AddInt32(&c.transmittedBlocks, 1) // c.transmittedBlocks++ c.Paint("*") msg := &ProtocolMessage{Num: uint16(atomic.AddUint32(&c.msgNum, 1) - 1), Type: MsgTypeWriteBlock, Data: &MsgClientWriteBlock{Block: workItem.block}} c.storeChannel <- &messageDispatch{msg: msg} atomic.AddInt32(&workItem.state, 1) default: panic("ASSERT!") } } else { time.Sleep(25 * time.Millisecond) } } }() } } }