<commit_before>/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2013 <NAME>, Cinchapi Software Collective
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.cinchapi.concourse.server.engine;

import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;

import org.cinchapi.common.annotate.DoNotInvoke;
import org.cinchapi.common.annotate.PackagePrivate;
import org.cinchapi.common.io.ByteBufferOutputStream;
import org.cinchapi.common.io.ByteBuffers;
import org.cinchapi.common.io.Byteable;
import org.cinchapi.common.io.ByteableCollections;
import org.cinchapi.common.io.Byteables;
import org.cinchapi.common.multithread.Lock;
import org.cinchapi.common.multithread.Lockable;
import org.cinchapi.common.multithread.Lockables;
import org.cinchapi.common.tools.Numbers;
import org.cinchapi.common.tools.Strings;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import static com.google.common.base.Preconditions.*;
import static org.mockito.Matchers.any;

/**
 * A versioned controlled collection of values, each of which is associated with
 * a {@code key} inside of a {@link Record}.
 * <p>
 * The values in a Field are maintained in insertion order and represented by:
 * <ul>
 * <li><strong>State</strong> - A snapshot of the values that <em>currently</em>
 * exist.</li>
 * <li><strong>History</strong> - A growing list of every written value ever
 * sorted by timestamp in ascending order. Whenever a write (add or remove)
 * occurs, the value is logged here. A value V is considered present at time T
 * if there are an odd number of values in the history <em>equal</em> to V with
 * a timestamp less than or equal to T.</li>
 * </ul>
 * <h2>Storage Requirements</h2>
 * <ul>
 * <li>The size required for the {@code state} is the sum of the size of each
 * Value plus 4 bytes.</li>
 * <li>The size required for the {@code history} is the product of 4 times the
 * total number of revisions plus the sum of the size of each value multiplied
 * by the number revisions involving that value.</li>
 * </ul>
 * <strong>Note:</strong> Because a Field is version controlled, it's size is
 * guaranteed to increase by at least the size of V for each write.
 * </p>
 * 
 * @param <K> - the {@link Byteable} key type
 * @param <V> - the {@link Storable} value type
 * @author jnelson
 */
