1919
2020package org .elasticsearch .indices ;
2121
22+ import com .carrotsearch .hppc .cursors .ObjectCursor ;
2223import org .apache .lucene .index .DirectoryReader ;
2324import org .apache .lucene .store .LockObtainFailedException ;
2425import org .apache .lucene .util .CollectionUtil ;
3334import org .elasticsearch .cluster .ClusterState ;
3435import org .elasticsearch .cluster .metadata .IndexMetaData ;
3536import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
37+ import org .elasticsearch .cluster .metadata .MappingMetaData ;
3638import org .elasticsearch .cluster .service .ClusterService ;
3739import org .elasticsearch .common .Nullable ;
3840import org .elasticsearch .common .breaker .CircuitBreaker ;
6668import org .elasticsearch .index .fielddata .IndexFieldDataCache ;
6769import org .elasticsearch .index .flush .FlushStats ;
6870import org .elasticsearch .index .get .GetStats ;
71+ import org .elasticsearch .index .mapper .MapperService ;
6972import org .elasticsearch .index .merge .MergeStats ;
7073import org .elasticsearch .index .recovery .RecoveryStats ;
7174import org .elasticsearch .index .refresh .RefreshStats ;
7477import org .elasticsearch .index .shard .IndexEventListener ;
7578import org .elasticsearch .index .shard .IndexShard ;
7679import org .elasticsearch .index .shard .IndexShardState ;
80+ import org .elasticsearch .index .shard .IndexingOperationListener ;
7781import org .elasticsearch .index .shard .IndexingStats ;
7882import org .elasticsearch .index .shard .ShardId ;
7983import org .elasticsearch .index .store .IndexStoreConfig ;
8892import org .elasticsearch .search .query .QuerySearchResult ;
8993import org .elasticsearch .threadpool .ThreadPool ;
9094
95+ import java .io .Closeable ;
9196import java .io .IOException ;
9297import java .nio .file .Files ;
9398import java .util .ArrayList ;
99+ import java .util .Collections ;
94100import java .util .EnumSet ;
95101import java .util .HashMap ;
96102import java .util .Iterator ;
@@ -324,44 +330,30 @@ public IndexService indexServiceSafe(Index index) {
324330 * @throws IndexAlreadyExistsException if the index already exists.
325331 */
326332 public synchronized IndexService createIndex (final NodeServicesProvider nodeServicesProvider , IndexMetaData indexMetaData , List <IndexEventListener > builtInListeners ) throws IOException {
333+
327334 if (!lifecycle .started ()) {
328335 throw new IllegalStateException ("Can't create an index [" + indexMetaData .getIndex () + "], node is closed" );
329336 }
330337 if (indexMetaData .getIndexUUID ().equals (IndexMetaData .INDEX_UUID_NA_VALUE )) {
331338 throw new IllegalArgumentException ("index must have a real UUID found value: [" + indexMetaData .getIndexUUID () + "]" );
332339 }
333340 final Index index = indexMetaData .getIndex ();
334- final Predicate <String > indexNameMatcher = (indexExpression ) -> indexNameExpressionResolver .matchesIndex (index .getName (), indexExpression , clusterService .state ());
335- final IndexSettings idxSettings = new IndexSettings (indexMetaData , this .settings , indexNameMatcher , indexScopeSetting );
336341 if (hasIndex (index )) {
337342 throw new IndexAlreadyExistsException (index );
338343 }
339- logger .debug ("creating Index [{}], shards [{}]/[{}{}]" ,
340- indexMetaData .getIndex (),
341- idxSettings .getNumberOfShards (),
342- idxSettings .getNumberOfReplicas (),
343- idxSettings .isShadowReplicaIndex () ? "s" : "" );
344-
345- final IndexModule indexModule = new IndexModule (idxSettings , indexStoreConfig , analysisRegistry );
346- pluginsService .onIndexModule (indexModule );
347- for (IndexEventListener listener : builtInListeners ) {
348- indexModule .addIndexEventListener (listener );
349- }
344+ List <IndexEventListener > finalListeners = new ArrayList <>(builtInListeners );
350345 final IndexEventListener onStoreClose = new IndexEventListener () {
351346 @ Override
352347 public void onStoreClosed (ShardId shardId ) {
353348 indicesQueryCache .onClose (shardId );
354349 }
355350 };
356- indexModule .addIndexEventListener (onStoreClose );
357- indexModule .addIndexEventListener (oldShardsStats );
358- final IndexEventListener listener = indexModule .freeze ();
359- listener .beforeIndexCreated (index , idxSettings .getSettings ());
360- final IndexService indexService = indexModule .newIndexService (nodeEnv , this , nodeServicesProvider , indicesQueryCache , mapperRegistry , indicesFieldDataCache , indexingMemoryController );
351+ finalListeners .add (onStoreClose );
352+ finalListeners .add (oldShardsStats );
353+ final IndexService indexService = createIndexService ("create index" , nodeServicesProvider , indexMetaData , indicesQueryCache , indicesFieldDataCache , finalListeners , indexingMemoryController );
361354 boolean success = false ;
362355 try {
363- assert indexService .getIndexEventListener () == listener ;
364- listener .afterIndexCreated (indexService );
356+ indexService .getIndexEventListener ().afterIndexCreated (indexService );
365357 indices = newMapBuilder (indices ).put (index .getUUID (), indexService ).immutableMap ();
366358 success = true ;
367359 return indexService ;
@@ -370,7 +362,54 @@ public void onStoreClosed(ShardId shardId) {
370362 indexService .close ("plugins_failed" , true );
371363 }
372364 }
365+ }
373366
367+ /**
368+ * This creates a new IndexService without registering it
369+ */
370+ private synchronized IndexService createIndexService (final String reason , final NodeServicesProvider nodeServicesProvider , IndexMetaData indexMetaData , IndicesQueryCache indicesQueryCache , IndicesFieldDataCache indicesFieldDataCache , List <IndexEventListener > builtInListeners , IndexingOperationListener ... indexingOperationListeners ) throws IOException {
371+ final Index index = indexMetaData .getIndex ();
372+ final Predicate <String > indexNameMatcher = (indexExpression ) -> indexNameExpressionResolver .matchesIndex (index .getName (), indexExpression , clusterService .state ());
373+ final IndexSettings idxSettings = new IndexSettings (indexMetaData , this .settings , indexNameMatcher , indexScopeSetting );
374+ logger .debug ("creating Index [{}], shards [{}]/[{}{}] - reason [{}]" ,
375+ indexMetaData .getIndex (),
376+ idxSettings .getNumberOfShards (),
377+ idxSettings .getNumberOfReplicas (),
378+ idxSettings .isShadowReplicaIndex () ? "s" : "" , reason );
379+
380+ final IndexModule indexModule = new IndexModule (idxSettings , indexStoreConfig , analysisRegistry );
381+ pluginsService .onIndexModule (indexModule );
382+ for (IndexEventListener listener : builtInListeners ) {
383+ indexModule .addIndexEventListener (listener );
384+ }
385+ final IndexEventListener listener = indexModule .freeze ();
386+ listener .beforeIndexCreated (index , idxSettings .getSettings ());
387+ return indexModule .newIndexService (nodeEnv , this , nodeServicesProvider , indicesQueryCache , mapperRegistry , indicesFieldDataCache , indexingOperationListeners );
388+ }
389+
390+ /**
391+ * This method verifies that the given {@link IndexMetaData} holds sane values to create an {@link IndexService}. This method will throw an
392+ * exception if the creation fails. The created {@link IndexService} will not be registered and will be closed immediately.
393+ */
394+ public synchronized void verifyIndexMetadata (final NodeServicesProvider nodeServicesProvider , IndexMetaData metaData ) throws IOException {
395+ final List <Closeable > closeables = new ArrayList <>();
396+ try {
397+ IndicesFieldDataCache indicesFieldDataCache = new IndicesFieldDataCache (settings , new IndexFieldDataCache .Listener () {});
398+ closeables .add (indicesFieldDataCache );
399+ IndicesQueryCache indicesQueryCache = new IndicesQueryCache (settings );
400+ closeables .add (indicesQueryCache );
401+ // this will also fail if some plugin fails etc. which is nice since we can verify that early
402+ final IndexService service = createIndexService ("metadata verification" , nodeServicesProvider ,
403+ metaData , indicesQueryCache , indicesFieldDataCache , Collections .emptyList ());
404+ for (ObjectCursor <MappingMetaData > typeMapping : metaData .getMappings ().values ()) {
405+ // don't apply the default mapping, it has been applied when the mapping was created
406+ service .mapperService ().merge (typeMapping .value .type (), typeMapping .value .source (),
407+ MapperService .MergeReason .MAPPING_RECOVERY , true );
408+ }
409+ closeables .add (() -> service .close ("metadata verification" , false ));
410+ } finally {
411+ IOUtils .close (closeables );
412+ }
374413 }
375414
376415 /**
0 commit comments