This is an automated email from the ASF dual-hosted git repository. dsmiley pushed a commit to branch branch_9x in repository https://gitbox.apache.org/repos/asf/solr.git
commit 8d1a795173d4a3da73578e4bae3bf59ee874e0f5 Author: NextBrickINC.com <[email protected]> AuthorDate: Thu Aug 27 21:41:36 2026 -0700 SOLR-18350: Live schema changes could disrupt requests in progress (#4817) At least theoretically. Co-authored-by: rayshrey <[email protected]> (cherry picked from commit 812408433c661cf61c9b6d2784787304e39907bf) --- changelog/unreleased/solr-18350-stable-schema.yml | 8 +++++ .../src/java/org/apache/solr/core/SolrCore.java | 9 +++++- .../org/apache/solr/handler/SchemaHandler.java | 34 +++++++++------------- .../handler/component/RealTimeGetComponent.java | 16 +++++----- .../java/org/apache/solr/request/SimpleFacets.java | 2 +- .../solr/search/PayloadCheckQParserPlugin.java | 2 +- .../solr/search/PayloadScoreQParserPlugin.java | 4 +-- .../org/apache/solr/search/ValueSourceParser.java | 2 +- .../org/apache/solr/search/neural/KnnQParser.java | 2 +- .../search/neural/VectorSimilarityQParser.java | 2 +- .../processor/ContentHashVersionProcessor.java | 2 +- .../DocBasedVersionConstraintsProcessor.java | 6 ++-- .../update/processor/TolerantUpdateProcessor.java | 2 +- .../processor/ContentHashVersionProcessorTest.java | 2 +- .../search/TextToVectorQParserPlugin.java | 2 +- .../TextToVectorUpdateProcessorFactory.java | 9 +++--- 16 files changed, 55 insertions(+), 49 deletions(-) diff --git a/changelog/unreleased/solr-18350-stable-schema.yml b/changelog/unreleased/solr-18350-stable-schema.yml new file mode 100644 index 00000000000..c496b588399 --- /dev/null +++ b/changelog/unreleased/solr-18350-stable-schema.yml @@ -0,0 +1,8 @@ +title: Keep request processing and searches on a stable schema snapshot when the schema changes concurrently +type: fixed +authors: + - name: Shrey Narayan + nick: NextbrickInc +links: + - name: SOLR-18350 + url: https://issues.apache.org/jira/browse/SOLR-18350 diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java index 3a5aab8411f..e78f9bc2208 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -349,7 +349,14 @@ public class SolrCore implements SolrInfoBean, Closeable { } /** - * @return the latest snapshot of the schema used by this core instance. + * Returns the latest snapshot of the schema used by this core instance. + * + * <p>Request processing code should normally use {@link SolrQueryRequest#getSchema()} so that the + * schema remains stable for the lifetime of the request. Code operating on a {@link + * SolrIndexSearcher} should normally use {@link SolrIndexSearcher#getSchema()} so that the schema + * matches the searcher. + * + * @return the latest schema snapshot * @see #setLatestSchema */ public IndexSchema getLatestSchema() { diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java index 5988989e3dc..e7360177912 100644 --- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java @@ -134,42 +134,38 @@ public class SchemaHandler extends RequestHandlerBase case "/schema": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, new GetSchema(req.getCore(), req.getCore().getLatestSchema()).getSchemaInfo()); + rsp, new GetSchema(req.getCore(), req.getSchema()).getSchemaInfo()); break; } case "/schema/version": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, - new GetSchema(req.getCore(), req.getCore().getLatestSchema()).getSchemaVersion()); + rsp, new GetSchema(req.getCore(), req.getSchema()).getSchemaVersion()); break; } case "/schema/uniquekey": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, - new GetSchema(req.getCore(), req.getCore().getLatestSchema()).getSchemaUniqueKey()); + rsp, new GetSchema(req.getCore(), req.getSchema()).getSchemaUniqueKey()); break; } case "/schema/similarity": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, - new GetSchema(req.getCore(), req.getCore().getLatestSchema()) - .getSchemaSimilarity()); + rsp, new GetSchema(req.getCore(), req.getSchema()).getSchemaSimilarity()); break; } case "/schema/name": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, new GetSchema(req.getCore(), req.getCore().getLatestSchema()).getSchemaName()); + rsp, new GetSchema(req.getCore(), req.getSchema()).getSchemaName()); break; } case "/schema/zkversion": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchema(req.getCore(), req.getCore().getLatestSchema()) + new GetSchema(req.getCore(), req.getSchema()) .getSchemaZkVersion(req.getParams().getInt("refreshIfBelowVersion", -1))); break; } @@ -191,22 +187,19 @@ public class SchemaHandler extends RequestHandlerBase if (parts.size() > 2) { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) + new GetSchemaField(req.getSchema(), req.getParams()) .getFieldInfo(parts.get(2))); } else { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) - .listSchemaFields()); + new GetSchemaField(req.getSchema(), req.getParams()).listSchemaFields()); } return; } case "copyfields": { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) - .listCopyFields()); + rsp, new GetSchemaField(req.getSchema(), req.getParams()).listCopyFields()); return; } case "dynamicfields": @@ -214,13 +207,12 @@ public class SchemaHandler extends RequestHandlerBase if (parts.size() > 2) { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) + new GetSchemaField(req.getSchema(), req.getParams()) .getDynamicFieldInfo(parts.get(2))); } else { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) - .listDynamicFields()); + new GetSchemaField(req.getSchema(), req.getParams()).listDynamicFields()); } return; } @@ -229,12 +221,12 @@ public class SchemaHandler extends RequestHandlerBase if (parts.size() > 2) { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) + new GetSchemaField(req.getSchema(), req.getParams()) .getFieldTypeInfo(parts.get(2))); } else { V2ApiUtils.squashIntoSolrResponseWithoutHeader( rsp, - new GetSchemaField(req.getCore().getLatestSchema(), req.getParams()) + new GetSchemaField(req.getSchema(), req.getParams()) .listSchemaFieldTypes()); } return; diff --git a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java index 04b878bfe2a..0d2731903ba 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java @@ -217,7 +217,7 @@ public class RealTimeGetComponent extends SearchComponent { } final SolrCore core = req.getCore(); - SchemaField idField = core.getLatestSchema().getUniqueKeyField(); + SchemaField idField = req.getSchema().getUniqueKeyField(); FieldType fieldType = idField.getType(); SolrDocumentList docList = new SolrDocumentList(); @@ -274,9 +274,7 @@ public class RealTimeGetComponent extends SearchComponent { SolrDocument doc; if (oper == UpdateLog.ADD) { - doc = - toSolrDoc( - (SolrInputDocument) entry.get(entry.size() - 1), core.getLatestSchema()); + doc = toSolrDoc((SolrInputDocument) entry.get(entry.size() - 1), req.getSchema()); // toSolrDoc filtered copy-field targets already if (transformer != null) { transformer.transform(doc, -1); // unknown docID @@ -350,7 +348,7 @@ public class RealTimeGetComponent extends SearchComponent { SolrDocumentFetcher docFetcher = searcherInfo.getSearcher().getDocFetcher(); Document luceneDocument = docFetcher.doc(docid, rsp.getReturnFields().getLuceneFieldNames()); - SolrDocument doc = toSolrDoc(luceneDocument, core.getLatestSchema()); + SolrDocument doc = toSolrDoc(luceneDocument, searcherInfo.getSearcher().getSchema()); if (reuseDvIters == null) { reuseDvIters = new DocValuesIteratorCache(searcherInfo.getSearcher()); } @@ -561,7 +559,7 @@ public class RealTimeGetComponent extends SearchComponent { try { // now fetch last document from index, and merge partialDoc on top of it SolrIndexSearcher searcher = searcherHolder.get(); - SchemaField idField = core.getLatestSchema().getUniqueKeyField(); + SchemaField idField = searcher.getSchema().getUniqueKeyField(); Term idTerm = new Term(idField.getName(), idBytes); int docid = searcher.getFirstMatch(idTerm); @@ -786,12 +784,12 @@ public class RealTimeGetComponent extends SearchComponent { int docId = searcher.getFirstMatch( new Term( - core.getLatestSchema().getUniqueKeyField().getName(), + searcher.getSchema().getUniqueKeyField().getName(), resolveStrategy == Resolution.ROOT_WITH_CHILDREN ? rootIdBytes : idBytes)); if (docId < 0) return null; if (resolveStrategy == Resolution.ROOT_WITH_CHILDREN - && core.getLatestSchema().isUsableForChildDocs()) { + && searcher.getSchema().isUsableForChildDocs()) { // check that this doc is in fact a root document as a prevention measure if (!hasRootTerm(searcher, rootIdBytes)) { throw new SolrException( @@ -802,7 +800,7 @@ public class RealTimeGetComponent extends SearchComponent { SolrDocument solrDoc = fetchSolrDoc(searcher, docId, makeReturnFields(core, onlyTheseFields, resolveStrategy)); - sid = toSolrInputDocument(solrDoc, core.getLatestSchema()); // filters copy-field targets + sid = toSolrInputDocument(solrDoc, searcher.getSchema()); // filters copy-field targets // the assertions above furthermore guarantee the result corresponds to idBytes } finally { searcherHolder.decref(); diff --git a/solr/core/src/java/org/apache/solr/request/SimpleFacets.java b/solr/core/src/java/org/apache/solr/request/SimpleFacets.java index 02a7f493e63..6f7bf58dd2a 100644 --- a/solr/core/src/java/org/apache/solr/request/SimpleFacets.java +++ b/solr/core/src/java/org/apache/solr/request/SimpleFacets.java @@ -1320,7 +1320,7 @@ public class SimpleFacets { final ParsedParams parsed = parseParams(FacetParams.FACET_INTERVAL, field); String[] intervalStrs = parsed.required.getFieldParams(parsed.facetValue, FacetParams.FACET_INTERVAL_SET); - SchemaField schemaField = searcher.getCore().getLatestSchema().getField(parsed.facetValue); + SchemaField schemaField = searcher.getSchema().getField(parsed.facetValue); if (parsed.params.getBool(GroupParams.GROUP_FACET, false)) { throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, diff --git a/solr/core/src/java/org/apache/solr/search/PayloadCheckQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/PayloadCheckQParserPlugin.java index fb802a52d56..e5c59090188 100644 --- a/solr/core/src/java/org/apache/solr/search/PayloadCheckQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/PayloadCheckQParserPlugin.java @@ -77,7 +77,7 @@ public class PayloadCheckQParserPlugin extends QParserPlugin { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "'payloads' not specified"); } - FieldType ft = req.getCore().getLatestSchema().getFieldType(field); + FieldType ft = req.getSchema().getFieldType(field); Analyzer analyzer = ft.getQueryAnalyzer(); SpanQuery query = null; try { diff --git a/solr/core/src/java/org/apache/solr/search/PayloadScoreQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/PayloadScoreQParserPlugin.java index c26853933cb..89566fdc8f7 100644 --- a/solr/core/src/java/org/apache/solr/search/PayloadScoreQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/PayloadScoreQParserPlugin.java @@ -69,7 +69,7 @@ public class PayloadScoreQParserPlugin extends QParserPlugin { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "query string missing"); } - FieldType ft = req.getCore().getLatestSchema().getFieldType(field); + FieldType ft = req.getSchema().getFieldType(field); Analyzer analyzer = ft.getQueryAnalyzer(); SpanQuery query; try { @@ -87,7 +87,7 @@ public class PayloadScoreQParserPlugin extends QParserPlugin { PayloadFunction payloadFunction = PayloadUtils.getPayloadFunction(func); if (payloadFunction == null) throw new SyntaxError("Unknown payload function: " + func); - PayloadDecoder payloadDecoder = req.getCore().getLatestSchema().getPayloadDecoder(field); + PayloadDecoder payloadDecoder = req.getSchema().getPayloadDecoder(field); return new PayloadScoreQuery(query, payloadFunction, payloadDecoder, includeSpanScore); } }; diff --git a/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java b/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java index c5c0d06dc7d..1024d30bc94 100644 --- a/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java +++ b/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java @@ -898,7 +898,7 @@ public abstract class ValueSourceParser implements NamedListInitializedPlugin { SolrException.ErrorCode.BAD_REQUEST, "Invalid payload function: " + func); } - IndexSchema schema = fp.getReq().getCore().getLatestSchema(); + IndexSchema schema = fp.getReq().getSchema(); PayloadDecoder decoder = schema.getPayloadDecoder(tinfo.field); if (decoder == null) { diff --git a/solr/core/src/java/org/apache/solr/search/neural/KnnQParser.java b/solr/core/src/java/org/apache/solr/search/neural/KnnQParser.java index fe6a84f18d7..e0b74105e39 100644 --- a/solr/core/src/java/org/apache/solr/search/neural/KnnQParser.java +++ b/solr/core/src/java/org/apache/solr/search/neural/KnnQParser.java @@ -50,7 +50,7 @@ public class KnnQParser extends AbstractVectorQParserBase { @Override public Query parse() throws SyntaxError { final String vectorField = getFieldName(); - final SchemaField schemaField = req.getCore().getLatestSchema().getField(vectorField); + final SchemaField schemaField = req.getSchema().getField(vectorField); final DenseVectorField denseVectorType = getCheckedFieldType(schemaField); final String vectorToSearch = getVectorToSearch(); final int topK = localParams.getInt(TOP_K, DEFAULT_TOP_K); diff --git a/solr/core/src/java/org/apache/solr/search/neural/VectorSimilarityQParser.java b/solr/core/src/java/org/apache/solr/search/neural/VectorSimilarityQParser.java index e3ec2f242f7..112df600fd5 100644 --- a/solr/core/src/java/org/apache/solr/search/neural/VectorSimilarityQParser.java +++ b/solr/core/src/java/org/apache/solr/search/neural/VectorSimilarityQParser.java @@ -44,7 +44,7 @@ public class VectorSimilarityQParser extends AbstractVectorQParserBase { @Override public Query parse() throws SyntaxError { final String fieldName = getFieldName(); - final SchemaField schemaField = req.getCore().getLatestSchema().getField(fieldName); + final SchemaField schemaField = req.getSchema().getField(fieldName); final DenseVectorField denseVectorType = getCheckedFieldType(schemaField); final String vectorToSearch = getVectorToSearch(); final float minTraverse = localParams.getFloat(MIN_TRAVERSE, DEFAULT_MIN_TRAVERSE); diff --git a/solr/core/src/java/org/apache/solr/update/processor/ContentHashVersionProcessor.java b/solr/core/src/java/org/apache/solr/update/processor/ContentHashVersionProcessor.java index 457dcc92e16..c993416cfb5 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/ContentHashVersionProcessor.java +++ b/solr/core/src/java/org/apache/solr/update/processor/ContentHashVersionProcessor.java @@ -78,7 +78,7 @@ public class ContentHashVersionProcessor extends UpdateRequestProcessor { super(next); this.core = req.getCore(); - IndexSchema schema = core.getLatestSchema(); + IndexSchema schema = req.getSchema(); this.hashField = schema.getField(hashFieldName); this.dropSameDocuments = dropSameDocuments; this.rsp = rsp; diff --git a/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java b/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java index 48ecc0f7eed..cbec1472649 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java +++ b/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java @@ -86,7 +86,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor this.supportMissingVersionOnOldDocs = supportMissingVersionOnOldDocs; this.core = req.getCore(); this.versionFieldNames = versionFields.toArray(EMPTY_STR_ARR); - IndexSchema schema = core.getLatestSchema(); + IndexSchema schema = req.getSchema(); userVersionFields = new SchemaField[versionFieldNames.length]; for (int i = 0; i < versionFieldNames.length; i++) { userVersionFields[i] = schema.getField(versionFieldNames[i]); @@ -469,7 +469,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor SolrInputDocument newDoc = createTombstoneDocument( - core.getLatestSchema(), + cmd.getReq().getSchema(), cmd.getId(), versionFieldNames, deleteParamValues, @@ -500,7 +500,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor SolrInputDocument newDoc = createTombstoneDocument( - core.getLatestSchema(), + cmd.getReq().getSchema(), cmd.getId(), versionFieldNames, deleteParamValues, diff --git a/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java b/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java index 0e2e1a6ca8a..bec2d21db22 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java +++ b/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java @@ -128,7 +128,7 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor { assert !DistribPhase.FROMLEADER.equals(distribPhase); this.zkController = this.req.getCoreContainer().getZkController(); - this.uniqueKeyField = this.req.getCore().getLatestSchema().getUniqueKeyField(); + this.uniqueKeyField = this.req.getSchema().getUniqueKeyField(); assert null != uniqueKeyField : "Factory didn't enforce uniqueKey field?"; } diff --git a/solr/core/src/test/org/apache/solr/update/processor/ContentHashVersionProcessorTest.java b/solr/core/src/test/org/apache/solr/update/processor/ContentHashVersionProcessorTest.java index 4a3764ed6a7..65cf6287fc2 100644 --- a/solr/core/src/test/org/apache/solr/update/processor/ContentHashVersionProcessorTest.java +++ b/solr/core/src/test/org/apache/solr/update/processor/ContentHashVersionProcessorTest.java @@ -96,8 +96,8 @@ public class ContentHashVersionProcessorTest extends UpdateProcessorTestBase { final IndexSchema indexSchema = mock(IndexSchema.class); when(indexSchema.getField("_hash_")).thenReturn(new SchemaField("_hash_", new BinaryField())); - when(solrCore.getLatestSchema()).thenReturn(indexSchema); when(req.getCore()).thenReturn(solrCore); + when(req.getSchema()).thenReturn(indexSchema); return new ContentHashVersionProcessor( ContentHashVersionProcessorFactory.buildFieldMatcher(includedFields), ContentHashVersionProcessorFactory.buildFieldMatcher(excludedFields), diff --git a/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/search/TextToVectorQParserPlugin.java b/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/search/TextToVectorQParserPlugin.java index 449b4b6dd76..111a49cc11a 100644 --- a/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/search/TextToVectorQParserPlugin.java +++ b/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/search/TextToVectorQParserPlugin.java @@ -86,7 +86,7 @@ public class TextToVectorQParserPlugin extends QParserPlugin SolrTextToVectorModel textToVector = modelStore.getModel(embeddingModelName); if (textToVector != null) { - final SchemaField schemaField = req.getCore().getLatestSchema().getField(getFieldName()); + final SchemaField schemaField = req.getSchema().getField(getFieldName()); final DenseVectorField denseVectorType = getCheckedFieldType(schemaField); int fieldDimensions = denseVectorType.getDimension(); VectorEncoding vectorEncoding = denseVectorType.getVectorEncoding(); diff --git a/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorFactory.java b/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorFactory.java index 07653df62dd..20cd9a09a74 100644 --- a/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorFactory.java +++ b/solr/modules/llm/src/java/org/apache/solr/llm/textvectorisation/update/processor/TextToVectorUpdateProcessorFactory.java @@ -69,18 +69,19 @@ public class TextToVectorUpdateProcessorFactory extends UpdateRequestProcessorFa @Override public UpdateRequestProcessor getInstance( SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next) { - IndexSchema latestSchema = req.getCore().getLatestSchema(); + IndexSchema requestSchema = req.getSchema(); - if (!latestSchema.isDynamicField(inputField) && !latestSchema.hasExplicitField(inputField)) { + if (!requestSchema.isDynamicField(inputField) && !requestSchema.hasExplicitField(inputField)) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "undefined field: \"" + inputField + "\""); } - if (!latestSchema.isDynamicField(outputField) && !latestSchema.hasExplicitField(outputField)) { + if (!requestSchema.isDynamicField(outputField) + && !requestSchema.hasExplicitField(outputField)) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "undefined field: \"" + outputField + "\""); } - final SchemaField outputFieldSchema = latestSchema.getField(outputField); + final SchemaField outputFieldSchema = requestSchema.getField(outputField); assertIsDenseVectorField(outputFieldSchema); ManagedTextToVectorModelStore modelStore =
