public HollowHashIndexResult findMatches(Object... query) {
        if (hashStateVolatile == null) {
            throw new IllegalStateException(this + " wasn't initialized");
        }
        int hashCode = 0;

        for(int i=0;i<query.length;i++) {
            if(query[i] == null)
                throw new IllegalArgumentException("querying by null unsupported; i=" + i);
            hashCode ^= HashCodes.hashInt(keyHashCode(query[i], i));
        }

        HollowHashIndexResult result;
        HollowHashIndexState hashState;
        do {
            result = null;
            hashState = hashStateVolatile;
            long bucket = hashCode & hashState.getMatchHashMask();
            long hashBucketBit = bucket * hashState.getBitsPerMatchHashEntry();
            boolean bucketIsEmpty = hashState.getMatchHashTable().getElementValue(hashBucketBit, hashState.getBitsPerTraverserField()[0]) == 0;

            while (!bucketIsEmpty) {
                if (matchIsEqual(hashState.getMatchHashTable(), hashBucketBit, query)) {
                    int selectSize = (int) hashState.getMatchHashTable().getElementValue(hashBucketBit + hashState.getBitsPerMatchHashKey(), hashState.getBitsPerSelectTableSize());
                    long selectBucketPointer = hashState.getMatchHashTable().getElementValue(hashBucketBit + hashState.getBitsPerMatchHashKey() + hashState.getBitsPerSelectTableSize(), hashState.getBitsPerSelectTablePointer());

                    result = new HollowHashIndexResult(hashState, selectBucketPointer, selectSize);
                    break;
                }

                bucket = (bucket + 1) & hashState.getMatchHashMask();
                hashBucketBit = bucket * hashState.getBitsPerMatchHashEntry();
                bucketIsEmpty = hashState.getMatchHashTable().getElementValue(hashBucketBit, hashState.getBitsPerTraverserField()[0]) == 0;
            }
        } while (hashState != hashStateVolatile);

        return result;
    }
@Test
    public void testBasicHashIndexFunctionality() throws Exception {
        mapper.add(new TypeA(1, 1.1d, new TypeB("one")));
        mapper.add(new TypeA(1, 1.1d, new TypeB("1")));
        mapper.add(new TypeA(2, 2.2d, new TypeB("two"), new TypeB("twenty"), new TypeB("two hundred")));
        mapper.add(new TypeA(3, 3.3d, new TypeB("three"), new TypeB("thirty"), new TypeB("three hundred")));
        mapper.add(new TypeA(4, 4.4d, new TypeB("four")));
        mapper.add(new TypeA(4, 4.5d, new TypeB("four"), new TypeB("forty")));

        roundTripSnapshot();

        HollowHashIndex index = new HollowHashIndex(readStateEngine, "TypeA", "a1", new String[]{"a1", "ab.element.b1.value"});

        Assert.assertNull("An entry that doesn't have any matches has a null iterator", index.findMatches(0, "notfound"));
        assertIteratorContainsAll(index.findMatches(1, "one").iterator(), 0);
        assertIteratorContainsAll(index.findMatches(1, "1").iterator(), 1);
        assertIteratorContainsAll(index.findMatches(2, "two").iterator(), 2);
        assertIteratorContainsAll(index.findMatches(2, "twenty").iterator(), 2);
        assertIteratorContainsAll(index.findMatches(2, "two hundred").iterator(), 2);
        assertIteratorContainsAll(index.findMatches(3, "three").iterator(), 3);
        assertIteratorContainsAll(index.findMatches(3, "thirty").iterator(), 3);
        assertIteratorContainsAll(index.findMatches(3, "three hundred").iterator(), 3);
        assertIteratorContainsAll(index.findMatches(4, "four").iterator(), 4, 5);
        assertIteratorContainsAll(index.findMatches(4, "forty").iterator(), 5);

    }