<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.flume.sink.solr.morphline;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.FlumeException;
import org.apache.flume.event.EventBuilder;
import org.apache.flume.interceptor.Interceptor;

import org.kitesdk.morphline.api.Command;
import org.kitesdk.morphline.api.Record;
import org.kitesdk.morphline.base.Fields;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;

/**
 * Flume Interceptor that executes a morphline on events that are intercepted.
 * 
 * Currently, there is a restriction in that the morphline must not generate more than one output
 * record for each input event.
 */
public class MorphlineInterceptor implements Interceptor {

  private final Context context;
  private final BlockingQueue<LocalMorphlineInterceptor> pool = new LinkedBlockingQueue();
  
  protected MorphlineInterceptor(Context context) {
    Preconditions.checkNotNull(context);
    this.context = context;
    returnToPool(new LocalMorphlineInterceptor(context)); // fail fast on morphline compilation exception
  }

  @Override
  public void initialize() {
  }

  @Override
  public void close() {
    List<LocalMorphlineInterceptor> interceptors = new ArrayList();
    pool.drainTo(interceptors);
    for (LocalMorphlineInterceptor interceptor : interceptors) {
      interceptor.close();
    }
  }

  @Override
  public List<Event> intercept(List<Event> events) {
    LocalMorphlineInterceptor interceptor = borrowFromPool();
    List<Event> results = interceptor.intercept(events);
    returnToPool(interceptor);
    return results;
  }
  
  @Override
  public Event intercept(Event event) {
    LocalMorphlineInterceptor interceptor = borrowFromPool();
    Event result = interceptor.intercept(event);
    returnToPool(interceptor);
    return result;
  }

  private void returnToPool(LocalMorphlineInterceptor interceptor) {
    try {
      pool.put(interceptor);
    } catch (InterruptedException e) {
      throw new FlumeException(e);
    }
  }
  
  private LocalMorphlineInterceptor borrowFromPool() {
    LocalMorphlineInterceptor interceptor = pool.poll();
    if (interceptor == null) {
      interceptor = new LocalMorphlineInterceptor(context);
    }
    return interceptor;
  }

  
  ///////////////////////////////////////////////////////////////////////////////
  // Nested classes:
  ///////////////////////////////////////////////////////////////////////////////
  /** Builder implementations MUST have a public no-arg constructor */
  public static class Builder implements Interceptor.Builder {<commit_msg>FLUME-2275. Improve scalability of MorphlineInterceptor under contention<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.flume.sink.solr.morphline;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.FlumeException;
import org.apache.flume.event.EventBuilder;
import org.apache.flume.interceptor.Interceptor;
import org.kitesdk.morphline.api.Command;
import org.kitesdk.morphline.api.Record;
import org.kitesdk.morphline.base.Fields;

import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;

/**
 * Flume Interceptor that executes a morphline on events that are intercepted.
 * 
 * Currently, there is a restriction in that the morphline must not generate more than one output
 * record for each input event.
 */
public class MorphlineInterceptor implements Interceptor {

  private final Context context;
  private final Queue<LocalMorphlineInterceptor> pool = new ConcurrentLinkedQueue<LocalMorphlineInterceptor>();
  
  protected MorphlineInterceptor(Context context) {
    Preconditions.checkNotNull(context);
    this.context = context;
    returnToPool(new LocalMorphlineInterceptor(context)); // fail fast on morphline compilation exception
  }

  @Override
  public void initialize() {
  }

  @Override
  public void close() {
    LocalMorphlineInterceptor interceptor;
    while ((interceptor = pool.poll()) != null) {
      interceptor.close();
    }
  }

  @Override
  public List<Event> intercept(List<Event> events) {
    LocalMorphlineInterceptor interceptor = borrowFromPool();
    List<Event> results = interceptor.intercept(events);
    returnToPool(interceptor);
    return results;
  }
  
  @Override
  public Event intercept(Event event) {
    LocalMorphlineInterceptor interceptor = borrowFromPool();
    Event result = interceptor.intercept(event);
    returnToPool(interceptor);
    return result;
  }

  private void returnToPool(LocalMorphlineInterceptor interceptor) {
    pool.add(interceptor);
  }
  
  private LocalMorphlineInterceptor borrowFromPool() {
    LocalMorphlineInterceptor interceptor = pool.poll();
    if (interceptor == null) {
      interceptor = new LocalMorphlineInterceptor(context);
    }
    return interceptor;
  }

  
  ///////////////////////////////////////////////////////////////////////////////
  // Nested classes:
  ///////////////////////////////////////////////////////////////////////////////
  /** Builder implementations MUST have a public no-arg constructor */
  public static class Builder implements Interceptor.Builder {
{'fraction_non_alphanumeric': 0.12104614541969054, 'fraction_numerical': 0.0016431603450636724, 'mean_word_length': 3.4809815950920244, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3322674', 'n_tokens_mistral': 1936, 'n_tokens_neox': 1896, 'n_words': 600}