forked from opensearch-project/data-prepper
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Connection changes for opensearch for opensearch-project#1985,2264.
Signed-off-by: mallikagogoi7 <[email protected]>
- Loading branch information
1 parent
3ce5b53
commit f5dbff3
Showing
24 changed files
with
1,578 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
...src/main/java/org/opensearch/dataprepper/plugins/source/opensearch/BufferAccumulator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
package org.opensearch.dataprepper.plugins.source.opensearch; | ||
|
||
import org.opensearch.dataprepper.model.buffer.Buffer; | ||
import org.opensearch.dataprepper.model.record.Record; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.time.Duration; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Objects; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.ScheduledFuture; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.TimeoutException; | ||
|
||
/** | ||
* Accumulates {@link Record} objects before placing them into a Data Prepper | ||
* {@link Buffer}. This class is not thread-safe and should only be used by one | ||
* thread at a time. | ||
* | ||
* @param <T> Type of record to accumulate | ||
*/ | ||
public class BufferAccumulator<T extends Record<?>> { | ||
private static final Logger LOG = LoggerFactory.getLogger(BufferAccumulator.class); | ||
|
||
private static final int MAX_FLUSH_RETRIES_ON_IO_EXCEPTION = Integer.MAX_VALUE; | ||
private static final Duration INITIAL_FLUSH_RETRY_DELAY_ON_IO_EXCEPTION = Duration.ofSeconds(5); | ||
|
||
private final Buffer<T> buffer; | ||
private final int numberOfRecordsToAccumulate; | ||
private final int bufferTimeoutMillis; | ||
private int totalWritten = 0; | ||
|
||
private final Collection<T> recordsAccumulated; | ||
|
||
private BufferAccumulator(final Buffer<T> buffer, final int numberOfRecordsToAccumulate, final Duration bufferTimeout) { | ||
this.buffer = Objects.requireNonNull(buffer, "buffer must be non-null."); | ||
this.numberOfRecordsToAccumulate = numberOfRecordsToAccumulate; | ||
Objects.requireNonNull(bufferTimeout, "bufferTimeout must be non-null."); | ||
this.bufferTimeoutMillis = (int) bufferTimeout.toMillis(); | ||
|
||
if(numberOfRecordsToAccumulate < 1) | ||
throw new IllegalArgumentException("numberOfRecordsToAccumulate must be greater than zero."); | ||
|
||
recordsAccumulated = new ArrayList<>(numberOfRecordsToAccumulate); | ||
} | ||
|
||
static <T extends Record<?>> BufferAccumulator<T> create(final Buffer<T> buffer, final int recordsToAccumulate, final Duration bufferTimeout) { | ||
return new BufferAccumulator<T>(buffer, recordsToAccumulate, bufferTimeout); | ||
} | ||
|
||
void add(final T record) throws Exception { | ||
recordsAccumulated.add(record); | ||
if (recordsAccumulated.size() >= numberOfRecordsToAccumulate) { | ||
flush(); | ||
} | ||
} | ||
|
||
void flush() throws Exception { | ||
try { | ||
flushAccumulatedToBuffer(); | ||
} catch (final TimeoutException timeoutException) { | ||
flushWithBackoff(); | ||
} | ||
} | ||
|
||
private boolean flushWithBackoff() throws Exception{ | ||
final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); | ||
long nextDelay = INITIAL_FLUSH_RETRY_DELAY_ON_IO_EXCEPTION.toMillis(); | ||
boolean flushedSuccessfully; | ||
|
||
for (int retryCount = 0; retryCount < MAX_FLUSH_RETRIES_ON_IO_EXCEPTION; retryCount++) { | ||
final ScheduledFuture<Boolean> flushBufferFuture = scheduledExecutorService.schedule(() -> { | ||
try { | ||
flushAccumulatedToBuffer(); | ||
return true; | ||
} catch (final TimeoutException e) { | ||
return false; | ||
} | ||
}, nextDelay, TimeUnit.MILLISECONDS); | ||
|
||
try { | ||
flushedSuccessfully = flushBufferFuture.get(); | ||
if (flushedSuccessfully) { | ||
LOG.info("Successfully flushed the buffer accumulator on retry attempt {}", retryCount + 1); | ||
scheduledExecutorService.shutdownNow(); | ||
return true; | ||
} | ||
} catch (final ExecutionException e) { | ||
LOG.warn("Retrying of flushing the buffer accumulator hit an exception: {}", e.getMessage()); | ||
scheduledExecutorService.shutdownNow(); | ||
throw e; | ||
} catch (final InterruptedException e) { | ||
LOG.warn("Retrying of flushing the buffer accumulator was interrupted: {}", e.getMessage()); | ||
scheduledExecutorService.shutdownNow(); | ||
throw e; | ||
} | ||
} | ||
|
||
LOG.warn("Flushing the bufferAccumulator failed after {} attempts", MAX_FLUSH_RETRIES_ON_IO_EXCEPTION); | ||
scheduledExecutorService.shutdownNow(); | ||
return false; | ||
} | ||
|
||
private void flushAccumulatedToBuffer() throws Exception { | ||
final int currentRecordCountAccumulated = recordsAccumulated.size(); | ||
if (currentRecordCountAccumulated > 0) { | ||
buffer.writeAll(recordsAccumulated, bufferTimeoutMillis); | ||
recordsAccumulated.clear(); | ||
totalWritten += currentRecordCountAccumulated; | ||
} | ||
} | ||
|
||
/** | ||
* Gets the total number of records written to the buffer. | ||
* | ||
* @return the total number of records written | ||
*/ | ||
public int getTotalWritten() { | ||
return totalWritten; | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
...in/java/org/opensearch/dataprepper/plugins/source/opensearch/OpenSearchClientBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
package org.opensearch.dataprepper.plugins.source.opensearch; | ||
|
||
import java.net.URL; | ||
import java.util.List; | ||
|
||
import co.elastic.clients.json.jackson.JacksonJsonpMapper; | ||
import co.elastic.clients.transport.ElasticsearchTransport; | ||
import co.elastic.clients.transport.rest_client.RestClientTransport; | ||
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; | ||
import org.apache.hc.core5.http.HttpHost; | ||
import org.apache.http.HttpHeaders; | ||
import org.apache.http.HttpResponseInterceptor; | ||
import org.apache.http.entity.ContentType; | ||
import org.apache.http.message.BasicHeader; | ||
import org.elasticsearch.client.RestClient; | ||
import org.opensearch.client.opensearch.OpenSearchClient; | ||
import co.elastic.clients.elasticsearch.ElasticsearchClient; | ||
import org.opensearch.client.transport.OpenSearchTransport; | ||
import org.opensearch.client.transport.httpclient5.ApacheHttpClient5TransportBuilder; | ||
|
||
/** | ||
* used for creating connection | ||
*/ | ||
public class OpenSearchClientBuilder { | ||
|
||
/** | ||
* This method create opensearch client based on host information, which will be used to call opensearch apis | ||
* @param url | ||
* @return | ||
*/ | ||
public OpenSearchClient createOpenSearchClient(final URL url){ | ||
final HttpHost host = new HttpHost(url.getProtocol(), url.getHost(), url.getPort()); | ||
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); | ||
final OpenSearchTransport transport = ApacheHttpClient5TransportBuilder | ||
.builder(host) | ||
.setMapper(new org.opensearch.client.json.jackson.JacksonJsonpMapper()) | ||
.build(); | ||
return new OpenSearchClient(transport); | ||
} | ||
|
||
/** | ||
* This method create Elasticsearch client based on host information, which will be used to call opensearch apis | ||
* @param url | ||
* @return | ||
*/ | ||
public ElasticsearchClient createElasticSearchClient(final URL url) { | ||
final String HEADER_NAME = "X-Elastic-Product"; | ||
final String HEADER_VALUE = "Elasticsearch"; | ||
|
||
RestClient client = org.elasticsearch.client.RestClient.builder(new org.apache.http.HttpHost(url.getHost(), url.getPort())). | ||
setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder | ||
.setDefaultHeaders(List.of(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()))) | ||
.addInterceptorLast((HttpResponseInterceptor) (response, context) -> response.addHeader(HEADER_NAME, HEADER_VALUE))).build(); | ||
JacksonJsonpMapper jacksonJsonpMapper = new JacksonJsonpMapper(); | ||
ElasticsearchTransport transport = new RestClientTransport(client, jacksonJsonpMapper); | ||
return new ElasticsearchClient(transport); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
...in/java/org/opensearch/dataprepper/plugins/source/opensearch/OpenSearchSourceService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
package org.opensearch.dataprepper.plugins.source.opensearch; | ||
|
||
import org.opensearch.dataprepper.plugins.source.opensearch.configuration.IndexParametersConfiguration; | ||
import org.opensearch.dataprepper.plugins.source.opensearch.model.ServiceInfo; | ||
import org.opensearch.dataprepper.plugins.source.opensearch.service.ElasticSearchService; | ||
import org.opensearch.dataprepper.plugins.source.opensearch.service.HostsService; | ||
import org.opensearch.dataprepper.plugins.source.opensearch.service.OpenSearchService; | ||
import org.opensearch.dataprepper.plugins.source.opensearch.worker.OpenSearchTimerWorker; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.Timer; | ||
|
||
/** | ||
* Service that will call both worker classes | ||
*/ | ||
public class OpenSearchSourceService { | ||
private static final Logger LOG = LoggerFactory.getLogger(OpenSearchSourceService.class); | ||
|
||
private final OpenSearchService openSearchService; | ||
|
||
private final ElasticSearchService elasticSearchService; | ||
|
||
private final HostsService hostsService; | ||
|
||
private final OpenSearchSourceConfiguration sourceConfig; | ||
|
||
private final BufferAccumulator bufferAccumulator; | ||
|
||
private final Timer timer = new Timer(); | ||
|
||
public OpenSearchSourceService(final OpenSearchSourceConfiguration sourceConfig, | ||
final HostsService hostsService, | ||
final OpenSearchService openSearchService, | ||
final ElasticSearchService elasticSearchService, | ||
final BufferAccumulator bufferAccumulator){ | ||
this.sourceConfig = sourceConfig; | ||
this.hostsService = hostsService; | ||
this.openSearchService = openSearchService; | ||
this.elasticSearchService =elasticSearchService; | ||
this.bufferAccumulator = bufferAccumulator; | ||
} | ||
|
||
public void processHosts(){ | ||
sourceConfig.getHosts().forEach(host ->{ | ||
final ServiceInfo serviceInfo = hostsService.findServiceDetailsByUrl(host); | ||
IndexParametersConfiguration index = sourceConfig.getIndexParametersConfiguration(); | ||
timer.scheduleAtFixedRate(new OpenSearchTimerWorker(openSearchService,elasticSearchService, | ||
sourceConfig,bufferAccumulator,serviceInfo,host), | ||
sourceConfig.getSchedulingParameterConfiguration().getStartTime().getSecond(), | ||
sourceConfig.getSchedulingParameterConfiguration().getRate().toMillis()); | ||
}); | ||
} | ||
public void stop(){ | ||
timer.cancel(); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
...n/java/org/opensearch/dataprepper/plugins/source/opensearch/codec/JacksonValueParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.dataprepper.plugins.source.opensearch.codec; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import jakarta.json.stream.JsonParser; | ||
import org.opensearch.client.json.JsonpDeserializerBase; | ||
import org.opensearch.client.json.JsonpMapper; | ||
import org.opensearch.client.json.jackson.JacksonJsonpParser; | ||
import java.io.IOException; | ||
import java.util.EnumSet; | ||
|
||
public class JacksonValueParser<T> extends JsonpDeserializerBase<T> { | ||
|
||
private final ObjectMapper objectMapper = new ObjectMapper(); | ||
private final Class<T> clazz; | ||
public JacksonValueParser(Class<T> clazz) { | ||
super(EnumSet.allOf(JsonParser.Event.class)); | ||
this.clazz = clazz; | ||
} | ||
@Override | ||
public T deserialize(JsonParser parser, JsonpMapper mapper, JsonParser.Event event) { | ||
|
||
if (!(parser instanceof JacksonJsonpParser)) { | ||
throw new IllegalArgumentException("Jackson's ObjectMapper can only be used with the JacksonJsonpProvider"); | ||
} | ||
com.fasterxml.jackson.core.JsonParser jkParser = ((JacksonJsonpParser) parser).jacksonParser(); | ||
|
||
try { | ||
return objectMapper.readValue(jkParser, clazz); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.