// Read is thread-safe func (sr *StorageReader) Read(p []byte) (n int, err error) { sr.mutex.Lock() defer sr.mutex.Unlock() if !sr.parent.alive { return -1, errors.New("EOF") } chunkId := sr.Offset / CHUNK_SIZE internalMsgId := uint64(sr.Offset % CHUNK_SIZE) sr.parent.dataCond.L.Lock() for sr.currentSub == nil || chunkId >= uint64(len(sr.parent.stores)) || internalMsgId >= sr.parent.stores[chunkId].Size { // Block for new data sr.parent.dataCond.Wait() sr.handleRollover() } sr.parent.dataCond.L.Unlock() // We have a valid reader, and can read from it nextMsgSize, err := sr.parent.stores[chunkId].SizeOf(internalMsgId) if err != nil { return 0, err } if nextMsgSize > uint64(len(p)) { return 0, fmt.Errorf("Message, of size %d, does not fit into available buffer", nextMsgSize) } target := p[0:nextMsgSize] _, err = sr.currentSub.Read(target) utils.Check(err) sr.Offset++ sr.handleRollover() return int(nextMsgSize), nil }
func (t *Track) startWriter(startId uint64) { t.writeChan = make(chan []byte, CHUNK_SIZE/100) // Buffer 1% of a chunk go func() { msgId := startId for { msg, more := <-t.writeChan if !more { t.alive = false return } chunkId := msgId / CHUNK_SIZE if chunkId == uint64(len(t.stores)) { if chunkId > 0 { t.stores[chunkId-1].switchToReadOnly() // Migrate the old chunk to readonly } storeId := fmt.Sprintf("%s%d", t.Id, chunkId) t.stores = append(t.stores, NewFileStorage(t.RootPath, storeId, CHUNK_SIZE)) } internalMsgId := int(msgId % CHUNK_SIZE) err := t.stores[chunkId].WriteMessage(internalMsgId, msg) utils.Check(err) msgId++ // Tell any waiting routines that there's new data t.dataCond.Broadcast() } }() }
func (t *Track) ReaderAt(offset uint64) (io.ReadCloser, error) { if offset < 0 { return nil, fmt.Errorf("Offset out of bounds: %d", offset) } r := &StorageReader{ parent: t, Offset: offset, mutex: &sync.Mutex{}, } chunkIndex := offset / CHUNK_SIZE msgIndex := offset % CHUNK_SIZE if chunkIndex < uint64(len(t.stores)) && uint64(msgIndex) < t.stores[chunkIndex].Size { var err error r.currentSub, err = t.stores[chunkIndex].ReaderAt(msgIndex) utils.Check(err) } return r, nil }