Skip to content

Commit

Permalink
Validating QAT Hardware Support before QAT Codecs are available (#169) (
Browse files Browse the repository at this point in the history
#171)

* validating QAT hardware support before making codecs available

Signed-off-by: Sarthak Aggarwal <sarthagg@amazon.com>

* Store result of `isQatAvailable` in static field

Signed-off-by: Andrew Ross <andrross@amazon.com>

---------

Signed-off-by: Sarthak Aggarwal <sarthagg@amazon.com>
Signed-off-by: Andrew Ross <andrross@amazon.com>
Co-authored-by: Andrew Ross <andrross@amazon.com>
(cherry picked from commit 3ab314b)

Co-authored-by: Sarthak Aggarwal <sarthagg@amazon.com>
  • Loading branch information
andrross and sarthakaggarwal97 authored Jul 26, 2024
1 parent edb801d commit 9fbbda2
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;

import org.opensearch.client.ResponseException;
import org.opensearch.client.RestClient;
import org.opensearch.client.RestClientBuilder;
import org.opensearch.cluster.metadata.IndexMetadata;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.common.Strings;
import org.opensearch.index.codec.customcodecs.Lucene99QatCodec;
import org.opensearch.index.codec.customcodecs.QatZipperFactory;
import org.opensearch.test.rest.OpenSearchRestTestCase;

Expand Down Expand Up @@ -64,6 +66,49 @@ public void testCreateIndexWithZstdCodec() throws IOException {
}
}

public void testCreateIndexWithQatCodecWithQatHardwareUnavailable() throws IOException {

assumeThat("Qat library is not available", QatZipperFactory.isQatAvailable(), is(false));
final String index = "custom-codecs-test-index";

// creating index
final ResponseException e = expectThrows(
ResponseException.class,
() -> createIndex(
index,
Settings.builder()
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
.put("index.codec", randomFrom(QAT_DEFLATE_CODEC, QAT_LZ4_CODEC))
.put("index.codec.compression_level", randomIntBetween(1, 6))
.build()
)
);
assertTrue(e.getResponse().toString().contains("400 Bad Request"));
}

public void testCreateIndexWithQatSPICodecWithQatHardwareUnavailable() throws IOException {

assumeThat("Qat library is not available", QatZipperFactory.isQatAvailable(), is(false));
final String index = "custom-codecs-test-index";

// creating index
final ResponseException e = expectThrows(
ResponseException.class,
() -> createIndex(
index,
Settings.builder()
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
.put("index.codec", randomFrom(Lucene99QatCodec.Mode.QAT_LZ4.getCodec(), Lucene99QatCodec.Mode.QAT_DEFLATE.getCodec()))
.put("index.codec.compression_level", randomIntBetween(1, 6))
.build()
)
);
assertTrue(e.getResponse().toString().contains("400 Bad Request"));

}

