forked from ironsweet/golucene
/
multiLevelSkipListWriter.go
127 lines (110 loc) · 3.24 KB
/
multiLevelSkipListWriter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package store
import (
"github.com/balzaczyy/golucene/core/util"
)
type MultiLevelSkipListWriterSPI interface {
WriteSkipData(level int, skipBuffer IndexOutput) error
}
/*
TODO: migrate original comment.
Note: this class was moved from package codec to store since it
caused cyclic dependency (store<->codec).
*/
type MultiLevelSkipListWriter struct {
spi MultiLevelSkipListWriterSPI
// number levels in this skip list
numberOfSkipLevels int
// the skip interval in ths list with level=0
skipInterval int
// skipInterval used for level > 0
skipMultiplier int
// for every skip level a different buffer is used
skipBuffer []*RAMOutputStream
}
/* Creates a MultiLevelSkipListWriter. */
func NewMultiLevelSkipListWriter(spi MultiLevelSkipListWriterSPI,
skipInterval, skipMultiplier, maxSkipLevels, df int) *MultiLevelSkipListWriter {
numberOfSkipLevels := 1
// calculate the maximum number of skip levels for this document frequency
if df > skipInterval {
numberOfSkipLevels = 1 + util.Log(int64(df/skipInterval), skipMultiplier)
}
// make sure it does not exceed maxSkipLevels
if numberOfSkipLevels > maxSkipLevels {
numberOfSkipLevels = maxSkipLevels
}
return &MultiLevelSkipListWriter{
spi: spi,
skipInterval: skipInterval,
skipMultiplier: skipMultiplier,
numberOfSkipLevels: numberOfSkipLevels,
}
}
/* Allocates internal skip buffers. */
func (w *MultiLevelSkipListWriter) init() {
w.skipBuffer = make([]*RAMOutputStream, w.numberOfSkipLevels)
for i, _ := range w.skipBuffer {
w.skipBuffer[i] = NewRAMOutputStreamBuffer()
}
}
/* Creates new buffers or empties the existing ones */
func (w *MultiLevelSkipListWriter) ResetSkip() {
if w.skipBuffer == nil {
w.init()
} else {
for _, v := range w.skipBuffer {
v.Reset()
}
}
}
/*
Writes the current skip data to the buffers. The current document
frequency determines the max level is skip ddata is to be written to.
*/
func (w *MultiLevelSkipListWriter) BufferSkip(df int) error {
assert(df%w.skipInterval == 0)
numLevels := 1
df /= w.skipInterval
// determine max level
for (df%w.skipMultiplier) == 0 && numLevels < w.numberOfSkipLevels {
numLevels++
df /= w.skipMultiplier
}
childPointer := int64(0)
var err error
for level := 0; level < numLevels; level++ {
if err = w.spi.WriteSkipData(level, w.skipBuffer[level]); err != nil {
return err
}
newChildPointer := w.skipBuffer[level].FilePointer()
if level != 0 {
// store child pointers for all levels except the lowest
if err = w.skipBuffer[level].WriteVLong(childPointer); err != nil {
return err
}
}
// remember the childPointer for the next level
childPointer = newChildPointer
}
return nil
}
/* Writes the buffered skip lists to the given output. */
func (w *MultiLevelSkipListWriter) WriteSkip(output IndexOutput) (int64, error) {
skipPointer := output.FilePointer()
if len(w.skipBuffer) == 0 {
return skipPointer, nil
}
for level := w.numberOfSkipLevels - 1; level > 0; level-- {
if length := w.skipBuffer[level].FilePointer(); length > 0 {
err := output.WriteVLong(length)
if err != nil {
return 0, err
}
err = w.skipBuffer[level].WriteTo(output)
if err != nil {
return 0, err
}
}
}
return skipPointer, w.skipBuffer[0].WriteTo(output)
}