1
package org.apache.lucene.util.packed;
4
* Licensed to the Apache Software Foundation (ASF) under one or more
5
* contributor license agreements. See the NOTICE file distributed with
6
* this work for additional information regarding copyright ownership.
7
* The ASF licenses this file to You under the Apache License, Version 2.0
8
* (the "License"); you may not use this file except in compliance with
9
* the License. You may obtain a copy of the License at
11
* http://www.apache.org/licenses/LICENSE-2.0
13
* Unless required by applicable law or agreed to in writing, software
14
* distributed under the License is distributed on an "AS IS" BASIS,
15
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
* See the License for the specific language governing permissions and
17
* limitations under the License.
20
import org.apache.lucene.store.*;
21
import org.apache.lucene.util.LuceneTestCase;
23
import java.util.ArrayList;
24
import java.util.List;
25
import java.util.Random;
26
import java.io.IOException;
28
public class TestPackedInts extends LuceneTestCase {
29
public void testBitsRequired() throws Exception {
30
assertEquals(61, PackedInts.bitsRequired((long)Math.pow(2, 61)-1));
31
assertEquals(61, PackedInts.bitsRequired(0x1FFFFFFFFFFFFFFFL));
32
assertEquals(62, PackedInts.bitsRequired(0x3FFFFFFFFFFFFFFFL));
33
assertEquals(63, PackedInts.bitsRequired(0x7FFFFFFFFFFFFFFFL));
36
public void testMaxValues() throws Exception {
37
assertEquals("1 bit -> max == 1",
38
1, PackedInts.maxValue(1));
39
assertEquals("2 bit -> max == 3",
40
3, PackedInts.maxValue(2));
41
assertEquals("8 bit -> max == 255",
42
255, PackedInts.maxValue(8));
43
assertEquals("63 bit -> max == Long.MAX_VALUE",
44
Long.MAX_VALUE, PackedInts.maxValue(63));
45
assertEquals("64 bit -> max == Long.MAX_VALUE (same as for 63 bit)",
46
Long.MAX_VALUE, PackedInts.maxValue(64));
49
public void testPackedInts() throws IOException {
51
for (int iter = 0; iter < num; iter++) {
53
for(int nbits=1;nbits<63;nbits++) {
54
final int valueCount = 100+random.nextInt(500);
55
final Directory d = newDirectory();
57
IndexOutput out = d.createOutput("out.bin");
58
PackedInts.Writer w = PackedInts.getWriter(
59
out, valueCount, nbits);
61
final long[] values = new long[valueCount];
62
for(int i=0;i<valueCount;i++) {
63
long v = random.nextLong() % ceil;
71
final long fp = out.getFilePointer();
74
IndexInput in = d.openInput("out.bin");
75
PackedInts.Reader r = PackedInts.getReader(in);
76
assertEquals(fp, in.getFilePointer());
77
for(int i=0;i<valueCount;i++) {
78
assertEquals("index=" + i + " ceil=" + ceil + " valueCount="
79
+ valueCount + " nbits=" + nbits + " for "
80
+ r.getClass().getSimpleName(), values[i], r.get(i));
90
public void testControlledEquality() {
91
final int VALUE_COUNT = 255;
92
final int BITS_PER_VALUE = 8;
94
List<PackedInts.Mutable> packedInts =
95
createPackedInts(VALUE_COUNT, BITS_PER_VALUE);
96
for (PackedInts.Mutable packedInt: packedInts) {
97
for (int i = 0 ; i < packedInt.size() ; i++) {
98
packedInt.set(i, i+1);
101
assertListEquality(packedInts);
104
public void testRandomEquality() {
105
final int[] VALUE_COUNTS = new int[]{0, 1, 5, 8, 100, 500};
106
final int MIN_BITS_PER_VALUE = 1;
107
final int MAX_BITS_PER_VALUE = 64;
109
for (int valueCount: VALUE_COUNTS) {
110
for (int bitsPerValue = MIN_BITS_PER_VALUE ;
111
bitsPerValue <= MAX_BITS_PER_VALUE ;
113
assertRandomEquality(valueCount, bitsPerValue, random.nextLong());
118
private void assertRandomEquality(int valueCount, int bitsPerValue, long randomSeed) {
119
List<PackedInts.Mutable> packedInts = createPackedInts(valueCount, bitsPerValue);
120
for (PackedInts.Mutable packedInt: packedInts) {
122
fill(packedInt, (long)(Math.pow(2, bitsPerValue)-1), randomSeed);
123
} catch (Exception e) {
124
e.printStackTrace(System.err);
126
"Exception while filling %s: valueCount=%d, bitsPerValue=%s",
127
packedInt.getClass().getSimpleName(),
128
valueCount, bitsPerValue));
131
assertListEquality(packedInts);
134
private List<PackedInts.Mutable> createPackedInts(
135
int valueCount, int bitsPerValue) {
136
List<PackedInts.Mutable> packedInts = new ArrayList<PackedInts.Mutable>();
137
if (bitsPerValue <= 8) {
138
packedInts.add(new Direct8(valueCount));
140
if (bitsPerValue <= 16) {
141
packedInts.add(new Direct16(valueCount));
143
if (bitsPerValue <= 31) {
144
packedInts.add(new Packed32(valueCount, bitsPerValue));
146
if (bitsPerValue <= 32) {
147
packedInts.add(new Direct32(valueCount));
149
if (bitsPerValue <= 63) {
150
packedInts.add(new Packed64(valueCount, bitsPerValue));
152
packedInts.add(new Direct64(valueCount));
156
private void fill(PackedInts.Mutable packedInt, long maxValue, long randomSeed) {
157
Random rnd2 = new Random(randomSeed);
159
for (int i = 0 ; i < packedInt.size() ; i++) {
160
long value = Math.abs(rnd2.nextLong() % maxValue);
161
packedInt.set(i, value);
162
assertEquals(String.format(
163
"The set/get of the value at index %d should match for %s",
164
i, packedInt.getClass().getSimpleName()),
165
value, packedInt.get(i));
169
private void assertListEquality(
170
List<? extends PackedInts.Reader> packedInts) {
171
assertListEquality("", packedInts);
174
private void assertListEquality(
175
String message, List<? extends PackedInts.Reader> packedInts) {
176
if (packedInts.size() == 0) {
179
PackedInts.Reader base = packedInts.get(0);
180
int valueCount = base.size();
181
for (PackedInts.Reader packedInt: packedInts) {
182
assertEquals(message + ". The number of values should be the same ",
183
valueCount, packedInt.size());
185
for (int i = 0 ; i < valueCount ; i++) {
186
for (int j = 1 ; j < packedInts.size() ; j++) {
187
assertEquals(String.format(
188
"%s. The value at index %d should be the same for %s and %s",
189
message, i, base.getClass().getSimpleName(),
190
packedInts.get(j).getClass().getSimpleName()),
191
base.get(i), packedInts.get(j).get(i));
196
public void testSingleValue() throws Exception {
197
Directory dir = newDirectory();
198
IndexOutput out = dir.createOutput("out");
199
PackedInts.Writer w = PackedInts.getWriter(out, 1, 8);
202
final long end = out.getFilePointer();
205
IndexInput in = dir.openInput("out");
206
PackedInts.getReader(in);
207
assertEquals(end, in.getFilePointer());
213
public void testSecondaryBlockChange() throws IOException {
214
PackedInts.Mutable mutable = new Packed64(26, 5);
216
assertEquals("The value #24 should be correct", 31, mutable.get(24));
218
assertEquals("The value #24 should remain unchanged", 31, mutable.get(24));
222
Check if the structures properly handle the case where
223
index * bitsPerValue > Integer.MAX_VALUE
225
NOTE: this test allocates 256 MB
227
public void testIntOverflow() {
228
int INDEX = (int)Math.pow(2, 30)+1;
231
Packed32 p32 = new Packed32(INDEX, BITS);
233
assertEquals("The value at position " + (INDEX-1)
234
+ " should be correct for Packed32", 1, p32.get(INDEX-1));
235
p32 = null; // To free the 256MB used
237
Packed64 p64 = new Packed64(INDEX, BITS);
239
assertEquals("The value at position " + (INDEX-1)
240
+ " should be correct for Packed64", 1, p64.get(INDEX-1));