|
|
|
@ -67,7 +67,9 @@ const (
|
|
|
|
|
chunkHeaderFirstTimeOffset = 1 |
|
|
|
|
chunkHeaderLastTimeOffset = 9 |
|
|
|
|
chunkLenWithHeader = chunkLen + chunkHeaderLen |
|
|
|
|
chunkMaxBatchSize = 64 // How many chunks to load at most in one batch.
|
|
|
|
|
chunkMaxBatchSize = 62 // Max no. of chunks to load or write in
|
|
|
|
|
// one batch. Note that 62 is the largest number of chunks that fit
|
|
|
|
|
// into 64kiB on disk because chunkHeaderLen is added to each 1k chunk.
|
|
|
|
|
|
|
|
|
|
indexingMaxBatchSize = 1024 * 1024 |
|
|
|
|
indexingBatchTimeout = 500 * time.Millisecond // Commit batch when idle for that long.
|
|
|
|
@ -380,7 +382,7 @@ func (p *persistence) persistChunks(fp model.Fingerprint, chunks []chunk) (index
|
|
|
|
|
} |
|
|
|
|
defer p.closeChunkFile(f) |
|
|
|
|
|
|
|
|
|
if err := writeChunks(f, chunks); err != nil { |
|
|
|
|
if err := p.writeChunks(f, chunks); err != nil { |
|
|
|
|
return -1, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -412,8 +414,8 @@ func (p *persistence) loadChunks(fp model.Fingerprint, indexes []int, indexOffse
|
|
|
|
|
chunks := make([]chunk, 0, len(indexes)) |
|
|
|
|
buf := p.bufPool.Get().([]byte) |
|
|
|
|
defer func() { |
|
|
|
|
// buf may change below, so wrap returning to the pool in a function.
|
|
|
|
|
// A simple 'defer p.bufPool.Put(buf)' would only return the original buf.
|
|
|
|
|
// buf may change below. An unwrapped 'defer p.bufPool.Put(buf)'
|
|
|
|
|
// would only put back the original buf.
|
|
|
|
|
p.bufPool.Put(buf) |
|
|
|
|
}() |
|
|
|
|
|
|
|
|
@ -1031,7 +1033,7 @@ func (p *persistence) dropAndPersistChunks(
|
|
|
|
|
offset = int(written / chunkLenWithHeader) |
|
|
|
|
|
|
|
|
|
if len(chunks) > 0 { |
|
|
|
|
if err = writeChunks(temp, chunks); err != nil { |
|
|
|
|
if err = p.writeChunks(temp, chunks); err != nil { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1585,6 +1587,37 @@ func (p *persistence) loadFPMappings() (fpMappings, model.Fingerprint, error) {
|
|
|
|
|
return fpm, highestMappedFP, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (p *persistence) writeChunks(w io.Writer, chunks []chunk) error { |
|
|
|
|
b := p.bufPool.Get().([]byte) |
|
|
|
|
defer func() { |
|
|
|
|
// buf may change below. An unwrapped 'defer p.bufPool.Put(buf)'
|
|
|
|
|
// would only put back the original buf.
|
|
|
|
|
p.bufPool.Put(b) |
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
for batchSize := chunkMaxBatchSize; len(chunks) > 0; chunks = chunks[batchSize:] { |
|
|
|
|
if batchSize > len(chunks) { |
|
|
|
|
batchSize = len(chunks) |
|
|
|
|
} |
|
|
|
|
writeSize := batchSize * chunkLenWithHeader |
|
|
|
|
if cap(b) < writeSize { |
|
|
|
|
b = make([]byte, writeSize) |
|
|
|
|
} |
|
|
|
|
b = b[:writeSize] |
|
|
|
|
|
|
|
|
|
for i, chunk := range chunks[:batchSize] { |
|
|
|
|
writeChunkHeader(b[i*chunkLenWithHeader:], chunk) |
|
|
|
|
if err := chunk.marshalToBuf(b[i*chunkLenWithHeader+chunkHeaderLen:]); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if _, err := w.Write(b); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func offsetForChunkIndex(i int) int64 { |
|
|
|
|
return int64(i * chunkLenWithHeader) |
|
|
|
|
} |
|
|
|
@ -1599,8 +1632,7 @@ func chunkIndexForOffset(offset int64) (int, error) {
|
|
|
|
|
return int(offset) / chunkLenWithHeader, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func writeChunkHeader(w io.Writer, c chunk) error { |
|
|
|
|
header := make([]byte, chunkHeaderLen) |
|
|
|
|
func writeChunkHeader(header []byte, c chunk) { |
|
|
|
|
header[chunkHeaderTypeOffset] = byte(c.encoding()) |
|
|
|
|
binary.LittleEndian.PutUint64( |
|
|
|
|
header[chunkHeaderFirstTimeOffset:], |
|
|
|
@ -1610,20 +1642,4 @@ func writeChunkHeader(w io.Writer, c chunk) error {
|
|
|
|
|
header[chunkHeaderLastTimeOffset:], |
|
|
|
|
uint64(c.newIterator().lastTimestamp()), |
|
|
|
|
) |
|
|
|
|
_, err := w.Write(header) |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func writeChunks(w io.Writer, chunks []chunk) error { |
|
|
|
|
b := bufio.NewWriterSize(w, len(chunks)*chunkLenWithHeader) |
|
|
|
|
for _, chunk := range chunks { |
|
|
|
|
if err := writeChunkHeader(b, chunk); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := chunk.marshal(b); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return b.Flush() |
|
|
|
|
} |
|
|
|
|