public void testCreateIndexWithQatCodec() throws IOException {
assumeThat("Qat library is available", QatZipperFactory.isQatAvailable(), is(true));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ public Optional<CodecServiceFactory> getCustomCodecServiceFactory(final IndexSet
|| codecName.equals(CustomCodecService.QAT_LZ4_CODEC)
|| codecName.equals(CustomCodecService.QAT_DEFLATE_CODEC)) {
return Optional.of(new CustomCodecServiceFactory());
} else {
if (!QatZipperFactory.isQatAvailable()
&& (codecName.equals(Lucene99QatCodec.Mode.QAT_LZ4.getCodec())
|| codecName.equals(Lucene99QatCodec.Mode.QAT_DEFLATE.getCodec()))) {
throw new IllegalArgumentException("QAT codecs are not supported. Please create indices with a different codec.");
}

}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,25 @@ public CustomCodecService(MapperService mapperService, IndexSettings indexSettin
if (mapperService == null) {
codecs.put(ZSTD_CODEC, new Zstd99Codec(compressionLevel));
codecs.put(ZSTD_NO_DICT_CODEC, new ZstdNoDict99Codec(compressionLevel));
codecs.put(QAT_LZ4_CODEC, new QatLz499Codec(compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
codecs.put(QAT_DEFLATE_CODEC, new QatDeflate99Codec(compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
if (QatZipperFactory.isQatAvailable()) {
codecs.put(QAT_LZ4_CODEC, new QatLz499Codec(compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
codecs.put(QAT_DEFLATE_CODEC, new QatDeflate99Codec(compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
}
} else {
codecs.put(ZSTD_CODEC, new Zstd99Codec(mapperService, logger, compressionLevel));
codecs.put(ZSTD_NO_DICT_CODEC, new ZstdNoDict99Codec(mapperService, logger, compressionLevel));
codecs.put(QAT_LZ4_CODEC, new QatLz499Codec(mapperService, logger, compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
codecs.put(QAT_DEFLATE_CODEC, new QatDeflate99Codec(mapperService, logger, compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
if (QatZipperFactory.isQatAvailable()) {
codecs.put(QAT_LZ4_CODEC, new QatLz499Codec(mapperService, logger, compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
codecs.put(QAT_DEFLATE_CODEC, new QatDeflate99Codec(mapperService, logger, compressionLevel, () -> {
return indexSettings.getValue(Lucene99QatCodec.INDEX_CODEC_QAT_MODE_SETTING);
}));
}
}
this.codecs = codecs.immutableMap();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public boolean supports(Setting<?> setting) {

@Override
public Set<String> aliases() {
if (!QatZipperFactory.isQatAvailable()) {
return Set.of();
}
return Mode.QAT_DEFLATE.getAliases();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public boolean supports(Setting<?> setting) {

@Override
public Set<String> aliases() {
if (!QatZipperFactory.isQatAvailable()) {
return Set.of();
}
return Mode.QAT_LZ4.getAliases();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,25 @@ public static QatZipper createInstance(Algorithm algorithm, int level, Mode mode
* @return true if QAT hardware is available, false otherwise.
*/
public static boolean isQatAvailable() {
try {
QatZipper qzip = QatZipperFactory.createInstance();
qzip.end();
return true;
} catch (UnsatisfiedLinkError | ExceptionInInitializerError | NoClassDefFoundError e) {
return false;
return QatAvailableHolder.IS_QAT_AVAILABLE;
}

/**
* Nested class to defer static initialization until {@link #isQatAvailable()} is invoked
*/
private static class QatAvailableHolder {
static final boolean IS_QAT_AVAILABLE;

static {
boolean isQatAvailable;
try {
final QatZipper qzip = QatZipperFactory.createInstance();
qzip.end();
isQatAvailable = true;
} catch (UnsatisfiedLinkError | ExceptionInInitializerError | NoClassDefFoundError e) {
isQatAvailable = false;
}
IS_QAT_AVAILABLE = isQatAvailable;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
import java.util.Collections;
import java.util.Optional;

import static org.opensearch.index.codec.customcodecs.CustomCodecService.QAT_DEFLATE_CODEC;
import static org.opensearch.index.codec.customcodecs.CustomCodecService.QAT_LZ4_CODEC;
import static org.opensearch.index.codec.customcodecs.CustomCodecService.ZSTD_CODEC;
import static org.opensearch.index.codec.customcodecs.CustomCodecService.ZSTD_NO_DICT_CODEC;
import static org.opensearch.index.engine.EngineConfig.INDEX_CODEC_COMPRESSION_LEVEL_SETTING;
Expand Down Expand Up @@ -176,6 +178,30 @@ public void testZstdNoDictMapperServiceNull() throws Exception {
assertEquals(Lucene99CustomCodec.DEFAULT_COMPRESSION_LEVEL, storedFieldsFormat.getCompressionLevel());
}

public void testQatCodecsNotAvailable() throws IOException {
if (!QatZipperFactory.isQatAvailable()) {
assertThrows(IllegalArgumentException.class, () -> createCodecService(false).codec("qat_lz4"));
assertThrows(IllegalArgumentException.class, () -> createCodecService(false).codec("qat_deflate"));

QatLz499Codec qatLz499Codec = new QatLz499Codec();
assertTrue(qatLz499Codec.aliases().isEmpty());

QatDeflate99Codec qatDeflate99Codec = new QatDeflate99Codec();
assertTrue(qatDeflate99Codec.aliases().isEmpty());
}
}

public void testCodecServiceFactoryQatUnavailable() throws IOException {
if (!QatZipperFactory.isQatAvailable()) {
Settings nodeSettings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
.put("index.codec", randomFrom(QAT_DEFLATE_CODEC, QAT_LZ4_CODEC))
.build();
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("_na", nodeSettings);
assertThrows(IllegalArgumentException.class, () -> plugin.getCustomCodecServiceFactory(indexSettings));
}
}

// write some docs with it, inspect .si to see this was the used compression
private void assertStoredFieldsCompressionEquals(Lucene99Codec.Mode expected, Codec actual) throws Exception {
SegmentReader sr = getSegmentReader(actual);
Expand Down

0 comments on commit 9fbbda2

Please sign in to comment.