From caf4192bcea6575ce57ac91308355604c9c90f43 Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Tue, 25 Jun 2024 10:38:58 +0530 Subject: [PATCH 1/8] Read and Write is working --- build.sbt | 33 +- scalastyle-config.xml | 298 ------------- src/main/resources/reference.conf | 2 +- .../com/erudika/lucene/store/s3/Main.java | 24 ++ .../erudika/lucene/store/s3/S3Directory.java | 390 ++++++++++++++++++ .../lucene/store/s3/S3DirectorySettings.java | 148 +++++++ .../lucene/store/s3/S3FileEntrySettings.java | 218 ++++++++++ .../lucene/store/s3/S3FileSystemStore.java | 26 ++ .../lucene/store/s3/S3SingletonClient.java | 36 ++ .../lucene/store/s3/S3StoreException.java | 142 +++++++ .../s3/handler/AbstractFileEntryHandler.java | 165 ++++++++ .../handler/ActualDeleteFileEntryHandler.java | 32 ++ .../store/s3/handler/FileEntryHandler.java | 116 ++++++ .../s3/handler/NoOpFileEntryHandler.java | 172 ++++++++ .../store/s3/index/AbstractS3IndexOutput.java | 77 ++++ .../index/ConfigurableBufferedIndexInput.java | 204 +++++++++ .../ConfigurableBufferedIndexOutput.java | 155 +++++++ .../index/FetchOnBufferReadS3IndexInput.java | 244 +++++++++++ .../s3/index/FetchOnOpenS3IndexInput.java | 109 +++++ .../store/s3/index/RAMS3IndexOutput.java | 261 ++++++++++++ .../store/s3/index/S3BufferedIndexInput.java | 45 ++ .../store/s3/index/S3BufferedIndexOutput.java | 45 ++ .../store/s3/index/S3IndexConfigurable.java | 41 ++ .../lucene/store/s3/index/S3IndexInput.java | 154 +++++++ .../lucene/store/s3/lock/NoOpLock.java | 49 +++ .../lucene/store/s3/lock/S3LegalHoldLock.java | 122 ++++++ .../erudika/lucene/store/s3/lock/S3Lock.java | 42 ++ .../store/s3/support/LuceneFileNames.java | 76 ++++ .../org/zouzias/spark/lucenerdd/Driver.scala | 82 ++++ .../org/zouzias/spark/lucenerdd/GZip.scala | 34 ++ .../zouzias/spark/lucenerdd/LuceneRDD.scala | 29 +- .../spark/lucenerdd/ReadSavedFile.scala | 36 ++ .../org/zouzias/spark/lucenerdd/Schema.scala | 22 + .../org/zouzias/spark/lucenerdd/UDF.scala | 16 + .../lucenerdd/config/LuceneRDDParams.scala | 6 +- .../partition/LuceneRDDPartition.scala | 38 +- .../spark/lucenerdd/store/IndexStorable.scala | 21 +- .../lucenerdd/versioning/Versionable.scala | 3 +- 38 files changed, 3383 insertions(+), 330 deletions(-) delete mode 100644 scalastyle-config.xml create mode 100644 src/main/scala/com/erudika/lucene/store/s3/Main.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3Directory.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java create mode 100644 src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java create mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala create mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala create mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala create mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala create mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala diff --git a/build.sbt b/build.sbt index 41f4b66b..9dff35d6 100644 --- a/build.sbt +++ b/build.sbt @@ -123,12 +123,37 @@ libraryDependencies ++= Seq( ) libraryDependencies ++= Seq( - "org.apache.spark" %% "spark-core" % sparkVersion % "provided", - "org.apache.spark" %% "spark-sql" % sparkVersion % "provided", - "org.apache.spark" %% "spark-mllib" % sparkVersion % "provided", + "org.apache.spark" %% "spark-core" % sparkVersion, + "org.apache.spark" %% "spark-sql" % sparkVersion, + "org.apache.spark" %% "spark-mllib" % sparkVersion , "com.holdenkarau" %% "spark-testing-base" % s"3.5.0_1.4.7" % "test" intransitive(), - "org.scala-lang" % "scala-library" % scalaVersion.value % "compile" + "org.scala-lang" % "scala-library" % scalaVersion.value ) +// https://mvnrepository.com/artifact/software.amazon.awssdk/s3 +libraryDependencies += "software.amazon.awssdk" % "s3" % "2.25.23" + +libraryDependencies += "com.upplication" % "s3fs" % "2.2.2" + +// https://mvnrepository.com/artifact/org.apache.spark/spark-sql-kafka-0-10 +libraryDependencies += "org.apache.spark" %% "spark-sql-kafka-0-10" % "3.5.1" + + +// https://mvnrepository.com/artifact/org.apache.spark/spark-hive +libraryDependencies += "org.apache.spark" %% "spark-hive" % "3.5.1" + +// https://mvnrepository.com/artifact/org.apache.spark/spark-streaming +libraryDependencies += "org.apache.spark" %% "spark-streaming" % "3.5.1" + +// https://mvnrepository.com/artifact/org.scala-lang/scala-reflect +libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.12.19" + +// https://mvnrepository.com/artifact/com.typesafe.scala-logging/scala-logging +libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5" + +// https://mvnrepository.com/artifact/org.typelevel/cats-kernel +libraryDependencies += "org.typelevel" %% "cats-kernel" % "2.10.0" + +libraryDependencies += "org.zouzias" %% "spark-lucenerdd" % "0.4.0" // Read version in code from build.sbt lazy val root = (project in file(".")). diff --git a/scalastyle-config.xml b/scalastyle-config.xml deleted file mode 100644 index 355e9642..00000000 --- a/scalastyle-config.xml +++ /dev/null @@ -1,298 +0,0 @@ - - - - - Scalastyle standard configuration - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ARROW, EQUALS, ELSE, TRY, CATCH, FINALLY, LARROW, RARROW - - - - - - ARROW, EQUALS, COMMA, COLON, IF, ELSE, DO, WHILE, FOR, MATCH, TRY, CATCH, FINALLY, LARROW, RARROW - - - - - - - - - ^FunSuite[A-Za-z]*$ - Tests must extend org.apache.spark.SparkFunSuite instead. - - - - - ^println$ - - - - - @VisibleForTesting - - - - - Runtime\.getRuntime\.addShutdownHook - - - - - mutable\.SynchronizedBuffer - - - - - Class\.forName - - - - - - JavaConversions - Instead of importing implicits in scala.collection.JavaConversions._, import - scala.collection.JavaConverters._ and use .asScala / .asJava methods - - - - - java,scala,3rdParty,spark - javax?\..* - scala\..* - - - - - - COMMA - - - - - - \)\{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 800> - - - - - 30 - - - - - 10 - - - - - 50 - - - - - - - - - - - -1,0,1,2,3 - - - diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 40728f25..5e6892b0 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -25,7 +25,7 @@ lucenerdd { // Use 'disk' to store the index in Java's temp directory // Otherwise the index will be stored in memory // Do not use memory, see http://lucene.apache.org/core/7_5_0/core/org/apache/lucene/store/RAMDirectory.html - store.mode = "disk" + store.mode = "s3" store.mode = ${?LUCENERDD_INDEX_STORE_MODE} stringfields{ diff --git a/src/main/scala/com/erudika/lucene/store/s3/Main.java b/src/main/scala/com/erudika/lucene/store/s3/Main.java new file mode 100644 index 00000000..4e3814eb --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/Main.java @@ -0,0 +1,24 @@ +package com.erudika.lucene.store.s3; + +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.IOContext; + +import java.io.IOException; +import java.util.Arrays; + +public class Main { + public static void main(String[] args) { + try { + Directory directory = new S3Directory("lucene-test", "lucene-kashyap"); + + System.out.println(Arrays.toString(directory.listAll())); + + System.out.println(directory.fileLength("_b_Lucene84_0.doc")); + + System.out.println(directory.openChecksumInput("_b_Lucene84_0.doc", new IOContext()).getChecksum()); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3Directory.java b/src/main/scala/com/erudika/lucene/store/s3/S3Directory.java new file mode 100644 index 00000000..d419573d --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/S3Directory.java @@ -0,0 +1,390 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3; + +import com.erudika.lucene.store.s3.handler.FileEntryHandler; +import com.erudika.lucene.store.s3.lock.NoOpLock; +import com.erudika.lucene.store.s3.lock.S3LegalHoldLock; +import com.erudika.lucene.store.s3.lock.S3Lock; +import com.erudika.lucene.store.s3.support.LuceneFileNames; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.store.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.ObjectIdentifier; +import software.amazon.awssdk.services.s3.model.S3Object; +import software.amazon.awssdk.services.s3.paginators.ListObjectsV2Iterable; + +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * A S3 based implementation of a Lucene Directory allowing the storage of a Lucene index within S3. + * The directory works against a single bucket, where the binary data is stored in objects. + * Each "object" has an entry in the S3, and different {@link com.erudika.lucene.store.s3.handler.FileEntryHandler} + * can be defines for different files (or files groups). + * + * @author kimchy + */ +public class S3Directory extends Directory { + + private static final Logger logger = LoggerFactory.getLogger(S3Directory.class); + + private S3DirectorySettings settings; + + private final ConcurrentHashMap fileSizes = new ConcurrentHashMap<>(); + + private final HashMap fileEntryHandlers = new HashMap(); + + private String bucket; + + private String path; + + private final S3Client s3 = S3SingletonClient.getS3Client(); + + /** + * Creates a new S3 directory. + * + * @param bucketName The bucket name + * @throws S3StoreException + */ + public S3Directory(final String bucketName, final String pathName) throws S3StoreException { + initialize(bucketName, pathName, new S3DirectorySettings()); + } + + /** + * Creates a new S3 directory. + * + * @param bucketName The table name that will be used + * @param settings The settings to configure the directory + */ + public S3Directory(final String bucketName, final String pathName, final S3DirectorySettings settings) { + initialize(bucketName, pathName, settings); + } + + private void initialize(final String bucket, final String path, S3DirectorySettings settings) { + this.bucket = bucket.toLowerCase(); + this.path = path; + this.settings = settings; + final Map fileEntrySettings = settings.getFileEntrySettings(); + // go over all the file entry settings and configure them + for (final String name : fileEntrySettings.keySet()) { + final S3FileEntrySettings feSettings = fileEntrySettings.get(name); + try { + final Class fileEntryHandlerClass = feSettings + .getSettingAsClass(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, null); + final FileEntryHandler fileEntryHandler = (FileEntryHandler) fileEntryHandlerClass.getConstructor().newInstance(); + fileEntryHandler.configure(this); + fileEntryHandlers.put(name, fileEntryHandler); + } catch (final Exception e) { + throw new IllegalArgumentException("Failed to create FileEntryHandler [" + + feSettings.getSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE) + "]"); + } + } + logger.info(fileEntrySettings.entrySet().stream().map(e -> e.getKey() + " -> " + e.getValue()).collect(Collectors.joining(", "))); + } + + /** + * ******************************************************************************************** + * CUSTOM METHODS + * ******************************************************************************************** + */ + + /** + * Returns true if the S3 bucket exists. + * + * @return true if the S3 bucket exists, false otherwise + * @throws IOException + * @throws UnsupportedOperationException If the S3 dialect does not support it + */ + public boolean bucketExists() { + try { + if (logger.isDebugEnabled()) { + logger.info("bucketExists({})", bucket); + } + s3.headBucket(b -> b.bucket(bucket)); + return true; + } catch (AwsServiceException | SdkClientException e) { + return false; + } + } + + /** + * @param name + * @return + * @throws IOException + */ + public boolean fileExists(final String name) throws IOException { + return getFileEntryHandler(name).fileExists(name); + } + + /** + * Deletes the S3 bucket (drops it) from the S3. + */ + public void delete() { + if (bucketExists()) { + if (logger.isDebugEnabled()) { + logger.info("delete({})", bucket); + } + emptyBucket(); + try { + s3.deleteBucket(b -> b.bucket(bucket)); + } catch (Exception e) { + logger.error("Bucket {} not empty - [{}]", bucket, e); + } + } + } + + /** + * Creates a new S3 bucket. + * + * @throws IOException + */ + public void create() { + if (!bucketExists()) { + if (logger.isDebugEnabled()) { + logger.info("create({})", bucket); + } + s3.createBucket(b -> b.bucket(bucket).objectLockEnabledForBucket(true)); + } + try { + if (logger.isDebugEnabled()) { + logger.info("write.lock created in {}", bucket); + } + // initialize the write.lock file immediately after bucket creation + s3.putObject(b -> b.bucket(bucket).key(IndexWriter.WRITE_LOCK_NAME), RequestBody.empty()); + } catch (Exception e) { } + } + + /** + * Empties a bucket on S3. + */ + public void emptyBucket() { + deleteObjectVersions(null); + } + + /** + * Deletes all object versions for a given prefix. If prefix is null, all objects are deleted. + * @param prefix a key prefix for filtering + */ + private void deleteObjectVersions(String prefix) { + LinkedList objects = new LinkedList<>(); + s3.listObjectVersionsPaginator(b -> b.bucket(bucket).prefix(prefix)).forEach((response) -> { + if (logger.isDebugEnabled()) { + logger.info("deleteContent({}, {})", bucket, response.versions().size()); + } + response.versions().forEach((content) -> { + objects.add(ObjectIdentifier.builder().key(content.key()).versionId(content.versionId()).build()); + }); + }); + + List keyz = new LinkedList<>(); + for (ObjectIdentifier key : objects) { + keyz.add(key); + if (keyz.size() >= 1000) { + s3.deleteObjects(b -> b.bucket(bucket).delete(bd -> bd.objects(keyz))); + keyz.clear(); + } + fileSizes.remove(key.key()); + } + if (!keyz.isEmpty()) { + s3.deleteObjects(b -> b.bucket(bucket).delete(bd -> bd.objects(keyz))); + } + } + + /** + * @param name + * @throws IOException + */ + public void forceDeleteFile(final String name) throws IOException { + if (logger.isDebugEnabled()) { + logger.info("forceDeleteFile({})", name); + } + deleteObjectVersions(name); + } + + /** + * @return @throws IOException + */ + protected Lock createLock() throws IOException { + return new NoOpLock(); + } + + /** + * @param name + * @return + */ + protected FileEntryHandler getFileEntryHandler(final String name) { + FileEntryHandler handler = fileEntryHandlers.get(name.substring(name.length() - 3)); + if (handler != null) { + return handler; + } + handler = fileEntryHandlers.get(name); + if (handler != null) { + return handler; + } + return fileEntryHandlers.get(S3DirectorySettings.DEFAULT_FILE_ENTRY); + } + + /** + * ******************************************************************************************** + * DIRECTORY METHODS + * ******************************************************************************************** + */ + @Override + public String[] listAll() { + if (logger.isDebugEnabled()) { + logger.info("listAll({})", bucket); + } + final LinkedList names = new LinkedList<>(); + try { + ListObjectsV2Iterable responses = s3.listObjectsV2Paginator(b -> b.bucket(bucket)); + for (ListObjectsV2Response response : responses) { + names.addAll(response.contents().stream().map(S3Object::key).toList()); + } + } catch (Exception e) { + logger.error("{}", e.toString()); + } + + return names.toArray(new String[]{}); + } + + @Override + public void deleteFile(final String name) throws IOException { + if (LuceneFileNames.isStaticFile(name)) { + // TODO is necessary?? + logger.warn("S3Directory.deleteFile({}), is static file", name); + forceDeleteFile(name); + } else { + getFileEntryHandler(name).deleteFile(name); + } + } + + @Override + public long fileLength(final String name) throws IOException { + return getFileEntryHandler(name).fileLength(name); + } + + @Override + public IndexOutput createOutput(final String name, final IOContext context) throws IOException { + if (LuceneFileNames.isStaticFile(name)) { + // TODO is necessary?? + logger.warn("S3Directory.createOutput({}), is static file", name); + forceDeleteFile(name); + } + return getFileEntryHandler(name).createOutput(name); + } + + @Override + public IndexInput openInput(final String name, final IOContext context) throws IOException { + return getFileEntryHandler(name).openInput(name); + } + + @Override + public void sync(final Collection names) throws IOException { + logger.warn("S3Directory.sync({})", names); + for (final String name : names) { + if (!fileExists(name)) { + throw new S3StoreException("Failed to sync, file " + name + " not found"); + } + } + } + + @Override + public void rename(final String from, final String to) throws IOException { + getFileEntryHandler(from).renameFile(from, to); + } + + @Override + public Lock obtainLock(final String name) throws IOException { + final Lock lock = createLock(); + ((S3Lock) lock).configure(this, name); + ((S3Lock) lock).obtain(); + return lock; +// return new NoOpLock(); + } + + @Override + public void close() throws IOException { + IOException last = null; + for (final FileEntryHandler fileEntryHandler : fileEntryHandlers.values()) { + try { + fileEntryHandler.close(); + } catch (final IOException e) { + last = e; + } + } + if (last != null) { + throw last; + } + } + + @Override + public IndexOutput createTempOutput(String prefix, String suffix, IOContext context) throws IOException { + String name = prefix.concat("_temp_").concat(suffix).concat(".tmp"); + if (LuceneFileNames.isStaticFile(name)) { + // TODO is necessary?? + logger.warn("S3Directory.createOutput({}), is static file", name); + forceDeleteFile(name); + } + return getFileEntryHandler(name).createOutput(name); + } + + @Override + public void syncMetaData() throws IOException { + } + + /** + * ********************************************************************************************* + * SETTER/GETTERS METHODS + * ********************************************************************************************* + */ + public String getBucket() { + return bucket; + } + + public String getPath() { + return path; + } + + public S3DirectorySettings getSettings() { + return settings; + } + + public S3Client getS3() { + return s3; + } + + public ConcurrentHashMap getFileSizes() { + return fileSizes; + } + + @Override + public Set getPendingDeletions() throws IOException { + return Collections.emptySet(); + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java b/src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java new file mode 100644 index 00000000..b8afcb2f --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java @@ -0,0 +1,148 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3; + +import com.erudika.lucene.store.s3.handler.ActualDeleteFileEntryHandler; +import com.erudika.lucene.store.s3.handler.NoOpFileEntryHandler; +import com.erudika.lucene.store.s3.index.FetchOnOpenS3IndexInput; +import com.erudika.lucene.store.s3.index.RAMS3IndexOutput; +import com.erudika.lucene.store.s3.index.S3IndexInput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * General directory level settings. + *

+ * The settings also holds {@link S3FileEntrySettings}, that can be registered with the directory settings. Note, that + * when registering them, they are registered under both the complete name and the 3 charecters name suffix. + *

+ * When creating the settings, it already holds sensible settings, they are: The default {@link S3FileEntrySettings} + * uses the file entry settings defaults. The "deletable", ""deleteable.new", and "deletable.new" uses the + * {@link org.apache.lucene.store.s3.handler.NoOpFileEntryHandler}. The "segments" and "segments.new" uses the null {@link org.apache.lucene.store.s3.handler.ActualDeleteFileEntryHandler}, + * {@link org.apache.lucene.store.s3.index.FetchOnOpenS3IndexInput}, and + * {@link org.apache.lucene.store.s3.index.RAMS3IndexOutput}. The file suffix "fnm" uses the + * {@link org.apache.lucene.store.s3.index.FetchOnOpenS3IndexInput}, and + * {@link org.apache.lucene.store.s3.index.RAMS3IndexOutput}. The file suffix "del" and "tmp" uses the + * {@link org.apache.lucene.store.s3.handler.ActualDeleteFileEntryHandler}. + * + * @author kimchy + */ +public class S3DirectorySettings { + + /** + * The default file entry settings name that are registered under. + */ + public static String DEFAULT_FILE_ENTRY = "__default__"; + private static final Logger logger = LoggerFactory.getLogger(S3DirectorySettings.class); + + /** + * A simple constant having the millisecond value of an hour. + */ + public static final long HOUR = 60 * 60 * 1000; + + private final HashMap fileEntrySettings = new HashMap(); + + /** + * Creates a new instance of the S3 directory settings with it's default values initialized. + */ + public S3DirectorySettings() { + final S3FileEntrySettings defaultSettings = new S3FileEntrySettings(); + fileEntrySettings.put(DEFAULT_FILE_ENTRY, defaultSettings); + + final S3FileEntrySettings deletableSettings = new S3FileEntrySettings(); + deletableSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, NoOpFileEntryHandler.class); + fileEntrySettings.put("deletable", deletableSettings); + fileEntrySettings.put("deleteable.new", deletableSettings); + // in case lucene fix the spelling mistake + fileEntrySettings.put("deletable.new", deletableSettings); + + final S3FileEntrySettings segmentsSettings = new S3FileEntrySettings(); + segmentsSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, ActualDeleteFileEntryHandler.class); + //todo +// segmentsSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, FetchOnOpenS3IndexInput.class); + segmentsSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, S3IndexInput.class); + segmentsSettings.setClassSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, RAMS3IndexOutput.class); + fileEntrySettings.put("segments", segmentsSettings); + fileEntrySettings.put("segments.new", segmentsSettings); + fileEntrySettings.put("doc", segmentsSettings); + + final S3FileEntrySettings dotDelSettings = new S3FileEntrySettings(); + dotDelSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, + ActualDeleteFileEntryHandler.class); + fileEntrySettings.put("del", dotDelSettings); + + final S3FileEntrySettings tmpSettings = new S3FileEntrySettings(); + tmpSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, ActualDeleteFileEntryHandler.class); + fileEntrySettings.put("tmp", dotDelSettings); + + final S3FileEntrySettings fnmSettings = new S3FileEntrySettings(); +// fnmSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, FetchOnOpenS3IndexInput.class); + fnmSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, S3IndexInput.class); + fnmSettings.setClassSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, RAMS3IndexOutput.class); + fileEntrySettings.put("fnm", fnmSettings); + } + + /** + * Registers a {@link S3FileEntrySettings} against the given name. The name can be the full name of the file, or + * it's 3 charecters suffix. + */ + public void registerFileEntrySettings(final String name, final S3FileEntrySettings fileEntrySettings) { + this.fileEntrySettings.put(name, fileEntrySettings); + } + + /** + * Returns the file entries map. Please don't change it during runtime. + */ + public Map getFileEntrySettings() { + return fileEntrySettings; + } + + /** + * Returns the file entries according to the name. If a direct match is found, it's registered + * {@link S3FileEntrySettings} is returned. If one is registered against the last 3 charecters, then it is returned. + * If none is found, the default file entry handler is returned. + */ + public S3FileEntrySettings getFileEntrySettings(final String name) { + final S3FileEntrySettings settings = getFileEntrySettingsWithoutDefault(name); + if (settings != null) { + return settings; + } + return getDefaultFileEntrySettings(); + } + + /** + * Same as {@link #getFileEntrySettings(String)}, only returns null if no match is found (instead of + * the default file entry handler settings). + */ + public S3FileEntrySettings getFileEntrySettingsWithoutDefault(final String name) { + final S3FileEntrySettings settings = fileEntrySettings.get(name.substring(name.length() - 3)); + if (settings != null) { + return settings; + } + return fileEntrySettings.get(name); + } + + /** + * Returns the default file entry handler settings. + */ + public S3FileEntrySettings getDefaultFileEntrySettings() { + logger.info("Returning default file entry settings"); + return fileEntrySettings.get(DEFAULT_FILE_ENTRY); + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java b/src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java new file mode 100644 index 00000000..32a4b31f --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java @@ -0,0 +1,218 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3; + +import com.erudika.lucene.store.s3.handler.ActualDeleteFileEntryHandler; +import com.erudika.lucene.store.s3.index.FetchOnBufferReadS3IndexInput; +import com.erudika.lucene.store.s3.index.RAMS3IndexOutput; +import com.erudika.lucene.store.s3.index.S3IndexInput; + +import java.util.Properties; + +/** + * A file entry level settings. An abstract view of any type of setting that cab be used by the actual file entry + * handler that uses it. + *

