2020import org .apache .lucene .codecs .MutablePointTree ;
2121import org .apache .lucene .codecs .PointsReader ;
2222import org .apache .lucene .codecs .PointsWriter ;
23+ import org .apache .lucene .document .column .BinaryValuesCursor ;
2324import org .apache .lucene .document .column .LongValuesCursor ;
2425import org .apache .lucene .store .DataOutput ;
2526import org .apache .lucene .util .ArrayUtil ;
@@ -48,6 +49,9 @@ class PointValuesWriter {
4849 private static final int POINTS_BUFFER_INT_VALUES = POINTS_BUFFER_BYTES / Integer .BYTES ;
4950 private static final int POINTS_BUFFER_LONG_VALUES = POINTS_BUFFER_BYTES / Long .BYTES ;
5051
52+ /** Minimum number of values to process per chunk in the dense N-D bulk path. */
53+ private static final int MIN_VALUES_PER_CHUNK = 64 ;
54+
5155 private byte [] densePointsBuffer ;
5256
5357 PointValuesWriter (Counter bytesUsed , FieldInfo fieldInfo ) {
@@ -98,7 +102,7 @@ void addDense1DIntValues(int firstDocID, LongValuesCursor cursor) throws IOExcep
98102 if (size == 0 ) {
99103 return ;
100104 }
101- final long ramBefore = reserveDense1D (firstDocID , size );
105+ final long ramBefore = reserveDense (firstDocID , size );
102106 final byte [] buffer = pointsDenseBuffer ();
103107 int remaining = size ;
104108 while (remaining > 0 ) {
@@ -107,7 +111,7 @@ void addDense1DIntValues(int firstDocID, LongValuesCursor cursor) throws IOExcep
107111 bytesOut .writeBytes (buffer , 0 , chunk * Integer .BYTES );
108112 remaining -= chunk ;
109113 }
110- commitDense1D (firstDocID , size , ramBefore );
114+ commitDense (firstDocID , size , ramBefore );
111115 }
112116
113117 void addDense1DLongValues (int firstDocID , LongValuesCursor cursor ) throws IOException {
@@ -116,7 +120,7 @@ void addDense1DLongValues(int firstDocID, LongValuesCursor cursor) throws IOExce
116120 if (size == 0 ) {
117121 return ;
118122 }
119- final long ramBefore = reserveDense1D (firstDocID , size );
123+ final long ramBefore = reserveDense (firstDocID , size );
120124 final byte [] dense = pointsDenseBuffer ();
121125 int remaining = size ;
122126 while (remaining > 0 ) {
@@ -125,7 +129,53 @@ void addDense1DLongValues(int firstDocID, LongValuesCursor cursor) throws IOExce
125129 bytesOut .writeBytes (dense , 0 , chunk * Long .BYTES );
126130 remaining -= chunk ;
127131 }
128- commitDense1D (firstDocID , size , ramBefore );
132+ commitDense (firstDocID , size , ramBefore );
133+ }
134+
135+ /**
136+ * Bulk-adds dense N-dimensional packed point values from a {@link BinaryValuesCursor}. Each value
137+ * is a pre-encoded packed byte array of {@code packedLength} bytes.
138+ */
139+ void addDenseNDValues (int firstDocID , BinaryValuesCursor cursor , int packedLength )
140+ throws IOException {
141+ if (fieldInfo .getPointDimensionCount () * fieldInfo .getPointNumBytes () != packedLength ) {
142+ throw new IllegalArgumentException (
143+ "field="
144+ + fieldInfo .name
145+ + ": packedLength="
146+ + packedLength
147+ + " does not match pointDimensionCount="
148+ + fieldInfo .getPointDimensionCount ()
149+ + " * pointNumBytes="
150+ + fieldInfo .getPointNumBytes ());
151+ }
152+ final int size = cursor .size ();
153+ if (size == 0 ) {
154+ return ;
155+ }
156+ final long ramBefore = reserveDense (firstDocID , size );
157+ final byte [] buffer = pointsDenseBuffer (packedLength );
158+ final int valuesPerBuffer = buffer .length / packedLength ;
159+ int remaining = size ;
160+ while (remaining > 0 ) {
161+ int chunk = Math .min (valuesPerBuffer , remaining );
162+ for (int i = 0 ; i < chunk ; i ++) {
163+ BytesRef value = cursor .nextValue ();
164+ if (value .length != packedLength ) {
165+ throw new IllegalArgumentException (
166+ "field="
167+ + fieldInfo .name
168+ + ": point value has length="
169+ + value .length
170+ + " but should be "
171+ + packedLength );
172+ }
173+ System .arraycopy (value .bytes , value .offset , buffer , i * packedLength , packedLength );
174+ }
175+ bytesOut .writeBytes (buffer , 0 , chunk * packedLength );
176+ remaining -= chunk ;
177+ }
178+ commitDense (firstDocID , size , ramBefore );
129179 }
130180
131181 private byte [] pointsDenseBuffer () {
@@ -135,6 +185,21 @@ private byte[] pointsDenseBuffer() {
135185 return densePointsBuffer ;
136186 }
137187
188+ /**
189+ * Returns a dense buffer sized to fit at least {@code POINTS_BUFFER_BYTES} worth of packed
190+ * values, or a larger buffer if {@code packedLength} requires it to hold at least {@code
191+ * MIN_VALUES_PER_CHUNK} values per chunk.
192+ */
193+ private byte [] pointsDenseBuffer (int packedLength ) {
194+ final int minBytes = packedLength * MIN_VALUES_PER_CHUNK ;
195+ if (densePointsBuffer == null ) {
196+ densePointsBuffer = new byte [Math .max (POINTS_BUFFER_BYTES , minBytes )];
197+ } else if (densePointsBuffer .length < minBytes ) {
198+ densePointsBuffer = new byte [minBytes ];
199+ }
200+ return densePointsBuffer ;
201+ }
202+
138203 private void validate1DPacked (int byteWidth ) {
139204 if (fieldInfo .getPointDimensionCount () != 1 || fieldInfo .getPointNumBytes () != byteWidth ) {
140205 throw new IllegalArgumentException (
@@ -149,7 +214,7 @@ private void validate1DPacked(int byteWidth) {
149214 }
150215 }
151216
152- private long reserveDense1D (int firstDocID , int size ) {
217+ private long reserveDense (int firstDocID , int size ) {
153218 assert firstDocID > lastDocID
154219 : "firstDocID=" + firstDocID + " must be > lastDocID=" + lastDocID ;
155220 final int oldLength = docIDs .length ;
@@ -163,7 +228,7 @@ private long reserveDense1D(int firstDocID, int size) {
163228 return bytes .ramBytesUsed ();
164229 }
165230
166- private void commitDense1D (int firstDocID , int size , long ramBefore ) {
231+ private void commitDense (int firstDocID , int size , long ramBefore ) {
167232 iwBytesUsed .addAndGet (bytes .ramBytesUsed () - ramBefore );
168233 numDocs += size ;
169234 lastDocID = firstDocID + size - 1 ;
0 commit comments