diff options
Diffstat (limited to 'container-search/src/main/java/com/yahoo/fs4/QueryResultPacket.java')
-rw-r--r-- | container-search/src/main/java/com/yahoo/fs4/QueryResultPacket.java | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/fs4/QueryResultPacket.java b/container-search/src/main/java/com/yahoo/fs4/QueryResultPacket.java new file mode 100644 index 00000000000..6a27beefb5e --- /dev/null +++ b/container-search/src/main/java/com/yahoo/fs4/QueryResultPacket.java @@ -0,0 +1,228 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.fs4; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A query result packet (code 217). This packet can be decoded only. + * + * @author bratseth + */ +public class QueryResultPacket extends Packet { + + /** The code of this type of package */ + private static final int code = 217; + + /** Whether mld data is included in this result */ + private boolean mldFeature = false; + + /** Whether sort data is included in this result */ + private boolean sortData = false; + + /** Whether coverage information is included in this result */ + private boolean coverageNodes = false; + private long coverageDocs = 0; + private long activeDocs = 0; + private long soonActiveDocs = 0; + private int degradedReason = 0; + private short nodesQueried = 0; + private short nodesReplied = 0; + + /** Whether the result contains grouping results **/ + private boolean groupDataFeature = false; + + /** Whether the result contains properties **/ + private boolean propsFeature = false; + + private long totalDocumentCount; + + private Number maxRank; + + private int docstamp; + + private byte[] groupData = null; + + private List<DocumentInfo> documents=new ArrayList<>(10); + + public FS4Properties[] propsArray; + + private int offset; + + private QueryResultPacket() { } + + public static QueryResultPacket create() { + return new QueryResultPacket(); + } + + public void setDocstamp(int docstamp){ this.docstamp=docstamp; } + + public int getDocstamp() { return docstamp; } + + /** Returns whether this has the mysterious mld feature */ + public boolean getMldFeature() { return mldFeature; } + + public boolean getCoverageFeature() { return true; } + + public long getCoverageDocs() { return coverageDocs; } + + public long getActiveDocs() { return activeDocs; } + + public long getSoonActiveDocs() { return soonActiveDocs; } + + public int getDegradedReason() { return degradedReason; } + + public boolean getCoverageFull() { + return coverageDocs == activeDocs; + } + + + /** @return offset returned by backend */ + public int getOffset() { return offset; } + + /** Only for testing. */ + public void setOffset(int offset) { + this.offset = offset; + } + + @Override + public void decodeBody(ByteBuffer buffer) { + IntBuffer ints = buffer.asIntBuffer(); + decodeFeatures(ints); + offset = ints.get(); + int documentCount = ints.get(); + buffer.position(buffer.position() + ints.position() * 4); + totalDocumentCount = buffer.getLong(); + maxRank = decodeMaxRank(buffer); + ints = buffer.asIntBuffer(); + docstamp = ints.get(); + buffer.position(buffer.position() + ints.position() * 4); + // do not access "ints" below here! + + if (coverageNodes) { + nodesQueried = buffer.getShort(); + nodesReplied = buffer.getShort(); + } + + byte[][] documentSortData = null; + if (sortData && documentCount > 0) { + documentSortData = decodeSortData(buffer, documentCount); + } + + if (groupDataFeature) { + int len = buffer.getInt(); + groupData = new byte[len]; + buffer.get(groupData); + } + + coverageDocs = buffer.getLong(); + activeDocs = buffer.getLong(); + soonActiveDocs = buffer.getLong(); + degradedReason = buffer.getInt(); + + decodeDocuments(buffer, documentCount, documentSortData); + if (propsFeature) { + int numMaps = buffer.getInt(); + propsArray = new FS4Properties[numMaps]; + for (int i = 0; i < numMaps; i++) { + propsArray[i] = new FS4Properties(); + propsArray[i].decode(buffer); + } + } + } + + private byte[][] decodeSortData(ByteBuffer buffer, int documentCount) { + int[] indexes = new int[documentCount]; + indexes[0] = 0; + for (int i = 1; i < documentCount; i++) { + indexes[i] = buffer.getInt(); + } + + int sortDataLengthInBytes = buffer.getInt(); + byte[][] ret = new byte[indexes.length][]; + + for (int i = 0; i < indexes.length; i++) { + int end = i + 1 >= indexes.length ? sortDataLengthInBytes : indexes[i + 1]; + int len = end - indexes[i]; + ret[i] = new byte[len]; + buffer.get(ret[i], 0, len); + } + return ret; + } + + private Number decodeMaxRank(ByteBuffer buffer) { + return Double.valueOf(buffer.getDouble()); + } + + /** + * feature bits + */ + private static final int QRF_MLD = 0x00000001; + private static final int QRF_COVERAGE_NODES = 0x00000002; + private static final int QRF_SORTDATA = 0x00000010; + private static final int QRF_UNUSED_1 = 0x00000020; + private static final int QRF_UNUSED_2 = 0x00000040; + private static final int QRF_GROUPDATA = 0x00000200; + private static final int QRF_PROPERTIES = 0x00000400; + + /** Decodes the feature int of this package data into boolean feature fields */ + private void decodeFeatures(IntBuffer buffer) { + int features = buffer.get(); + mldFeature = (QRF_MLD & features) != 0; + sortData = (QRF_SORTDATA & features) != 0; + coverageNodes = (QRF_COVERAGE_NODES & features) != 0; + groupDataFeature = (QRF_GROUPDATA & features) != 0; + propsFeature = (QRF_PROPERTIES & features) != 0; + } + + private void decodeDocuments(ByteBuffer buffer, int documentCount, byte[][] documentSortData) { + for (int i = 0; i < documentCount; i++) { + byte[] sort = documentSortData == null ? null : documentSortData[i]; + documents.add(new DocumentInfo(buffer, this, sort)); + } + } + + public int getCode() { return code; } + + protected void codeDecodedHook(int code) { + if ( code != QueryResultPacket.code) + throw new RuntimeException("Programming error, packet " + getCode() + "Not expected."); + } + + public int getDocumentCount() { return documents.size(); } + + public String toString() { + return "Query result x packet [" + getDocumentCount() + " documents]"; + } + + /** Returns the opaque grouping results **/ + public byte[] getGroupData() { return groupData; } + + + /** Returns the total number of documents avalable for this query */ + public long getTotalDocumentCount() { return totalDocumentCount; } + + /** Only for testing. */ + public void setTotalDocumentCount(long totalDocumentCount) { + this.totalDocumentCount = totalDocumentCount; + } + + /** Returns a read-only list containing the DocumentInfo objects of this result */ + public List<DocumentInfo> getDocuments() { + return Collections.unmodifiableList(documents); + } + + public void addDocument(DocumentInfo document) { + documents.add(document); + } + + // TODO: Handle new maxRank intelligently + public int getMaxRank() { return maxRank.intValue(); } + + public short getNodesQueried() { return nodesQueried; } + public short getNodesReplied() { return nodesReplied; } + +} |