-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for transferring raw files to NFS storage (#73)
Adds a new service RawFileMoveService to Pravega Sensor collector to enable file transfer from a host to a mounted NFS storage. The service uses SQL database and SQLite transaction to ensure data accuracy and avoid duplication.
- Loading branch information
1 parent
c21db24
commit d0c4ddc
Showing
12 changed files
with
767 additions
and
4 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
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
65 changes: 65 additions & 0 deletions
65
...ega-sensor-collector/src/main/java/io/pravega/sensor/collector/writetonfs/FileConfig.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,65 @@ | ||
/** | ||
* Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
*/ | ||
package io.pravega.sensor.collector.writetonfs; | ||
|
||
/* | ||
* Configuration file. | ||
*/ | ||
public class FileConfig { | ||
public final String stateDatabaseFileName; | ||
public final String fileSpec; | ||
public final String fileExtension; | ||
public final String nfsMountPath; | ||
public final String routingKey; | ||
public final String eventTemplateStr; | ||
public final String fileType; | ||
/** | ||
* Also known as samplesPerEvent. | ||
*/ | ||
public final int maxRecordsPerEvent; | ||
|
||
public final boolean enableDeleteCompletedFiles; | ||
public final boolean exactlyOnce; | ||
public final double transactionTimeoutMinutes; | ||
|
||
public final long minTimeInMillisToUpdateFile; | ||
|
||
public FileConfig(String stateDatabaseFileName, String fileSpec, String fileExtension, String nfsMountPath,String routingKey, String eventTemplateStr, int maxRecordsPerEvent, boolean enableDeleteCompletedFiles, boolean exactlyOnce, double transactionTimeoutMinutes, long minTimeInMillisToUpdateFile, String fileType) { | ||
this.stateDatabaseFileName = stateDatabaseFileName; | ||
this.fileSpec = fileSpec; | ||
this.fileExtension = fileExtension; | ||
this.nfsMountPath = nfsMountPath; | ||
this.routingKey = routingKey; | ||
this.eventTemplateStr = eventTemplateStr; | ||
this.maxRecordsPerEvent = maxRecordsPerEvent; | ||
this.enableDeleteCompletedFiles = enableDeleteCompletedFiles; | ||
this.exactlyOnce = exactlyOnce; | ||
this.transactionTimeoutMinutes = transactionTimeoutMinutes; | ||
this.minTimeInMillisToUpdateFile = minTimeInMillisToUpdateFile; | ||
this.fileType = fileType; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "FileConfig{" | ||
+ "stateDatabaseFileName='" + stateDatabaseFileName + '\'' | ||
+ ", fileSpec='" + fileSpec + '\'' | ||
+ ", fileExtension='" + fileExtension + '\'' | ||
+ ", nfsMountPath='" + nfsMountPath + '\'' | ||
+ ", fileType='" + fileType + '\'' | ||
+ ", routingKey='" + routingKey + '\'' | ||
+ ", eventTemplateStr='" + eventTemplateStr + '\'' | ||
+ ", maxRecordsPerEvent=" + maxRecordsPerEvent | ||
+ ", enableDeleteCompletedFiles=" + enableDeleteCompletedFiles | ||
+ ", exactlyOnce=" + exactlyOnce | ||
+ ", transactionTimeoutMinutes=" + transactionTimeoutMinutes | ||
+ '}'; | ||
} | ||
} |
175 changes: 175 additions & 0 deletions
175
...ensor-collector/src/main/java/io/pravega/sensor/collector/writetonfs/FileMoveService.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,175 @@ | ||
/** | ||
* Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
*/ | ||
package io.pravega.sensor.collector.writetonfs; | ||
|
||
import com.google.common.util.concurrent.ThreadFactoryBuilder; | ||
import io.pravega.sensor.collector.DeviceDriver; | ||
import io.pravega.sensor.collector.DeviceDriverConfig; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.ScheduledFuture; | ||
import java.util.concurrent.ThreadFactory; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* File transfer service with common implementation logic for all files. | ||
*/ | ||
public abstract class FileMoveService extends DeviceDriver { | ||
private static final Logger LOG = LoggerFactory.getLogger(FileMoveService.class); | ||
|
||
private static final String FILE_SPEC_KEY = "FILE_SPEC"; | ||
private static final String FILE_EXT = "FILE_EXTENSION"; | ||
private static final String NFS_MOUNT_PATH = "NFS_MOUNT_PATH"; | ||
private static final String DELETE_COMPLETED_FILES_KEY = "DELETE_COMPLETED_FILES"; | ||
private static final String DATABASE_FILE_KEY = "DATABASE_FILE"; | ||
private static final String EVENT_TEMPLATE_KEY = "EVENT_TEMPLATE"; | ||
private static final String SAMPLES_PER_EVENT_KEY = "SAMPLES_PER_EVENT"; | ||
private static final String INTERVAL_MS_KEY = "INTERVAL_MS"; | ||
|
||
private static final String ROUTING_KEY_KEY = "ROUTING_KEY"; | ||
private static final String EXACTLY_ONCE_KEY = "EXACTLY_ONCE"; | ||
private static final String TRANSACTION_TIMEOUT_MINUTES_KEY = "TRANSACTION_TIMEOUT_MINUTES"; | ||
private static final String MIN_TIME_IN_MILLIS_TO_UPDATE_FILE_KEY = "MIN_TIME_IN_MILLIS_TO_UPDATE_FILE"; | ||
|
||
private static final int DEFAULT_SAMPLES_PER_EVENT_KEY = 100; | ||
|
||
private static final int DEFAULT_INTERVAL_MS_KEY = 10000; | ||
|
||
private final FileProcessor processor; | ||
private final ScheduledExecutorService executor; | ||
|
||
private ScheduledFuture<?> watchFiletask; | ||
private ScheduledFuture<?> processFileTask; | ||
|
||
public FileMoveService(DeviceDriverConfig config) { | ||
super(config); | ||
final FileConfig fileSequenceConfig = new FileConfig( | ||
getDatabaseFileName(), | ||
getFileSpec(), | ||
getFileExtension(), | ||
getNFSMountPath(), | ||
getRoutingKey(), | ||
getEventTemplate(), | ||
getSamplesPerEvent(), | ||
getDeleteCompletedFiles(), | ||
getExactlyOnce(), | ||
getTransactionTimeoutMinutes(), | ||
getMinTimeInMillisToUpdateFile(), | ||
config.getClassName()); | ||
LOG.info("File Transfer Config: {}", fileSequenceConfig); | ||
processor = FileProcessor.create(fileSequenceConfig); | ||
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat( | ||
FileMoveService.class.getSimpleName() + "-" + config.getInstanceName() + "-%d").build(); | ||
executor = Executors.newScheduledThreadPool(1, namedThreadFactory); | ||
} | ||
|
||
String getFileSpec() { | ||
return getProperty(FILE_SPEC_KEY); | ||
} | ||
|
||
String getFileExtension() { | ||
return getProperty(FILE_EXT, ""); | ||
} | ||
|
||
String getNFSMountPath() { | ||
return getProperty(NFS_MOUNT_PATH, ""); | ||
} | ||
|
||
boolean getDeleteCompletedFiles() { | ||
return Boolean.parseBoolean(getProperty(DELETE_COMPLETED_FILES_KEY, Boolean.toString(true))); | ||
} | ||
|
||
String getDatabaseFileName() { | ||
return getProperty(DATABASE_FILE_KEY); | ||
} | ||
|
||
String getEventTemplate() { | ||
return getProperty(EVENT_TEMPLATE_KEY, "{}"); | ||
} | ||
|
||
int getSamplesPerEvent() { | ||
return Integer.parseInt(getProperty(SAMPLES_PER_EVENT_KEY, Integer.toString(DEFAULT_SAMPLES_PER_EVENT_KEY))); | ||
} | ||
|
||
long getIntervalMs() { | ||
return Long.parseLong(getProperty(INTERVAL_MS_KEY, Long.toString(DEFAULT_INTERVAL_MS_KEY))); | ||
} | ||
|
||
protected String getRoutingKey() { | ||
return getProperty(ROUTING_KEY_KEY, ""); | ||
} | ||
|
||
boolean getExactlyOnce() { | ||
return Boolean.parseBoolean(getProperty(EXACTLY_ONCE_KEY, Boolean.toString(true))); | ||
} | ||
|
||
/** | ||
* This time duration must not exceed the controller property controller.transaction.maxLeaseValue (milliseconds). | ||
*/ | ||
double getTransactionTimeoutMinutes() { | ||
return Double.parseDouble(getProperty(TRANSACTION_TIMEOUT_MINUTES_KEY, Double.toString(18.0 * 60.0))); | ||
} | ||
|
||
long getMinTimeInMillisToUpdateFile() { | ||
return Long.parseLong(getProperty(MIN_TIME_IN_MILLIS_TO_UPDATE_FILE_KEY, "5000")); | ||
} | ||
|
||
protected void watchFiles() { | ||
LOG.trace("watchFiles: BEGIN"); | ||
try { | ||
processor.watchFiles(); | ||
} catch (Exception e) { | ||
LOG.error("watchFiles: watch file error", e); | ||
// Continue on any errors. We will retry on the next iteration. | ||
} | ||
LOG.trace("watchFiles: END"); | ||
} | ||
|
||
protected void processFiles() { | ||
LOG.trace("processFiles: BEGIN"); | ||
try { | ||
processor.processFiles(); | ||
} catch (Exception e) { | ||
LOG.error("processFiles: Process file error", e); | ||
// Continue on any errors. We will retry on the next iteration. | ||
} | ||
LOG.trace("processFiles: END"); | ||
} | ||
|
||
@Override | ||
protected void doStart() { | ||
watchFiletask = executor.scheduleAtFixedRate( | ||
this::watchFiles, | ||
0, | ||
getIntervalMs(), | ||
TimeUnit.MILLISECONDS); | ||
/* | ||
Submits a periodic action that becomes enabled immediately for the first time, | ||
and subsequently with the delay of 1 milliseconds between the termination of one execution and the commencement of the next | ||
ie immediately after completion of first action. | ||
*/ | ||
processFileTask = executor.scheduleWithFixedDelay( | ||
this::processFiles, | ||
0, | ||
1, | ||
TimeUnit.MILLISECONDS); | ||
notifyStarted(); | ||
} | ||
|
||
@Override | ||
protected void doStop() { | ||
LOG.info("doStop: Cancelling transfer task and process file task"); | ||
watchFiletask.cancel(false); | ||
processFileTask.cancel(false); | ||
} | ||
} |
Oops, something went wrong.