PageRenderTime 42ms CodeModel.GetById 2ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 1ms

/ToMigrate/Raven.Database/Storage/IndexDefinitionStorage.cs

Relevant Search: With Applications for Solr and Elasticsearch

'Chapter 4. Taming tokens'. If you want to know how to extract ideas rather than words this book is for you. Learn concepts of precision and recall, making trade-offs between them and controlling the specificity of matches. Amazon Affiliate Link
http://github.com/ayende/ravendb
C# | 680 lines | 566 code | 104 blank | 10 comment | 65 complexity | 5e3c8eddfcb3f020ac398412906f304e MD5 | raw file
  1//-----------------------------------------------------------------------
  2// <copyright file="IndexDefinitionStorage.cs" company="Hibernating Rhinos LTD">
  3//     Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4// </copyright>
  5//-----------------------------------------------------------------------
  6using System;
  7using System.Collections.Concurrent;
  8using System.Collections.Generic;
  9using System.ComponentModel;
 10using System.Globalization;
 11using System.IO;
 12using System.Linq;
 13using System.Security.Cryptography;
 14using System.Text;
 15using System.Threading;
 16using Lucene.Net.Analysis.Standard;
 17using Lucene.Net.Documents;
 18using Mono.CSharp;
 19using Mono.CSharp.Linq;
 20using Raven.Abstractions.Data;
 21using Raven.Abstractions.Logging;
 22using Raven.Database.Indexing.IndexMerging;
 23using Raven.Imports.Newtonsoft.Json;
 24using Raven.Abstractions;
 25using Raven.Abstractions.Extensions;
 26using Raven.Abstractions.Indexing;
 27using Raven.Abstractions.MEF;
 28using Raven.Database.Config;
 29using Raven.Database.Extensions;
 30using Raven.Database.Linq;
 31using Raven.Database.Plugins;
 32using Raven.Database.Indexing;
 33
 34namespace Raven.Database.Storage
 35{
 36    public class IndexDefinitionStorage
 37    {
 38        private const string IndexDefDir = "IndexDefinitions";
 39
 40        private readonly ReaderWriterLockSlim currentlyIndexingLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
 41        public long currentlyIndexing;
 42
 43        private readonly ConcurrentDictionary<int, AbstractViewGenerator> indexCache =
 44            new ConcurrentDictionary<int, AbstractViewGenerator>();
 45
 46        private readonly ConcurrentDictionary<int, AbstractTransformer> transformCache =
 47            new ConcurrentDictionary<int, AbstractTransformer>();
 48
 49        private readonly ConcurrentDictionary<string, int> indexNameToId =
 50            new ConcurrentDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
 51
 52        private readonly ConcurrentDictionary<string, int> transformNameToId =
 53            new ConcurrentDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
 54
 55        private readonly ConcurrentDictionary<int, TransformerDefinition> transformDefinitions =
 56            new ConcurrentDictionary<int, TransformerDefinition>();
 57
 58        private readonly ConcurrentDictionary<int, IndexDefinition> indexDefinitions =
 59            new ConcurrentDictionary<int, IndexDefinition>();
 60
 61        private readonly ConcurrentDictionary<int, IndexDefinition> newDefinitionsThisSession =
 62            new ConcurrentDictionary<int, IndexDefinition>();
 63
 64        private static readonly ILog logger = LogManager.GetCurrentClassLogger();
 65        private readonly string path;
 66        private readonly RavenConfiguration configuration;
 67
 68        private readonly ITransactionalStorage transactionalStorage;
 69
 70        private readonly OrderedPartCollection<AbstractDynamicCompilationExtension> extensions;
 71
 72        [CLSCompliant(false)]
 73        public IndexDefinitionStorage(
 74            RavenConfiguration configuration,
 75            ITransactionalStorage transactionalStorage,
 76            string path,
 77            OrderedPartCollection<AbstractDynamicCompilationExtension> extensions)
 78        {
 79            this.configuration = configuration;
 80            this.transactionalStorage = transactionalStorage;
 81            this.extensions = extensions; // this is used later in the ctor, so it must appears first
 82            this.path = Path.Combine(path, IndexDefDir);
 83
 84            if (Directory.Exists(this.path) == false && configuration.Core.RunInMemory == false)
 85                Directory.CreateDirectory(this.path);
 86        }
 87
 88        internal Dictionary<int, DocumentDatabase.IndexFailDetails> Initialize()
 89        {
 90            Dictionary<int, DocumentDatabase.IndexFailDetails> reason = null;
 91            if (configuration.Core.RunInMemory == false)
 92                reason = ReadFromDisk();
 93            newDefinitionsThisSession.Clear();
 94
 95            return reason;
 96        }
 97
 98        public bool IsNewThisSession(IndexDefinition definition)
 99        {
100            return newDefinitionsThisSession.ContainsKey(definition.IndexId);
101        }
102
103        private Dictionary<int, DocumentDatabase.IndexFailDetails> ReadFromDisk()
104        {
105            var indexFailReason = new Dictionary<int, DocumentDatabase.IndexFailDetails>();
106            if (logger.IsDebugEnabled)
107                logger.Debug("Reading index definitions from disk...");
108
109            foreach (var indexDefinition in ReadIndexDefinitionsFromDisk())
110            {
111                try
112                {
113                    if (Contains(indexDefinition.Name)) // checking if there are no older indexes with the same name
114                        RemoveIndexAndCleanup(indexDefinition.Name);
115
116                    ResolveAnalyzers(indexDefinition);
117                    AddAndCompileIndex(indexDefinition);
118                    AddIndex(indexDefinition.IndexId, indexDefinition);
119                }
120                catch (Exception e)
121                {
122                    var reason = new DocumentDatabase.IndexFailDetails
123                    {
124                        IndexName = indexDefinition.Name,
125                        Reason = string.Format("Index '{0}-({1})' couldn't be compiled", indexDefinition.IndexId, indexDefinition.Name),
126                        Ex = e
127                    };
128
129                    indexFailReason.Add(indexDefinition.IndexId, reason);
130
131                    using (LogContext.WithDatabase(configuration.DatabaseName))
132                    {
133                        logger.WarnException(string.Format("Could not compile index '{0} ({1})', skipping bad index", indexDefinition.IndexId, indexDefinition.Name), e);
134                    }
135                }
136            }
137
138            if (logger.IsDebugEnabled)
139            {
140                logger.Debug("Read {0} index definitions", indexDefinitions.Count);
141
142                logger.Debug("Reading transformer definitions from disk...");
143            }
144
145            foreach (var transformerDefinition in ReadTransformerDefinitionsFromDisk())
146            {
147                try
148                {
149                    RemoveTransformer(transformerDefinition.Name);
150
151                    var generator = CompileTransform(transformerDefinition);
152                    transformCache[transformerDefinition.TransfomerId] = generator;
153                    AddTransform(transformerDefinition.TransfomerId, transformerDefinition);
154                }
155                catch (Exception e)
156                {
157                    logger.WarnException(string.Format("Could not compile transformer '{0} ({1})', skipping bad transformer", transformerDefinition.TransfomerId, transformerDefinition.Name), e);
158                }
159            }
160
161            if (logger.IsDebugEnabled)
162                logger.Debug("Read {0} transform definitions", transformDefinitions.Count);
163
164            return indexFailReason;
165        }
166
167        private IEnumerable<IndexDefinition> ReadIndexDefinitionsFromDisk()
168        {
169            var result = new SortedList<int, IndexDefinition>();
170
171            foreach (var index in Directory.GetFiles(path, "*.index"))
172            {
173                try
174                {
175                    var indexDefinition = JsonConvert.DeserializeObject<IndexDefinition>(File.ReadAllText(index), Default.Converters);
176                    result.Add(indexDefinition.IndexId, indexDefinition);
177                }
178                catch (Exception e)
179                {
180                    logger.WarnException("Could not compile index " + index + ", skipping bad index", e);
181                }
182            }
183
184            return result.Values;
185        }
186
187        private IEnumerable<TransformerDefinition> ReadTransformerDefinitionsFromDisk()
188        {
189            var result = new SortedList<int, TransformerDefinition>();
190
191            foreach (var transformer in Directory.GetFiles(path, "*.transform"))
192            {
193                try
194                {
195                    var transformerDefinition = JsonConvert.DeserializeObject<TransformerDefinition>(File.ReadAllText(transformer), Default.Converters);
196
197                    result.Add(transformerDefinition.TransfomerId, transformerDefinition);
198                }
199                catch (Exception e)
200                {
201                    logger.WarnException("Could not compile transformer " + transformer + ", skipping bad transformer", e);
202                }
203            }
204
205            return result.Values;
206        }
207
208        private void RemoveIndexAndCleanup(string name)
209        {
210            var index = GetIndexDefinition(name);
211            if (index == null)
212                return;
213
214            transactionalStorage.Batch(accessor =>
215            {
216                accessor.Indexing.PrepareIndexForDeletion(index.IndexId);
217                accessor.Indexing.DeleteIndex(index.IndexId, CancellationToken.None);
218            });
219
220            RemoveIndex(index.IndexId);
221        }
222
223        public int IndexesCount
224        {
225            get { return indexCache.Count; }
226        }
227
228        public int ResultTransformersCount
229        {
230            get { return transformCache.Count; }
231        }
232
233        public string[] IndexNames
234        {
235            get { return IndexDefinitions.Values.OrderBy(x => x.Name).Select(x => x.Name).ToArray(); }
236        }
237
238        public int[] Indexes
239        {
240            get { return indexCache.Keys.OrderBy(name => name).ToArray(); }
241        }
242
243        public string IndexDefinitionsPath
244        {
245            get { return path; }
246        }
247
248        public string[] TransformerNames
249        {
250            get
251            {
252                return transformDefinitions.Values
253                                           .Where(x => !x.Temporary)
254                                           .OrderBy(x => x.Name)
255                                           .Select(x => x.Name)
256                                           .ToArray();
257            }
258        }
259
260        public ConcurrentDictionary<int, IndexDefinition> IndexDefinitions
261        {
262            get { return indexDefinitions; }
263        }
264
265        public string CreateAndPersistIndex(IndexDefinition indexDefinition)
266        {
267            var transformer = AddAndCompileIndex(indexDefinition);
268            if (configuration.Core.RunInMemory == false)
269            {
270                WriteIndexDefinition(indexDefinition);
271            }
272            return transformer.Name;
273        }
274
275        private void WriteIndexDefinition(IndexDefinition indexDefinition)
276        {
277            if (configuration.Core.RunInMemory)
278                return;
279            var indexName = System.IO.Path.Combine(path, indexDefinition.IndexId + ".index");
280            var serializedObject = JsonConvert.SerializeObject(indexDefinition, Formatting.Indented, Default.Converters);
281            File.WriteAllText(indexName, serializedObject);
282        }
283
284        private void WriteTransformerDefinition(TransformerDefinition transformerDefinition)
285        {
286            if (configuration.Core.RunInMemory)
287                return;
288
289            string transformerFileName = System.IO.Path.Combine(path, transformerDefinition.TransfomerId + ".transform");
290
291            File.WriteAllText(transformerFileName,
292                              JsonConvert.SerializeObject(transformerDefinition, Formatting.Indented, Default.Converters));
293        }
294
295        [CLSCompliant(false)]
296        public string CreateTransform(TransformerDefinition transformerDefinition, AbstractTransformer transformer)
297        {
298            transformCache.AddOrUpdate(transformerDefinition.TransfomerId, transformer, (s, viewGenerator) => transformer);
299            return transformer.Name;
300        }
301
302        [CLSCompliant(false)]
303        public void PersistTransform(TransformerDefinition transformerDefinition)
304        {
305            if (configuration.Core.RunInMemory == false)
306            {
307                WriteTransformerDefinition(transformerDefinition);
308            }
309        }
310
311        public void UpdateIndexDefinitionWithoutUpdatingCompiledIndex(IndexDefinition definition)
312        {
313            IndexDefinitions.AddOrUpdate(definition.IndexId, s =>
314            {
315                throw new InvalidOperationException(
316                    "Cannot find index named: " +
317                    definition.IndexId);
318            }, (s, indexDefinition) => definition);
319            WriteIndexDefinition(definition);
320        }
321
322        private DynamicViewCompiler AddAndCompileIndex(IndexDefinition indexDefinition)
323        {
324            var transformer = new DynamicViewCompiler(indexDefinition.Name, indexDefinition, extensions, path,
325                                                      configuration);
326            var generator = transformer.GenerateInstance();
327            indexCache.AddOrUpdate(indexDefinition.IndexId, generator, (s, viewGenerator) => generator);
328
329            logger.Info("New index {0}:\r\n{1}\r\nCompiled to:\r\n{2}", transformer.Name, transformer.CompiledQueryText,
330                        transformer.CompiledQueryText);
331            return transformer;
332        }
333
334        [CLSCompliant(false)]
335        public AbstractTransformer CompileTransform(TransformerDefinition transformerDefinition)
336        {
337            var transformer = new DynamicTransformerCompiler(transformerDefinition, configuration, extensions,
338                                                             transformerDefinition.Name, path);
339            var generator = transformer.GenerateInstance();
340
341            logger.Info("New transformer {0}:\r\n{1}\r\nCompiled to:\r\n{2}", transformer.Name,
342                        transformer.CompiledQueryText,
343                        transformer.CompiledQueryText);
344            return generator;
345        }
346
347        public void RegisterNewIndexInThisSession(string name, IndexDefinition definition)
348        {
349            newDefinitionsThisSession.TryAdd(definition.IndexId, definition);
350        }
351
352        public void AddIndex(int id, IndexDefinition definition)
353        {
354            IndexDefinitions.AddOrUpdate(id, definition, (s1, def) =>
355            {
356                if (def.IsCompiled)
357                    throw new InvalidOperationException("Index " + id + " is a compiled index, and cannot be replaced");
358                return definition;
359            });
360            indexNameToId[definition.Name] = id;
361
362            UpdateIndexMappingFile();
363        }
364
365        public void AddTransform(int id, TransformerDefinition definition)
366        {
367            transformDefinitions.AddOrUpdate(id, definition, (s1, def) => definition);
368            transformNameToId[definition.Name] = id;
369
370            UpdateTransformerMappingFile();
371        }
372
373        public void RemoveIndex(int id, bool removeByNameMapping = true)
374        {
375            AbstractViewGenerator ignoredViewGenerator;
376            int ignoredId;
377            if (indexCache.TryRemove(id, out ignoredViewGenerator) && removeByNameMapping)
378                indexNameToId.TryRemove(ignoredViewGenerator.Name, out ignoredId);
379            IndexDefinition ignoredIndexDefinition;
380            IndexDefinitions.TryRemove(id, out ignoredIndexDefinition);
381            newDefinitionsThisSession.TryRemove(id, out ignoredIndexDefinition);
382            if (configuration.Core.RunInMemory)
383                return;
384            File.Delete(GetIndexSourcePath(id) + ".index");
385            UpdateIndexMappingFile();
386        }
387
388        private string GetIndexSourcePath(int id)
389        {
390            return System.IO.Path.Combine(path, id.ToString());
391        }
392
393        public IndexDefinition GetIndexDefinition(string name)
394        {
395            int id = 0;
396            if (indexNameToId.TryGetValue(name, out id))
397            {
398                IndexDefinition indexDefinition = IndexDefinitions[id];
399                if (indexDefinition.Fields.Count == 0)
400                {
401                    AbstractViewGenerator abstractViewGenerator = GetViewGenerator(id);
402                    indexDefinition.Fields = abstractViewGenerator.Fields;
403                }
404                return indexDefinition;
405            }
406            return null;
407        }
408
409        public IndexDefinition GetIndexDefinition(int id)
410        {
411            IndexDefinition value;
412            IndexDefinitions.TryGetValue(id, out value);
413            return value;
414        }
415
416        public TransformerDefinition GetTransformerDefinition(string name)
417        {
418            int id;
419            if (transformNameToId.TryGetValue(name, out id))
420                return transformDefinitions[id];
421            return null;
422        }
423
424        public IEnumerable<TransformerDefinition> GetAllTransformerDefinitions()
425        {
426            return transformDefinitions.Select(definition => definition.Value);
427        }
428
429        public IndexMergeResults ProposeIndexMergeSuggestions()
430        {
431            var indexMerger = new IndexMerger(IndexDefinitions.ToDictionary(x => x.Key, x => x.Value));
432            return indexMerger.ProposeIndexMergeSuggestions();
433        }
434
435        public TransformerDefinition GetTransformerDefinition(int id)
436        {
437            TransformerDefinition value;
438            transformDefinitions.TryGetValue(id, out value);
439            return value;
440        }
441
442        [CLSCompliant(false)]
443        public AbstractViewGenerator GetViewGenerator(string name)
444        {
445            int id = 0;
446            if (indexNameToId.TryGetValue(name, out id))
447                return indexCache[id];
448            return null;
449        }
450
451        [CLSCompliant(false)]
452        public AbstractViewGenerator GetViewGenerator(int id)
453        {
454            AbstractViewGenerator value;
455            if (indexCache.TryGetValue(id, out value) == false)
456                return null;
457            return value;
458        }
459
460        public IndexCreationOptions FindIndexCreationOptions(IndexDefinition newIndexDef)
461        {
462            var currentIndexDefinition = GetIndexDefinition(newIndexDef.Name);
463            if (currentIndexDefinition == null)
464            {
465                if (CheckIfIndexIsBeenDeleted(newIndexDef))
466                {
467                    //index is been deleted ignoring this index
468                    return IndexCreationOptions.Noop;
469                }
470                if (newIndexDef.IndexVersion == null)
471                    newIndexDef.IndexVersion = 0;
472                return IndexCreationOptions.Create;
473            }
474            
475            if (newIndexDef.IndexVersion == null)
476                newIndexDef.IndexVersion = currentIndexDefinition.IndexVersion + 1;
477            if (currentIndexDefinition.IsTestIndex) // always update test indexes
478                return IndexCreationOptions.Update;
479
480            newIndexDef.IndexId = currentIndexDefinition.IndexId;
481            var result = currentIndexDefinition.Equals(newIndexDef);
482            if (result)
483                return IndexCreationOptions.Noop;
484
485            // try to compare to find changes which doesn't require removing compiled index
486            return currentIndexDefinition.Equals(newIndexDef, ignoreFormatting: true, ignoreMaxIndexOutput: true)
487                ? IndexCreationOptions.UpdateWithoutUpdatingCompiledIndex : IndexCreationOptions.Update;
488        }
489
490        private bool CheckIfIndexIsBeenDeleted(IndexDefinition definition)
491        {
492            return CheckIfIndexVersionIsEqualOrSmaller(definition, Constants.RavenReplicationIndexesTombstones)
493                || CheckIfIndexVersionIsEqualOrSmaller(definition, "Raven/Indexes/PendingDeletion");
494        }
495
496        private bool CheckIfIndexVersionIsEqualOrSmaller(IndexDefinition definition, string listName)
497        {
498            bool res = false;
499            if (definition.IndexVersion == null) return false;
500            transactionalStorage.Batch(action =>
501            {
502                var li = action.Lists.Read(listName, definition.Name);
503                if (li == null) return;
504                int version;
505                string versionStr = li.Data.Value<string>("IndexVersion");
506                // The index that we are trying to add is deleted
507                if (int.TryParse(versionStr, out version))
508                {
509                    if (version >= definition.IndexVersion.Value)
510                    {
511                        if (version > definition.IndexVersion.Value)
512                            logger.Error("Trying to add an index ({0}) with a version smaller than the deleted version, this should not happen", definition.Name);
513                        res = true;
514                    }
515                }
516                else
517                {
518                    logger.Error("Failed to parse index version of index {0}", definition.Name);
519                }
520            });
521            return res;
522        }
523
524public bool Contains(string indexName)
525        {
526            return indexNameToId.ContainsKey(indexName);
527        }
528
529        public static void ResolveAnalyzers(IndexDefinition indexDefinition)
530        {
531            // Stick Lucene.Net's namespace to all analyzer aliases that are missing a namespace
532            var analyzerNames = (from analyzer in indexDefinition.Analyzers
533                                 where analyzer.Value.IndexOf('.') == -1
534                                 select analyzer).ToArray();
535
536            // Only do this for analyzer that actually exist; we do this here to be able to throw a correct error later on
537            foreach (
538                var a in
539                    analyzerNames.Where(
540                        a => typeof(StandardAnalyzer).Assembly.GetType("Lucene.Net.Analysis." + a.Value) != null))
541            {
542                indexDefinition.Analyzers[a.Key] = "Lucene.Net.Analysis." + a.Value;
543            }
544        }
545
546        public IDisposable TryRemoveIndexContext()
547        {
548            if (currentlyIndexingLock.TryEnterWriteLock(TimeSpan.FromSeconds(60)) == false)
549                throw new InvalidOperationException(
550                    "Cannot modify indexes while indexing is in progress (already waited full minute). Try again later");
551            return new DisposableAction(currentlyIndexingLock.ExitWriteLock);
552        }
553
554
555        public bool IsCurrentlyIndexing()
556        {
557            return Interlocked.Read(ref currentlyIndexing) != 0;
558        }
559
560        [CLSCompliant(false)]
561        public IDisposable CurrentlyIndexing()
562        {
563            currentlyIndexingLock.EnterReadLock();
564            Interlocked.Increment(ref currentlyIndexing);
565            return new DisposableAction(() =>
566            {
567                currentlyIndexingLock.ExitReadLock();
568                Interlocked.Decrement(ref currentlyIndexing);
569            });
570        }
571
572        public bool RemoveTransformer(string name)
573        {
574            var transformer = GetTransformerDefinition(name);
575            if (transformer == null)
576                return false;
577            RemoveTransformer(transformer.TransfomerId);
578
579            return true;
580        }
581
582        public void RemoveIndex(string name)
583        {
584            var index = GetIndexDefinition(name);
585            if (index == null) return;
586            RemoveIndex(index.IndexId);
587        }
588
589        public void RemoveTransformer(int id)
590        {
591            AbstractTransformer ignoredViewGenerator;
592            int ignoredId;
593            if (transformCache.TryRemove(id, out ignoredViewGenerator))
594                transformNameToId.TryRemove(ignoredViewGenerator.Name, out ignoredId);
595            TransformerDefinition ignoredIndexDefinition;
596            transformDefinitions.TryRemove(id, out ignoredIndexDefinition);
597            if (configuration.Core.RunInMemory)
598                return;
599            File.Delete(GetIndexSourcePath(id) + ".transform");
600            UpdateTransformerMappingFile();
601        }
602
603        [CLSCompliant(false)]
604        public AbstractTransformer GetTransformer(int id)
605        {
606            AbstractTransformer value;
607            if (transformCache.TryGetValue(id, out value) == false)
608                return null;
609            return value;
610        }
611
612        [CLSCompliant(false)]
613        public AbstractTransformer GetTransformer(string name)
614        {
615            int id = 0;
616            if (transformNameToId.TryGetValue(name, out id))
617                return transformCache[id];
618            return null;
619        }
620
621        internal bool ReplaceIndex(string indexName, string indexToSwapName)
622        {
623            var index = GetIndexDefinition(indexName);
624            if (index == null)
625                return false;
626
627            int _;
628            indexNameToId.TryRemove(index.Name, out _);
629            index.IsSideBySideIndex = false;
630
631            var indexToReplace = GetIndexDefinition(indexToSwapName);
632            index.Name = indexToReplace != null ? indexToReplace.Name : indexToSwapName;
633            CreateAndPersistIndex(index);
634            AddIndex(index.IndexId, index);
635
636            return true;
637        }
638
639        private void UpdateIndexMappingFile()
640        {
641            if (configuration.Core.RunInMemory)
642                return;
643
644            var sb = new StringBuilder();
645
646            foreach (var index in indexNameToId)
647            {
648                sb.Append(string.Format("{0} - {1}{2}", index.Value, index.Key, Environment.NewLine));
649            }
650
651            File.WriteAllText(System.IO.Path.Combine(path, "indexes.txt"), sb.ToString());
652        }
653
654        private void UpdateTransformerMappingFile()
655        {
656            if (configuration.Core.RunInMemory)
657                return;
658
659            var sb = new StringBuilder();
660
661            foreach (var transform in transformNameToId)
662            {
663                sb.Append(string.Format("{0} - {1}{2}", transform.Value, transform.Key, Environment.NewLine));
664            }
665
666            File.WriteAllText(System.IO.Path.Combine(path, "transformers.txt"), sb.ToString());
667        }
668
669        public void UpdateTransformerDefinitionWithoutUpdatingCompiledTransformer(TransformerDefinition definition)
670        {
671            transformDefinitions.AddOrUpdate(definition.TransfomerId, s =>
672            {
673                throw new InvalidOperationException(
674                    "Cannot find transformer named: " +
675                    definition.TransfomerId);
676            }, (s, transformerDefinition) => definition);
677            WriteTransformerDefinition(definition);
678        }
679    }
680}