+ * Holds the {@link #FILE_ENTRY_HANDLER_TYPE} that defines the type of the + * {@link com.erudika.lucene.store.s3.handler.FileEntryHandler} that will be created and initialized with the settings. + *

+ * Default values for a new instanciated instnce are: + * {@link com.erudika.lucene.store.s3.handler.MarkDeleteFileEntryHandler} for the {@link #FILE_ENTRY_HANDLER_TYPE} + * setting, {@link com.erudika.lucene.store.s3.index.FetchOnBufferReadS3IndexInput} for the + * {@link #INDEX_INPUT_TYPE_SETTING} setting, and {@link org.apache.lucene.store.s3.index.RAMAndFileS3IndexOutput} for + * the {@link #INDEX_OUTPUT_TYPE_SETTING} setting. + * + * @author kimchy + */ +public class S3FileEntrySettings { + + /** + * The class name of the {@link org.apache.lucene.store.IndexInput}. Only applies to + * {@link org.apache.lucene.store.s3.handler.FileEntryHandler}s that use it. + */ + public static final String INDEX_INPUT_TYPE_SETTING = "indexInput.type"; + + /** + * The class name of the {@link org.apache.lucene.store.IndexOutput}. Only applies to + * {@link org.apache.lucene.store.s3.handler.FileEntryHandler}s that use it. + */ + public static final String INDEX_OUTPUT_TYPE_SETTING = "indexOutput.type"; + + /** + * The class name of the {@link org.apache.lucene.store.s3.handler.FileEntryHandler}. + */ + public static final String FILE_ENTRY_HANDLER_TYPE = "type"; + + private final Properties settings = new Properties(); + + /** + * Creates a new file entry settings, and intialize it to default values. + */ + public S3FileEntrySettings() { + setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, ActualDeleteFileEntryHandler.class); + //TODO: Fix this +// setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, FetchOnBufferReadS3IndexInput.class); + setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, S3IndexInput.class); + setClassSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, RAMS3IndexOutput.class); + } + + /** + * Returns the inner java properties. + */ + public Properties getProperties() { + return settings; + } + + /** + * Returns the value match for the given setting. null if no setting is found. + * + * @param setting The setting name + * @return The value of the setting, or null if none is found + */ + public String getSetting(final String setting) { + return settings.getProperty(setting); + } + + /** + * Returns the value that matches the given setting. If none is found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @return The value of the setting, or defaultValue if none is found. + */ + public String getSetting(final String setting, final String defaultValue) { + return settings.getProperty(setting, defaultValue); + } + + /** + * Returns the float value that matches the given setting. If none if found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @return The value of the setting, or defaultValue if none is found. + */ + public float getSettingAsFloat(final String setting, final float defaultValue) { + final String sValue = getSetting(setting); + if (sValue == null) { + return defaultValue; + } + return Float.parseFloat(sValue); + } + + /** + * Returns the int value that matches the given setting. If none if found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @return The value of the setting, or defaultValue if none is found. + */ + public int getSettingAsInt(final String setting, final int defaultValue) { + final String sValue = getSetting(setting); + if (sValue == null) { + return defaultValue; + } + return Integer.parseInt(sValue); + } + + /** + * Returns the long value that matches the given setting. If none if found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @return The value of the setting, or defaultValue if none is found. + */ + public long getSettingAsLong(final String setting, final long defaultValue) { + final String sValue = getSetting(setting); + if (sValue == null) { + return defaultValue; + } + return Long.parseLong(sValue); + } + + /** + * Returns the class value that matches the given setting. If none if found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @return The value of the setting, or defaultValue if none is found. + */ + public Class getSettingAsClass(final String setting, final Class defaultValue) throws ClassNotFoundException { + return getSettingAsClass(setting, defaultValue, Thread.currentThread().getContextClassLoader()); + } + + /** + * Returns the class value that matches the given setting. If none if found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @param classLoader The class loader to be used to load the class + * @return The value of the setting, or defaultValue if none is found. + * @throws ClassNotFoundException + */ + public Class getSettingAsClass(final String setting, final Class defaultValue, final ClassLoader classLoader) + throws ClassNotFoundException { + final String sValue = getSetting(setting); + if (sValue == null) { + return defaultValue; + } + return Class.forName(sValue, true, classLoader); + } + + /** + * Returns the boolean value that matches the given setting. If none if found, the default value is used. + * + * @param setting The setting name + * @param defaultValue The default value to be used if no setting is found + * @return The value of the setting, or defaultValue if none is found. + */ + public boolean getSettingAsBoolean(final String setting, final boolean defaultValue) { + final String sValue = getSetting(setting); + if (sValue == null) { + return defaultValue; + } + return Boolean.valueOf(sValue).booleanValue(); + } + + public S3FileEntrySettings setSetting(final String setting, final String value) { + settings.setProperty(setting, value); + return this; + } + + public S3FileEntrySettings setBooleanSetting(final String setting, final boolean value) { + setSetting(setting, String.valueOf(value)); + return this; + } + + public S3FileEntrySettings setFloatSetting(final String setting, final float value) { + setSetting(setting, String.valueOf(value)); + return this; + } + + public S3FileEntrySettings setIntSetting(final String setting, final int value) { + setSetting(setting, String.valueOf(value)); + return this; + } + + public S3FileEntrySettings setLongSetting(final String setting, final long value) { + setSetting(setting, String.valueOf(value)); + return this; + } + + public S3FileEntrySettings setClassSetting(final String setting, final Class clazz) { + setSetting(setting, clazz.getName()); + return this; + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java b/src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java new file mode 100644 index 00000000..4a35d6b1 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java @@ -0,0 +1,26 @@ +package com.erudika.lucene.store.s3; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.util.HashMap; + +public class S3FileSystemStore { + private static FileSystem fileSystem; + private static FileSystem fileSystem2; + + public static FileSystem getS3FileSystem() throws IOException { + if (fileSystem == null) { + fileSystem = FileSystems.newFileSystem(URI.create("s3://lucene-test"), new HashMap()); + } + return fileSystem; + } + + public static FileSystem getTaxonomyS3FileSystem() throws IOException { + if (fileSystem2 == null) { + fileSystem2 = FileSystems.newFileSystem(URI.create("s3://avinash-test-1"), new HashMap()); + } + return fileSystem2; + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java b/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java new file mode 100644 index 00000000..61d62aed --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java @@ -0,0 +1,36 @@ +package com.erudika.lucene.store.s3; + +import com.amazonaws.ClientConfiguration; +import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +public class S3SingletonClient { + private static S3Client s3Client; + + private S3SingletonClient(){ + + } + + public static S3Client getS3Client(){ + if(s3Client == null){ + + ClientConfiguration clientConfiguration = new ClientConfiguration() + .withMaxErrorRetry(10) + .withMaxConnections(1000); + + s3Client = S3Client.builder() + .credentialsProvider(() -> new AwsSessionCredentials + .Builder() + .accessKeyId("ASIA2E3GK2GH3NV2SO6E") //This is from E2E account + .secretAccessKey("FxjTfKJY6QfDyo3iYaG7oKg4hx0nqqRbJ53rhdMy") + .sessionToken("IQoJb3JpZ2luX2VjEA0aCXVzLXdlc3QtMiJHMEUCIQDEq/6ShmSHnXVPjINNeg1Gbfv1sic9rqF/xtQSe+nTmwIgRcH7qqqfJ79k28NMGnG+sG89KG80t1xWQENUT2QhzhMqoAMItv//////////ARAAGgw2OTc2MDk5MzMxOTkiDALDMrROyEiDFN4QBCr0ApoQMhYaD/zLX2NO4jF+Y3wXQy5Yr6IERyfHN1nOyeS69forL62SgVNaaKQlY7IjUyTlQQdfOxjCYNMIzOnzZnRXeQwqoB0YFl2ot9e80n8o9/vybPOFewtyI/VfBp4kHcqBKlL+6ZSvdHcrv5sNr87Hao9ztf7vDO8s8TGIvm74vbz901OaQLx77Jmt7n0j26CxWnBROIx9JqRQN5ZJQEcWpHD2bKnt4JqwIDfPH2EswcaAjNQut61hqUgQLqjoBrXBDVl3hztHJByQ72FDMTNq6VhkIZwrbTOGPpfFi+fr6xCCpmb+Nr1GSOjB3OwOUOS52No9Tz6vBJCIes3+Bh7J4o/GX1TUp5YewmIrKGCgIiWaGl+/Rl88KMzU9V+p/lzhNaUnT3OL91YDppfQgtqBB1nolfRIw4JEtObySweXpuf5zi514ygFmYp5X+pM7D51Rdc5cUAO0SXOjhn6Ig+wLWeUU+smsi96J7B6ReeSO+wmZTDHmumzBjqmAUrMHymm0/LKKQe579EaAo0hm3eSORXoH1BFFQmBX5LmaaHrAagczQqheXG+JkSR3AWXsenAZ3GpvcxKDcobFmTDi0DH6skyWZrXiy+TnTrGrTVlXlCaNuNp6uMuuhpHZF/eeczjj5nMgBtja9A8LWecSUMuS60Mz7pmT/C5CDM67+buEeu8YwqWeEmR1uZRNya8CTVyeb1X94XsVNlok1fAU/U1/D4=") + .build() + ) + .region(Region.US_WEST_2) + .build(); + } + return s3Client; + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java b/src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java new file mode 100644 index 00000000..4beb7e15 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java @@ -0,0 +1,142 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * A nestable checked S3 exception. + * + * @author kimchy + */ +public class S3StoreException extends IOException { + + private static final long serialVersionUID = 6238846660780283933L; + + /** + * Root cause of this nested exception + */ + private Throwable cause; + + /** + * Construct a S3StoreException with the specified detail message. + * + * @param msg the detail message + */ + public S3StoreException(final String msg) { + super(msg); + } + + /** + * Construct a S3StoreException with the specified detail message and nested exception. + * + * @param msg the detail message + * @param ex the nested exception + */ + public S3StoreException(final String msg, final Throwable ex) { + super(msg); + cause = ex; + } + + /** + * Return the nested cause, or null if none. + */ + @Override + public Throwable getCause() { + // Even if you cannot set the cause of this exception other than through + // the constructor, we check for the cause being "this" here, as the + // cause + // could still be set to "this" via reflection: for example, by a + // remoting + // deserializer like Hessian's. + return cause == this ? null : cause; + } + + /** + * Return the detail message, including the message from the nested exception if there is one. + */ + @Override + public String getMessage() { + if (getCause() == null) { + return super.getMessage(); + } else { + return super.getMessage() + "; nested exception is " + getCause().getClass().getName() + ": " + + getCause().getMessage(); + } + } + + /** + * Print the composite message and the embedded stack trace to the specified stream. + * + * @param ps the print stream + */ + @Override + public void printStackTrace(final PrintStream ps) { + if (getCause() == null) { + super.printStackTrace(ps); + } else { + ps.println(this); + getCause().printStackTrace(ps); + } + } + + /** + * Print the composite message and the embedded stack trace to the specified print writer. + * + * @param pw the print writer + */ + @Override + public void printStackTrace(final PrintWriter pw) { + if (getCause() == null) { + super.printStackTrace(pw); + } else { + pw.println(this); + getCause().printStackTrace(pw); + } + } + + /** + * Check whether this exception contains an exception of the given class: either it is of the given class itself or + * it contains a nested cause of the given class. + *

+ * Currently just traverses S3StoreException causes. Will use the JDK 1.4 exception cause mechanism once requires + * JDK 1.4. + * + * @param exClass the exception class to look for + */ + public boolean contains(final Class exClass) { + if (exClass == null) { + return false; + } + Throwable ex = this; + while (ex != null) { + if (exClass.isInstance(ex)) { + return true; + } + if (ex instanceof S3StoreException) { + // Cast is necessary on JDK 1.3, where Throwable does not + // provide a "getCause" method itself. + ex = ex.getCause(); + } else { + ex = null; + } + } + return false; + } + +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java new file mode 100644 index 00000000..ea13ab9c --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java @@ -0,0 +1,165 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.handler; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; +import com.erudika.lucene.store.s3.S3StoreException; +import com.erudika.lucene.store.s3.index.S3IndexConfigurable; +import org.apache.lucene.store.IndexInput; +import org.apache.lucene.store.IndexOutput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; + +import java.io.IOException; + +/** + * A base file entry handler that supports most of the file entry base operations. + *

+ * Supports the creation of configurable IndexInput and IndexOutput, base on the + * {@link S3FileEntrySettings#INDEX_INPUT_TYPE_SETTING} and {@link S3FileEntrySettings#INDEX_OUTPUT_TYPE_SETTING}. + *

+ * Does not implement the deletion of files. + * + * @author kimchy + */ +public abstract class AbstractFileEntryHandler implements FileEntryHandler { + + private static final Logger logger = LoggerFactory.getLogger(AbstractFileEntryHandler.class); + + protected S3Directory s3Directory; + + protected String bucket; + + @Override + public void configure(final S3Directory s3Directory) { + this.s3Directory = s3Directory; + bucket = s3Directory.getBucket(); + } + + @Override + public boolean fileExists(final String name) throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("fileExists({})", name); + } + s3Directory.getS3().headObject(b -> b.bucket(bucket).key(name)); + return true; + } catch (AwsServiceException | SdkClientException e) { + return false; + } + } + + @Override + public long fileModified(final String name) throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("fileModified({})", name); + } + ResponseInputStream res = s3Directory.getS3().getObject(b -> b.bucket(bucket).key(name)); + return res.response().lastModified().toEpochMilli(); + } catch (Exception e) { + return 0L; + } + } + + @Override + public void touchFile(final String name) throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("touchFile({})", name); + } + ResponseInputStream res = s3Directory.getS3().getObject(b -> b.bucket(bucket).key(name)); + + s3Directory.getS3().putObject(b -> b.bucket(bucket).key(name), + RequestBody.fromInputStream(res, res.response().contentLength())); + } catch (Exception e) { + logger.error(null, e); + } + } + + @Override + public void renameFile(final String from, final String to) throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("renameFile({}, {})", from, to); + } + s3Directory.getS3().copyObject(b -> b.sourceBucket(bucket).sourceKey(from).destinationBucket(bucket).destinationKey(to)); + s3Directory.getFileSizes().put(to, s3Directory.getFileSizes().remove(from)); + deleteFile(from); + } catch (Exception e) { + logger.error(null, e); + } + } + + @Override + public long fileLength(final String name) throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("fileLength({})", name); + } + return s3Directory.getFileSizes().computeIfAbsent(name, n -> + s3Directory.getS3().getObject(b -> b.bucket(bucket).key(name)).response().contentLength() + ); + } catch (Exception e) { + logger.error(null, e); + return 0L; + } + } + + @Override + public IndexInput openInput(final String name) throws IOException { + IndexInput indexInput; + logger.info("openInput called with : {}", name); + final S3FileEntrySettings settings = s3Directory.getSettings().getFileEntrySettings(name); + try { + final Class inputClass = settings.getSettingAsClass(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, null); + indexInput = (IndexInput) inputClass.getConstructor().newInstance(); + } catch (final Exception e) { + throw new S3StoreException("Failed to create indexInput instance [" + + settings.getSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING) + "]", e); + } + ((S3IndexConfigurable) indexInput).configure(name, s3Directory, settings); + return indexInput; + } + + @Override + public IndexOutput createOutput(final String name) throws IOException { + IndexOutput indexOutput; + logger.info("createOutput called with : "+name); + final S3FileEntrySettings settings = s3Directory.getSettings().getFileEntrySettings(name); + try { + final Class inputClass = settings.getSettingAsClass(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, + null); + indexOutput = (IndexOutput) inputClass.getConstructor(String.class).newInstance(name); + } catch (final Exception e) { + throw new S3StoreException("Failed to create indexOutput instance [" + + settings.getSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING) + "]", e); + } + ((S3IndexConfigurable) indexOutput).configure(name, s3Directory, settings); + return indexOutput; + } + + @Override + public void close() throws IOException { + // do nothing + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java new file mode 100644 index 00000000..77129e19 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.handler; + +import java.io.IOException; + +/** + * Removes file entries from the database by deleting the relevant rows from the database. + * + * @author kimchy + */ +public class ActualDeleteFileEntryHandler extends AbstractFileEntryHandler { + + @Override + public void deleteFile(final String name) throws IOException { + s3Directory.forceDeleteFile(name); + s3Directory.getFileSizes().remove(name); + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java new file mode 100644 index 00000000..543eda7b --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java @@ -0,0 +1,116 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.handler; + +import com.erudika.lucene.store.s3.S3Directory; +import org.apache.lucene.store.IndexInput; +import org.apache.lucene.store.IndexOutput; + +import java.io.IOException; + +/** + * A file entry handler acts as a delegate to the {@link S3Directory} for all "file" level operations. Allows the + * {@link S3Directory} to be abstracted from any specific implementation details regarding a file entry, and have + * several different file entries for different files or files groups. + * + * @author kimchy + * @see com.erudika.lucene.store.s3.S3DirectorySettings#registerFileEntrySettings(String, + * com.erudika.lucene.store.s3.S3FileEntrySettings) + */ +public interface FileEntryHandler { + + /** + * Called after the entry is created (during the {@link S3Directory} initialization process. + */ + void configure(S3Directory s3Directory); + + /** + * Checks if the file exists for the given file name. + * + * @param name The name of the file + * @return true of the file exists, false if it does not. + * @throws IOException + */ + boolean fileExists(final String name) throws IOException; + + /** + * Returns the last modified date of the file. + * + * @param name The name of the file + * @return The last modified date in millis. + * @throws IOException + */ + long fileModified(final String name) throws IOException; + + /** + * Updates the last modified date of the file to the current time. + * + * @param name The name of the file + * @throws IOException + */ + void touchFile(final String name) throws IOException; + + /** + * Deletes the given file name. + * + * @param name The name of the file to delete + * @throws IOException + */ + void deleteFile(final String name) throws IOException; + + /** + * Renames the file entry from "from" to "to". The from entry is the one that maps to the actual file entry handler. + * + * @param from The name to rename from + * @param to The name to rename to + * @throws IOException + */ + void renameFile(final String from, final String to) throws IOException; + + /** + * Returns the length of the file (in bytes). + * + * @param name The name of the file + * @return The length of the file (in bytes) + * @throws IOException + */ + long fileLength(final String name) throws IOException; + + /** + * Opens an IndexInput in order to read the file contents. + * + * @param name The name of the file + * @return An IndexInput in order to read the file contents. + * @throws IOException + */ + IndexInput openInput(String name) throws IOException; + + /** + * Creates an IndexOutput in order to write the file contents. + * + * @param name The name of the file + * @return An IndexOutput to write the file contents + * @throws IOException + */ + IndexOutput createOutput(String name) throws IOException; + + /** + * Closes the file entry handler. + * + * @throws IOException + */ + void close() throws IOException; +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java new file mode 100644 index 00000000..fa63727a --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java @@ -0,0 +1,172 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.handler; + +import com.erudika.lucene.store.s3.S3Directory; +import org.apache.lucene.store.IndexInput; +import org.apache.lucene.store.IndexOutput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * A No Operation file entry handler. Performs no actual dirty operations, and returns empty data for read operations. + * + * @author kimchy + */ +public class NoOpFileEntryHandler implements FileEntryHandler { + + private static final Logger logger = LoggerFactory.getLogger(NoOpFileEntryHandler.class); + + private static class NoOpIndexInput extends IndexInput { + + protected NoOpIndexInput() { + super("NoOpIndexInput"); + } + + @Override + public byte readByte() throws IOException { + return 0; + } + + @Override + public void readBytes(final byte[] b, final int offset, final int len) throws IOException { + + } + + @Override + public void close() throws IOException { + + } + + @Override + public long getFilePointer() { + return 0; + } + + @Override + public void seek(final long pos) throws IOException { + } + + @Override + public long length() { + return 0; + } + + @Override + public IndexInput slice(final String sliceDescription, final long offset, final long length) + throws IOException { + // TODO Auto-generated method stub + logger.debug("NoOpFileEntryHandler.NoOpIndexInput.slice()"); + return null; + } + } + + @SuppressWarnings("unused") + private static class NoOpIndexOutput extends IndexOutput { + + protected NoOpIndexOutput() { + super("NoOpIndexOutput", "NoOpIndexOutput"); + } + + @Override + public void writeByte(final byte b) throws IOException { + + } + + @Override + public void writeBytes(final byte[] b, final int offset, final int length) throws IOException { + + } + + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + } + + @Override + public long getFilePointer() { + return 0; + } + + public void seek(final long pos) throws IOException { + } + + public long length() throws IOException { + return 0; + } + + @Override + public long getChecksum() throws IOException { + // TODO Auto-generated method stub + logger.debug("NoOpFileEntryHandler.NoOpIndexOutput.slice()"); + return 0; + } + } + + private static IndexInput indexInput = new NoOpIndexInput(); + + private static IndexOutput indexOutput = new NoOpIndexOutput(); + + @Override + public void configure(final S3Directory s3Directory) { + } + + @Override + public boolean fileExists(final String name) throws IOException { + return false; + } + + @Override + public long fileModified(final String name) throws IOException { + return 0; + } + + @Override + public void touchFile(final String name) throws IOException { + } + + @Override + public void deleteFile(final String name) throws IOException { + } + + @Override + public void renameFile(final String from, final String to) throws IOException { + } + + @Override + public long fileLength(final String name) throws IOException { + return 0; + } + + @Override + public IndexInput openInput(final String name) throws IOException { + return indexInput; + } + + @Override + public IndexOutput createOutput(final String name) throws IOException { + return indexOutput; + } + + @Override + public void close() throws IOException { + // do notihng + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java new file mode 100644 index 00000000..927a29b9 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java @@ -0,0 +1,77 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.sync.RequestBody; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author kimchy + */ +public abstract class AbstractS3IndexOutput extends S3BufferedIndexOutput { + + private static final Logger logger = LoggerFactory.getLogger(AbstractS3IndexOutput.class); + + protected String name; + + protected S3Directory s3Directory; + + protected AbstractS3IndexOutput(final String resourceDescription) { + super(resourceDescription); + } + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + super.configure(name, s3Directory, settings); + this.name = name; + this.s3Directory = s3Directory; + } + + @Override + public void close() throws IOException { + super.close(); + doBeforeClose(); + try { + if (logger.isDebugEnabled()) { + logger.info("close({})", name); + } + final InputStream is = openInputStream(); + s3Directory.getFileSizes().put(name, length()); + s3Directory.getS3().putObject(b -> b.bucket(s3Directory.getBucket()).key(name), + RequestBody.fromInputStream(is, length())); + } catch (Exception e) { + logger.error(null, e); + } + doAfterClose(); + } + + protected abstract InputStream openInputStream() throws IOException; + + protected void doAfterClose() throws IOException { + + } + + protected void doBeforeClose() throws IOException { + + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java new file mode 100644 index 00000000..32726c0b --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java @@ -0,0 +1,204 @@ +package com.erudika.lucene.store.s3.index; + +import org.apache.lucene.store.IndexInput; + +import java.io.IOException; + +/** + * A simple base class that performs index input memory based buffering. Allows the buffer size to be configurable. + * + * @author kimchy + */ +// NEED TO BE MONITORED AGAINST LUCENE (EXATCLY THE SAME) +public abstract class ConfigurableBufferedIndexInput extends IndexInput { + + protected ConfigurableBufferedIndexInput(final String resourceDescription, final int bufferSize) { + super(resourceDescription); + checkBufferSize(bufferSize); + this.bufferSize = bufferSize; + } + + /** + * Default buffer size + */ + public static final int BUFFER_SIZE = 1024; + + protected int bufferSize = BUFFER_SIZE; + + protected byte[] buffer; + + protected long bufferStart = 0; // position in file of buffer + protected int bufferLength = 0; // end of valid bytes + protected int bufferPosition = 0; // next byte to read + + @Override + public byte readByte() throws IOException { + if (bufferPosition >= bufferLength) { + refill(); + } + return buffer[bufferPosition++]; + } + + /** + * Change the buffer size used by this IndexInput + */ + public void setBufferSize(final int newSize) { + assert buffer == null || bufferSize == buffer.length; + if (newSize != bufferSize) { + checkBufferSize(newSize); + bufferSize = newSize; + if (buffer != null) { + // Resize the existing buffer and carefully save as + // many bytes as possible starting from the current + // bufferPosition + final byte[] newBuffer = new byte[newSize]; + final int leftInBuffer = bufferLength - bufferPosition; + final int numToCopy; + if (leftInBuffer > newSize) { + numToCopy = newSize; + } else { + numToCopy = leftInBuffer; + } + System.arraycopy(buffer, bufferPosition, newBuffer, 0, numToCopy); + bufferStart += bufferPosition; + bufferPosition = 0; + bufferLength = numToCopy; + buffer = newBuffer; + } + } + } + + /** + * Returns buffer size. @see #setBufferSize + */ + public int getBufferSize() { + return bufferSize; + } + + private void checkBufferSize(final int bufferSize) { + if (bufferSize <= 0) { + throw new IllegalArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")"); + } + } + + @Override + public void readBytes(final byte[] b, int offset, int len) throws IOException { + if (len <= bufferLength - bufferPosition) { + // the buffer contains enough data to satistfy this request + if (len > 0) { + System.arraycopy(buffer, bufferPosition, b, offset, len); + } + bufferPosition += len; + } else { + // the buffer does not have enough data. First serve all we've got. + final int available = bufferLength - bufferPosition; + if (available > 0) { + System.arraycopy(buffer, bufferPosition, b, offset, available); + offset += available; + len -= available; + bufferPosition += available; + } + // and now, read the remaining 'len' bytes: + if (len < bufferSize) { + // If the amount left to read is small enough, do it in the + // usual + // buffered way: fill the buffer and copy from it: + refill(); + if (bufferLength < len) { + // Throw an exception when refill() could not read len + // bytes: + System.arraycopy(buffer, 0, b, offset, bufferLength); + throw new IOException("read past EOF"); + } else { + System.arraycopy(buffer, 0, b, offset, len); + bufferPosition = len; + } + } else { + // The amount left to read is larger than the buffer - there's + // no + // performance reason not to read it all at once. Note that + // unlike + // the previous code of this function, there is no need to do a + // seek + // here, because there's no need to reread what we had in the + // buffer. + final long after = bufferStart + bufferPosition + len; + if (after > length()) { + throw new IOException("read past EOF"); + } + readInternal(b, offset, len); + bufferStart = after; + bufferPosition = 0; + bufferLength = 0; // trigger refill() on read + } + } + } + + protected void refill() throws IOException { + final long start = bufferStart + bufferPosition; + long end = start + bufferSize; + if (end > length()) { + end = length(); + } + bufferLength = (int) (end - start); + if (bufferLength <= 0) { + throw new IOException("read past EOF"); + } + + if (buffer == null) { + buffer = new byte[bufferSize]; // allocate buffer lazily + seekInternal(bufferStart); + } + readInternal(buffer, 0, bufferLength); + + bufferStart = start; + bufferPosition = 0; + } + + /** + * Expert: implements buffer refill. Reads bytes from the current position in the input. + * + * @param b the array to read bytes into + * @param offset the offset in the array to start storing bytes + * @param length the number of bytes to read + */ + protected abstract void readInternal(byte[] b, int offset, int length) throws IOException; + + @Override + public long getFilePointer() { + return bufferStart + bufferPosition; + } + + @Override + public void seek(final long pos) throws IOException { + if (pos >= bufferStart && pos < bufferStart + bufferLength) { + bufferPosition = (int) (pos - bufferStart); // seek within buffer + } else { + bufferStart = pos; + bufferPosition = 0; + bufferLength = 0; // trigger refill() on read() + seekInternal(pos); + } + } + + /** + * Expert: implements seek. Sets current position in this file, where the next {@link #readInternal(byte[],int,int)} + * will occur. + * + * @see #readInternal(byte[],int,int) + */ + protected abstract void seekInternal(long pos) throws IOException; + + @Override + public IndexInput clone() { + final ConfigurableBufferedIndexInput clone = (ConfigurableBufferedIndexInput) super.clone(); + + clone.buffer = null; + clone.bufferLength = 0; + clone.bufferPosition = 0; + clone.bufferStart = getFilePointer(); + + return clone; + } + +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java new file mode 100644 index 00000000..030d2a77 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java @@ -0,0 +1,155 @@ +package com.erudika.lucene.store.s3.index; + +import org.apache.lucene.store.IndexOutput; + +import java.io.IOException; + +/** + * A simple base class that performs index output memory based buffering. The buffer size if configurable. + * + * @author kimchy + */ +// NEED TO BE MONITORED AGAINST LUCENE +public abstract class ConfigurableBufferedIndexOutput extends IndexOutput { + + public static final int DEFAULT_BUFFER_SIZE = 16384; + + private byte[] buffer; + private long bufferStart = 0; // position in file of buffer + private int bufferPosition = 0; // position in buffer + + protected int bufferSize = DEFAULT_BUFFER_SIZE; + + protected ConfigurableBufferedIndexOutput(final String resourceDescription) { + super(resourceDescription, "ConfigurableBufferedIndexOutput"); + } + + protected void initBuffer(final int bufferSize) { + this.bufferSize = bufferSize; + buffer = new byte[bufferSize]; + } + + /** + * Writes a single byte. + * + * @see org.apache.lucene.store.IndexInput#readByte() + */ + @Override + public void writeByte(final byte b) throws IOException { + if (bufferPosition >= bufferSize) { + flush(); + } + buffer[bufferPosition++] = b; + } + + /** + * Writes an array of bytes. + * + * @param b the bytes to write + * @param length the number of bytes to write + * @see org.apache.lucene.store.IndexInput#readBytes(byte[],int,int) + */ + @Override + public void writeBytes(final byte[] b, final int offset, final int length) throws IOException { + int bytesLeft = bufferSize - bufferPosition; + // is there enough space in the buffer? + if (bytesLeft >= length) { + // we add the data to the end of the buffer + System.arraycopy(b, offset, buffer, bufferPosition, length); + bufferPosition += length; + // if the buffer is full, flush it + if (bufferSize - bufferPosition == 0) { + flush(); + } + } else { + // is data larger then buffer? + if (length > bufferSize) { + // we flush the buffer + if (bufferPosition > 0) { + flush(); + } + // and write data at once + flushBuffer(b, offset, length); + bufferStart += length; + } else { + // we fill/flush the buffer (until the input is written) + int pos = 0; // position in the input data + int pieceLength; + while (pos < length) { + pieceLength = length - pos < bytesLeft ? length - pos : bytesLeft; + System.arraycopy(b, pos + offset, buffer, bufferPosition, pieceLength); + pos += pieceLength; + bufferPosition += pieceLength; + // if the buffer is full, flush it + bytesLeft = bufferSize - bufferPosition; + if (bytesLeft == 0) { + flush(); + bytesLeft = bufferSize; + } + } + } + } + } + + /** + * Forces any buffered output to be written. + */ + public void flush() throws IOException { + flushBuffer(buffer, bufferPosition); + bufferStart += bufferPosition; + bufferPosition = 0; + } + + /** + * Expert: implements buffer write. Writes bytes at the current position in the output. + * + * @param b the bytes to write + * @param len the number of bytes to write + */ + private void flushBuffer(final byte[] b, final int len) throws IOException { + flushBuffer(b, 0, len); + } + + /** + * Expert: implements buffer write. Writes bytes at the current position in the output. + * + * @param b the bytes to write + * @param offset the offset in the byte array + * @param len the number of bytes to write + */ + protected abstract void flushBuffer(byte[] b, int offset, int len) throws IOException; + + /** + * Closes this stream to further operations. + */ + @Override + public void close() throws IOException { + flush(); + } + + /** + * Returns the current position in this file, where the next write will occur. + * + * @see #seek(long) + */ + @Override + public long getFilePointer() { + return bufferStart + bufferPosition; + } + + /** + * Sets current position in this file, where the next write will occur. + * + * @see #getFilePointer() + */ + public void seek(final long pos) throws IOException { + flush(); + bufferStart = pos; + } + + /** + * The number of bytes in the file. + */ + public abstract long length() throws IOException; + +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java new file mode 100644 index 00000000..c9f48b73 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java @@ -0,0 +1,244 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; +import org.apache.lucene.store.BufferedIndexInput; +import org.apache.lucene.store.IndexInput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.ResponseTransformer; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * An IndexInput implementation, that for every buffer refill will go and fetch the data from the database. + * + * @author kimchy + */ +public class FetchOnBufferReadS3IndexInput extends S3BufferedIndexInput { + + private static final Logger logger = LoggerFactory.getLogger(FetchOnBufferReadS3IndexInput.class); + + private String name; + + // lazy intialize the length + private long totalLength = -1; + + private long position = 0; + + private S3Directory s3Directory; + + public FetchOnBufferReadS3IndexInput() { + super("FetchOnBufferReadS3IndexInput"); + } + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + super.configure(name, s3Directory, settings); + this.s3Directory = s3Directory; + this.name = name; + } + + // Overriding refill here since we can execute a single query to get both + // the length and the buffer data + // resulted in not the nicest OO design, where the buffer information is + // protected in the S3BufferedIndexInput + // class + // and code duplication between this method and S3BufferedIndexInput. + // Performance is much better this way! + @Override + protected void refill() throws IOException { + if (logger.isDebugEnabled()) { + logger.info("refill({})", name); + } + ResponseInputStream res = s3Directory.getS3(). + getObject(b -> b.bucket(s3Directory.getBucket()).key(name)); + + synchronized (this) { + if (totalLength == -1) { + totalLength = res.response().contentLength(); + } + } + + final long start = bufferStart + bufferPosition; + long end = start + bufferSize; + if (end > length()) { + end = length(); + } + bufferLength = (int) (end - start); + if (bufferLength <= 0) { + throw new IOException("read past EOF"); + } + + if (buffer == null) { + buffer = new byte[bufferSize]; // allocate buffer + // lazily + seekInternal(bufferStart); + } + // START replace read internal + readInternal(res, buffer, 0, bufferLength); + + bufferStart = start; + bufferPosition = 0; + } + +// @Override +// protected void readInternal(byte[] b, int offset, int length) throws IOException { +// GetObjectRequest getObjectRequest = GetObjectRequest.builder() +// .bucket(s3Directory.getBucket()) +// .key(name) +// .range("bytes=" + offset + "-" + (offset + length - 1)) +// .build(); +// +// try { +// ResponseBytes getObjectResponse = s3Directory.getS3().getObject(getObjectRequest, ResponseTransformer.toBytes()); +// byte[] objectBytes = getObjectResponse.asByteArray(); +// System.arraycopy(objectBytes, 0, b, 0, objectBytes.length); +// synchronized (this) { +// if (totalLength == -1) { +// totalLength = getObjectResponse.response().contentLength(); +// } +// } +// } catch (Exception e) { +// throw new IOException("Unable to read from S3 object", e); +// } +// } + + @Override + protected synchronized void readInternal(final byte[] b, final int offset, final int length) throws IOException { + if (logger.isDebugEnabled()) { + logger.info("readInternal({})", name); + } + ResponseInputStream res = s3Directory.getS3(). + getObject(bd -> bd.bucket(s3Directory.getBucket()).key(name)); + + if (buffer == null) { + buffer = new byte[bufferSize]; + seekInternal(bufferStart); + } +// readInternal(res, buffer, 0, bufferLength); + readInternal(res, b, 0, bufferLength); + + if (totalLength == -1) { + totalLength = res.response().contentLength(); + } + } + + private synchronized void readInternal(final ResponseInputStream res, + final byte[] b, final int offset, final int length) throws IOException { + final long curPos = getFilePointer(); + if (curPos != position) { + position = curPos; + } + res.skip(position); + res.read(b, offset, length); + position += length; + } + + @Override + protected void seekInternal(final long pos) throws IOException { + position = pos; + } + + @Override + public void close() throws IOException { + } + + @Override + public synchronized long length() { + if (totalLength == -1) { + try { + totalLength = s3Directory.fileLength(name); + } catch (final IOException e) { + // do nothing here for now, much better for performance + } + } + return totalLength; + } + + @Override + public IndexInput slice(final String sliceDescription, final long offset, final long length) throws IOException { + // TODO Auto-generated method stub + logger.debug("FetchOnBufferReadS3IndexInput.slice()"); + + return new SlicedIndexInput(sliceDescription, this, offset, length); + } + + /** + * Implementation of an IndexInput that reads from a portion of a file. + */ + private static final class SlicedIndexInput extends BufferedIndexInput { + + IndexInput base; + long fileOffset; + long length; + + SlicedIndexInput(final String sliceDescription, final IndexInput base, final long offset, final long length) { + super(sliceDescription == null ? base.toString() : base.toString() + " [slice=" + sliceDescription + "]", + BufferedIndexInput.BUFFER_SIZE); + if (offset < 0 || length < 0 || offset + length > base.length()) { + throw new IllegalArgumentException("slice() " + sliceDescription + " out of bounds: " + base); + } + this.base = base.clone(); + fileOffset = offset; + this.length = length; + } + + @Override + public SlicedIndexInput clone() { + final SlicedIndexInput clone = (SlicedIndexInput) super.clone(); + clone.base = base.clone(); + clone.fileOffset = fileOffset; + clone.length = length; + return clone; + } + + @Override + protected void readInternal(ByteBuffer bb) throws IOException { + long start = getFilePointer(); + if (start + bb.remaining() > length) { + throw new EOFException("read past EOF: " + this); + } + base.seek(fileOffset + start); + base.readBytes(bb.array(), bb.position(), bb.remaining()); + bb.position(bb.position() + bb.remaining()); + } + + @Override + protected void seekInternal(final long pos) { + } + + @Override + public void close() throws IOException { + base.close(); + } + + @Override + public long length() { + return length; + } + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java new file mode 100644 index 00000000..36486f09 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java @@ -0,0 +1,109 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; +import org.apache.lucene.store.IndexInput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; + +import java.io.IOException; + +/** + * An IndexInput implementation that will read all the relevant data from the S3 when created, and will + * cache it until it is closed. + *

+ * Used for small file entries in the database like the segments file. + * + * @author kimchy + */ +public class FetchOnOpenS3IndexInput extends IndexInput implements S3IndexConfigurable { + + private static final Logger logger = LoggerFactory.getLogger(FetchOnOpenS3IndexInput.class); + + // There is no synchronizaiton since Lucene RAMDirecoty performs no + // synchronizations. + // Need to get to the bottom of it. + public FetchOnOpenS3IndexInput() { + super("FetchOnOpenS3IndexInput"); + } + + private long length; + + private int position = 0; + + private byte[] data; + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + if (logger.isDebugEnabled()) { + logger.info("configure({})", name); + } + ResponseInputStream res = s3Directory.getS3(). + getObject(b -> b.bucket(s3Directory.getBucket()).key(name)); + + synchronized (this) { + length = res.response().contentLength(); + } + data = new byte[(int) length]; + res.read(data); + if (data.length != length) { + throw new IOException("read past EOF"); + } + } + + @Override + public byte readByte() throws IOException { + return data[position++]; + } + + @Override + public void readBytes(final byte[] b, final int offset, final int len) throws IOException { + System.arraycopy(data, position, b, offset, len); + position += len; + } + + @Override + public void close() throws IOException { + + } + + @Override + public long getFilePointer() { + return position; + } + + @Override + public void seek(final long pos) throws IOException { + position = (int) pos; + } + + @Override + public long length() { + return length; + } + + @Override + public IndexInput slice(final String sliceDescription, final long offset, final long length) throws IOException { + // TODO Auto-generated method stub + logger.debug("FetchOnOpenS3IndexInput.slice()"); + return null; + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java new file mode 100644 index 00000000..27b14184 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java @@ -0,0 +1,261 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; +import org.apache.lucene.store.BufferedChecksum; +import org.apache.lucene.store.IndexOutput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.zip.CRC32; +import java.util.zip.Checksum; + +/** + * An IndexOutput implementation that initially writes the data to a memory buffer. Once it exceeds the + * configured threshold ( {@link #INDEX_OUTPUT_THRESHOLD_SETTING}, will start working with a temporary file, releasing + * the previous buffer. + * + * @author kimchy + */ +public class RAMS3IndexOutput extends IndexOutput implements S3IndexConfigurable { + + + private RAMIndexOutput ramIndexOutput; + private final Checksum crc; + + public RAMS3IndexOutput(String name) { + super("RAMAndFileS3IndexOutput", name); + crc = new BufferedChecksum(new CRC32()); + } + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + ramIndexOutput = new RAMIndexOutput(); + ramIndexOutput.configure(name, s3Directory, settings); + } + + @Override + public void writeByte(final byte b) throws IOException { + ramIndexOutput.writeByte(b); + crc.update(b); + } + + @Override + public void writeBytes(final byte[] b, final int offset, final int length) throws IOException { + ramIndexOutput.writeBytes(b, offset, length); + crc.update(b, offset, length); + } + + @Override + public void close() throws IOException { + ramIndexOutput.close(); + } + + @Override + public long getFilePointer() { + return ramIndexOutput.getFilePointer(); + } + + @Override + public long getChecksum() throws IOException { + return crc.getValue(); + } + + /** + * An IndexOutput implemenation that stores all the data written to it in memory, and flushes it to the + * database when the output is closed. + *

+ * Useful for small file entries like the segment file. + * + * @author kimchy + */ + class RAMIndexOutput extends AbstractS3IndexOutput { + + private final Logger logger = LoggerFactory.getLogger(RAMS3IndexOutput.class); + + public RAMIndexOutput() { + super("RAMS3IndexOutput"); + } + + private class RAMFile { + + ArrayList buffers = new ArrayList(); + long length; + } + + private class RAMInputStream extends InputStream { + + private long position; + + private int buffer; + + private int bufferPos; + + private long markedPosition; + + @Override + public synchronized void reset() throws IOException { + position = markedPosition; + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public void mark(final int readlimit) { + markedPosition = position; + } + + @Override + public int read(final byte[] dest, int destOffset, final int len) throws IOException { + if (position == file.length) { + return -1; + } + int remainder = (int) (position + len > file.length ? file.length - position : len); + final long oldPosition = position; + while (remainder != 0) { + if (bufferPos == bufferSize) { + bufferPos = 0; + buffer++; + } + int bytesToCopy = bufferSize - bufferPos; + bytesToCopy = bytesToCopy >= remainder ? remainder : bytesToCopy; + final byte[] buf = file.buffers.get(buffer); + System.arraycopy(buf, bufferPos, dest, destOffset, bytesToCopy); + destOffset += bytesToCopy; + position += bytesToCopy; + bufferPos += bytesToCopy; + remainder -= bytesToCopy; + } + return (int) (position - oldPosition); + } + + @Override + public int read() throws IOException { + if (position == file.length) { + return -1; + } + if (bufferPos == bufferSize) { + bufferPos = 0; + buffer++; + } + final byte[] buf = file.buffers.get(buffer); + position++; + return buf[bufferPos++] & 0xFF; + } + } + + private RAMFile file; + + private int pointer = 0; + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + super.configure(name, s3Directory, settings); + file = new RAMFile(); + this.name = name; + this.s3Directory = s3Directory; + } + + @Override + public void flushBuffer(final byte[] src, final int offset, final int len) { + byte[] buffer; + int bufferPos = offset; + while (bufferPos != len) { + final int bufferNumber = pointer / bufferSize; + final int bufferOffset = pointer % bufferSize; + final int bytesInBuffer = bufferSize - bufferOffset; + final int remainInSrcBuffer = len - bufferPos; + final int bytesToCopy = bytesInBuffer >= remainInSrcBuffer ? remainInSrcBuffer : bytesInBuffer; + + if (bufferNumber == file.buffers.size()) { + buffer = new byte[bufferSize]; + file.buffers.add(buffer); + } else { + buffer = file.buffers.get(bufferNumber); + } + + System.arraycopy(src, bufferPos, buffer, bufferOffset, bytesToCopy); + bufferPos += bytesToCopy; + pointer += bytesToCopy; + } + + if (pointer > file.length) { + file.length = pointer; + } + } + + @Override + protected InputStream openInputStream() throws IOException { + return new RAMInputStream(); + } + + @Override + protected void doAfterClose() throws IOException { +// file = null; + } + + @Override + public void seek(final long pos) throws IOException { + super.seek(pos); + pointer = (int) pos; + } + + @Override + public long length() { + return file.length; + } + + public void flushToIndexOutput(final IndexOutput indexOutput) throws IOException { + super.flush(); + if (file.buffers.isEmpty()) { + return; + } + if (file.buffers.size() == 1) { + indexOutput.writeBytes(file.buffers.get(0), (int) file.length); + return; + } + final int tempSize = file.buffers.size() - 1; + int i; + for (i = 0; i < tempSize; i++) { + indexOutput.writeBytes(file.buffers.get(i), bufferSize); + } + final int leftOver = (int) (file.length % bufferSize); + if (leftOver == 0) { + indexOutput.writeBytes(file.buffers.get(i), bufferSize); + } else { + indexOutput.writeBytes(file.buffers.get(i), leftOver); + } + } + + @Override + public long getChecksum() throws IOException { + // TODO Auto-generated method stub + logger.debug("RAMS3IndexOutput.getChecksum()"); + return 0; + } + } + +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java new file mode 100644 index 00000000..edc02a14 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java @@ -0,0 +1,45 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; + +import java.io.IOException; + +/** + * A simple base class that performs index input memory based buffering. The buffer size can be configured under the + * {@link #BUFFER_SIZE_SETTING} name. + * + * @author kimchy + */ +public abstract class S3BufferedIndexInput extends ConfigurableBufferedIndexInput implements S3IndexConfigurable { + + /** + * The buffer size setting name. See {@link S3FileEntrySettings#setIntSetting(String, int)}. Should be set in bytes. + */ + public static final String BUFFER_SIZE_SETTING = "indexInput.bufferSize"; + + protected S3BufferedIndexInput(final String resourceDescription) { + super(resourceDescription, BUFFER_SIZE); + } + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + setBufferSize(settings.getSettingAsInt(BUFFER_SIZE_SETTING, BUFFER_SIZE)); + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java new file mode 100644 index 00000000..9445ccea --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java @@ -0,0 +1,45 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; + +import java.io.IOException; + +/** + * A simple base class that performs index output memory based buffering. The buffer size can be configured under the + * {@link #BUFFER_SIZE_SETTING} name. + * + * @author kimchy + */ +public abstract class S3BufferedIndexOutput extends ConfigurableBufferedIndexOutput implements S3IndexConfigurable { + + /** + * The buffer size setting name. See {@link S3FileEntrySettings#setIntSetting(String, int)}. Should be set in bytes. + */ + public static final String BUFFER_SIZE_SETTING = "indexOutput.bufferSize"; + + protected S3BufferedIndexOutput(final String resourceDescription) { + super(resourceDescription); + } + + @Override + public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) + throws IOException { + initBuffer(settings.getSettingAsInt(BUFFER_SIZE_SETTING, DEFAULT_BUFFER_SIZE)); + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java new file mode 100644 index 00000000..caa1da18 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java @@ -0,0 +1,41 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; + +import java.io.IOException; + +/** + * An additional interface that each implementation of IndexInput and IndexOutput must + * implement. Used to configure newly created IndexInput and IndexOutput S3 based + * implementation. + * + * @author kimchy + */ +public interface S3IndexConfigurable { + + /** + * Configures the newly created IndexInput or IndexOutput implementations. + * + * @param name The name of the file entry + * @param s3Directory The S3 directory instance + * @param settings The relevant file entry settings + * @throws IOException + */ + void configure(String name, S3Directory s3Directory, S3FileEntrySettings settings) throws IOException; +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java new file mode 100644 index 00000000..d03d290d --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java @@ -0,0 +1,154 @@ +package com.erudika.lucene.store.s3.index; + +import com.erudika.lucene.store.s3.S3Directory; +import com.erudika.lucene.store.s3.S3FileEntrySettings; +import org.apache.lucene.store.BufferedIndexInput; +import org.apache.lucene.store.IndexInput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.ResponseTransformer; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class S3IndexInput extends BufferedIndexInput implements S3IndexConfigurable{ + + private S3Directory s3Directory; + private String name; + private long position = 0; + private long length = -1; + + private static final Logger logger = LoggerFactory.getLogger(S3IndexInput.class); + + public S3IndexInput() { + super("S3IndexInput"); + setBufferSize(51200); + } + + + @Override + public void configure(String name, S3Directory s3Directory, S3FileEntrySettings settings) throws IOException { + this.s3Directory = s3Directory; + this.name = name; + } + + @Override + protected void readInternal(ByteBuffer b) throws IOException { + synchronized (this) { + if (position + b.remaining() > length()) { + throw new EOFException("read past EOF: " + this); + } + ResponseInputStream res = s3Directory.getS3().getObject( + GetObjectRequest.builder() + .bucket(s3Directory.getBucket()) + .key(name).build() + ); + + res.skip(position); + position += b.remaining(); + byte[] data = res.readAllBytes(); + logger.info("Name: " + name + + " Reading from S3 at position: " + position + + " with buffer size: " + getBufferSize() + + " and remaining: " + b.remaining() + + " and data length: " + data.length + ); + b.put(data, 0, b.remaining()); + + } + + } + + @Override + protected void seekInternal(long pos) throws IOException { + synchronized (this){ + if(pos < 0) { + throw new IllegalArgumentException("Seek position cannot be negative"); + } + if(pos > length()) { + throw new EOFException("Seek position is past EOF"); + } + logger.info("Name: " + name + " Seeking to position: " + pos); + position = pos; + } + + } + + @Override + public void close() throws IOException { + //DO NOTHING + } + + @Override + public long length() { + if(length == -1){ + length = s3Directory.getS3().getObject( + GetObjectRequest.builder() + .bucket(s3Directory.getBucket()) + .key(name).build(), + ResponseTransformer.toInputStream() + ).response().contentLength(); + } + return length; + } + + /** + * Implementation of an IndexInput that reads from a portion of a file. + */ + private static final class SlicedIndexInput extends BufferedIndexInput { + + IndexInput base; + long fileOffset; + long length; + + SlicedIndexInput(final String sliceDescription, final IndexInput base, final long offset, final long length) { + super(sliceDescription == null ? base.toString() : base.toString() + " [slice=" + sliceDescription + "]", + BufferedIndexInput.BUFFER_SIZE); + if (offset < 0 || length < 0 || offset + length > base.length()) { + throw new IllegalArgumentException("slice() " + sliceDescription + " out of bounds: " + base); + } + this.base = base.clone(); + fileOffset = offset; + this.length = length; + } + + @Override + public SlicedIndexInput clone() { + final SlicedIndexInput clone = (SlicedIndexInput) super.clone(); + clone.base = base.clone(); + clone.fileOffset = fileOffset; + clone.length = length; + return clone; + } + + @Override + protected void readInternal(ByteBuffer bb) throws IOException { + long start = getFilePointer(); + if (start + bb.remaining() > length) { + throw new EOFException("read past EOF: " + this); + } + base.seek(fileOffset + start); + base.readBytes(bb.array(), bb.position(), bb.remaining()); + bb.position(bb.position() + bb.remaining()); + } + + @Override + protected void seekInternal(final long pos) { + } + + @Override + public void close() throws IOException { + base.close(); + } + + @Override + public long length() { + return length; + } + } + +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java b/src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java new file mode 100644 index 00000000..5ca0f663 --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java @@ -0,0 +1,49 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.lock; + +import com.erudika.lucene.store.s3.S3Directory; +import org.apache.lucene.store.Lock; + +import java.io.IOException; + +/** + * A simple no op lock. Performs no locking. + * + * @author kimchy + */ +public class NoOpLock extends Lock implements S3Lock { + + @Override + public void configure(final S3Directory s3Directory, final String name) throws IOException { + // do nothing + } + + @Override + public void obtain() throws IOException { + // do nothing + } + + @Override + public void close() throws IOException { + // do nothing + } + + @Override + public void ensureValid() throws IOException { + // do nothing + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java b/src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java new file mode 100644 index 00000000..878eee2a --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java @@ -0,0 +1,122 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.lock; + +import com.erudika.lucene.store.s3.S3Directory; +import org.apache.lucene.store.AlreadyClosedException; +import org.apache.lucene.store.Lock; +import org.apache.lucene.store.LockObtainFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.services.s3.model.ObjectLockLegalHold; +import software.amazon.awssdk.services.s3.model.ObjectLockLegalHoldStatus; +import software.amazon.awssdk.services.s3.model.PutObjectLegalHoldRequest; + +import java.io.IOException; + +import static software.amazon.awssdk.services.s3.model.ObjectLockLegalHoldStatus.OFF; +import static software.amazon.awssdk.services.s3.model.ObjectLockLegalHoldStatus.ON; + +/** + *

+ * A lock based on legal holds on S3 objects. + * + *

+ * The benefits of using this lock is the ability to release it. + * + * @author Alex Bogdanovski [alex@erudika.com] + */ +public class S3LegalHoldLock extends Lock implements S3Lock { + + private static final Logger logger = LoggerFactory.getLogger(S3LegalHoldLock.class); + + private S3Directory s3Directory; + private String name; + + @Override + public void configure(final S3Directory s3Directory, final String name) throws IOException { + this.s3Directory = s3Directory; + this.name = name; + } + + @Override + public void obtain() throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("obtain({})", name); + } + putObjectLegalHold(ON); + } catch (AwsServiceException | SdkClientException e) { + throw new LockObtainFailedException("Lock object could not be created: ", e); + } + } + + @Override + public void close() throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("close({})", name); + } +// res = s3Directory.getS3().getObjectLegalHold(b -> b.bucket(s3Directory.getBucket()).key(name)); + + putObjectLegalHold(OFF); +// LOCKS.remove(name); + } catch (AwsServiceException | SdkClientException e) { + throw new AlreadyClosedException("Lock was already released: ", e); + } + +// if (res != null && res.legalHold().status().equals(OFF)) { +// throw new AlreadyClosedException("Lock was already released: " + this); +// } + } + + @Override + public void ensureValid() throws IOException { + try { + if (logger.isDebugEnabled()) { + logger.info("ensureValid({})", name); + } + if (!isLegalHoldOn()) { + // TODO should throw AlreadyClosedException?? + throw new AlreadyClosedException("Lock instance already released: " + this); + } + } catch (AwsServiceException | SdkClientException e) { + throw new AlreadyClosedException("Lock object not found: " + this); + } + } + + private boolean isLegalHoldOn() { + return s3Directory.getS3().getObjectLegalHold(b -> + b.bucket(s3Directory.getBucket()).key(name)).legalHold().status().equals(ON); + } + + private void putObjectLegalHold(ObjectLockLegalHoldStatus status) { + + s3Directory.getS3().putObjectLegalHold(PutObjectLegalHoldRequest + .builder() + .bucket(s3Directory.getBucket()) + .key(name) + .legalHold(ObjectLockLegalHold.builder().status(status).build()) + .build()); + } + + @Override + public String toString() { + return "S3LegalHoldLock[" + s3Directory.getBucket() + "/" + name + "]"; + } +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java b/src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java new file mode 100644 index 00000000..3b52b8ec --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java @@ -0,0 +1,42 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.lock; + +import com.erudika.lucene.store.s3.S3Directory; + +import java.io.IOException; + +/** + * An extension insterface for Lucene Lock class. + * + * @author kimchy + */ +public interface S3Lock { + + /** + * Configures the lock. Called just after the lock is instantiated. + * + * @param s3Directory The directory using the lock + * @param name The name of the lock + * @throws IOException + */ + void configure(S3Directory s3Directory, String name) throws IOException; + + /** + * @throws IOException + */ + void obtain() throws IOException; +} diff --git a/src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java b/src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java new file mode 100644 index 00000000..35a09b0d --- /dev/null +++ b/src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java @@ -0,0 +1,76 @@ +/* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* + * Copyright 2004-2019 the original author or authors. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.erudika.lucene.store.s3.support; + +import org.apache.lucene.index.IndexFileNames; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashSet; +import java.util.Set; + +/** + * A set of utility methods for index file names. + * + * @author kimchy + */ +public class LuceneFileNames { + + public static final Logger logger = LoggerFactory.getLogger(LuceneFileNames.class); + + private static final Set STATIC_FILES; + + static { + STATIC_FILES = new HashSet(); + STATIC_FILES.add(IndexFileNames.SEGMENTS); + STATIC_FILES.add(IndexFileNames.PENDING_SEGMENTS); + STATIC_FILES.add("clearcache"); + STATIC_FILES.add("spellcheck.version"); + } + + /** + * Returns if this file name is a static file. A static file is a file that is updated and changed by Lucene. + */ + public static boolean isStaticFile(final String name) { + logger.debug("LuceneFileNames.isStaticFile({})", name); + return STATIC_FILES.contains(name); + } + + /** + * Returns if the name is a segment file or not. + */ + public static boolean isSegmentsFile(final String name) { + logger.debug("LuceneFileNames.isSegmentsFile({})", name); + return name.equals(IndexFileNames.SEGMENTS) || name.equals(IndexFileNames.PENDING_SEGMENTS); + } + +} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala b/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala new file mode 100644 index 00000000..b451a4cd --- /dev/null +++ b/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala @@ -0,0 +1,82 @@ +/* + + */ + +package org.zouzias.spark.lucenerdd + +import org.apache.hadoop.io.compress.GzipCodec +import org.apache.spark.sql.{Row, SparkSession} +import org.apache.spark.sql.functions.{col, expr, from_json} +import org.zouzias.spark.lucenerdd.UDF.updateIdUDF + +import java.util + +object Driver { + def main(args: Array[String]): Unit = { + val spark = SparkSession + .builder + .appName("Indexer") + .config("spark.master", "local") + .config("spark.driver.userClassPathFirst","true") + .config("spark.executor.userClassPathFirst","true") + .config("spark.executor.instances", "1") + .getOrCreate() + + val df = spark + .read + .format("kafka") + .option("kafka.bootstrap.servers", "localhost:9092") + .option("subscribe", "callSync") + .load() + + val interactionDf = df + .selectExpr("CAST(key AS STRING)", "CAST(value AS STRING) as value") + .select(from_json( col("value"), Schema.kafkaSchema, new util.HashMap[String, String]())) + .select("from_json(value).*") + .withColumn("meeting", updateIdUDF(col("zipped_data"))) + .drop("zipped_data") + .withColumn("struct_meeting", + from_json(col("meeting"), + Schema.meetingSchema, + new util.HashMap[String, String]())) + .drop("meeting") + .selectExpr("*", "struct_meeting.*") + .drop("struct_meeting") + + interactionDf.printSchema() + + // interactionDf + // .writeStream + // .format("parquet") + // .option("path", "spark-warehouse/data") + // .option("checkpointLocation","spark-warehouse/checkpoint") + // .start() + // .awaitTermination() + + val transcriptDf = interactionDf + .selectExpr("account_id", + "meeting_id", + "meetingInfo.time", + "meetingInfo.userId as user_id", + "explode(meetingInfo.transcript) as transcript") + .withColumn("start_time", expr("transcript.startTime")) + .withColumn("end_time", expr("transcript.endTime")) + .withColumn("phrase", expr("transcript.phrase")) + .withColumn("speaker", expr("transcript.speaker")) + .withColumn("convId", expr("transcript.convId")) + .drop("transcript") + + val luceneRDD: LuceneRDD[Row] = LuceneRDD(transcriptDf) + + luceneRDD.cache() + + luceneRDD.phraseQuery("phrase","hello").foreach(println) + +// val sqlContext= new org.apache.spark.sql.SQLContext(spark.sparkContext) +// import sqlContext.implicits._ + luceneRDD.saveAsObjectFile("spark-warehouse/lucene_text_"+System.currentTimeMillis()) + + luceneRDD.unpersist() + + } +} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala b/src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala new file mode 100644 index 00000000..933a5f12 --- /dev/null +++ b/src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala @@ -0,0 +1,34 @@ +/* + + */ +package org.zouzias.spark.lucenerdd + +import java.io.{ByteArrayInputStream, ByteArrayOutputStream} +import java.util.Base64 +import java.util.zip.{GZIPInputStream, GZIPOutputStream} +import scala.util.Try + +object GZip { + + def compress(input: Array[Byte]): Array[Byte] = { + val bos = new ByteArrayOutputStream(input.length) + val gzip = new GZIPOutputStream(bos) + gzip.write(input) + gzip.close() + val compressed = bos.toByteArray + bos.close() + compressed + } + + def decompress(compressed: Array[Byte]): Option[String] = + Try { + val decodedString = Base64.getDecoder.decode(compressed) + val inputStream = new GZIPInputStream(new ByteArrayInputStream(decodedString)) + scala.io.Source.fromInputStream(inputStream).mkString + }.toOption + + def main(args: Array[String]): Unit = { + val str = "" +// println(decompress(str.getBytes)) + } +} \ No newline at end of file diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/LuceneRDD.scala b/src/main/scala/org/zouzias/spark/lucenerdd/LuceneRDD.scala index 0813e398..b6acb007 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/LuceneRDD.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/LuceneRDD.scala @@ -393,11 +393,12 @@ object LuceneRDD extends Versionable queryAnalyzer: String, similarity: String, indexAnalyzerPerField: Map[String, String], - queryAnalyzerPerField: Map[String, String]) + queryAnalyzerPerField: Map[String, String], + isReadOnly: Boolean = false) (implicit conv: T => Document): LuceneRDD[T] = { val partitions = elems.mapPartitionsWithIndex[AbstractLuceneRDDPartition[T]]( (partId, iter) => Iterator(LuceneRDDPartition(iter, partId, indexAnalyzer, queryAnalyzer, - similarity, indexAnalyzerPerField, queryAnalyzerPerField)), + similarity, indexAnalyzerPerField, queryAnalyzerPerField, isReadOnly)), preservesPartitioning = true) new LuceneRDD[T](partitions, indexAnalyzer, queryAnalyzer, indexAnalyzerPerField, queryAnalyzerPerField, similarity) @@ -496,6 +497,24 @@ object LuceneRDD extends Versionable Map.empty[String, String]) } + /** + * Constructor with default index, query analyzers and Lucene similarity and isReadOnly preference + * + * @param dataFrame Input DataFrame + * @return + */ + def apply(dataFrame: DataFrame, isReadOnly: Boolean) + : LuceneRDD[Row] = { + apply[Row](dataFrame.rdd, + getOrElseEn(IndexAnalyzerConfigName), + getOrElseEn(QueryAnalyzerConfigName), + getOrElseClassic(), + Map.empty[String, String], + Map.empty[String, String], + isReadOnly + ) + } + /** * Entity linkage between two [[DataFrame]] by blocking / filtering * on one or more columns. @@ -551,7 +570,8 @@ object LuceneRDD extends Versionable luceneRDDParams.queryAnalyzer, luceneRDDParams.similarity, luceneRDDParams.indexAnalyzerPerField, - luceneRDDParams.queryAnalyzerPerField) + luceneRDDParams.queryAnalyzerPerField, + luceneRDDParams.isReadOnly) // Multi-query lucene index qs.map(q => (q, lucenePart.query(rowToQuery(q), topK).results.toArray)) @@ -603,7 +623,8 @@ object LuceneRDD extends Versionable luceneRDDParams.queryAnalyzer, luceneRDDParams.similarity, luceneRDDParams.indexAnalyzerPerField, - luceneRDDParams.queryAnalyzerPerField) + luceneRDDParams.queryAnalyzerPerField, + luceneRDDParams.isReadOnly) // Multi-query lucene index iterQueries.map(q => (q, lucenePart.query(rowToQuery(q), topK).results.toArray)) diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala b/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala new file mode 100644 index 00000000..ae1a5881 --- /dev/null +++ b/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala @@ -0,0 +1,36 @@ +package org.zouzias.spark.lucenerdd + +import org.apache.spark.sql.types.{IntegerType, StructField, StructType} +import org.apache.spark.sql.{Row, SparkSession} + +object ReadSavedFile { + def main(args: Array[String]): Unit = { + val spark = SparkSession + .builder + .appName("Indexer") + .config("spark.master", "local") + .config("spark.driver.userClassPathFirst","true") + .config("spark.executor.userClassPathFirst","true") + .config("spark.executor.instances", "1") + .getOrCreate() + + // Define the schema + val schema = new StructType() + .add(StructField("value", IntegerType, nullable = false)) + + // Create a Seq of Rows + val data = Seq(Row(1), Row(2), Row(3)) + + // Create DataFrame + val df = spark.createDataFrame( + spark.sparkContext.parallelize(data), + schema + ) + + val luceneRDD = LuceneRDD(df, true) +// val rdd: LuceneRDD[Row] = sc.objectFile("spark-warehouse/lucene_text_1715102057572").asInstanceOf[LuceneRDD[Row]] + luceneRDD.phraseQuery("phrase","hello").foreach(println) + + } + +} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala b/src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala new file mode 100644 index 00000000..088a9cdb --- /dev/null +++ b/src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala @@ -0,0 +1,22 @@ +/* + + */ +package org.zouzias.spark.lucenerdd + +object Schema { + val kafkaSchema: String = + """ + |{"type":"struct","fields":[{"name":"account_id","type":"string","nullable":true,"metadata":{}},{"name":"account_name","type":"string","nullable":true,"metadata":{}},{"name":"created_at","type":"long","nullable":true,"metadata":{}},{"name":"created_time","type":"long","nullable":true,"metadata":{}},{"name":"data","type":"string","nullable":true,"metadata":{}},{"name":"entity_type","type":"string","nullable":true,"metadata":{}},{"name":"event_type","type":"string","nullable":true,"metadata":{}},{"name":"id","type":"string","nullable":true,"metadata":{}},{"name":"is_pci","type":"boolean","nullable":true,"metadata":{}},{"name":"job_id","type":"string","nullable":true,"metadata":{}},{"name":"job_processing_entity_id","type":"string","nullable":true,"metadata":{}},{"name":"meeting_id","type":"string","nullable":true,"metadata":{}},{"name":"modified_at","type":"long","nullable":true,"metadata":{}},{"name":"partner_meeting_id","type":"string","nullable":true,"metadata":{}},{"name":"previous_call_time","type":"string","nullable":true,"metadata":{}},{"name":"version","type":"long","nullable":true,"metadata":{}},{"name":"zipped_data","type":"string","nullable":true,"metadata":{}}]} + |""".stripMargin + + val meetingSchema: String = + """ + |{"type":"struct","fields":[{"name":"meetingInfo","type":{"type":"struct","fields":[{"name":"accountId","type":"string","nullable":true,"metadata":{}},{"name":"audioPath","type":"string","nullable":true,"metadata":{}},{"name":"audioProperties","type":{"type":"struct","fields":[{"name":"call-mp3","type":{"type":"struct","fields":[{"name":"bitRate","type":"long","nullable":true,"metadata":{}},{"name":"channelCount","type":"long","nullable":true,"metadata":{}},{"name":"duration","type":"double","nullable":true,"metadata":{}},{"name":"samplingRate","type":"long","nullable":true,"metadata":{}}]},"nullable":true,"metadata":{}}]},"nullable":true,"metadata":{}},{"name":"bucketName","type":"string","nullable":true,"metadata":{}},{"name":"callLevelData","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"callLevelKey","type":"string","nullable":true,"metadata":{}},{"name":"value","type":"string","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"criteria","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"criteriaId","type":"string","nullable":true,"metadata":{}},{"name":"frequency","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"count","type":"long","nullable":true,"metadata":{}},{"name":"phrase","type":"string","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"present","type":"boolean","nullable":true,"metadata":{}},{"name":"snippets","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"confidence","type":"double","nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"evidence","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"duration","type":"long","nullable":true,"metadata":{}},{"name":"endOfInteractions","type":"boolean","nullable":true,"metadata":{}},{"name":"entityType","type":"string","nullable":true,"metadata":{}},{"name":"id","type":"string","nullable":true,"metadata":{}},{"name":"parameters","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"name","type":"string","nullable":true,"metadata":{}},{"name":"value","type":{"type":"array","elementType":"string","containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"partnerMeetingId","type":"string","nullable":true,"metadata":{}},{"name":"signal","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"frequency","type":{"type":"array","elementType":"string","containsNull":true},"nullable":true,"metadata":{}},{"name":"present","type":"boolean","nullable":true,"metadata":{}},{"name":"signalId","type":"string","nullable":true,"metadata":{}},{"name":"snippets","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"confidence","type":"double","nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"evidence","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"splitInteraction","type":"boolean","nullable":true,"metadata":{}},{"name":"startOfInteractions","type":"boolean","nullable":true,"metadata":{}},{"name":"status","type":"string","nullable":true,"metadata":{}},{"name":"time","type":"string","nullable":true,"metadata":{}},{"name":"totalSplitCount","type":"long","nullable":true,"metadata":{}},{"name":"transcript","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"confidence","type":{"type":"array","elementType":"double","containsNull":true},"nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"phrase","type":"string","nullable":true,"metadata":{}},{"name":"speaker","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}},{"name":"times","type":{"type":"array","elementType":"long","containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"transcriptPath","type":"string","nullable":true,"metadata":{}},{"name":"userId","type":"string","nullable":true,"metadata":{}}]},"nullable":true,"metadata":{}}]} + |""".stripMargin + + val transcriptSchema: String = + """ + |{"type":"struct","fields":[{"name":"confidence","type":{"type":"array","elementType":"double","containsNull":true},"nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"phrase","type":"string","nullable":true,"metadata":{}},{"name":"speaker","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}},{"name":"times","type":{"type":"array","elementType":"long","containsNull":true},"nullable":true,"metadata":{}}]} + |""".stripMargin + +} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala b/src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala new file mode 100644 index 00000000..211c8799 --- /dev/null +++ b/src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala @@ -0,0 +1,16 @@ +package org.zouzias.spark.lucenerdd + +/* + + */ +import org.apache.spark.sql.expressions.UserDefinedFunction +import org.apache.spark.sql.functions.udf + +object UDF { + + val unzipData: (String => String) = (unzipped: String) => { + GZip.decompress(unzipped.getBytes).get + } + val updateIdUDF: UserDefinedFunction = udf(unzipData) + +} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/config/LuceneRDDParams.scala b/src/main/scala/org/zouzias/spark/lucenerdd/config/LuceneRDDParams.scala index 06925878..7e7e1e84 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/config/LuceneRDDParams.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/config/LuceneRDDParams.scala @@ -31,7 +31,8 @@ case class LuceneRDDParams(indexAnalyzer: String, queryAnalyzer: String, similarity: String, indexAnalyzerPerField: Map[String, String], - queryAnalyzerPerField: Map[String, String]) extends Serializable + queryAnalyzerPerField: Map[String, String], + isReadOnly: Boolean) extends Serializable object LuceneRDDParams extends AnalyzerConfigurable with SimilarityConfigurable { @@ -40,6 +41,7 @@ object LuceneRDDParams extends AnalyzerConfigurable with SimilarityConfigurable getOrElseEn(QueryAnalyzerConfigName), getOrElseClassic(), Map.empty[String, String], - Map.empty[String, String]) + Map.empty[String, String], + false) } } diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/partition/LuceneRDDPartition.scala b/src/main/scala/org/zouzias/spark/lucenerdd/partition/LuceneRDDPartition.scala index bbbf8906..62b213e7 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/partition/LuceneRDDPartition.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/partition/LuceneRDDPartition.scala @@ -59,7 +59,8 @@ private[lucenerdd] class LuceneRDDPartition[T] private val queryAnalyzerName: String, private val similarityName: String, private val indexAnalyzerPerField: Map[String, String], - private val queryAnalyzerPerField: Map[String, String]) + private val queryAnalyzerPerField: Map[String, String], + private val isReadOnly: Boolean = false) (implicit docConversion: T => Document, override implicit val kTag: ClassTag[T]) extends AbstractLuceneRDDPartition[T] @@ -86,21 +87,23 @@ private[lucenerdd] class LuceneRDDPartition[T] private val (iterOriginal, iterIndex) = iter.duplicate - private val startTime = new DateTime(System.currentTimeMillis()) - logInfo(s"[partId=${partitionId}]Indexing process initiated at ${startTime}...") - iterIndex.foreach { case elem => - // (implicitly) convert type T to Lucene document - val doc = docConversion(elem) - indexWriter.addDocument(FacetsConfig.build(taxoWriter, doc)) + if(!isReadOnly) { + val startTime = new DateTime(System.currentTimeMillis()) + logInfo(s"[partId=${partitionId}]Indexing process initiated at ${startTime}...") + iterIndex.foreach { case elem => + // (implicitly) convert type T to Lucene document + val doc = docConversion(elem) + indexWriter.addDocument(FacetsConfig.build(taxoWriter, doc)) + } + val endTime = new DateTime(System.currentTimeMillis()) + logInfo(s"[partId=${partitionId}]Indexing process completed at ${endTime}...") + logInfo(s"[partId=${partitionId}]Indexing process took ${(endTime.getMillis + - startTime.getMillis) / 1000} seconds...") + + // Close the indexWriter and taxonomyWriter (for faceted search) + closeAllWriters() + logDebug(s"[partId=${partitionId}]Closing index writers...") } - private val endTime = new DateTime(System.currentTimeMillis()) - logInfo(s"[partId=${partitionId}]Indexing process completed at ${endTime}...") - logInfo(s"[partId=${partitionId}]Indexing process took ${(endTime.getMillis - - startTime.getMillis) / 1000} seconds...") - - // Close the indexWriter and taxonomyWriter (for faceted search) - closeAllWriters() - logDebug(s"[partId=${partitionId}]Closing index writers...") logDebug(s"[partId=${partitionId}]Instantiating index/facet readers") private val indexReader = DirectoryReader.open(IndexDir) @@ -282,11 +285,12 @@ object LuceneRDDPartition { queryAnalyzerName: String, similarityName: String, indexAnalyzerPerField: Map[String, String] = Map.empty, - queryAnalyzerPerField: Map[String, String] = Map.empty) + queryAnalyzerPerField: Map[String, String] = Map.empty, + isReadOnly: Boolean = false) (implicit docConversion: T => Document) : LuceneRDDPartition[T] = { new LuceneRDDPartition[T](iter, partitionId, indexAnalyzerName, queryAnalyzerName, similarityName, indexAnalyzerPerField, - queryAnalyzerPerField)(docConversion, classTag[T]) + queryAnalyzerPerField, isReadOnly)(docConversion, classTag[T]) } } diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala b/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala index 766ef71d..27d93c53 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala @@ -16,13 +16,18 @@ */ package org.zouzias.spark.lucenerdd.store -import java.nio.file.{Files, Path} +import com.erudika.lucene.store.s3.{S3Directory, S3FileSystemStore} +import com.upplication.s3fs.S3FileSystem +import java.nio.file.{FileSystems, Files, Path} import org.apache.lucene.facet.FacetsConfig import org.apache.lucene.store._ import org.zouzias.spark.lucenerdd.config.Configurable import org.apache.spark.internal.Logging +import java.net.URI +import java.util + /** * Storage of a Lucene index Directory * @@ -44,12 +49,16 @@ trait IndexStorable extends Configurable private val indexDirName = s"indexDirectory.${System.currentTimeMillis()}.${Thread.currentThread().getId}" - private val indexDir = Files.createTempDirectory(indexDirName) + private val indexS3FileSystem = S3FileSystemStore.getS3FileSystem +// private val indexDir = Files.createTempDirectory(indexDirName) + private val indexDir = indexS3FileSystem.getPath("lucene-kashyap") private val taxonomyDirName = s"taxonomyDirectory-${System.currentTimeMillis()}.${Thread.currentThread().getId}" - private val taxonomyDir = Files.createTempDirectory(taxonomyDirName) + private val taxonomyS3FileSystem = S3FileSystemStore.getTaxonomyS3FileSystem +// private val taxonomyDir = Files.createTempDirectory(taxonomyDirName) + private val taxonomyDir = taxonomyS3FileSystem.getPath("lucene-kashyap-taxonomy") protected val IndexDir = storageMode(indexDir) @@ -74,6 +83,12 @@ trait IndexStorable extends Configurable // directoryPath.toFile.deleteOnExit() // Delete on exit new MMapDirectory(directoryPath, new SingleInstanceLockFactory) } + case "s3" => + logInfo(s"Config parameter ${IndexStoreKey} is set to 's3'") + logInfo(s"Bucket Name: ${directoryPath.toString}") + val bucket: String = directoryPath.getFileSystem.asInstanceOf[S3FileSystem].getKey + val path: String = directoryPath.toString + new S3Directory(bucket, path) case ow => logInfo(s"Config parameter ${IndexStoreKey} is set to ${ow}") logInfo("Lucene index will be storage in memory (default)") diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/versioning/Versionable.scala b/src/main/scala/org/zouzias/spark/lucenerdd/versioning/Versionable.scala index 1ff18a4d..989a635a 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/versioning/Versionable.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/versioning/Versionable.scala @@ -27,6 +27,7 @@ trait Versionable { */ def version(): Map[String, Any] = { // BuildInfo is automatically generated using sbt plugin `sbt-buildinfo` - org.zouzias.spark.lucenerdd.BuildInfo.toMap +// org.zouzias.spark.lucenerdd.BuildInfo.toMap + Map("version" -> "0.0.1") } } From 49b6cc87333a7ac1dc3712563e89dbd173443d6d Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Sun, 15 Sep 2024 19:27:27 +0530 Subject: [PATCH 2/8] Fix --- checkpoint_dir/.metadata.crc | Bin 0 -> 12 bytes checkpoint_dir/commits/.0.crc | Bin 0 -> 12 bytes checkpoint_dir/commits/0 | 2 + checkpoint_dir/metadata | 1 + checkpoint_dir/offsets/.0.crc | Bin 0 -> 16 bytes checkpoint_dir/offsets/.1.crc | Bin 0 -> 16 bytes checkpoint_dir/offsets/0 | 3 + checkpoint_dir/offsets/1 | 3 + checkpoint_dir/sources/0/.0.crc | Bin 0 -> 12 bytes checkpoint_dir/sources/0/0 | Bin 0 -> 27 bytes checkpoint_dir_1/.metadata.crc | Bin 0 -> 12 bytes checkpoint_dir_1/commits/.0.crc | Bin 0 -> 12 bytes checkpoint_dir_1/commits/.1.crc | Bin 0 -> 12 bytes checkpoint_dir_1/commits/.2.crc | Bin 0 -> 12 bytes checkpoint_dir_1/commits/.3.crc | Bin 0 -> 12 bytes checkpoint_dir_1/commits/0 | 2 + checkpoint_dir_1/commits/1 | 2 + checkpoint_dir_1/commits/2 | 2 + checkpoint_dir_1/commits/3 | 2 + checkpoint_dir_1/metadata | 1 + checkpoint_dir_1/offsets/.0.crc | Bin 0 -> 16 bytes checkpoint_dir_1/offsets/.1.crc | Bin 0 -> 16 bytes checkpoint_dir_1/offsets/.2.crc | Bin 0 -> 16 bytes checkpoint_dir_1/offsets/.3.crc | Bin 0 -> 16 bytes checkpoint_dir_1/offsets/0 | 3 + checkpoint_dir_1/offsets/1 | 3 + checkpoint_dir_1/offsets/2 | 3 + checkpoint_dir_1/offsets/3 | 3 + checkpoint_dir_1/sources/0/.0.crc | Bin 0 -> 12 bytes checkpoint_dir_1/sources/0/0 | Bin 0 -> 21 bytes .../lucene_text_1714990337528/._SUCCESS.crc | Bin 0 -> 8 bytes .../.part-00000.gz.crc | Bin 0 -> 160 bytes .../lucene_text_1714990337528/_SUCCESS | 0 .../lucene_text_1714990337528/part-00000.gz | Bin 0 -> 19369 bytes .../lucene_text_1715101627025/._SUCCESS.crc | Bin 0 -> 8 bytes .../.part-00000.gz.crc | Bin 0 -> 160 bytes .../lucene_text_1715101627025/_SUCCESS | 0 .../lucene_text_1715101627025/part-00000.gz | Bin 0 -> 19369 bytes .../lucene_text_1715102057572/._SUCCESS.crc | Bin 0 -> 8 bytes .../lucene_text_1715102057572/.part-00000.crc | Bin 0 -> 1804 bytes .../lucene_text_1715102057572/_SUCCESS | 0 .../lucene_text_1715102057572/part-00000 | Bin 0 -> 229854 bytes .../lucene_text_1715147755491/._SUCCESS.crc | Bin 0 -> 8 bytes .../lucene_text_1715147755491/.part-00000.crc | Bin 0 -> 1804 bytes .../lucene_text_1715147755491/_SUCCESS | 0 .../lucene_text_1715147755491/part-00000 | Bin 0 -> 229854 bytes .../lucene_text_1715262452600/._SUCCESS.crc | Bin 0 -> 8 bytes .../lucene_text_1715262452600/.part-00000.crc | Bin 0 -> 1804 bytes .../lucene_text_1715262452600/_SUCCESS | 0 .../lucene_text_1715262452600/part-00000 | Bin 0 -> 229854 bytes .../lucene_text_1719131524623/._SUCCESS.crc | Bin 0 -> 8 bytes .../lucene_text_1719131524623/.part-00000.crc | Bin 0 -> 12 bytes .../lucene_text_1719131524623/_SUCCESS | 0 .../lucene_text_1719131524623/part-00000 | Bin 0 -> 95 bytes .../lucene_text_1719291413827/._SUCCESS.crc | Bin 0 -> 8 bytes .../lucene_text_1719291413827/.part-00000.crc | Bin 0 -> 3588 bytes .../lucene_text_1719291413827/_SUCCESS | 0 .../lucene_text_1719291413827/part-00000 | Bin 0 -> 457836 bytes .../lucene/store/s3/S3SingletonClient.java | 6 +- .../index/ConfigurableBufferedIndexInput.java | 2 +- .../index/FetchOnBufferReadS3IndexInput.java | 22 ------ .../org/zouzias/spark/lucenerdd/Driver.scala | 1 - .../spark/lucenerdd/KafkaStreamingQuery.scala | 63 ++++++++++++++++++ .../spark/lucenerdd/ReadSavedFile.scala | 2 +- 64 files changed, 98 insertions(+), 28 deletions(-) create mode 100644 checkpoint_dir/.metadata.crc create mode 100644 checkpoint_dir/commits/.0.crc create mode 100644 checkpoint_dir/commits/0 create mode 100644 checkpoint_dir/metadata create mode 100644 checkpoint_dir/offsets/.0.crc create mode 100644 checkpoint_dir/offsets/.1.crc create mode 100644 checkpoint_dir/offsets/0 create mode 100644 checkpoint_dir/offsets/1 create mode 100644 checkpoint_dir/sources/0/.0.crc create mode 100644 checkpoint_dir/sources/0/0 create mode 100644 checkpoint_dir_1/.metadata.crc create mode 100644 checkpoint_dir_1/commits/.0.crc create mode 100644 checkpoint_dir_1/commits/.1.crc create mode 100644 checkpoint_dir_1/commits/.2.crc create mode 100644 checkpoint_dir_1/commits/.3.crc create mode 100644 checkpoint_dir_1/commits/0 create mode 100644 checkpoint_dir_1/commits/1 create mode 100644 checkpoint_dir_1/commits/2 create mode 100644 checkpoint_dir_1/commits/3 create mode 100644 checkpoint_dir_1/metadata create mode 100644 checkpoint_dir_1/offsets/.0.crc create mode 100644 checkpoint_dir_1/offsets/.1.crc create mode 100644 checkpoint_dir_1/offsets/.2.crc create mode 100644 checkpoint_dir_1/offsets/.3.crc create mode 100644 checkpoint_dir_1/offsets/0 create mode 100644 checkpoint_dir_1/offsets/1 create mode 100644 checkpoint_dir_1/offsets/2 create mode 100644 checkpoint_dir_1/offsets/3 create mode 100644 checkpoint_dir_1/sources/0/.0.crc create mode 100644 checkpoint_dir_1/sources/0/0 create mode 100644 spark-warehouse/lucene_text_1714990337528/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1714990337528/.part-00000.gz.crc create mode 100644 spark-warehouse/lucene_text_1714990337528/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1714990337528/part-00000.gz create mode 100644 spark-warehouse/lucene_text_1715101627025/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1715101627025/.part-00000.gz.crc create mode 100644 spark-warehouse/lucene_text_1715101627025/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1715101627025/part-00000.gz create mode 100644 spark-warehouse/lucene_text_1715102057572/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1715102057572/.part-00000.crc create mode 100644 spark-warehouse/lucene_text_1715102057572/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1715102057572/part-00000 create mode 100644 spark-warehouse/lucene_text_1715147755491/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1715147755491/.part-00000.crc create mode 100644 spark-warehouse/lucene_text_1715147755491/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1715147755491/part-00000 create mode 100644 spark-warehouse/lucene_text_1715262452600/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1715262452600/.part-00000.crc create mode 100644 spark-warehouse/lucene_text_1715262452600/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1715262452600/part-00000 create mode 100644 spark-warehouse/lucene_text_1719131524623/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1719131524623/.part-00000.crc create mode 100644 spark-warehouse/lucene_text_1719131524623/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1719131524623/part-00000 create mode 100644 spark-warehouse/lucene_text_1719291413827/._SUCCESS.crc create mode 100644 spark-warehouse/lucene_text_1719291413827/.part-00000.crc create mode 100644 spark-warehouse/lucene_text_1719291413827/_SUCCESS create mode 100644 spark-warehouse/lucene_text_1719291413827/part-00000 create mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala diff --git a/checkpoint_dir/.metadata.crc b/checkpoint_dir/.metadata.crc new file mode 100644 index 0000000000000000000000000000000000000000..97345d1b2df84cded89e1e0b8c402a636f4b1774 GIT binary patch literal 12 TcmYc;N@ieSU}AX8`XU0ql39igbRBwl( zm#l!)%Ko77ZIKCm(+fL^EjE|(hMW3ZArCES?2s4EfiRm|OE5s?B{9qWZDov1VaBimy7)p^1-su!6;E({{=oAsV$1HOjRbp3qw~`p2 OokLMSoZ@d**5k$^B28id literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1714990337528/_SUCCESS b/spark-warehouse/lucene_text_1714990337528/_SUCCESS new file mode 100644 index 00000000..e69de29b diff --git a/spark-warehouse/lucene_text_1714990337528/part-00000.gz b/spark-warehouse/lucene_text_1714990337528/part-00000.gz new file mode 100644 index 0000000000000000000000000000000000000000..2efcc8e07a0384289464e9c5217294acc7446205 GIT binary patch literal 19369 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 literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715101627025/._SUCCESS.crc b/spark-warehouse/lucene_text_1715101627025/._SUCCESS.crc new file mode 100644 index 0000000000000000000000000000000000000000..3b7b044936a890cd8d651d349a752d819d71d22c GIT binary patch literal 8 PcmYc;N@ieSU}69O2$TUk literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715101627025/.part-00000.gz.crc b/spark-warehouse/lucene_text_1715101627025/.part-00000.gz.crc new file mode 100644 index 0000000000000000000000000000000000000000..e6038d3e585489cdf8b9522006857492e4c3c894 GIT binary patch literal 160 zcmV;R0AK%Oa$^7h00IDxY+cvVYan$&@1f-;pe+(MUA;WrIQ|3XuGO;tKMvj@>Bwl( zm#l!)%Ko77ZIKCm(+fL^EjE|(hMW3ZArCES?2s4EfiRm|OE5s?B{9qWZDov1VaBimy7)p^1-su!6;E({{=oAsV$1HOjRbp3qw~`p2 OokLMSoZ@d**5k$^B28id literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715101627025/_SUCCESS b/spark-warehouse/lucene_text_1715101627025/_SUCCESS new file mode 100644 index 00000000..e69de29b diff --git a/spark-warehouse/lucene_text_1715101627025/part-00000.gz b/spark-warehouse/lucene_text_1715101627025/part-00000.gz new file mode 100644 index 0000000000000000000000000000000000000000..2efcc8e07a0384289464e9c5217294acc7446205 GIT binary patch literal 19369 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 literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715102057572/._SUCCESS.crc b/spark-warehouse/lucene_text_1715102057572/._SUCCESS.crc new file mode 100644 index 0000000000000000000000000000000000000000..3b7b044936a890cd8d651d349a752d819d71d22c GIT binary patch literal 8 PcmYc;N@ieSU}69O2$TUk literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715102057572/.part-00000.crc b/spark-warehouse/lucene_text_1715102057572/.part-00000.crc new file mode 100644 index 0000000000000000000000000000000000000000..6e53c85115739e2a91a52ff55c7371f5b412ab8a GIT binary patch literal 1804 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 z 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 J_R^O-{{t@Qw8#Je literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715262452600/._SUCCESS.crc b/spark-warehouse/lucene_text_1715262452600/._SUCCESS.crc new file mode 100644 index 0000000000000000000000000000000000000000..3b7b044936a890cd8d651d349a752d819d71d22c GIT binary patch literal 8 PcmYc;N@ieSU}69O2$TUk literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1715262452600/.part-00000.crc b/spark-warehouse/lucene_text_1715262452600/.part-00000.crc new file mode 100644 index 0000000000000000000000000000000000000000..1982259b8c046166e3e0dc87755086888b9201aa GIT binary patch literal 1804 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 literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1719131524623/_SUCCESS b/spark-warehouse/lucene_text_1719131524623/_SUCCESS new file mode 100644 index 00000000..e69de29b diff --git a/spark-warehouse/lucene_text_1719131524623/part-00000 b/spark-warehouse/lucene_text_1719131524623/part-00000 new file mode 100644 index 0000000000000000000000000000000000000000..ec779f2548ba4cb615a052a0ce14729457c37856 GIT binary patch literal 95 zcmWG`4P;ZyFG|--EJ#ewNY%?oOv%qL(96u%^DE8C2`|blNleN~Rl=&msj?)s7^Z{) W4E_XumD<+PqW<8yD__#|_dEbnAtMF= literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1719291413827/._SUCCESS.crc b/spark-warehouse/lucene_text_1719291413827/._SUCCESS.crc new file mode 100644 index 0000000000000000000000000000000000000000..3b7b044936a890cd8d651d349a752d819d71d22c GIT binary patch literal 8 PcmYc;N@ieSU}69O2$TUk literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1719291413827/.part-00000.crc b/spark-warehouse/lucene_text_1719291413827/.part-00000.crc new file mode 100644 index 0000000000000000000000000000000000000000..422c04f30737a4c5032e2e5e44a3294dc162db0b GIT binary patch literal 3588 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 K64Oe!9`oYoQU*By literal 0 HcmV?d00001 diff --git a/spark-warehouse/lucene_text_1719291413827/_SUCCESS b/spark-warehouse/lucene_text_1719291413827/_SUCCESS new file mode 100644 index 00000000..e69de29b diff --git a/spark-warehouse/lucene_text_1719291413827/part-00000 b/spark-warehouse/lucene_text_1719291413827/part-00000 new file mode 100644 index 0000000000000000000000000000000000000000..375e8d213ec7f938cff2699a2db4097be9698da6 GIT binary patch literal 457836 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 new AwsSessionCredentials .Builder() - .accessKeyId("ASIA2E3GK2GH3NV2SO6E") //This is from E2E account - .secretAccessKey("FxjTfKJY6QfDyo3iYaG7oKg4hx0nqqRbJ53rhdMy") - .sessionToken("IQoJb3JpZ2luX2VjEA0aCXVzLXdlc3QtMiJHMEUCIQDEq/6ShmSHnXVPjINNeg1Gbfv1sic9rqF/xtQSe+nTmwIgRcH7qqqfJ79k28NMGnG+sG89KG80t1xWQENUT2QhzhMqoAMItv//////////ARAAGgw2OTc2MDk5MzMxOTkiDALDMrROyEiDFN4QBCr0ApoQMhYaD/zLX2NO4jF+Y3wXQy5Yr6IERyfHN1nOyeS69forL62SgVNaaKQlY7IjUyTlQQdfOxjCYNMIzOnzZnRXeQwqoB0YFl2ot9e80n8o9/vybPOFewtyI/VfBp4kHcqBKlL+6ZSvdHcrv5sNr87Hao9ztf7vDO8s8TGIvm74vbz901OaQLx77Jmt7n0j26CxWnBROIx9JqRQN5ZJQEcWpHD2bKnt4JqwIDfPH2EswcaAjNQut61hqUgQLqjoBrXBDVl3hztHJByQ72FDMTNq6VhkIZwrbTOGPpfFi+fr6xCCpmb+Nr1GSOjB3OwOUOS52No9Tz6vBJCIes3+Bh7J4o/GX1TUp5YewmIrKGCgIiWaGl+/Rl88KMzU9V+p/lzhNaUnT3OL91YDppfQgtqBB1nolfRIw4JEtObySweXpuf5zi514ygFmYp5X+pM7D51Rdc5cUAO0SXOjhn6Ig+wLWeUU+smsi96J7B6ReeSO+wmZTDHmumzBjqmAUrMHymm0/LKKQe579EaAo0hm3eSORXoH1BFFQmBX5LmaaHrAagczQqheXG+JkSR3AWXsenAZ3GpvcxKDcobFmTDi0DH6skyWZrXiy+TnTrGrTVlXlCaNuNp6uMuuhpHZF/eeczjj5nMgBtja9A8LWecSUMuS60Mz7pmT/C5CDM67+buEeu8YwqWeEmR1uZRNya8CTVyeb1X94XsVNlok1fAU/U1/D4=") + .accessKeyId("") //This is from E2E account + .secretAccessKey("") + .sessionToken("") .build() ) .region(Region.US_WEST_2) diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java index 32726c0b..bec38dde 100644 --- a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java +++ b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java @@ -21,7 +21,7 @@ protected ConfigurableBufferedIndexInput(final String resourceDescription, final /** * Default buffer size */ - public static final int BUFFER_SIZE = 1024; + public static final int BUFFER_SIZE = 160000000; protected int bufferSize = BUFFER_SIZE; diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java index c9f48b73..6de94832 100644 --- a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java +++ b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java @@ -105,28 +105,6 @@ protected void refill() throws IOException { bufferPosition = 0; } -// @Override -// protected void readInternal(byte[] b, int offset, int length) throws IOException { -// GetObjectRequest getObjectRequest = GetObjectRequest.builder() -// .bucket(s3Directory.getBucket()) -// .key(name) -// .range("bytes=" + offset + "-" + (offset + length - 1)) -// .build(); -// -// try { -// ResponseBytes getObjectResponse = s3Directory.getS3().getObject(getObjectRequest, ResponseTransformer.toBytes()); -// byte[] objectBytes = getObjectResponse.asByteArray(); -// System.arraycopy(objectBytes, 0, b, 0, objectBytes.length); -// synchronized (this) { -// if (totalLength == -1) { -// totalLength = getObjectResponse.response().contentLength(); -// } -// } -// } catch (Exception e) { -// throw new IOException("Unable to read from S3 object", e); -// } -// } - @Override protected synchronized void readInternal(final byte[] b, final int offset, final int length) throws IOException { if (logger.isDebugEnabled()) { diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala b/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala index b451a4cd..04d340f9 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala @@ -4,7 +4,6 @@ package org.zouzias.spark.lucenerdd -import org.apache.hadoop.io.compress.GzipCodec import org.apache.spark.sql.{Row, SparkSession} import org.apache.spark.sql.functions.{col, expr, from_json} import org.zouzias.spark.lucenerdd.UDF.updateIdUDF diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala b/src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala new file mode 100644 index 00000000..e52b7dc1 --- /dev/null +++ b/src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala @@ -0,0 +1,63 @@ +package org.zouzias.spark.lucenerdd + +import org.apache.spark.sql.{DataFrame, Encoder, Encoders, ForeachWriter, Row, SparkSession} +import org.apache.spark.sql.functions.{col, expr, from_json} +import org.zouzias.spark.lucenerdd.UDF.updateIdUDF + +object KafkaStreamingQuery { + def main(args: Array[String]): Unit = { + val spark = SparkSession + .builder + .appName("Indexer") + .config("spark.master", "local") + .config("spark.driver.userClassPathFirst","true") + .config("spark.executor.userClassPathFirst","true") + .config("spark.executor.instances", "1") + .getOrCreate() + + val df: DataFrame = spark + .readStream + .format("kafka") + .option("kafka.bootstrap.servers", "localhost:9092") + .option("subscribe", "query") + .option("startingOffsets", "earliest") + .load() + + implicit val enc: Encoder[(String, String)] = Encoders.product[(String, String)] + val modified_df = df.selectExpr("CAST(key AS STRING)", "CAST(value AS STRING)") + .as[(String, String)] + .select("value") + val luceneRDD = LuceneRDD(df, true) + + modified_df + .writeStream + .foreach(new ForeachWriter[Row] { + + def open(partitionId: Long, version: Long): Boolean = { + // Open connection + true + } + + def process(record: Row): Unit = { + // val rdd: LuceneRDD[Row] = sc.objectFile("spark-warehouse/lucene_text_1715102057572").asInstanceOf[LuceneRDD[Row]] + luceneRDD.phraseQuery("phrase",record.getString(0)).foreach(println) + } + + def close(errorOrNull: Throwable): Unit = { + // Close the connection + } + }) + .start() + .awaitTermination() + +// val writing_df = modified_df.writeStream +// .format("console") +// .option("checkpointLocation","checkpoint_dir"+System.currentTimeMillis()) +// .outputMode("append") +// .start() +// +// +// writing_df.awaitTermination() + } + +} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala b/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala index ae1a5881..0e5f8a63 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala @@ -26,7 +26,7 @@ object ReadSavedFile { spark.sparkContext.parallelize(data), schema ) - + println("Starting...") val luceneRDD = LuceneRDD(df, true) // val rdd: LuceneRDD[Row] = sc.objectFile("spark-warehouse/lucene_text_1715102057572").asInstanceOf[LuceneRDD[Row]] luceneRDD.phraseQuery("phrase","hello").foreach(println) From 86e87400aa24daf0f5fc656fe8c434f754b18364 Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Sun, 15 Sep 2024 19:29:07 +0530 Subject: [PATCH 3/8] Fix --- .../com/erudika/lucene/store/s3/S3SingletonClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java b/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java index 240be0f4..db5937b8 100644 --- a/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java +++ b/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java @@ -23,9 +23,9 @@ public static S3Client getS3Client(){ s3Client = S3Client.builder() .credentialsProvider(() -> new AwsSessionCredentials .Builder() - .accessKeyId("") //This is from E2E account - .secretAccessKey("") - .sessionToken("") +// .accessKeyId("") //This is from E2E account +// .secretAccessKey("") +// .sessionToken("") .build() ) .region(Region.US_WEST_2) From 9e541db80510532b95f6cb737709177b36225d40 Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Mon, 16 Sep 2024 19:03:52 +0530 Subject: [PATCH 4/8] Remove unwanted folders and files --- .gitignore | 1 + checkpoint_dir/.metadata.crc | Bin 12 -> 0 bytes checkpoint_dir/commits/.0.crc | Bin 12 -> 0 bytes checkpoint_dir/commits/0 | 2 -- checkpoint_dir/metadata | 1 - checkpoint_dir/offsets/.0.crc | Bin 16 -> 0 bytes checkpoint_dir/offsets/.1.crc | Bin 16 -> 0 bytes checkpoint_dir/offsets/0 | 3 --- checkpoint_dir/offsets/1 | 3 --- checkpoint_dir/sources/0/.0.crc | Bin 12 -> 0 bytes checkpoint_dir/sources/0/0 | Bin 27 -> 0 bytes checkpoint_dir_1/.metadata.crc | Bin 12 -> 0 bytes checkpoint_dir_1/commits/.0.crc | Bin 12 -> 0 bytes checkpoint_dir_1/commits/.1.crc | Bin 12 -> 0 bytes checkpoint_dir_1/commits/.2.crc | Bin 12 -> 0 bytes checkpoint_dir_1/commits/.3.crc | Bin 12 -> 0 bytes checkpoint_dir_1/commits/0 | 2 -- checkpoint_dir_1/commits/1 | 2 -- checkpoint_dir_1/commits/2 | 2 -- checkpoint_dir_1/commits/3 | 2 -- checkpoint_dir_1/metadata | 1 - checkpoint_dir_1/offsets/.0.crc | Bin 16 -> 0 bytes checkpoint_dir_1/offsets/.1.crc | Bin 16 -> 0 bytes checkpoint_dir_1/offsets/.2.crc | Bin 16 -> 0 bytes checkpoint_dir_1/offsets/.3.crc | Bin 16 -> 0 bytes checkpoint_dir_1/offsets/0 | 3 --- checkpoint_dir_1/offsets/1 | 3 --- checkpoint_dir_1/offsets/2 | 3 --- checkpoint_dir_1/offsets/3 | 3 --- checkpoint_dir_1/sources/0/.0.crc | Bin 12 -> 0 bytes checkpoint_dir_1/sources/0/0 | Bin 21 -> 0 bytes .../lucene_text_1714990337528/._SUCCESS.crc | Bin 8 -> 0 bytes .../.part-00000.gz.crc | Bin 160 -> 0 bytes .../lucene_text_1714990337528/_SUCCESS | 0 .../lucene_text_1714990337528/part-00000.gz | Bin 19369 -> 0 bytes .../lucene_text_1715101627025/._SUCCESS.crc | Bin 8 -> 0 bytes .../.part-00000.gz.crc | Bin 160 -> 0 bytes .../lucene_text_1715101627025/_SUCCESS | 0 .../lucene_text_1715101627025/part-00000.gz | Bin 19369 -> 0 bytes .../lucene_text_1715102057572/._SUCCESS.crc | Bin 8 -> 0 bytes .../lucene_text_1715102057572/.part-00000.crc | Bin 1804 -> 0 bytes .../lucene_text_1715102057572/_SUCCESS | 0 .../lucene_text_1715102057572/part-00000 | Bin 229854 -> 0 bytes .../lucene_text_1715147755491/._SUCCESS.crc | Bin 8 -> 0 bytes .../lucene_text_1715147755491/.part-00000.crc | Bin 1804 -> 0 bytes .../lucene_text_1715147755491/_SUCCESS | 0 .../lucene_text_1715147755491/part-00000 | Bin 229854 -> 0 bytes .../lucene_text_1715262452600/._SUCCESS.crc | Bin 8 -> 0 bytes .../lucene_text_1715262452600/.part-00000.crc | Bin 1804 -> 0 bytes .../lucene_text_1715262452600/_SUCCESS | 0 .../lucene_text_1715262452600/part-00000 | Bin 229854 -> 0 bytes .../lucene_text_1719131524623/._SUCCESS.crc | Bin 8 -> 0 bytes .../lucene_text_1719131524623/.part-00000.crc | Bin 12 -> 0 bytes .../lucene_text_1719131524623/_SUCCESS | 0 .../lucene_text_1719131524623/part-00000 | Bin 95 -> 0 bytes .../lucene_text_1719291413827/._SUCCESS.crc | Bin 8 -> 0 bytes .../lucene_text_1719291413827/.part-00000.crc | Bin 3588 -> 0 bytes .../lucene_text_1719291413827/_SUCCESS | 0 .../lucene_text_1719291413827/part-00000 | Bin 457836 -> 0 bytes 59 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 checkpoint_dir/.metadata.crc delete mode 100644 checkpoint_dir/commits/.0.crc delete mode 100644 checkpoint_dir/commits/0 delete mode 100644 checkpoint_dir/metadata delete mode 100644 checkpoint_dir/offsets/.0.crc delete mode 100644 checkpoint_dir/offsets/.1.crc delete mode 100644 checkpoint_dir/offsets/0 delete mode 100644 checkpoint_dir/offsets/1 delete mode 100644 checkpoint_dir/sources/0/.0.crc delete mode 100644 checkpoint_dir/sources/0/0 delete mode 100644 checkpoint_dir_1/.metadata.crc delete mode 100644 checkpoint_dir_1/commits/.0.crc delete mode 100644 checkpoint_dir_1/commits/.1.crc delete mode 100644 checkpoint_dir_1/commits/.2.crc delete mode 100644 checkpoint_dir_1/commits/.3.crc delete mode 100644 checkpoint_dir_1/commits/0 delete mode 100644 checkpoint_dir_1/commits/1 delete mode 100644 checkpoint_dir_1/commits/2 delete mode 100644 checkpoint_dir_1/commits/3 delete mode 100644 checkpoint_dir_1/metadata delete mode 100644 checkpoint_dir_1/offsets/.0.crc delete mode 100644 checkpoint_dir_1/offsets/.1.crc delete mode 100644 checkpoint_dir_1/offsets/.2.crc delete mode 100644 checkpoint_dir_1/offsets/.3.crc delete mode 100644 checkpoint_dir_1/offsets/0 delete mode 100644 checkpoint_dir_1/offsets/1 delete mode 100644 checkpoint_dir_1/offsets/2 delete mode 100644 checkpoint_dir_1/offsets/3 delete mode 100644 checkpoint_dir_1/sources/0/.0.crc delete mode 100644 checkpoint_dir_1/sources/0/0 delete mode 100644 spark-warehouse/lucene_text_1714990337528/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1714990337528/.part-00000.gz.crc delete mode 100644 spark-warehouse/lucene_text_1714990337528/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1714990337528/part-00000.gz delete mode 100644 spark-warehouse/lucene_text_1715101627025/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1715101627025/.part-00000.gz.crc delete mode 100644 spark-warehouse/lucene_text_1715101627025/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1715101627025/part-00000.gz delete mode 100644 spark-warehouse/lucene_text_1715102057572/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1715102057572/.part-00000.crc delete mode 100644 spark-warehouse/lucene_text_1715102057572/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1715102057572/part-00000 delete mode 100644 spark-warehouse/lucene_text_1715147755491/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1715147755491/.part-00000.crc delete mode 100644 spark-warehouse/lucene_text_1715147755491/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1715147755491/part-00000 delete mode 100644 spark-warehouse/lucene_text_1715262452600/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1715262452600/.part-00000.crc delete mode 100644 spark-warehouse/lucene_text_1715262452600/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1715262452600/part-00000 delete mode 100644 spark-warehouse/lucene_text_1719131524623/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1719131524623/.part-00000.crc delete mode 100644 spark-warehouse/lucene_text_1719131524623/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1719131524623/part-00000 delete mode 100644 spark-warehouse/lucene_text_1719291413827/._SUCCESS.crc delete mode 100644 spark-warehouse/lucene_text_1719291413827/.part-00000.crc delete mode 100644 spark-warehouse/lucene_text_1719291413827/_SUCCESS delete mode 100644 spark-warehouse/lucene_text_1719291413827/part-00000 diff --git a/.gitignore b/.gitignore index 819dc185..23bc9bf2 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ project/plugins/project/ # Scala-IDE specific .scala_dependencies .worksheet +.bsp \ No newline at end of file diff --git a/checkpoint_dir/.metadata.crc b/checkpoint_dir/.metadata.crc deleted file mode 100644 index 97345d1b2df84cded89e1e0b8c402a636f4b1774..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12 TcmYc;N@ieSU}AX8`XU0ql39igbRBwl( zm#l!)%Ko77ZIKCm(+fL^EjE|(hMW3ZArCES?2s4EfiRm|OE5s?B{9qWZDov1VaBimy7)p^1-su!6;E({{=oAsV$1HOjRbp3qw~`p2 OokLMSoZ@d**5k$^B28id diff --git a/spark-warehouse/lucene_text_1714990337528/_SUCCESS b/spark-warehouse/lucene_text_1714990337528/_SUCCESS deleted file mode 100644 index e69de29b..00000000 diff --git a/spark-warehouse/lucene_text_1714990337528/part-00000.gz b/spark-warehouse/lucene_text_1714990337528/part-00000.gz deleted file mode 100644 index 2efcc8e07a0384289464e9c5217294acc7446205..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19369 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 diff --git a/spark-warehouse/lucene_text_1715101627025/._SUCCESS.crc b/spark-warehouse/lucene_text_1715101627025/._SUCCESS.crc deleted file mode 100644 index 3b7b044936a890cd8d651d349a752d819d71d22c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmYc;N@ieSU}69O2$TUk diff --git a/spark-warehouse/lucene_text_1715101627025/.part-00000.gz.crc b/spark-warehouse/lucene_text_1715101627025/.part-00000.gz.crc deleted file mode 100644 index e6038d3e585489cdf8b9522006857492e4c3c894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160 zcmV;R0AK%Oa$^7h00IDxY+cvVYan$&@1f-;pe+(MUA;WrIQ|3XuGO;tKMvj@>Bwl( zm#l!)%Ko77ZIKCm(+fL^EjE|(hMW3ZArCES?2s4EfiRm|OE5s?B{9qWZDov1VaBimy7)p^1-su!6;E({{=oAsV$1HOjRbp3qw~`p2 OokLMSoZ@d**5k$^B28id diff --git a/spark-warehouse/lucene_text_1715101627025/_SUCCESS b/spark-warehouse/lucene_text_1715101627025/_SUCCESS deleted file mode 100644 index e69de29b..00000000 diff --git a/spark-warehouse/lucene_text_1715101627025/part-00000.gz b/spark-warehouse/lucene_text_1715101627025/part-00000.gz deleted file mode 100644 index 2efcc8e07a0384289464e9c5217294acc7446205..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19369 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 diff --git a/spark-warehouse/lucene_text_1715102057572/._SUCCESS.crc b/spark-warehouse/lucene_text_1715102057572/._SUCCESS.crc deleted file mode 100644 index 3b7b044936a890cd8d651d349a752d819d71d22c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmYc;N@ieSU}69O2$TUk diff --git a/spark-warehouse/lucene_text_1715102057572/.part-00000.crc b/spark-warehouse/lucene_text_1715102057572/.part-00000.crc deleted file mode 100644 index 6e53c85115739e2a91a52ff55c7371f5b412ab8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1804 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 z 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 J_R^O-{{t@Qw8#Je diff --git a/spark-warehouse/lucene_text_1715262452600/._SUCCESS.crc b/spark-warehouse/lucene_text_1715262452600/._SUCCESS.crc deleted file mode 100644 index 3b7b044936a890cd8d651d349a752d819d71d22c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmYc;N@ieSU}69O2$TUk diff --git a/spark-warehouse/lucene_text_1715262452600/.part-00000.crc b/spark-warehouse/lucene_text_1715262452600/.part-00000.crc deleted file mode 100644 index 1982259b8c046166e3e0dc87755086888b9201aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1804 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 diff --git a/spark-warehouse/lucene_text_1719131524623/_SUCCESS b/spark-warehouse/lucene_text_1719131524623/_SUCCESS deleted file mode 100644 index e69de29b..00000000 diff --git a/spark-warehouse/lucene_text_1719131524623/part-00000 b/spark-warehouse/lucene_text_1719131524623/part-00000 deleted file mode 100644 index ec779f2548ba4cb615a052a0ce14729457c37856..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95 zcmWG`4P;ZyFG|--EJ#ewNY%?oOv%qL(96u%^DE8C2`|blNleN~Rl=&msj?)s7^Z{) W4E_XumD<+PqW<8yD__#|_dEbnAtMF= diff --git a/spark-warehouse/lucene_text_1719291413827/._SUCCESS.crc b/spark-warehouse/lucene_text_1719291413827/._SUCCESS.crc deleted file mode 100644 index 3b7b044936a890cd8d651d349a752d819d71d22c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmYc;N@ieSU}69O2$TUk diff --git a/spark-warehouse/lucene_text_1719291413827/.part-00000.crc b/spark-warehouse/lucene_text_1719291413827/.part-00000.crc deleted file mode 100644 index 422c04f30737a4c5032e2e5e44a3294dc162db0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3588 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 K64Oe!9`oYoQU*By diff --git a/spark-warehouse/lucene_text_1719291413827/_SUCCESS b/spark-warehouse/lucene_text_1719291413827/_SUCCESS deleted file mode 100644 index e69de29b..00000000 diff --git a/spark-warehouse/lucene_text_1719291413827/part-00000 b/spark-warehouse/lucene_text_1719291413827/part-00000 deleted file mode 100644 index 375e8d213ec7f938cff2699a2db4097be9698da6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 457836 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 Date: Mon, 16 Sep 2024 19:06:48 +0530 Subject: [PATCH 5/8] Update gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 23bc9bf2..079be671 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ project/plugins/project/ # Scala-IDE specific .scala_dependencies .worksheet -.bsp \ No newline at end of file +.bsp + +src/main/scala/com/* \ No newline at end of file From 5a7b26c26b65622104b00ff5b760b65a49c5ffdc Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Mon, 16 Sep 2024 19:13:24 +0530 Subject: [PATCH 6/8] Remove S3 Directory Library --- .../com/erudika/lucene/store/s3/Main.java | 24 -- .../erudika/lucene/store/s3/S3Directory.java | 390 ------------------ .../lucene/store/s3/S3DirectorySettings.java | 148 ------- .../lucene/store/s3/S3FileEntrySettings.java | 218 ---------- .../lucene/store/s3/S3FileSystemStore.java | 26 -- .../lucene/store/s3/S3SingletonClient.java | 36 -- .../lucene/store/s3/S3StoreException.java | 142 ------- .../s3/handler/AbstractFileEntryHandler.java | 165 -------- .../handler/ActualDeleteFileEntryHandler.java | 32 -- .../store/s3/handler/FileEntryHandler.java | 116 ------ .../s3/handler/NoOpFileEntryHandler.java | 172 -------- .../store/s3/index/AbstractS3IndexOutput.java | 77 ---- .../index/ConfigurableBufferedIndexInput.java | 204 --------- .../ConfigurableBufferedIndexOutput.java | 155 ------- .../index/FetchOnBufferReadS3IndexInput.java | 222 ---------- .../s3/index/FetchOnOpenS3IndexInput.java | 109 ----- .../store/s3/index/RAMS3IndexOutput.java | 261 ------------ .../store/s3/index/S3BufferedIndexInput.java | 45 -- .../store/s3/index/S3BufferedIndexOutput.java | 45 -- .../store/s3/index/S3IndexConfigurable.java | 41 -- .../lucene/store/s3/index/S3IndexInput.java | 154 ------- .../lucene/store/s3/lock/NoOpLock.java | 49 --- .../lucene/store/s3/lock/S3LegalHoldLock.java | 122 ------ .../erudika/lucene/store/s3/lock/S3Lock.java | 42 -- .../store/s3/support/LuceneFileNames.java | 76 ---- 25 files changed, 3071 deletions(-) delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/Main.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3Directory.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java delete mode 100644 src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java diff --git a/src/main/scala/com/erudika/lucene/store/s3/Main.java b/src/main/scala/com/erudika/lucene/store/s3/Main.java deleted file mode 100644 index 4e3814eb..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/Main.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.erudika.lucene.store.s3; - -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.IOContext; - -import java.io.IOException; -import java.util.Arrays; - -public class Main { - public static void main(String[] args) { - try { - Directory directory = new S3Directory("lucene-test", "lucene-kashyap"); - - System.out.println(Arrays.toString(directory.listAll())); - - System.out.println(directory.fileLength("_b_Lucene84_0.doc")); - - System.out.println(directory.openChecksumInput("_b_Lucene84_0.doc", new IOContext()).getChecksum()); - - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3Directory.java b/src/main/scala/com/erudika/lucene/store/s3/S3Directory.java deleted file mode 100644 index d419573d..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/S3Directory.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3; - -import com.erudika.lucene.store.s3.handler.FileEntryHandler; -import com.erudika.lucene.store.s3.lock.NoOpLock; -import com.erudika.lucene.store.s3.lock.S3LegalHoldLock; -import com.erudika.lucene.store.s3.lock.S3Lock; -import com.erudika.lucene.store.s3.support.LuceneFileNames; -import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.store.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; -import software.amazon.awssdk.awscore.exception.AwsServiceException; -import software.amazon.awssdk.core.exception.SdkClientException; -import software.amazon.awssdk.core.sync.RequestBody; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; -import software.amazon.awssdk.services.s3.model.ObjectIdentifier; -import software.amazon.awssdk.services.s3.model.S3Object; -import software.amazon.awssdk.services.s3.paginators.ListObjectsV2Iterable; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -/** - * A S3 based implementation of a Lucene Directory allowing the storage of a Lucene index within S3. - * The directory works against a single bucket, where the binary data is stored in objects. - * Each "object" has an entry in the S3, and different {@link com.erudika.lucene.store.s3.handler.FileEntryHandler} - * can be defines for different files (or files groups). - * - * @author kimchy - */ -public class S3Directory extends Directory { - - private static final Logger logger = LoggerFactory.getLogger(S3Directory.class); - - private S3DirectorySettings settings; - - private final ConcurrentHashMap fileSizes = new ConcurrentHashMap<>(); - - private final HashMap fileEntryHandlers = new HashMap(); - - private String bucket; - - private String path; - - private final S3Client s3 = S3SingletonClient.getS3Client(); - - /** - * Creates a new S3 directory. - * - * @param bucketName The bucket name - * @throws S3StoreException - */ - public S3Directory(final String bucketName, final String pathName) throws S3StoreException { - initialize(bucketName, pathName, new S3DirectorySettings()); - } - - /** - * Creates a new S3 directory. - * - * @param bucketName The table name that will be used - * @param settings The settings to configure the directory - */ - public S3Directory(final String bucketName, final String pathName, final S3DirectorySettings settings) { - initialize(bucketName, pathName, settings); - } - - private void initialize(final String bucket, final String path, S3DirectorySettings settings) { - this.bucket = bucket.toLowerCase(); - this.path = path; - this.settings = settings; - final Map fileEntrySettings = settings.getFileEntrySettings(); - // go over all the file entry settings and configure them - for (final String name : fileEntrySettings.keySet()) { - final S3FileEntrySettings feSettings = fileEntrySettings.get(name); - try { - final Class fileEntryHandlerClass = feSettings - .getSettingAsClass(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, null); - final FileEntryHandler fileEntryHandler = (FileEntryHandler) fileEntryHandlerClass.getConstructor().newInstance(); - fileEntryHandler.configure(this); - fileEntryHandlers.put(name, fileEntryHandler); - } catch (final Exception e) { - throw new IllegalArgumentException("Failed to create FileEntryHandler [" - + feSettings.getSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE) + "]"); - } - } - logger.info(fileEntrySettings.entrySet().stream().map(e -> e.getKey() + " -> " + e.getValue()).collect(Collectors.joining(", "))); - } - - /** - * ******************************************************************************************** - * CUSTOM METHODS - * ******************************************************************************************** - */ - - /** - * Returns true if the S3 bucket exists. - * - * @return true if the S3 bucket exists, false otherwise - * @throws IOException - * @throws UnsupportedOperationException If the S3 dialect does not support it - */ - public boolean bucketExists() { - try { - if (logger.isDebugEnabled()) { - logger.info("bucketExists({})", bucket); - } - s3.headBucket(b -> b.bucket(bucket)); - return true; - } catch (AwsServiceException | SdkClientException e) { - return false; - } - } - - /** - * @param name - * @return - * @throws IOException - */ - public boolean fileExists(final String name) throws IOException { - return getFileEntryHandler(name).fileExists(name); - } - - /** - * Deletes the S3 bucket (drops it) from the S3. - */ - public void delete() { - if (bucketExists()) { - if (logger.isDebugEnabled()) { - logger.info("delete({})", bucket); - } - emptyBucket(); - try { - s3.deleteBucket(b -> b.bucket(bucket)); - } catch (Exception e) { - logger.error("Bucket {} not empty - [{}]", bucket, e); - } - } - } - - /** - * Creates a new S3 bucket. - * - * @throws IOException - */ - public void create() { - if (!bucketExists()) { - if (logger.isDebugEnabled()) { - logger.info("create({})", bucket); - } - s3.createBucket(b -> b.bucket(bucket).objectLockEnabledForBucket(true)); - } - try { - if (logger.isDebugEnabled()) { - logger.info("write.lock created in {}", bucket); - } - // initialize the write.lock file immediately after bucket creation - s3.putObject(b -> b.bucket(bucket).key(IndexWriter.WRITE_LOCK_NAME), RequestBody.empty()); - } catch (Exception e) { } - } - - /** - * Empties a bucket on S3. - */ - public void emptyBucket() { - deleteObjectVersions(null); - } - - /** - * Deletes all object versions for a given prefix. If prefix is null, all objects are deleted. - * @param prefix a key prefix for filtering - */ - private void deleteObjectVersions(String prefix) { - LinkedList objects = new LinkedList<>(); - s3.listObjectVersionsPaginator(b -> b.bucket(bucket).prefix(prefix)).forEach((response) -> { - if (logger.isDebugEnabled()) { - logger.info("deleteContent({}, {})", bucket, response.versions().size()); - } - response.versions().forEach((content) -> { - objects.add(ObjectIdentifier.builder().key(content.key()).versionId(content.versionId()).build()); - }); - }); - - List keyz = new LinkedList<>(); - for (ObjectIdentifier key : objects) { - keyz.add(key); - if (keyz.size() >= 1000) { - s3.deleteObjects(b -> b.bucket(bucket).delete(bd -> bd.objects(keyz))); - keyz.clear(); - } - fileSizes.remove(key.key()); - } - if (!keyz.isEmpty()) { - s3.deleteObjects(b -> b.bucket(bucket).delete(bd -> bd.objects(keyz))); - } - } - - /** - * @param name - * @throws IOException - */ - public void forceDeleteFile(final String name) throws IOException { - if (logger.isDebugEnabled()) { - logger.info("forceDeleteFile({})", name); - } - deleteObjectVersions(name); - } - - /** - * @return @throws IOException - */ - protected Lock createLock() throws IOException { - return new NoOpLock(); - } - - /** - * @param name - * @return - */ - protected FileEntryHandler getFileEntryHandler(final String name) { - FileEntryHandler handler = fileEntryHandlers.get(name.substring(name.length() - 3)); - if (handler != null) { - return handler; - } - handler = fileEntryHandlers.get(name); - if (handler != null) { - return handler; - } - return fileEntryHandlers.get(S3DirectorySettings.DEFAULT_FILE_ENTRY); - } - - /** - * ******************************************************************************************** - * DIRECTORY METHODS - * ******************************************************************************************** - */ - @Override - public String[] listAll() { - if (logger.isDebugEnabled()) { - logger.info("listAll({})", bucket); - } - final LinkedList names = new LinkedList<>(); - try { - ListObjectsV2Iterable responses = s3.listObjectsV2Paginator(b -> b.bucket(bucket)); - for (ListObjectsV2Response response : responses) { - names.addAll(response.contents().stream().map(S3Object::key).toList()); - } - } catch (Exception e) { - logger.error("{}", e.toString()); - } - - return names.toArray(new String[]{}); - } - - @Override - public void deleteFile(final String name) throws IOException { - if (LuceneFileNames.isStaticFile(name)) { - // TODO is necessary?? - logger.warn("S3Directory.deleteFile({}), is static file", name); - forceDeleteFile(name); - } else { - getFileEntryHandler(name).deleteFile(name); - } - } - - @Override - public long fileLength(final String name) throws IOException { - return getFileEntryHandler(name).fileLength(name); - } - - @Override - public IndexOutput createOutput(final String name, final IOContext context) throws IOException { - if (LuceneFileNames.isStaticFile(name)) { - // TODO is necessary?? - logger.warn("S3Directory.createOutput({}), is static file", name); - forceDeleteFile(name); - } - return getFileEntryHandler(name).createOutput(name); - } - - @Override - public IndexInput openInput(final String name, final IOContext context) throws IOException { - return getFileEntryHandler(name).openInput(name); - } - - @Override - public void sync(final Collection names) throws IOException { - logger.warn("S3Directory.sync({})", names); - for (final String name : names) { - if (!fileExists(name)) { - throw new S3StoreException("Failed to sync, file " + name + " not found"); - } - } - } - - @Override - public void rename(final String from, final String to) throws IOException { - getFileEntryHandler(from).renameFile(from, to); - } - - @Override - public Lock obtainLock(final String name) throws IOException { - final Lock lock = createLock(); - ((S3Lock) lock).configure(this, name); - ((S3Lock) lock).obtain(); - return lock; -// return new NoOpLock(); - } - - @Override - public void close() throws IOException { - IOException last = null; - for (final FileEntryHandler fileEntryHandler : fileEntryHandlers.values()) { - try { - fileEntryHandler.close(); - } catch (final IOException e) { - last = e; - } - } - if (last != null) { - throw last; - } - } - - @Override - public IndexOutput createTempOutput(String prefix, String suffix, IOContext context) throws IOException { - String name = prefix.concat("_temp_").concat(suffix).concat(".tmp"); - if (LuceneFileNames.isStaticFile(name)) { - // TODO is necessary?? - logger.warn("S3Directory.createOutput({}), is static file", name); - forceDeleteFile(name); - } - return getFileEntryHandler(name).createOutput(name); - } - - @Override - public void syncMetaData() throws IOException { - } - - /** - * ********************************************************************************************* - * SETTER/GETTERS METHODS - * ********************************************************************************************* - */ - public String getBucket() { - return bucket; - } - - public String getPath() { - return path; - } - - public S3DirectorySettings getSettings() { - return settings; - } - - public S3Client getS3() { - return s3; - } - - public ConcurrentHashMap getFileSizes() { - return fileSizes; - } - - @Override - public Set getPendingDeletions() throws IOException { - return Collections.emptySet(); - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java b/src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java deleted file mode 100644 index b8afcb2f..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/S3DirectorySettings.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3; - -import com.erudika.lucene.store.s3.handler.ActualDeleteFileEntryHandler; -import com.erudika.lucene.store.s3.handler.NoOpFileEntryHandler; -import com.erudika.lucene.store.s3.index.FetchOnOpenS3IndexInput; -import com.erudika.lucene.store.s3.index.RAMS3IndexOutput; -import com.erudika.lucene.store.s3.index.S3IndexInput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; - -/** - * General directory level settings. - *

- * The settings also holds {@link S3FileEntrySettings}, that can be registered with the directory settings. Note, that - * when registering them, they are registered under both the complete name and the 3 charecters name suffix. - *

- * When creating the settings, it already holds sensible settings, they are: The default {@link S3FileEntrySettings} - * uses the file entry settings defaults. The "deletable", ""deleteable.new", and "deletable.new" uses the - * {@link org.apache.lucene.store.s3.handler.NoOpFileEntryHandler}. The "segments" and "segments.new" uses the null {@link org.apache.lucene.store.s3.handler.ActualDeleteFileEntryHandler}, - * {@link org.apache.lucene.store.s3.index.FetchOnOpenS3IndexInput}, and - * {@link org.apache.lucene.store.s3.index.RAMS3IndexOutput}. The file suffix "fnm" uses the - * {@link org.apache.lucene.store.s3.index.FetchOnOpenS3IndexInput}, and - * {@link org.apache.lucene.store.s3.index.RAMS3IndexOutput}. The file suffix "del" and "tmp" uses the - * {@link org.apache.lucene.store.s3.handler.ActualDeleteFileEntryHandler}. - * - * @author kimchy - */ -public class S3DirectorySettings { - - /** - * The default file entry settings name that are registered under. - */ - public static String DEFAULT_FILE_ENTRY = "__default__"; - private static final Logger logger = LoggerFactory.getLogger(S3DirectorySettings.class); - - /** - * A simple constant having the millisecond value of an hour. - */ - public static final long HOUR = 60 * 60 * 1000; - - private final HashMap fileEntrySettings = new HashMap(); - - /** - * Creates a new instance of the S3 directory settings with it's default values initialized. - */ - public S3DirectorySettings() { - final S3FileEntrySettings defaultSettings = new S3FileEntrySettings(); - fileEntrySettings.put(DEFAULT_FILE_ENTRY, defaultSettings); - - final S3FileEntrySettings deletableSettings = new S3FileEntrySettings(); - deletableSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, NoOpFileEntryHandler.class); - fileEntrySettings.put("deletable", deletableSettings); - fileEntrySettings.put("deleteable.new", deletableSettings); - // in case lucene fix the spelling mistake - fileEntrySettings.put("deletable.new", deletableSettings); - - final S3FileEntrySettings segmentsSettings = new S3FileEntrySettings(); - segmentsSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, ActualDeleteFileEntryHandler.class); - //todo -// segmentsSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, FetchOnOpenS3IndexInput.class); - segmentsSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, S3IndexInput.class); - segmentsSettings.setClassSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, RAMS3IndexOutput.class); - fileEntrySettings.put("segments", segmentsSettings); - fileEntrySettings.put("segments.new", segmentsSettings); - fileEntrySettings.put("doc", segmentsSettings); - - final S3FileEntrySettings dotDelSettings = new S3FileEntrySettings(); - dotDelSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, - ActualDeleteFileEntryHandler.class); - fileEntrySettings.put("del", dotDelSettings); - - final S3FileEntrySettings tmpSettings = new S3FileEntrySettings(); - tmpSettings.setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, ActualDeleteFileEntryHandler.class); - fileEntrySettings.put("tmp", dotDelSettings); - - final S3FileEntrySettings fnmSettings = new S3FileEntrySettings(); -// fnmSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, FetchOnOpenS3IndexInput.class); - fnmSettings.setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, S3IndexInput.class); - fnmSettings.setClassSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, RAMS3IndexOutput.class); - fileEntrySettings.put("fnm", fnmSettings); - } - - /** - * Registers a {@link S3FileEntrySettings} against the given name. The name can be the full name of the file, or - * it's 3 charecters suffix. - */ - public void registerFileEntrySettings(final String name, final S3FileEntrySettings fileEntrySettings) { - this.fileEntrySettings.put(name, fileEntrySettings); - } - - /** - * Returns the file entries map. Please don't change it during runtime. - */ - public Map getFileEntrySettings() { - return fileEntrySettings; - } - - /** - * Returns the file entries according to the name. If a direct match is found, it's registered - * {@link S3FileEntrySettings} is returned. If one is registered against the last 3 charecters, then it is returned. - * If none is found, the default file entry handler is returned. - */ - public S3FileEntrySettings getFileEntrySettings(final String name) { - final S3FileEntrySettings settings = getFileEntrySettingsWithoutDefault(name); - if (settings != null) { - return settings; - } - return getDefaultFileEntrySettings(); - } - - /** - * Same as {@link #getFileEntrySettings(String)}, only returns null if no match is found (instead of - * the default file entry handler settings). - */ - public S3FileEntrySettings getFileEntrySettingsWithoutDefault(final String name) { - final S3FileEntrySettings settings = fileEntrySettings.get(name.substring(name.length() - 3)); - if (settings != null) { - return settings; - } - return fileEntrySettings.get(name); - } - - /** - * Returns the default file entry handler settings. - */ - public S3FileEntrySettings getDefaultFileEntrySettings() { - logger.info("Returning default file entry settings"); - return fileEntrySettings.get(DEFAULT_FILE_ENTRY); - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java b/src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java deleted file mode 100644 index 32a4b31f..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/S3FileEntrySettings.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3; - -import com.erudika.lucene.store.s3.handler.ActualDeleteFileEntryHandler; -import com.erudika.lucene.store.s3.index.FetchOnBufferReadS3IndexInput; -import com.erudika.lucene.store.s3.index.RAMS3IndexOutput; -import com.erudika.lucene.store.s3.index.S3IndexInput; - -import java.util.Properties; - -/** - * A file entry level settings. An abstract view of any type of setting that cab be used by the actual file entry - * handler that uses it. - *

- * Holds the {@link #FILE_ENTRY_HANDLER_TYPE} that defines the type of the - * {@link com.erudika.lucene.store.s3.handler.FileEntryHandler} that will be created and initialized with the settings. - *

- * Default values for a new instanciated instnce are: - * {@link com.erudika.lucene.store.s3.handler.MarkDeleteFileEntryHandler} for the {@link #FILE_ENTRY_HANDLER_TYPE} - * setting, {@link com.erudika.lucene.store.s3.index.FetchOnBufferReadS3IndexInput} for the - * {@link #INDEX_INPUT_TYPE_SETTING} setting, and {@link org.apache.lucene.store.s3.index.RAMAndFileS3IndexOutput} for - * the {@link #INDEX_OUTPUT_TYPE_SETTING} setting. - * - * @author kimchy - */ -public class S3FileEntrySettings { - - /** - * The class name of the {@link org.apache.lucene.store.IndexInput}. Only applies to - * {@link org.apache.lucene.store.s3.handler.FileEntryHandler}s that use it. - */ - public static final String INDEX_INPUT_TYPE_SETTING = "indexInput.type"; - - /** - * The class name of the {@link org.apache.lucene.store.IndexOutput}. Only applies to - * {@link org.apache.lucene.store.s3.handler.FileEntryHandler}s that use it. - */ - public static final String INDEX_OUTPUT_TYPE_SETTING = "indexOutput.type"; - - /** - * The class name of the {@link org.apache.lucene.store.s3.handler.FileEntryHandler}. - */ - public static final String FILE_ENTRY_HANDLER_TYPE = "type"; - - private final Properties settings = new Properties(); - - /** - * Creates a new file entry settings, and intialize it to default values. - */ - public S3FileEntrySettings() { - setClassSetting(S3FileEntrySettings.FILE_ENTRY_HANDLER_TYPE, ActualDeleteFileEntryHandler.class); - //TODO: Fix this -// setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, FetchOnBufferReadS3IndexInput.class); - setClassSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, S3IndexInput.class); - setClassSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, RAMS3IndexOutput.class); - } - - /** - * Returns the inner java properties. - */ - public Properties getProperties() { - return settings; - } - - /** - * Returns the value match for the given setting. null if no setting is found. - * - * @param setting The setting name - * @return The value of the setting, or null if none is found - */ - public String getSetting(final String setting) { - return settings.getProperty(setting); - } - - /** - * Returns the value that matches the given setting. If none is found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @return The value of the setting, or defaultValue if none is found. - */ - public String getSetting(final String setting, final String defaultValue) { - return settings.getProperty(setting, defaultValue); - } - - /** - * Returns the float value that matches the given setting. If none if found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @return The value of the setting, or defaultValue if none is found. - */ - public float getSettingAsFloat(final String setting, final float defaultValue) { - final String sValue = getSetting(setting); - if (sValue == null) { - return defaultValue; - } - return Float.parseFloat(sValue); - } - - /** - * Returns the int value that matches the given setting. If none if found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @return The value of the setting, or defaultValue if none is found. - */ - public int getSettingAsInt(final String setting, final int defaultValue) { - final String sValue = getSetting(setting); - if (sValue == null) { - return defaultValue; - } - return Integer.parseInt(sValue); - } - - /** - * Returns the long value that matches the given setting. If none if found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @return The value of the setting, or defaultValue if none is found. - */ - public long getSettingAsLong(final String setting, final long defaultValue) { - final String sValue = getSetting(setting); - if (sValue == null) { - return defaultValue; - } - return Long.parseLong(sValue); - } - - /** - * Returns the class value that matches the given setting. If none if found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @return The value of the setting, or defaultValue if none is found. - */ - public Class getSettingAsClass(final String setting, final Class defaultValue) throws ClassNotFoundException { - return getSettingAsClass(setting, defaultValue, Thread.currentThread().getContextClassLoader()); - } - - /** - * Returns the class value that matches the given setting. If none if found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @param classLoader The class loader to be used to load the class - * @return The value of the setting, or defaultValue if none is found. - * @throws ClassNotFoundException - */ - public Class getSettingAsClass(final String setting, final Class defaultValue, final ClassLoader classLoader) - throws ClassNotFoundException { - final String sValue = getSetting(setting); - if (sValue == null) { - return defaultValue; - } - return Class.forName(sValue, true, classLoader); - } - - /** - * Returns the boolean value that matches the given setting. If none if found, the default value is used. - * - * @param setting The setting name - * @param defaultValue The default value to be used if no setting is found - * @return The value of the setting, or defaultValue if none is found. - */ - public boolean getSettingAsBoolean(final String setting, final boolean defaultValue) { - final String sValue = getSetting(setting); - if (sValue == null) { - return defaultValue; - } - return Boolean.valueOf(sValue).booleanValue(); - } - - public S3FileEntrySettings setSetting(final String setting, final String value) { - settings.setProperty(setting, value); - return this; - } - - public S3FileEntrySettings setBooleanSetting(final String setting, final boolean value) { - setSetting(setting, String.valueOf(value)); - return this; - } - - public S3FileEntrySettings setFloatSetting(final String setting, final float value) { - setSetting(setting, String.valueOf(value)); - return this; - } - - public S3FileEntrySettings setIntSetting(final String setting, final int value) { - setSetting(setting, String.valueOf(value)); - return this; - } - - public S3FileEntrySettings setLongSetting(final String setting, final long value) { - setSetting(setting, String.valueOf(value)); - return this; - } - - public S3FileEntrySettings setClassSetting(final String setting, final Class clazz) { - setSetting(setting, clazz.getName()); - return this; - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java b/src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java deleted file mode 100644 index 4a35d6b1..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/S3FileSystemStore.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.erudika.lucene.store.s3; - -import java.io.IOException; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.util.HashMap; - -public class S3FileSystemStore { - private static FileSystem fileSystem; - private static FileSystem fileSystem2; - - public static FileSystem getS3FileSystem() throws IOException { - if (fileSystem == null) { - fileSystem = FileSystems.newFileSystem(URI.create("s3://lucene-test"), new HashMap()); - } - return fileSystem; - } - - public static FileSystem getTaxonomyS3FileSystem() throws IOException { - if (fileSystem2 == null) { - fileSystem2 = FileSystems.newFileSystem(URI.create("s3://avinash-test-1"), new HashMap()); - } - return fileSystem2; - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java b/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java deleted file mode 100644 index db5937b8..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/S3SingletonClient.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.erudika.lucene.store.s3; - -import com.amazonaws.ClientConfiguration; -import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.s3.S3Client; - -public class S3SingletonClient { - private static S3Client s3Client; - - private S3SingletonClient(){ - - } - - public static S3Client getS3Client(){ - if(s3Client == null){ - - ClientConfiguration clientConfiguration = new ClientConfiguration() - .withMaxErrorRetry(10) - .withMaxConnections(1000); - - s3Client = S3Client.builder() - .credentialsProvider(() -> new AwsSessionCredentials - .Builder() -// .accessKeyId("") //This is from E2E account -// .secretAccessKey("") -// .sessionToken("") - .build() - ) - .region(Region.US_WEST_2) - .build(); - } - return s3Client; - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java b/src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java deleted file mode 100644 index 4beb7e15..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/S3StoreException.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3; - -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; - -/** - * A nestable checked S3 exception. - * - * @author kimchy - */ -public class S3StoreException extends IOException { - - private static final long serialVersionUID = 6238846660780283933L; - - /** - * Root cause of this nested exception - */ - private Throwable cause; - - /** - * Construct a S3StoreException with the specified detail message. - * - * @param msg the detail message - */ - public S3StoreException(final String msg) { - super(msg); - } - - /** - * Construct a S3StoreException with the specified detail message and nested exception. - * - * @param msg the detail message - * @param ex the nested exception - */ - public S3StoreException(final String msg, final Throwable ex) { - super(msg); - cause = ex; - } - - /** - * Return the nested cause, or null if none. - */ - @Override - public Throwable getCause() { - // Even if you cannot set the cause of this exception other than through - // the constructor, we check for the cause being "this" here, as the - // cause - // could still be set to "this" via reflection: for example, by a - // remoting - // deserializer like Hessian's. - return cause == this ? null : cause; - } - - /** - * Return the detail message, including the message from the nested exception if there is one. - */ - @Override - public String getMessage() { - if (getCause() == null) { - return super.getMessage(); - } else { - return super.getMessage() + "; nested exception is " + getCause().getClass().getName() + ": " - + getCause().getMessage(); - } - } - - /** - * Print the composite message and the embedded stack trace to the specified stream. - * - * @param ps the print stream - */ - @Override - public void printStackTrace(final PrintStream ps) { - if (getCause() == null) { - super.printStackTrace(ps); - } else { - ps.println(this); - getCause().printStackTrace(ps); - } - } - - /** - * Print the composite message and the embedded stack trace to the specified print writer. - * - * @param pw the print writer - */ - @Override - public void printStackTrace(final PrintWriter pw) { - if (getCause() == null) { - super.printStackTrace(pw); - } else { - pw.println(this); - getCause().printStackTrace(pw); - } - } - - /** - * Check whether this exception contains an exception of the given class: either it is of the given class itself or - * it contains a nested cause of the given class. - *

- * Currently just traverses S3StoreException causes. Will use the JDK 1.4 exception cause mechanism once requires - * JDK 1.4. - * - * @param exClass the exception class to look for - */ - public boolean contains(final Class exClass) { - if (exClass == null) { - return false; - } - Throwable ex = this; - while (ex != null) { - if (exClass.isInstance(ex)) { - return true; - } - if (ex instanceof S3StoreException) { - // Cast is necessary on JDK 1.3, where Throwable does not - // provide a "getCause" method itself. - ex = ex.getCause(); - } else { - ex = null; - } - } - return false; - } - -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java deleted file mode 100644 index ea13ab9c..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/handler/AbstractFileEntryHandler.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.handler; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; -import com.erudika.lucene.store.s3.S3StoreException; -import com.erudika.lucene.store.s3.index.S3IndexConfigurable; -import org.apache.lucene.store.IndexInput; -import org.apache.lucene.store.IndexOutput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.awscore.exception.AwsServiceException; -import software.amazon.awssdk.core.ResponseInputStream; -import software.amazon.awssdk.core.exception.SdkClientException; -import software.amazon.awssdk.core.sync.RequestBody; -import software.amazon.awssdk.services.s3.model.GetObjectResponse; - -import java.io.IOException; - -/** - * A base file entry handler that supports most of the file entry base operations. - *

- * Supports the creation of configurable IndexInput and IndexOutput, base on the - * {@link S3FileEntrySettings#INDEX_INPUT_TYPE_SETTING} and {@link S3FileEntrySettings#INDEX_OUTPUT_TYPE_SETTING}. - *

- * Does not implement the deletion of files. - * - * @author kimchy - */ -public abstract class AbstractFileEntryHandler implements FileEntryHandler { - - private static final Logger logger = LoggerFactory.getLogger(AbstractFileEntryHandler.class); - - protected S3Directory s3Directory; - - protected String bucket; - - @Override - public void configure(final S3Directory s3Directory) { - this.s3Directory = s3Directory; - bucket = s3Directory.getBucket(); - } - - @Override - public boolean fileExists(final String name) throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("fileExists({})", name); - } - s3Directory.getS3().headObject(b -> b.bucket(bucket).key(name)); - return true; - } catch (AwsServiceException | SdkClientException e) { - return false; - } - } - - @Override - public long fileModified(final String name) throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("fileModified({})", name); - } - ResponseInputStream res = s3Directory.getS3().getObject(b -> b.bucket(bucket).key(name)); - return res.response().lastModified().toEpochMilli(); - } catch (Exception e) { - return 0L; - } - } - - @Override - public void touchFile(final String name) throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("touchFile({})", name); - } - ResponseInputStream res = s3Directory.getS3().getObject(b -> b.bucket(bucket).key(name)); - - s3Directory.getS3().putObject(b -> b.bucket(bucket).key(name), - RequestBody.fromInputStream(res, res.response().contentLength())); - } catch (Exception e) { - logger.error(null, e); - } - } - - @Override - public void renameFile(final String from, final String to) throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("renameFile({}, {})", from, to); - } - s3Directory.getS3().copyObject(b -> b.sourceBucket(bucket).sourceKey(from).destinationBucket(bucket).destinationKey(to)); - s3Directory.getFileSizes().put(to, s3Directory.getFileSizes().remove(from)); - deleteFile(from); - } catch (Exception e) { - logger.error(null, e); - } - } - - @Override - public long fileLength(final String name) throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("fileLength({})", name); - } - return s3Directory.getFileSizes().computeIfAbsent(name, n -> - s3Directory.getS3().getObject(b -> b.bucket(bucket).key(name)).response().contentLength() - ); - } catch (Exception e) { - logger.error(null, e); - return 0L; - } - } - - @Override - public IndexInput openInput(final String name) throws IOException { - IndexInput indexInput; - logger.info("openInput called with : {}", name); - final S3FileEntrySettings settings = s3Directory.getSettings().getFileEntrySettings(name); - try { - final Class inputClass = settings.getSettingAsClass(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING, null); - indexInput = (IndexInput) inputClass.getConstructor().newInstance(); - } catch (final Exception e) { - throw new S3StoreException("Failed to create indexInput instance [" - + settings.getSetting(S3FileEntrySettings.INDEX_INPUT_TYPE_SETTING) + "]", e); - } - ((S3IndexConfigurable) indexInput).configure(name, s3Directory, settings); - return indexInput; - } - - @Override - public IndexOutput createOutput(final String name) throws IOException { - IndexOutput indexOutput; - logger.info("createOutput called with : "+name); - final S3FileEntrySettings settings = s3Directory.getSettings().getFileEntrySettings(name); - try { - final Class inputClass = settings.getSettingAsClass(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING, - null); - indexOutput = (IndexOutput) inputClass.getConstructor(String.class).newInstance(name); - } catch (final Exception e) { - throw new S3StoreException("Failed to create indexOutput instance [" - + settings.getSetting(S3FileEntrySettings.INDEX_OUTPUT_TYPE_SETTING) + "]", e); - } - ((S3IndexConfigurable) indexOutput).configure(name, s3Directory, settings); - return indexOutput; - } - - @Override - public void close() throws IOException { - // do nothing - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java deleted file mode 100644 index 77129e19..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/handler/ActualDeleteFileEntryHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.handler; - -import java.io.IOException; - -/** - * Removes file entries from the database by deleting the relevant rows from the database. - * - * @author kimchy - */ -public class ActualDeleteFileEntryHandler extends AbstractFileEntryHandler { - - @Override - public void deleteFile(final String name) throws IOException { - s3Directory.forceDeleteFile(name); - s3Directory.getFileSizes().remove(name); - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java deleted file mode 100644 index 543eda7b..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/handler/FileEntryHandler.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.handler; - -import com.erudika.lucene.store.s3.S3Directory; -import org.apache.lucene.store.IndexInput; -import org.apache.lucene.store.IndexOutput; - -import java.io.IOException; - -/** - * A file entry handler acts as a delegate to the {@link S3Directory} for all "file" level operations. Allows the - * {@link S3Directory} to be abstracted from any specific implementation details regarding a file entry, and have - * several different file entries for different files or files groups. - * - * @author kimchy - * @see com.erudika.lucene.store.s3.S3DirectorySettings#registerFileEntrySettings(String, - * com.erudika.lucene.store.s3.S3FileEntrySettings) - */ -public interface FileEntryHandler { - - /** - * Called after the entry is created (during the {@link S3Directory} initialization process. - */ - void configure(S3Directory s3Directory); - - /** - * Checks if the file exists for the given file name. - * - * @param name The name of the file - * @return true of the file exists, false if it does not. - * @throws IOException - */ - boolean fileExists(final String name) throws IOException; - - /** - * Returns the last modified date of the file. - * - * @param name The name of the file - * @return The last modified date in millis. - * @throws IOException - */ - long fileModified(final String name) throws IOException; - - /** - * Updates the last modified date of the file to the current time. - * - * @param name The name of the file - * @throws IOException - */ - void touchFile(final String name) throws IOException; - - /** - * Deletes the given file name. - * - * @param name The name of the file to delete - * @throws IOException - */ - void deleteFile(final String name) throws IOException; - - /** - * Renames the file entry from "from" to "to". The from entry is the one that maps to the actual file entry handler. - * - * @param from The name to rename from - * @param to The name to rename to - * @throws IOException - */ - void renameFile(final String from, final String to) throws IOException; - - /** - * Returns the length of the file (in bytes). - * - * @param name The name of the file - * @return The length of the file (in bytes) - * @throws IOException - */ - long fileLength(final String name) throws IOException; - - /** - * Opens an IndexInput in order to read the file contents. - * - * @param name The name of the file - * @return An IndexInput in order to read the file contents. - * @throws IOException - */ - IndexInput openInput(String name) throws IOException; - - /** - * Creates an IndexOutput in order to write the file contents. - * - * @param name The name of the file - * @return An IndexOutput to write the file contents - * @throws IOException - */ - IndexOutput createOutput(String name) throws IOException; - - /** - * Closes the file entry handler. - * - * @throws IOException - */ - void close() throws IOException; -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java b/src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java deleted file mode 100644 index fa63727a..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/handler/NoOpFileEntryHandler.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.handler; - -import com.erudika.lucene.store.s3.S3Directory; -import org.apache.lucene.store.IndexInput; -import org.apache.lucene.store.IndexOutput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -/** - * A No Operation file entry handler. Performs no actual dirty operations, and returns empty data for read operations. - * - * @author kimchy - */ -public class NoOpFileEntryHandler implements FileEntryHandler { - - private static final Logger logger = LoggerFactory.getLogger(NoOpFileEntryHandler.class); - - private static class NoOpIndexInput extends IndexInput { - - protected NoOpIndexInput() { - super("NoOpIndexInput"); - } - - @Override - public byte readByte() throws IOException { - return 0; - } - - @Override - public void readBytes(final byte[] b, final int offset, final int len) throws IOException { - - } - - @Override - public void close() throws IOException { - - } - - @Override - public long getFilePointer() { - return 0; - } - - @Override - public void seek(final long pos) throws IOException { - } - - @Override - public long length() { - return 0; - } - - @Override - public IndexInput slice(final String sliceDescription, final long offset, final long length) - throws IOException { - // TODO Auto-generated method stub - logger.debug("NoOpFileEntryHandler.NoOpIndexInput.slice()"); - return null; - } - } - - @SuppressWarnings("unused") - private static class NoOpIndexOutput extends IndexOutput { - - protected NoOpIndexOutput() { - super("NoOpIndexOutput", "NoOpIndexOutput"); - } - - @Override - public void writeByte(final byte b) throws IOException { - - } - - @Override - public void writeBytes(final byte[] b, final int offset, final int length) throws IOException { - - } - - public void flush() throws IOException { - } - - @Override - public void close() throws IOException { - } - - @Override - public long getFilePointer() { - return 0; - } - - public void seek(final long pos) throws IOException { - } - - public long length() throws IOException { - return 0; - } - - @Override - public long getChecksum() throws IOException { - // TODO Auto-generated method stub - logger.debug("NoOpFileEntryHandler.NoOpIndexOutput.slice()"); - return 0; - } - } - - private static IndexInput indexInput = new NoOpIndexInput(); - - private static IndexOutput indexOutput = new NoOpIndexOutput(); - - @Override - public void configure(final S3Directory s3Directory) { - } - - @Override - public boolean fileExists(final String name) throws IOException { - return false; - } - - @Override - public long fileModified(final String name) throws IOException { - return 0; - } - - @Override - public void touchFile(final String name) throws IOException { - } - - @Override - public void deleteFile(final String name) throws IOException { - } - - @Override - public void renameFile(final String from, final String to) throws IOException { - } - - @Override - public long fileLength(final String name) throws IOException { - return 0; - } - - @Override - public IndexInput openInput(final String name) throws IOException { - return indexInput; - } - - @Override - public IndexOutput createOutput(final String name) throws IOException { - return indexOutput; - } - - @Override - public void close() throws IOException { - // do notihng - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java deleted file mode 100644 index 927a29b9..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/AbstractS3IndexOutput.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.core.sync.RequestBody; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author kimchy - */ -public abstract class AbstractS3IndexOutput extends S3BufferedIndexOutput { - - private static final Logger logger = LoggerFactory.getLogger(AbstractS3IndexOutput.class); - - protected String name; - - protected S3Directory s3Directory; - - protected AbstractS3IndexOutput(final String resourceDescription) { - super(resourceDescription); - } - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - super.configure(name, s3Directory, settings); - this.name = name; - this.s3Directory = s3Directory; - } - - @Override - public void close() throws IOException { - super.close(); - doBeforeClose(); - try { - if (logger.isDebugEnabled()) { - logger.info("close({})", name); - } - final InputStream is = openInputStream(); - s3Directory.getFileSizes().put(name, length()); - s3Directory.getS3().putObject(b -> b.bucket(s3Directory.getBucket()).key(name), - RequestBody.fromInputStream(is, length())); - } catch (Exception e) { - logger.error(null, e); - } - doAfterClose(); - } - - protected abstract InputStream openInputStream() throws IOException; - - protected void doAfterClose() throws IOException { - - } - - protected void doBeforeClose() throws IOException { - - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java deleted file mode 100644 index bec38dde..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexInput.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.erudika.lucene.store.s3.index; - -import org.apache.lucene.store.IndexInput; - -import java.io.IOException; - -/** - * A simple base class that performs index input memory based buffering. Allows the buffer size to be configurable. - * - * @author kimchy - */ -// NEED TO BE MONITORED AGAINST LUCENE (EXATCLY THE SAME) -public abstract class ConfigurableBufferedIndexInput extends IndexInput { - - protected ConfigurableBufferedIndexInput(final String resourceDescription, final int bufferSize) { - super(resourceDescription); - checkBufferSize(bufferSize); - this.bufferSize = bufferSize; - } - - /** - * Default buffer size - */ - public static final int BUFFER_SIZE = 160000000; - - protected int bufferSize = BUFFER_SIZE; - - protected byte[] buffer; - - protected long bufferStart = 0; // position in file of buffer - protected int bufferLength = 0; // end of valid bytes - protected int bufferPosition = 0; // next byte to read - - @Override - public byte readByte() throws IOException { - if (bufferPosition >= bufferLength) { - refill(); - } - return buffer[bufferPosition++]; - } - - /** - * Change the buffer size used by this IndexInput - */ - public void setBufferSize(final int newSize) { - assert buffer == null || bufferSize == buffer.length; - if (newSize != bufferSize) { - checkBufferSize(newSize); - bufferSize = newSize; - if (buffer != null) { - // Resize the existing buffer and carefully save as - // many bytes as possible starting from the current - // bufferPosition - final byte[] newBuffer = new byte[newSize]; - final int leftInBuffer = bufferLength - bufferPosition; - final int numToCopy; - if (leftInBuffer > newSize) { - numToCopy = newSize; - } else { - numToCopy = leftInBuffer; - } - System.arraycopy(buffer, bufferPosition, newBuffer, 0, numToCopy); - bufferStart += bufferPosition; - bufferPosition = 0; - bufferLength = numToCopy; - buffer = newBuffer; - } - } - } - - /** - * Returns buffer size. @see #setBufferSize - */ - public int getBufferSize() { - return bufferSize; - } - - private void checkBufferSize(final int bufferSize) { - if (bufferSize <= 0) { - throw new IllegalArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")"); - } - } - - @Override - public void readBytes(final byte[] b, int offset, int len) throws IOException { - if (len <= bufferLength - bufferPosition) { - // the buffer contains enough data to satistfy this request - if (len > 0) { - System.arraycopy(buffer, bufferPosition, b, offset, len); - } - bufferPosition += len; - } else { - // the buffer does not have enough data. First serve all we've got. - final int available = bufferLength - bufferPosition; - if (available > 0) { - System.arraycopy(buffer, bufferPosition, b, offset, available); - offset += available; - len -= available; - bufferPosition += available; - } - // and now, read the remaining 'len' bytes: - if (len < bufferSize) { - // If the amount left to read is small enough, do it in the - // usual - // buffered way: fill the buffer and copy from it: - refill(); - if (bufferLength < len) { - // Throw an exception when refill() could not read len - // bytes: - System.arraycopy(buffer, 0, b, offset, bufferLength); - throw new IOException("read past EOF"); - } else { - System.arraycopy(buffer, 0, b, offset, len); - bufferPosition = len; - } - } else { - // The amount left to read is larger than the buffer - there's - // no - // performance reason not to read it all at once. Note that - // unlike - // the previous code of this function, there is no need to do a - // seek - // here, because there's no need to reread what we had in the - // buffer. - final long after = bufferStart + bufferPosition + len; - if (after > length()) { - throw new IOException("read past EOF"); - } - readInternal(b, offset, len); - bufferStart = after; - bufferPosition = 0; - bufferLength = 0; // trigger refill() on read - } - } - } - - protected void refill() throws IOException { - final long start = bufferStart + bufferPosition; - long end = start + bufferSize; - if (end > length()) { - end = length(); - } - bufferLength = (int) (end - start); - if (bufferLength <= 0) { - throw new IOException("read past EOF"); - } - - if (buffer == null) { - buffer = new byte[bufferSize]; // allocate buffer lazily - seekInternal(bufferStart); - } - readInternal(buffer, 0, bufferLength); - - bufferStart = start; - bufferPosition = 0; - } - - /** - * Expert: implements buffer refill. Reads bytes from the current position in the input. - * - * @param b the array to read bytes into - * @param offset the offset in the array to start storing bytes - * @param length the number of bytes to read - */ - protected abstract void readInternal(byte[] b, int offset, int length) throws IOException; - - @Override - public long getFilePointer() { - return bufferStart + bufferPosition; - } - - @Override - public void seek(final long pos) throws IOException { - if (pos >= bufferStart && pos < bufferStart + bufferLength) { - bufferPosition = (int) (pos - bufferStart); // seek within buffer - } else { - bufferStart = pos; - bufferPosition = 0; - bufferLength = 0; // trigger refill() on read() - seekInternal(pos); - } - } - - /** - * Expert: implements seek. Sets current position in this file, where the next {@link #readInternal(byte[],int,int)} - * will occur. - * - * @see #readInternal(byte[],int,int) - */ - protected abstract void seekInternal(long pos) throws IOException; - - @Override - public IndexInput clone() { - final ConfigurableBufferedIndexInput clone = (ConfigurableBufferedIndexInput) super.clone(); - - clone.buffer = null; - clone.bufferLength = 0; - clone.bufferPosition = 0; - clone.bufferStart = getFilePointer(); - - return clone; - } - -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java deleted file mode 100644 index 030d2a77..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/ConfigurableBufferedIndexOutput.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.erudika.lucene.store.s3.index; - -import org.apache.lucene.store.IndexOutput; - -import java.io.IOException; - -/** - * A simple base class that performs index output memory based buffering. The buffer size if configurable. - * - * @author kimchy - */ -// NEED TO BE MONITORED AGAINST LUCENE -public abstract class ConfigurableBufferedIndexOutput extends IndexOutput { - - public static final int DEFAULT_BUFFER_SIZE = 16384; - - private byte[] buffer; - private long bufferStart = 0; // position in file of buffer - private int bufferPosition = 0; // position in buffer - - protected int bufferSize = DEFAULT_BUFFER_SIZE; - - protected ConfigurableBufferedIndexOutput(final String resourceDescription) { - super(resourceDescription, "ConfigurableBufferedIndexOutput"); - } - - protected void initBuffer(final int bufferSize) { - this.bufferSize = bufferSize; - buffer = new byte[bufferSize]; - } - - /** - * Writes a single byte. - * - * @see org.apache.lucene.store.IndexInput#readByte() - */ - @Override - public void writeByte(final byte b) throws IOException { - if (bufferPosition >= bufferSize) { - flush(); - } - buffer[bufferPosition++] = b; - } - - /** - * Writes an array of bytes. - * - * @param b the bytes to write - * @param length the number of bytes to write - * @see org.apache.lucene.store.IndexInput#readBytes(byte[],int,int) - */ - @Override - public void writeBytes(final byte[] b, final int offset, final int length) throws IOException { - int bytesLeft = bufferSize - bufferPosition; - // is there enough space in the buffer? - if (bytesLeft >= length) { - // we add the data to the end of the buffer - System.arraycopy(b, offset, buffer, bufferPosition, length); - bufferPosition += length; - // if the buffer is full, flush it - if (bufferSize - bufferPosition == 0) { - flush(); - } - } else { - // is data larger then buffer? - if (length > bufferSize) { - // we flush the buffer - if (bufferPosition > 0) { - flush(); - } - // and write data at once - flushBuffer(b, offset, length); - bufferStart += length; - } else { - // we fill/flush the buffer (until the input is written) - int pos = 0; // position in the input data - int pieceLength; - while (pos < length) { - pieceLength = length - pos < bytesLeft ? length - pos : bytesLeft; - System.arraycopy(b, pos + offset, buffer, bufferPosition, pieceLength); - pos += pieceLength; - bufferPosition += pieceLength; - // if the buffer is full, flush it - bytesLeft = bufferSize - bufferPosition; - if (bytesLeft == 0) { - flush(); - bytesLeft = bufferSize; - } - } - } - } - } - - /** - * Forces any buffered output to be written. - */ - public void flush() throws IOException { - flushBuffer(buffer, bufferPosition); - bufferStart += bufferPosition; - bufferPosition = 0; - } - - /** - * Expert: implements buffer write. Writes bytes at the current position in the output. - * - * @param b the bytes to write - * @param len the number of bytes to write - */ - private void flushBuffer(final byte[] b, final int len) throws IOException { - flushBuffer(b, 0, len); - } - - /** - * Expert: implements buffer write. Writes bytes at the current position in the output. - * - * @param b the bytes to write - * @param offset the offset in the byte array - * @param len the number of bytes to write - */ - protected abstract void flushBuffer(byte[] b, int offset, int len) throws IOException; - - /** - * Closes this stream to further operations. - */ - @Override - public void close() throws IOException { - flush(); - } - - /** - * Returns the current position in this file, where the next write will occur. - * - * @see #seek(long) - */ - @Override - public long getFilePointer() { - return bufferStart + bufferPosition; - } - - /** - * Sets current position in this file, where the next write will occur. - * - * @see #getFilePointer() - */ - public void seek(final long pos) throws IOException { - flush(); - bufferStart = pos; - } - - /** - * The number of bytes in the file. - */ - public abstract long length() throws IOException; - -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java deleted file mode 100644 index 6de94832..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnBufferReadS3IndexInput.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; -import org.apache.lucene.store.BufferedIndexInput; -import org.apache.lucene.store.IndexInput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.core.ResponseBytes; -import software.amazon.awssdk.core.ResponseInputStream; -import software.amazon.awssdk.core.sync.ResponseTransformer; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.GetObjectRequest; -import software.amazon.awssdk.services.s3.model.GetObjectResponse; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * An IndexInput implementation, that for every buffer refill will go and fetch the data from the database. - * - * @author kimchy - */ -public class FetchOnBufferReadS3IndexInput extends S3BufferedIndexInput { - - private static final Logger logger = LoggerFactory.getLogger(FetchOnBufferReadS3IndexInput.class); - - private String name; - - // lazy intialize the length - private long totalLength = -1; - - private long position = 0; - - private S3Directory s3Directory; - - public FetchOnBufferReadS3IndexInput() { - super("FetchOnBufferReadS3IndexInput"); - } - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - super.configure(name, s3Directory, settings); - this.s3Directory = s3Directory; - this.name = name; - } - - // Overriding refill here since we can execute a single query to get both - // the length and the buffer data - // resulted in not the nicest OO design, where the buffer information is - // protected in the S3BufferedIndexInput - // class - // and code duplication between this method and S3BufferedIndexInput. - // Performance is much better this way! - @Override - protected void refill() throws IOException { - if (logger.isDebugEnabled()) { - logger.info("refill({})", name); - } - ResponseInputStream res = s3Directory.getS3(). - getObject(b -> b.bucket(s3Directory.getBucket()).key(name)); - - synchronized (this) { - if (totalLength == -1) { - totalLength = res.response().contentLength(); - } - } - - final long start = bufferStart + bufferPosition; - long end = start + bufferSize; - if (end > length()) { - end = length(); - } - bufferLength = (int) (end - start); - if (bufferLength <= 0) { - throw new IOException("read past EOF"); - } - - if (buffer == null) { - buffer = new byte[bufferSize]; // allocate buffer - // lazily - seekInternal(bufferStart); - } - // START replace read internal - readInternal(res, buffer, 0, bufferLength); - - bufferStart = start; - bufferPosition = 0; - } - - @Override - protected synchronized void readInternal(final byte[] b, final int offset, final int length) throws IOException { - if (logger.isDebugEnabled()) { - logger.info("readInternal({})", name); - } - ResponseInputStream res = s3Directory.getS3(). - getObject(bd -> bd.bucket(s3Directory.getBucket()).key(name)); - - if (buffer == null) { - buffer = new byte[bufferSize]; - seekInternal(bufferStart); - } -// readInternal(res, buffer, 0, bufferLength); - readInternal(res, b, 0, bufferLength); - - if (totalLength == -1) { - totalLength = res.response().contentLength(); - } - } - - private synchronized void readInternal(final ResponseInputStream res, - final byte[] b, final int offset, final int length) throws IOException { - final long curPos = getFilePointer(); - if (curPos != position) { - position = curPos; - } - res.skip(position); - res.read(b, offset, length); - position += length; - } - - @Override - protected void seekInternal(final long pos) throws IOException { - position = pos; - } - - @Override - public void close() throws IOException { - } - - @Override - public synchronized long length() { - if (totalLength == -1) { - try { - totalLength = s3Directory.fileLength(name); - } catch (final IOException e) { - // do nothing here for now, much better for performance - } - } - return totalLength; - } - - @Override - public IndexInput slice(final String sliceDescription, final long offset, final long length) throws IOException { - // TODO Auto-generated method stub - logger.debug("FetchOnBufferReadS3IndexInput.slice()"); - - return new SlicedIndexInput(sliceDescription, this, offset, length); - } - - /** - * Implementation of an IndexInput that reads from a portion of a file. - */ - private static final class SlicedIndexInput extends BufferedIndexInput { - - IndexInput base; - long fileOffset; - long length; - - SlicedIndexInput(final String sliceDescription, final IndexInput base, final long offset, final long length) { - super(sliceDescription == null ? base.toString() : base.toString() + " [slice=" + sliceDescription + "]", - BufferedIndexInput.BUFFER_SIZE); - if (offset < 0 || length < 0 || offset + length > base.length()) { - throw new IllegalArgumentException("slice() " + sliceDescription + " out of bounds: " + base); - } - this.base = base.clone(); - fileOffset = offset; - this.length = length; - } - - @Override - public SlicedIndexInput clone() { - final SlicedIndexInput clone = (SlicedIndexInput) super.clone(); - clone.base = base.clone(); - clone.fileOffset = fileOffset; - clone.length = length; - return clone; - } - - @Override - protected void readInternal(ByteBuffer bb) throws IOException { - long start = getFilePointer(); - if (start + bb.remaining() > length) { - throw new EOFException("read past EOF: " + this); - } - base.seek(fileOffset + start); - base.readBytes(bb.array(), bb.position(), bb.remaining()); - bb.position(bb.position() + bb.remaining()); - } - - @Override - protected void seekInternal(final long pos) { - } - - @Override - public void close() throws IOException { - base.close(); - } - - @Override - public long length() { - return length; - } - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java deleted file mode 100644 index 36486f09..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/FetchOnOpenS3IndexInput.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; -import org.apache.lucene.store.IndexInput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.core.ResponseInputStream; -import software.amazon.awssdk.services.s3.model.GetObjectResponse; - -import java.io.IOException; - -/** - * An IndexInput implementation that will read all the relevant data from the S3 when created, and will - * cache it until it is closed. - *

- * Used for small file entries in the database like the segments file. - * - * @author kimchy - */ -public class FetchOnOpenS3IndexInput extends IndexInput implements S3IndexConfigurable { - - private static final Logger logger = LoggerFactory.getLogger(FetchOnOpenS3IndexInput.class); - - // There is no synchronizaiton since Lucene RAMDirecoty performs no - // synchronizations. - // Need to get to the bottom of it. - public FetchOnOpenS3IndexInput() { - super("FetchOnOpenS3IndexInput"); - } - - private long length; - - private int position = 0; - - private byte[] data; - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - if (logger.isDebugEnabled()) { - logger.info("configure({})", name); - } - ResponseInputStream res = s3Directory.getS3(). - getObject(b -> b.bucket(s3Directory.getBucket()).key(name)); - - synchronized (this) { - length = res.response().contentLength(); - } - data = new byte[(int) length]; - res.read(data); - if (data.length != length) { - throw new IOException("read past EOF"); - } - } - - @Override - public byte readByte() throws IOException { - return data[position++]; - } - - @Override - public void readBytes(final byte[] b, final int offset, final int len) throws IOException { - System.arraycopy(data, position, b, offset, len); - position += len; - } - - @Override - public void close() throws IOException { - - } - - @Override - public long getFilePointer() { - return position; - } - - @Override - public void seek(final long pos) throws IOException { - position = (int) pos; - } - - @Override - public long length() { - return length; - } - - @Override - public IndexInput slice(final String sliceDescription, final long offset, final long length) throws IOException { - // TODO Auto-generated method stub - logger.debug("FetchOnOpenS3IndexInput.slice()"); - return null; - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java deleted file mode 100644 index 27b14184..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/RAMS3IndexOutput.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; -import org.apache.lucene.store.BufferedChecksum; -import org.apache.lucene.store.IndexOutput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.zip.CRC32; -import java.util.zip.Checksum; - -/** - * An IndexOutput implementation that initially writes the data to a memory buffer. Once it exceeds the - * configured threshold ( {@link #INDEX_OUTPUT_THRESHOLD_SETTING}, will start working with a temporary file, releasing - * the previous buffer. - * - * @author kimchy - */ -public class RAMS3IndexOutput extends IndexOutput implements S3IndexConfigurable { - - - private RAMIndexOutput ramIndexOutput; - private final Checksum crc; - - public RAMS3IndexOutput(String name) { - super("RAMAndFileS3IndexOutput", name); - crc = new BufferedChecksum(new CRC32()); - } - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - ramIndexOutput = new RAMIndexOutput(); - ramIndexOutput.configure(name, s3Directory, settings); - } - - @Override - public void writeByte(final byte b) throws IOException { - ramIndexOutput.writeByte(b); - crc.update(b); - } - - @Override - public void writeBytes(final byte[] b, final int offset, final int length) throws IOException { - ramIndexOutput.writeBytes(b, offset, length); - crc.update(b, offset, length); - } - - @Override - public void close() throws IOException { - ramIndexOutput.close(); - } - - @Override - public long getFilePointer() { - return ramIndexOutput.getFilePointer(); - } - - @Override - public long getChecksum() throws IOException { - return crc.getValue(); - } - - /** - * An IndexOutput implemenation that stores all the data written to it in memory, and flushes it to the - * database when the output is closed. - *

- * Useful for small file entries like the segment file. - * - * @author kimchy - */ - class RAMIndexOutput extends AbstractS3IndexOutput { - - private final Logger logger = LoggerFactory.getLogger(RAMS3IndexOutput.class); - - public RAMIndexOutput() { - super("RAMS3IndexOutput"); - } - - private class RAMFile { - - ArrayList buffers = new ArrayList(); - long length; - } - - private class RAMInputStream extends InputStream { - - private long position; - - private int buffer; - - private int bufferPos; - - private long markedPosition; - - @Override - public synchronized void reset() throws IOException { - position = markedPosition; - } - - @Override - public boolean markSupported() { - return true; - } - - @Override - public void mark(final int readlimit) { - markedPosition = position; - } - - @Override - public int read(final byte[] dest, int destOffset, final int len) throws IOException { - if (position == file.length) { - return -1; - } - int remainder = (int) (position + len > file.length ? file.length - position : len); - final long oldPosition = position; - while (remainder != 0) { - if (bufferPos == bufferSize) { - bufferPos = 0; - buffer++; - } - int bytesToCopy = bufferSize - bufferPos; - bytesToCopy = bytesToCopy >= remainder ? remainder : bytesToCopy; - final byte[] buf = file.buffers.get(buffer); - System.arraycopy(buf, bufferPos, dest, destOffset, bytesToCopy); - destOffset += bytesToCopy; - position += bytesToCopy; - bufferPos += bytesToCopy; - remainder -= bytesToCopy; - } - return (int) (position - oldPosition); - } - - @Override - public int read() throws IOException { - if (position == file.length) { - return -1; - } - if (bufferPos == bufferSize) { - bufferPos = 0; - buffer++; - } - final byte[] buf = file.buffers.get(buffer); - position++; - return buf[bufferPos++] & 0xFF; - } - } - - private RAMFile file; - - private int pointer = 0; - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - super.configure(name, s3Directory, settings); - file = new RAMFile(); - this.name = name; - this.s3Directory = s3Directory; - } - - @Override - public void flushBuffer(final byte[] src, final int offset, final int len) { - byte[] buffer; - int bufferPos = offset; - while (bufferPos != len) { - final int bufferNumber = pointer / bufferSize; - final int bufferOffset = pointer % bufferSize; - final int bytesInBuffer = bufferSize - bufferOffset; - final int remainInSrcBuffer = len - bufferPos; - final int bytesToCopy = bytesInBuffer >= remainInSrcBuffer ? remainInSrcBuffer : bytesInBuffer; - - if (bufferNumber == file.buffers.size()) { - buffer = new byte[bufferSize]; - file.buffers.add(buffer); - } else { - buffer = file.buffers.get(bufferNumber); - } - - System.arraycopy(src, bufferPos, buffer, bufferOffset, bytesToCopy); - bufferPos += bytesToCopy; - pointer += bytesToCopy; - } - - if (pointer > file.length) { - file.length = pointer; - } - } - - @Override - protected InputStream openInputStream() throws IOException { - return new RAMInputStream(); - } - - @Override - protected void doAfterClose() throws IOException { -// file = null; - } - - @Override - public void seek(final long pos) throws IOException { - super.seek(pos); - pointer = (int) pos; - } - - @Override - public long length() { - return file.length; - } - - public void flushToIndexOutput(final IndexOutput indexOutput) throws IOException { - super.flush(); - if (file.buffers.isEmpty()) { - return; - } - if (file.buffers.size() == 1) { - indexOutput.writeBytes(file.buffers.get(0), (int) file.length); - return; - } - final int tempSize = file.buffers.size() - 1; - int i; - for (i = 0; i < tempSize; i++) { - indexOutput.writeBytes(file.buffers.get(i), bufferSize); - } - final int leftOver = (int) (file.length % bufferSize); - if (leftOver == 0) { - indexOutput.writeBytes(file.buffers.get(i), bufferSize); - } else { - indexOutput.writeBytes(file.buffers.get(i), leftOver); - } - } - - @Override - public long getChecksum() throws IOException { - // TODO Auto-generated method stub - logger.debug("RAMS3IndexOutput.getChecksum()"); - return 0; - } - } - -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java deleted file mode 100644 index edc02a14..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexInput.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; - -import java.io.IOException; - -/** - * A simple base class that performs index input memory based buffering. The buffer size can be configured under the - * {@link #BUFFER_SIZE_SETTING} name. - * - * @author kimchy - */ -public abstract class S3BufferedIndexInput extends ConfigurableBufferedIndexInput implements S3IndexConfigurable { - - /** - * The buffer size setting name. See {@link S3FileEntrySettings#setIntSetting(String, int)}. Should be set in bytes. - */ - public static final String BUFFER_SIZE_SETTING = "indexInput.bufferSize"; - - protected S3BufferedIndexInput(final String resourceDescription) { - super(resourceDescription, BUFFER_SIZE); - } - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - setBufferSize(settings.getSettingAsInt(BUFFER_SIZE_SETTING, BUFFER_SIZE)); - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java deleted file mode 100644 index 9445ccea..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/S3BufferedIndexOutput.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; - -import java.io.IOException; - -/** - * A simple base class that performs index output memory based buffering. The buffer size can be configured under the - * {@link #BUFFER_SIZE_SETTING} name. - * - * @author kimchy - */ -public abstract class S3BufferedIndexOutput extends ConfigurableBufferedIndexOutput implements S3IndexConfigurable { - - /** - * The buffer size setting name. See {@link S3FileEntrySettings#setIntSetting(String, int)}. Should be set in bytes. - */ - public static final String BUFFER_SIZE_SETTING = "indexOutput.bufferSize"; - - protected S3BufferedIndexOutput(final String resourceDescription) { - super(resourceDescription); - } - - @Override - public void configure(final String name, final S3Directory s3Directory, final S3FileEntrySettings settings) - throws IOException { - initBuffer(settings.getSettingAsInt(BUFFER_SIZE_SETTING, DEFAULT_BUFFER_SIZE)); - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java deleted file mode 100644 index caa1da18..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexConfigurable.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; - -import java.io.IOException; - -/** - * An additional interface that each implementation of IndexInput and IndexOutput must - * implement. Used to configure newly created IndexInput and IndexOutput S3 based - * implementation. - * - * @author kimchy - */ -public interface S3IndexConfigurable { - - /** - * Configures the newly created IndexInput or IndexOutput implementations. - * - * @param name The name of the file entry - * @param s3Directory The S3 directory instance - * @param settings The relevant file entry settings - * @throws IOException - */ - void configure(String name, S3Directory s3Directory, S3FileEntrySettings settings) throws IOException; -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java b/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java deleted file mode 100644 index d03d290d..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/index/S3IndexInput.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.erudika.lucene.store.s3.index; - -import com.erudika.lucene.store.s3.S3Directory; -import com.erudika.lucene.store.s3.S3FileEntrySettings; -import org.apache.lucene.store.BufferedIndexInput; -import org.apache.lucene.store.IndexInput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.core.ResponseInputStream; -import software.amazon.awssdk.core.sync.ResponseTransformer; -import software.amazon.awssdk.services.s3.model.GetObjectRequest; -import software.amazon.awssdk.services.s3.model.GetObjectResponse; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.ByteBuffer; - -public class S3IndexInput extends BufferedIndexInput implements S3IndexConfigurable{ - - private S3Directory s3Directory; - private String name; - private long position = 0; - private long length = -1; - - private static final Logger logger = LoggerFactory.getLogger(S3IndexInput.class); - - public S3IndexInput() { - super("S3IndexInput"); - setBufferSize(51200); - } - - - @Override - public void configure(String name, S3Directory s3Directory, S3FileEntrySettings settings) throws IOException { - this.s3Directory = s3Directory; - this.name = name; - } - - @Override - protected void readInternal(ByteBuffer b) throws IOException { - synchronized (this) { - if (position + b.remaining() > length()) { - throw new EOFException("read past EOF: " + this); - } - ResponseInputStream res = s3Directory.getS3().getObject( - GetObjectRequest.builder() - .bucket(s3Directory.getBucket()) - .key(name).build() - ); - - res.skip(position); - position += b.remaining(); - byte[] data = res.readAllBytes(); - logger.info("Name: " + name - + " Reading from S3 at position: " + position - + " with buffer size: " + getBufferSize() - + " and remaining: " + b.remaining() - + " and data length: " + data.length - ); - b.put(data, 0, b.remaining()); - - } - - } - - @Override - protected void seekInternal(long pos) throws IOException { - synchronized (this){ - if(pos < 0) { - throw new IllegalArgumentException("Seek position cannot be negative"); - } - if(pos > length()) { - throw new EOFException("Seek position is past EOF"); - } - logger.info("Name: " + name + " Seeking to position: " + pos); - position = pos; - } - - } - - @Override - public void close() throws IOException { - //DO NOTHING - } - - @Override - public long length() { - if(length == -1){ - length = s3Directory.getS3().getObject( - GetObjectRequest.builder() - .bucket(s3Directory.getBucket()) - .key(name).build(), - ResponseTransformer.toInputStream() - ).response().contentLength(); - } - return length; - } - - /** - * Implementation of an IndexInput that reads from a portion of a file. - */ - private static final class SlicedIndexInput extends BufferedIndexInput { - - IndexInput base; - long fileOffset; - long length; - - SlicedIndexInput(final String sliceDescription, final IndexInput base, final long offset, final long length) { - super(sliceDescription == null ? base.toString() : base.toString() + " [slice=" + sliceDescription + "]", - BufferedIndexInput.BUFFER_SIZE); - if (offset < 0 || length < 0 || offset + length > base.length()) { - throw new IllegalArgumentException("slice() " + sliceDescription + " out of bounds: " + base); - } - this.base = base.clone(); - fileOffset = offset; - this.length = length; - } - - @Override - public SlicedIndexInput clone() { - final SlicedIndexInput clone = (SlicedIndexInput) super.clone(); - clone.base = base.clone(); - clone.fileOffset = fileOffset; - clone.length = length; - return clone; - } - - @Override - protected void readInternal(ByteBuffer bb) throws IOException { - long start = getFilePointer(); - if (start + bb.remaining() > length) { - throw new EOFException("read past EOF: " + this); - } - base.seek(fileOffset + start); - base.readBytes(bb.array(), bb.position(), bb.remaining()); - bb.position(bb.position() + bb.remaining()); - } - - @Override - protected void seekInternal(final long pos) { - } - - @Override - public void close() throws IOException { - base.close(); - } - - @Override - public long length() { - return length; - } - } - -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java b/src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java deleted file mode 100644 index 5ca0f663..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/lock/NoOpLock.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.lock; - -import com.erudika.lucene.store.s3.S3Directory; -import org.apache.lucene.store.Lock; - -import java.io.IOException; - -/** - * A simple no op lock. Performs no locking. - * - * @author kimchy - */ -public class NoOpLock extends Lock implements S3Lock { - - @Override - public void configure(final S3Directory s3Directory, final String name) throws IOException { - // do nothing - } - - @Override - public void obtain() throws IOException { - // do nothing - } - - @Override - public void close() throws IOException { - // do nothing - } - - @Override - public void ensureValid() throws IOException { - // do nothing - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java b/src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java deleted file mode 100644 index 878eee2a..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/lock/S3LegalHoldLock.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.lock; - -import com.erudika.lucene.store.s3.S3Directory; -import org.apache.lucene.store.AlreadyClosedException; -import org.apache.lucene.store.Lock; -import org.apache.lucene.store.LockObtainFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.awscore.exception.AwsServiceException; -import software.amazon.awssdk.core.exception.SdkClientException; -import software.amazon.awssdk.services.s3.model.ObjectLockLegalHold; -import software.amazon.awssdk.services.s3.model.ObjectLockLegalHoldStatus; -import software.amazon.awssdk.services.s3.model.PutObjectLegalHoldRequest; - -import java.io.IOException; - -import static software.amazon.awssdk.services.s3.model.ObjectLockLegalHoldStatus.OFF; -import static software.amazon.awssdk.services.s3.model.ObjectLockLegalHoldStatus.ON; - -/** - *

- * A lock based on legal holds on S3 objects. - * - *

- * The benefits of using this lock is the ability to release it. - * - * @author Alex Bogdanovski [alex@erudika.com] - */ -public class S3LegalHoldLock extends Lock implements S3Lock { - - private static final Logger logger = LoggerFactory.getLogger(S3LegalHoldLock.class); - - private S3Directory s3Directory; - private String name; - - @Override - public void configure(final S3Directory s3Directory, final String name) throws IOException { - this.s3Directory = s3Directory; - this.name = name; - } - - @Override - public void obtain() throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("obtain({})", name); - } - putObjectLegalHold(ON); - } catch (AwsServiceException | SdkClientException e) { - throw new LockObtainFailedException("Lock object could not be created: ", e); - } - } - - @Override - public void close() throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("close({})", name); - } -// res = s3Directory.getS3().getObjectLegalHold(b -> b.bucket(s3Directory.getBucket()).key(name)); - - putObjectLegalHold(OFF); -// LOCKS.remove(name); - } catch (AwsServiceException | SdkClientException e) { - throw new AlreadyClosedException("Lock was already released: ", e); - } - -// if (res != null && res.legalHold().status().equals(OFF)) { -// throw new AlreadyClosedException("Lock was already released: " + this); -// } - } - - @Override - public void ensureValid() throws IOException { - try { - if (logger.isDebugEnabled()) { - logger.info("ensureValid({})", name); - } - if (!isLegalHoldOn()) { - // TODO should throw AlreadyClosedException?? - throw new AlreadyClosedException("Lock instance already released: " + this); - } - } catch (AwsServiceException | SdkClientException e) { - throw new AlreadyClosedException("Lock object not found: " + this); - } - } - - private boolean isLegalHoldOn() { - return s3Directory.getS3().getObjectLegalHold(b -> - b.bucket(s3Directory.getBucket()).key(name)).legalHold().status().equals(ON); - } - - private void putObjectLegalHold(ObjectLockLegalHoldStatus status) { - - s3Directory.getS3().putObjectLegalHold(PutObjectLegalHoldRequest - .builder() - .bucket(s3Directory.getBucket()) - .key(name) - .legalHold(ObjectLockLegalHold.builder().status(status).build()) - .build()); - } - - @Override - public String toString() { - return "S3LegalHoldLock[" + s3Directory.getBucket() + "/" + name + "]"; - } -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java b/src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java deleted file mode 100644 index 3b52b8ec..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/lock/S3Lock.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.lock; - -import com.erudika.lucene.store.s3.S3Directory; - -import java.io.IOException; - -/** - * An extension insterface for Lucene Lock class. - * - * @author kimchy - */ -public interface S3Lock { - - /** - * Configures the lock. Called just after the lock is instantiated. - * - * @param s3Directory The directory using the lock - * @param name The name of the lock - * @throws IOException - */ - void configure(S3Directory s3Directory, String name) throws IOException; - - /** - * @throws IOException - */ - void obtain() throws IOException; -} diff --git a/src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java b/src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java deleted file mode 100644 index 35a09b0d..00000000 --- a/src/main/scala/com/erudika/lucene/store/s3/support/LuceneFileNames.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /* - * Copyright 2004-2019 the original author or authors. - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.erudika.lucene.store.s3.support; - -import org.apache.lucene.index.IndexFileNames; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashSet; -import java.util.Set; - -/** - * A set of utility methods for index file names. - * - * @author kimchy - */ -public class LuceneFileNames { - - public static final Logger logger = LoggerFactory.getLogger(LuceneFileNames.class); - - private static final Set STATIC_FILES; - - static { - STATIC_FILES = new HashSet(); - STATIC_FILES.add(IndexFileNames.SEGMENTS); - STATIC_FILES.add(IndexFileNames.PENDING_SEGMENTS); - STATIC_FILES.add("clearcache"); - STATIC_FILES.add("spellcheck.version"); - } - - /** - * Returns if this file name is a static file. A static file is a file that is updated and changed by Lucene. - */ - public static boolean isStaticFile(final String name) { - logger.debug("LuceneFileNames.isStaticFile({})", name); - return STATIC_FILES.contains(name); - } - - /** - * Returns if the name is a segment file or not. - */ - public static boolean isSegmentsFile(final String name) { - logger.debug("LuceneFileNames.isSegmentsFile({})", name); - return name.equals(IndexFileNames.SEGMENTS) || name.equals(IndexFileNames.PENDING_SEGMENTS); - } - -} From c94ee8d9c7b3f9f4ffe6e180cf6f8eb819a92e80 Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Mon, 16 Sep 2024 19:35:03 +0530 Subject: [PATCH 7/8] Remove Test files --- src/main/resources/reference.conf | 3 +- .../org/zouzias/spark/lucenerdd/Driver.scala | 81 ------------------- .../org/zouzias/spark/lucenerdd/GZip.scala | 34 -------- .../spark/lucenerdd/KafkaStreamingQuery.scala | 63 --------------- .../spark/lucenerdd/ReadSavedFile.scala | 36 --------- .../org/zouzias/spark/lucenerdd/Schema.scala | 22 ----- .../org/zouzias/spark/lucenerdd/UDF.scala | 16 ---- 7 files changed, 2 insertions(+), 253 deletions(-) delete mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala delete mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala delete mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala delete mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala delete mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala delete mode 100644 src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 5e6892b0..773e5b01 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -25,7 +25,8 @@ lucenerdd { // Use 'disk' to store the index in Java's temp directory // Otherwise the index will be stored in memory // Do not use memory, see http://lucene.apache.org/core/7_5_0/core/org/apache/lucene/store/RAMDirectory.html - store.mode = "s3" + // store.mode = "s3" + store.mode = "disk" store.mode = ${?LUCENERDD_INDEX_STORE_MODE} stringfields{ diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala b/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala deleted file mode 100644 index 04d340f9..00000000 --- a/src/main/scala/org/zouzias/spark/lucenerdd/Driver.scala +++ /dev/null @@ -1,81 +0,0 @@ -/* - - */ - -package org.zouzias.spark.lucenerdd - -import org.apache.spark.sql.{Row, SparkSession} -import org.apache.spark.sql.functions.{col, expr, from_json} -import org.zouzias.spark.lucenerdd.UDF.updateIdUDF - -import java.util - -object Driver { - def main(args: Array[String]): Unit = { - val spark = SparkSession - .builder - .appName("Indexer") - .config("spark.master", "local") - .config("spark.driver.userClassPathFirst","true") - .config("spark.executor.userClassPathFirst","true") - .config("spark.executor.instances", "1") - .getOrCreate() - - val df = spark - .read - .format("kafka") - .option("kafka.bootstrap.servers", "localhost:9092") - .option("subscribe", "callSync") - .load() - - val interactionDf = df - .selectExpr("CAST(key AS STRING)", "CAST(value AS STRING) as value") - .select(from_json( col("value"), Schema.kafkaSchema, new util.HashMap[String, String]())) - .select("from_json(value).*") - .withColumn("meeting", updateIdUDF(col("zipped_data"))) - .drop("zipped_data") - .withColumn("struct_meeting", - from_json(col("meeting"), - Schema.meetingSchema, - new util.HashMap[String, String]())) - .drop("meeting") - .selectExpr("*", "struct_meeting.*") - .drop("struct_meeting") - - interactionDf.printSchema() - - // interactionDf - // .writeStream - // .format("parquet") - // .option("path", "spark-warehouse/data") - // .option("checkpointLocation","spark-warehouse/checkpoint") - // .start() - // .awaitTermination() - - val transcriptDf = interactionDf - .selectExpr("account_id", - "meeting_id", - "meetingInfo.time", - "meetingInfo.userId as user_id", - "explode(meetingInfo.transcript) as transcript") - .withColumn("start_time", expr("transcript.startTime")) - .withColumn("end_time", expr("transcript.endTime")) - .withColumn("phrase", expr("transcript.phrase")) - .withColumn("speaker", expr("transcript.speaker")) - .withColumn("convId", expr("transcript.convId")) - .drop("transcript") - - val luceneRDD: LuceneRDD[Row] = LuceneRDD(transcriptDf) - - luceneRDD.cache() - - luceneRDD.phraseQuery("phrase","hello").foreach(println) - -// val sqlContext= new org.apache.spark.sql.SQLContext(spark.sparkContext) -// import sqlContext.implicits._ - luceneRDD.saveAsObjectFile("spark-warehouse/lucene_text_"+System.currentTimeMillis()) - - luceneRDD.unpersist() - - } -} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala b/src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala deleted file mode 100644 index 933a5f12..00000000 --- a/src/main/scala/org/zouzias/spark/lucenerdd/GZip.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* - - */ -package org.zouzias.spark.lucenerdd - -import java.io.{ByteArrayInputStream, ByteArrayOutputStream} -import java.util.Base64 -import java.util.zip.{GZIPInputStream, GZIPOutputStream} -import scala.util.Try - -object GZip { - - def compress(input: Array[Byte]): Array[Byte] = { - val bos = new ByteArrayOutputStream(input.length) - val gzip = new GZIPOutputStream(bos) - gzip.write(input) - gzip.close() - val compressed = bos.toByteArray - bos.close() - compressed - } - - def decompress(compressed: Array[Byte]): Option[String] = - Try { - val decodedString = Base64.getDecoder.decode(compressed) - val inputStream = new GZIPInputStream(new ByteArrayInputStream(decodedString)) - scala.io.Source.fromInputStream(inputStream).mkString - }.toOption - - def main(args: Array[String]): Unit = { - val str = "" -// println(decompress(str.getBytes)) - } -} \ No newline at end of file diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala b/src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala deleted file mode 100644 index e52b7dc1..00000000 --- a/src/main/scala/org/zouzias/spark/lucenerdd/KafkaStreamingQuery.scala +++ /dev/null @@ -1,63 +0,0 @@ -package org.zouzias.spark.lucenerdd - -import org.apache.spark.sql.{DataFrame, Encoder, Encoders, ForeachWriter, Row, SparkSession} -import org.apache.spark.sql.functions.{col, expr, from_json} -import org.zouzias.spark.lucenerdd.UDF.updateIdUDF - -object KafkaStreamingQuery { - def main(args: Array[String]): Unit = { - val spark = SparkSession - .builder - .appName("Indexer") - .config("spark.master", "local") - .config("spark.driver.userClassPathFirst","true") - .config("spark.executor.userClassPathFirst","true") - .config("spark.executor.instances", "1") - .getOrCreate() - - val df: DataFrame = spark - .readStream - .format("kafka") - .option("kafka.bootstrap.servers", "localhost:9092") - .option("subscribe", "query") - .option("startingOffsets", "earliest") - .load() - - implicit val enc: Encoder[(String, String)] = Encoders.product[(String, String)] - val modified_df = df.selectExpr("CAST(key AS STRING)", "CAST(value AS STRING)") - .as[(String, String)] - .select("value") - val luceneRDD = LuceneRDD(df, true) - - modified_df - .writeStream - .foreach(new ForeachWriter[Row] { - - def open(partitionId: Long, version: Long): Boolean = { - // Open connection - true - } - - def process(record: Row): Unit = { - // val rdd: LuceneRDD[Row] = sc.objectFile("spark-warehouse/lucene_text_1715102057572").asInstanceOf[LuceneRDD[Row]] - luceneRDD.phraseQuery("phrase",record.getString(0)).foreach(println) - } - - def close(errorOrNull: Throwable): Unit = { - // Close the connection - } - }) - .start() - .awaitTermination() - -// val writing_df = modified_df.writeStream -// .format("console") -// .option("checkpointLocation","checkpoint_dir"+System.currentTimeMillis()) -// .outputMode("append") -// .start() -// -// -// writing_df.awaitTermination() - } - -} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala b/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala deleted file mode 100644 index 0e5f8a63..00000000 --- a/src/main/scala/org/zouzias/spark/lucenerdd/ReadSavedFile.scala +++ /dev/null @@ -1,36 +0,0 @@ -package org.zouzias.spark.lucenerdd - -import org.apache.spark.sql.types.{IntegerType, StructField, StructType} -import org.apache.spark.sql.{Row, SparkSession} - -object ReadSavedFile { - def main(args: Array[String]): Unit = { - val spark = SparkSession - .builder - .appName("Indexer") - .config("spark.master", "local") - .config("spark.driver.userClassPathFirst","true") - .config("spark.executor.userClassPathFirst","true") - .config("spark.executor.instances", "1") - .getOrCreate() - - // Define the schema - val schema = new StructType() - .add(StructField("value", IntegerType, nullable = false)) - - // Create a Seq of Rows - val data = Seq(Row(1), Row(2), Row(3)) - - // Create DataFrame - val df = spark.createDataFrame( - spark.sparkContext.parallelize(data), - schema - ) - println("Starting...") - val luceneRDD = LuceneRDD(df, true) -// val rdd: LuceneRDD[Row] = sc.objectFile("spark-warehouse/lucene_text_1715102057572").asInstanceOf[LuceneRDD[Row]] - luceneRDD.phraseQuery("phrase","hello").foreach(println) - - } - -} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala b/src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala deleted file mode 100644 index 088a9cdb..00000000 --- a/src/main/scala/org/zouzias/spark/lucenerdd/Schema.scala +++ /dev/null @@ -1,22 +0,0 @@ -/* - - */ -package org.zouzias.spark.lucenerdd - -object Schema { - val kafkaSchema: String = - """ - |{"type":"struct","fields":[{"name":"account_id","type":"string","nullable":true,"metadata":{}},{"name":"account_name","type":"string","nullable":true,"metadata":{}},{"name":"created_at","type":"long","nullable":true,"metadata":{}},{"name":"created_time","type":"long","nullable":true,"metadata":{}},{"name":"data","type":"string","nullable":true,"metadata":{}},{"name":"entity_type","type":"string","nullable":true,"metadata":{}},{"name":"event_type","type":"string","nullable":true,"metadata":{}},{"name":"id","type":"string","nullable":true,"metadata":{}},{"name":"is_pci","type":"boolean","nullable":true,"metadata":{}},{"name":"job_id","type":"string","nullable":true,"metadata":{}},{"name":"job_processing_entity_id","type":"string","nullable":true,"metadata":{}},{"name":"meeting_id","type":"string","nullable":true,"metadata":{}},{"name":"modified_at","type":"long","nullable":true,"metadata":{}},{"name":"partner_meeting_id","type":"string","nullable":true,"metadata":{}},{"name":"previous_call_time","type":"string","nullable":true,"metadata":{}},{"name":"version","type":"long","nullable":true,"metadata":{}},{"name":"zipped_data","type":"string","nullable":true,"metadata":{}}]} - |""".stripMargin - - val meetingSchema: String = - """ - |{"type":"struct","fields":[{"name":"meetingInfo","type":{"type":"struct","fields":[{"name":"accountId","type":"string","nullable":true,"metadata":{}},{"name":"audioPath","type":"string","nullable":true,"metadata":{}},{"name":"audioProperties","type":{"type":"struct","fields":[{"name":"call-mp3","type":{"type":"struct","fields":[{"name":"bitRate","type":"long","nullable":true,"metadata":{}},{"name":"channelCount","type":"long","nullable":true,"metadata":{}},{"name":"duration","type":"double","nullable":true,"metadata":{}},{"name":"samplingRate","type":"long","nullable":true,"metadata":{}}]},"nullable":true,"metadata":{}}]},"nullable":true,"metadata":{}},{"name":"bucketName","type":"string","nullable":true,"metadata":{}},{"name":"callLevelData","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"callLevelKey","type":"string","nullable":true,"metadata":{}},{"name":"value","type":"string","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"criteria","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"criteriaId","type":"string","nullable":true,"metadata":{}},{"name":"frequency","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"count","type":"long","nullable":true,"metadata":{}},{"name":"phrase","type":"string","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"present","type":"boolean","nullable":true,"metadata":{}},{"name":"snippets","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"confidence","type":"double","nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"evidence","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"duration","type":"long","nullable":true,"metadata":{}},{"name":"endOfInteractions","type":"boolean","nullable":true,"metadata":{}},{"name":"entityType","type":"string","nullable":true,"metadata":{}},{"name":"id","type":"string","nullable":true,"metadata":{}},{"name":"parameters","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"name","type":"string","nullable":true,"metadata":{}},{"name":"value","type":{"type":"array","elementType":"string","containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"partnerMeetingId","type":"string","nullable":true,"metadata":{}},{"name":"signal","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"frequency","type":{"type":"array","elementType":"string","containsNull":true},"nullable":true,"metadata":{}},{"name":"present","type":"boolean","nullable":true,"metadata":{}},{"name":"signalId","type":"string","nullable":true,"metadata":{}},{"name":"snippets","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"confidence","type":"double","nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"evidence","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"splitInteraction","type":"boolean","nullable":true,"metadata":{}},{"name":"startOfInteractions","type":"boolean","nullable":true,"metadata":{}},{"name":"status","type":"string","nullable":true,"metadata":{}},{"name":"time","type":"string","nullable":true,"metadata":{}},{"name":"totalSplitCount","type":"long","nullable":true,"metadata":{}},{"name":"transcript","type":{"type":"array","elementType":{"type":"struct","fields":[{"name":"confidence","type":{"type":"array","elementType":"double","containsNull":true},"nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"phrase","type":"string","nullable":true,"metadata":{}},{"name":"speaker","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}},{"name":"times","type":{"type":"array","elementType":"long","containsNull":true},"nullable":true,"metadata":{}}]},"containsNull":true},"nullable":true,"metadata":{}},{"name":"transcriptPath","type":"string","nullable":true,"metadata":{}},{"name":"userId","type":"string","nullable":true,"metadata":{}}]},"nullable":true,"metadata":{}}]} - |""".stripMargin - - val transcriptSchema: String = - """ - |{"type":"struct","fields":[{"name":"confidence","type":{"type":"array","elementType":"double","containsNull":true},"nullable":true,"metadata":{}},{"name":"convId","type":"long","nullable":true,"metadata":{}},{"name":"endTime","type":"long","nullable":true,"metadata":{}},{"name":"phrase","type":"string","nullable":true,"metadata":{}},{"name":"speaker","type":"string","nullable":true,"metadata":{}},{"name":"startTime","type":"long","nullable":true,"metadata":{}},{"name":"times","type":{"type":"array","elementType":"long","containsNull":true},"nullable":true,"metadata":{}}]} - |""".stripMargin - -} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala b/src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala deleted file mode 100644 index 211c8799..00000000 --- a/src/main/scala/org/zouzias/spark/lucenerdd/UDF.scala +++ /dev/null @@ -1,16 +0,0 @@ -package org.zouzias.spark.lucenerdd - -/* - - */ -import org.apache.spark.sql.expressions.UserDefinedFunction -import org.apache.spark.sql.functions.udf - -object UDF { - - val unzipData: (String => String) = (unzipped: String) => { - GZip.decompress(unzipped.getBytes).get - } - val updateIdUDF: UserDefinedFunction = udf(unzipData) - -} From 04ac11f5c0f764e57281a9c2aa7aa6239a608ebe Mon Sep 17 00:00:00 2001 From: Nasit Kashyap Vinodbhai Date: Mon, 16 Sep 2024 19:50:03 +0530 Subject: [PATCH 8/8] Refactor code --- src/main/resources/reference.conf | 2 + .../spark/lucenerdd/store/IndexStorable.scala | 57 +++++++++++++++---- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 773e5b01..6df16b07 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -26,6 +26,8 @@ lucenerdd { // Otherwise the index will be stored in memory // Do not use memory, see http://lucene.apache.org/core/7_5_0/core/org/apache/lucene/store/RAMDirectory.html // store.mode = "s3" + // store.s3.index.bucket = "lucene-kashyap" + // store.s3.taxonomy.bucket = "lucene-kashyap-taxonomy" store.mode = "disk" store.mode = ${?LUCENERDD_INDEX_STORE_MODE} diff --git a/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala b/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala index 27d93c53..621d7f44 100644 --- a/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala +++ b/src/main/scala/org/zouzias/spark/lucenerdd/store/IndexStorable.scala @@ -44,21 +44,59 @@ trait IndexStorable extends Configurable private val IndexStoreKey = "lucenerdd.index.store.mode" - private val tmpJavaDir = System.getProperty("java.io.tmpdir") - private val indexDirName = s"indexDirectory.${System.currentTimeMillis()}.${Thread.currentThread().getId}" - private val indexS3FileSystem = S3FileSystemStore.getS3FileSystem -// private val indexDir = Files.createTempDirectory(indexDirName) - private val indexDir = indexS3FileSystem.getPath("lucene-kashyap") + + private var indexDir = Files.createTempDirectory(indexDirName) + if (Config.hasPath(IndexStoreKey)) { + val storageMode = Config.getString(IndexStoreKey) + + storageMode match { + case "disk" => { + val tmpJavaDir = System.getProperty("java.io.tmpdir") + logInfo(s"Config parameter ${IndexStoreKey} is set to 'disk'") + logInfo("Lucene index will be storage in disk") + logInfo(s"Index disk location ${tmpJavaDir}") + indexDir = Files.createTempDirectory(indexDirName) + } + + case "s3" => { + val indexS3FileSystem = S3FileSystemStore.getS3FileSystem + val bucketName = Config.getString("lucenerdd.index.store.s3.index.bucket") + logInfo(s"Config parameter ${IndexStoreKey} is set to 'S3'") + logInfo("Lucene index will be storage in S3") + logInfo(s"Index S3 Bucket location ${bucketName}") + + indexDir = indexS3FileSystem.getPath(bucketName) + } + } + } private val taxonomyDirName = - s"taxonomyDirectory-${System.currentTimeMillis()}.${Thread.currentThread().getId}" + s"taxonomyDirectory-${System.currentTimeMillis()}.${Thread.currentThread().getId}" + private var taxonomyDir = Files.createTempDirectory(taxonomyDirName) + + if (Config.hasPath(IndexStoreKey)) { + val storageMode = Config.getString(IndexStoreKey) + storageMode match { + case "disk" => { + logInfo(s"Config parameter ${IndexStoreKey} is set to 'disk'") + logInfo("Lucene index will be storage in disk") + logInfo(s"Index disk location ${taxonomyDirName}") + taxonomyDir = Files.createTempDirectory(taxonomyDirName) + } - private val taxonomyS3FileSystem = S3FileSystemStore.getTaxonomyS3FileSystem -// private val taxonomyDir = Files.createTempDirectory(taxonomyDirName) - private val taxonomyDir = taxonomyS3FileSystem.getPath("lucene-kashyap-taxonomy") + case "s3" => { + val taxonomyS3FileSystem = S3FileSystemStore.getTaxonomyS3FileSystem + val bucketName = Config.getString("lucenerdd.index.store.s3.taxonomy.bucket") + logInfo(s"Config parameter ${IndexStoreKey} is set to 'S3'") + logInfo("Lucene taxonomy will be storage in S3") + logInfo(s"Taxonomy S3 Bucket location ${bucketName}") + taxonomyDir = taxonomyS3FileSystem.getPath(bucketName) + } + } + } protected val IndexDir = storageMode(indexDir) @@ -79,7 +117,6 @@ trait IndexStorable extends Configurable case "disk" => { logInfo(s"Config parameter ${IndexStoreKey} is set to 'disk'") logInfo("Lucene index will be storage in disk") - logInfo(s"Index disk location ${tmpJavaDir}") // directoryPath.toFile.deleteOnExit() // Delete on exit new MMapDirectory(directoryPath, new SingleInstanceLockFactory) }