@ThreadSafe
@PackagePrivate
abstract class Field<K extends Byteable, V extends Storable> implements
		Byteable,
		Lockable { /* package-private */

	/**
	 * Encode a Field identified by {@code key} with values belong to
	 * {@code valueClass} and {@code components} into a ByteBuffer. The encoded
	 * format is:
	 * <ol>
	 * <li>keyClassSize</li>
	 * <li>valueClassSize</li>
	 * <li>keySize</li>
	 * <li>component1Size</li>
	 * <li>...</li>
	 * <li>componentNSize</li>
	 * <li>keyClass</li>
	 * <li>valueClass</li>
	 * <li>key</li>
	 * <li>component1</li>
	 * <li>...</li>
	 * <li>componentN</li>
	 * </ol>
	 * 
	 * @param key
	 * @param valueClass
	 * @param components
	 * @return the encoded ByteBuffer
	 */
	@SafeVarargs
	public static <K extends Byteable, V extends Storable> ByteBuffer encodeAsByteBuffer(
			K key, Class<V> valueClass, Field<K, V>.Component... components) {
		ByteBufferOutputStream out = new ByteBufferOutputStream();
	
		// The key and value class names are stored in the Field so that the
		// components can be deserialized reflectively.
		Text keyClassName = Text.fromString(key.getClass().getName());
		Text valueClassName = valueClass == null ? Text.EMPTY : Text
				.fromString(valueClass.getName());
	
		// encode sizes
		out.write(keyClassName.size());
		out.write(valueClassName.size());
		out.write(key.size());
		for (Field<K, V>.Component component : components) {
			out.write(component.size());
		}
	
		// encode data
		out.write(keyClassName);
		out.write(valueClassName);
		out.write(key);
		for (Field<K, V>.Component component : components) {
			out.write(component);
		}
		out.close();
		log.debug("INFO FOR FIELD IDENTIFIED BY {}", key);
		log.debug("keyClassName is {} and {} bytes", keyClassName, keyClassName.size());
		log.debug("valueClassName is {} and {} bytes", valueClassName, valueClassName.size());
		log.debug("key is {} and {} bytes", key, key.size());
		log.debug("state is {} and {} bytes", components[0], components[0].size());
		log.debug("history is {} and {} bytes", components[1], components[1].size());
		log.debug("Total buffer is {} bytes", out.size());
		return out.toByteBuffer();
	}
	/**
	 * Return a <em>mock</em> field of {@code type}. Use this method instead
	 * of mocking {@code type} directly to ensure that the mock is compatible
	 * with the assumptions made in {@link Record}.
	 * 
	 * @param type
	 * @return the {@code field}
	 */
	@SuppressWarnings("unchecked")
	public static <T extends Field<K, V>, K extends Byteable, V extends Storable> T mock(
			Class<T> type) {
		T field = Mockito.mock(type);
		Mockito.doReturn(Lists.<V>newArrayList()).when(field).getValues();
		Mockito.doNothing().when(field).add((V) any(Storable.class));
		Mockito.doNothing().when(field).remove((V) any(Storable.class));
		Mockito.doThrow(UnsupportedOperationException.class).when(field)
				.getBytes();
		Mockito.doThrow(UnsupportedOperationException.class).when(field).size();
		return field;
	
	}

	/**
	 * The maximum number of bytes that can be used to encode a single Value.<commit_msg>Removed unnecessary debug logging<commit_after>/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2013 <NAME>, Cinchapi Software Collective
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.cinchapi.concourse.server.engine;

import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;

import org.cinchapi.common.annotate.DoNotInvoke;
import org.cinchapi.common.annotate.PackagePrivate;
import org.cinchapi.common.io.ByteBufferOutputStream;
import org.cinchapi.common.io.ByteBuffers;
import org.cinchapi.common.io.Byteable;
import org.cinchapi.common.io.ByteableCollections;
import org.cinchapi.common.io.Byteables;
import org.cinchapi.common.multithread.Lock;
import org.cinchapi.common.multithread.Lockable;
import org.cinchapi.common.multithread.Lockables;
import org.cinchapi.common.tools.Numbers;
import org.cinchapi.common.tools.Strings;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import static com.google.common.base.Preconditions.*;
import static org.mockito.Matchers.any;

/**
 * A versioned controlled collection of values, each of which is associated with
 * a {@code key} inside of a {@link Record}.
 * <p>
 * The values in a Field are maintained in insertion order and represented by:
 * <ul>
 * <li><strong>State</strong> - A snapshot of the values that <em>currently</em>
 * exist.</li>
 * <li><strong>History</strong> - A growing list of every written value ever
 * sorted by timestamp in ascending order. Whenever a write (add or remove)
 * occurs, the value is logged here. A value V is considered present at time T
 * if there are an odd number of values in the history <em>equal</em> to V with
 * a timestamp less than or equal to T.</li>
 * </ul>
 * <h2>Storage Requirements</h2>
 * <ul>
 * <li>The size required for the {@code state} is the sum of the size of each
 * Value plus 4 bytes.</li>
 * <li>The size required for the {@code history} is the product of 4 times the
 * total number of revisions plus the sum of the size of each value multiplied
 * by the number revisions involving that value.</li>
 * </ul>
 * <strong>Note:</strong> Because a Field is version controlled, it's size is
 * guaranteed to increase by at least the size of V for each write.
 * </p>
 * 
 * @param <K> - the {@link Byteable} key type
 * @param <V> - the {@link Storable} value type
 * @author jnelson
 */
@ThreadSafe
@PackagePrivate
abstract class Field<K extends Byteable, V extends Storable> implements
		Byteable,
		Lockable { /* package-private */

	/**
	 * Encode a Field identified by {@code key} with values belong to
	 * {@code valueClass} and {@code components} into a ByteBuffer. The encoded
	 * format is:
	 * <ol>
	 * <li>keyClassSize</li>
	 * <li>valueClassSize</li>
	 * <li>keySize</li>
	 * <li>component1Size</li>
	 * <li>...</li>
	 * <li>componentNSize</li>
	 * <li>keyClass</li>
	 * <li>valueClass</li>
	 * <li>key</li>
	 * <li>component1</li>
	 * <li>...</li>
	 * <li>componentN</li>
	 * </ol>
	 * 
	 * @param key
	 * @param valueClass
	 * @param components
	 * @return the encoded ByteBuffer
	 */
	@SafeVarargs
	public static <K extends Byteable, V extends Storable> ByteBuffer encodeAsByteBuffer(
			K key, Class<V> valueClass, Field<K, V>.Component... components) {
		ByteBufferOutputStream out = new ByteBufferOutputStream();
	
		// The key and value class names are stored in the Field so that the
		// components can be deserialized reflectively.
		Text keyClassName = Text.fromString(key.getClass().getName());
		Text valueClassName = valueClass == null ? Text.EMPTY : Text
				.fromString(valueClass.getName());
	
		// encode sizes
		out.write(keyClassName.size());
		out.write(valueClassName.size());
		out.write(key.size());
		for (Field<K, V>.Component component : components) {
			out.write(component.size());
		}
	
		// encode data
		out.write(keyClassName);
		out.write(valueClassName);
		out.write(key);
		for (Field<K, V>.Component component : components) {
			out.write(component);
		}
		out.close();
		return out.toByteBuffer();
	}
	/**
	 * Return a <em>mock</em> field of {@code type}. Use this method instead
	 * of mocking {@code type} directly to ensure that the mock is compatible
	 * with the assumptions made in {@link Record}.
	 * 
	 * @param type
	 * @return the {@code field}
	 */
	@SuppressWarnings("unchecked")
	public static <T extends Field<K, V>, K extends Byteable, V extends Storable> T mock(
			Class<T> type) {
		T field = Mockito.mock(type);
		Mockito.doReturn(Lists.<V>newArrayList()).when(field).getValues();
		Mockito.doNothing().when(field).add((V) any(Storable.class));
		Mockito.doNothing().when(field).remove((V) any(Storable.class));
		Mockito.doThrow(UnsupportedOperationException.class).when(field)
				.getBytes();
		Mockito.doThrow(UnsupportedOperationException.class).when(field).size();
		return field;
	
	}

	/**
	 * The maximum number of bytes that can be used to encode a single Value.
{'fraction_non_alphanumeric': 0.1181234718826406, 'fraction_numerical': 0.002139364303178484, 'mean_word_length': 4.22723642172524, 'pattern_counts': {'":': 0, '<': 137, '<?xml version=': 0, '>': 137, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4444266', 'n_tokens_mistral': 4054, 'n_tokens_neox': 3817, 'n_words': 1353}