Remove race conditions when accessing the last chunk

This commit is contained in:
Junegunn Choi 2015-01-04 05:01:13 +09:00
parent 0dd024a09f
commit d2f7acbc69
3 changed files with 36 additions and 20 deletions

View File

@ -42,14 +42,6 @@ func CountItems(cs []*Chunk) int {
return CHUNK_SIZE*(len(cs)-1) + len(*(cs[len(cs)-1])) return CHUNK_SIZE*(len(cs)-1) + len(*(cs[len(cs)-1]))
} }
func (cl *ChunkList) Count() int {
return cl.count
}
func (cl *ChunkList) Chunks() []*Chunk {
return cl.chunks
}
func (cl *ChunkList) Push(data string) { func (cl *ChunkList) Push(data string) {
cl.mutex.Lock() cl.mutex.Lock()
defer cl.mutex.Unlock() defer cl.mutex.Unlock()
@ -63,11 +55,24 @@ func (cl *ChunkList) Push(data string) {
cl.count += 1 cl.count += 1
} }
func (cl *ChunkList) Snapshot() []*Chunk { func (cl *ChunkList) Snapshot() ([]*Chunk, int) {
cl.mutex.Lock() cl.mutex.Lock()
defer cl.mutex.Unlock() defer cl.mutex.Unlock()
ret := make([]*Chunk, len(cl.chunks)) ret := make([]*Chunk, len(cl.chunks))
copy(ret, cl.chunks) copy(ret, cl.chunks)
return ret
// Duplicate the last chunk
if cnt := len(ret); cnt > 0 {
ret[cnt-1] = ret[cnt-1].dupe()
}
return ret, cl.count
}
func (c *Chunk) dupe() *Chunk {
newChunk := make(Chunk, len(*c))
for idx, ptr := range *c {
newChunk[idx] = ptr
}
return &newChunk
} }

View File

@ -11,8 +11,8 @@ func TestChunkList(t *testing.T) {
}) })
// Snapshot // Snapshot
snapshot := cl.Snapshot() snapshot, count := cl.Snapshot()
if len(snapshot) > 0 { if len(snapshot) > 0 || count > 0 {
t.Error("Snapshot should be empty now") t.Error("Snapshot should be empty now")
} }
@ -26,8 +26,8 @@ func TestChunkList(t *testing.T) {
} }
// But the new snapshot should contain the added items // But the new snapshot should contain the added items
snapshot = cl.Snapshot() snapshot, count = cl.Snapshot()
if len(snapshot) != 1 { if len(snapshot) != 1 && count != 2 {
t.Error("Snapshot should not be empty now") t.Error("Snapshot should not be empty now")
} }
@ -55,12 +55,20 @@ func TestChunkList(t *testing.T) {
} }
// New snapshot // New snapshot
snapshot = cl.Snapshot() snapshot, count = cl.Snapshot()
if len(snapshot) != 3 || !snapshot[0].IsFull() || if len(snapshot) != 3 || !snapshot[0].IsFull() ||
!snapshot[1].IsFull() || snapshot[2].IsFull() { !snapshot[1].IsFull() || snapshot[2].IsFull() || count != CHUNK_SIZE*2+2 {
t.Error("Expected two full chunks and one more chunk") t.Error("Expected two full chunks and one more chunk")
} }
if len(*snapshot[2]) != 2 { if len(*snapshot[2]) != 2 {
t.Error("Unexpected number of items") t.Error("Unexpected number of items")
} }
cl.Push("hello")
cl.Push("world")
lastChunkCount := len(*snapshot[len(snapshot)-1])
if lastChunkCount != 2 {
t.Error("Unexpected number of items:", lastChunkCount)
}
} }

View File

@ -90,8 +90,9 @@ func Run(options *Options) {
}) })
} }
snapshot, _ := chunkList.Snapshot()
matches, cancelled := matcher.scan(MatchRequest{ matches, cancelled := matcher.scan(MatchRequest{
chunks: chunkList.Snapshot(), chunks: snapshot,
pattern: pattern}, limit) pattern: pattern}, limit)
if !cancelled && (filtering || if !cancelled && (filtering ||
@ -127,11 +128,13 @@ func Run(options *Options) {
case EVT_READ_NEW, EVT_READ_FIN: case EVT_READ_NEW, EVT_READ_FIN:
reading = reading && evt == EVT_READ_NEW reading = reading && evt == EVT_READ_NEW
terminal.UpdateCount(chunkList.Count(), !reading) snapshot, count := chunkList.Snapshot()
matcher.Reset(chunkList.Snapshot(), terminal.Input(), false) terminal.UpdateCount(count, !reading)
matcher.Reset(snapshot, terminal.Input(), false)
case EVT_SEARCH_NEW: case EVT_SEARCH_NEW:
matcher.Reset(chunkList.Snapshot(), terminal.Input(), true) snapshot, _ := chunkList.Snapshot()
matcher.Reset(snapshot, terminal.Input(), true)
delay = false delay = false
case EVT_SEARCH_PROGRESS: case EVT_SEARCH_PROGRESS: