Exemple #1
0
// 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
}
Exemple #2
0
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
}
Exemple #3
0
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)
					}
				}
			}()
		}
	}
}