// Path: src/main/java/org/killbill/billing/plugin/meter/timeline/sources/SourceSamplesForTimestamp.java
// @SuppressWarnings("unchecked")
// public class SourceSamplesForTimestamp {
// 
//     private static final String KEY_SOURCE = "H";
//     private static final String KEY_CATEGORY = "V";
//     private static final String KEY_TIMESTAMP = "T";
//     private static final String KEY_SAMPLES = "S";
// 
//     private final Integer sourceId;
//     private final String category;
//     private final DateTime timestamp;
//     // A map from sample id to sample value for that timestamp
//     private final Map<Integer, ScalarSample> samples;
// 
//     public SourceSamplesForTimestamp(final int sourceId, final String category, final DateTime timestamp) {
//         this(sourceId, category, timestamp, new HashMap<Integer, ScalarSample>());
//     }
// 
//     @JsonCreator
//     public SourceSamplesForTimestamp(@JsonProperty(KEY_SOURCE) final Integer sourceId, @JsonProperty(KEY_CATEGORY) final String category,
//                                      @JsonProperty(KEY_TIMESTAMP) final DateTime timestamp, @JsonProperty(KEY_SAMPLES) final Map<Integer, ScalarSample> samples) {
//         this.sourceId = sourceId;
//         this.category = category;
//         this.timestamp = timestamp;
//         this.samples = samples;
//     }
// 
//     public int getSourceId() {
//         return sourceId;
//     }
// 
//     public String getCategory() {
//         return category;
//     }
// 
//     public DateTime getTimestamp() {
//         return timestamp;
//     }
// 
//     public Map<Integer, ScalarSample> getSamples() {
//         return samples;
//     }
// 
//     @Override
//     public String toString() {
//         final StringBuilder sb = new StringBuilder();
//         sb.append("SourceSamplesForTimestamp");
//         sb.append("{category='").append(category).append('\'');
//         sb.append(", sourceId=").append(sourceId);
//         sb.append(", timestamp=").append(timestamp);
//         sb.append(", samples=").append(samples);
//         sb.append('}');
// 
//         return sb.toString();
//     }
// 
//     @Override
//     public boolean equals(final Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (o == null || getClass() != o.getClass()) {
//             return false;
//         }
// 
//         final SourceSamplesForTimestamp that = (SourceSamplesForTimestamp) o;
// 
//         if (category != null ? !category.equals(that.category) : that.category != null) {
//             return false;
//         }
//         if (samples != null ? !samples.equals(that.samples) : that.samples != null) {
//             return false;
//         }
//         if (sourceId != null ? !sourceId.equals(that.sourceId) : that.sourceId != null) {
//             return false;
//         }
//         if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null) {
//             return false;
//         }
// 
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = sourceId != null ? sourceId.hashCode() : 0;
//         result = 31 * result + (category != null ? category.hashCode() : 0);
//         result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
//         result = 31 * result + (samples != null ? samples.hashCode() : 0);
//         return result;
//     }
// 
//     @JsonValue
//     public Map<String, Object> toMap() {
//         return ImmutableMap.of(KEY_SOURCE, sourceId, KEY_CATEGORY, category, KEY_TIMESTAMP, timestamp, KEY_SAMPLES, samples);
//     }
// }


import com.fasterxml.util.membuf.MemBuffersForBytes;
import com.fasterxml.util.membuf.StreamyBytesMemBuffer;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import org.killbill.billing.plugin.meter.timeline.sources.SourceSamplesForTimestamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import com.fasterxml.jackson.dataformat.smile.SmileGenerator;
import com.fasterxml.jackson.datatype.joda.JodaModule;

    private final String basePath;
    private final String prefix;
    private final boolean deleteFilesOnClose;
    private final AtomicLong samplesforTimestampWritten = new AtomicLong();
    private final Object recyclingMonitor = new Object();

    private final StreamyBytesMemBuffer inputBuffer;
    private StreamyBytesPersistentOutputStream out = null;
    private SmileGenerator smileGenerator;

    public FileBackedBuffer(final String basePath, final String prefix, final int segmentsSize, final int maxNbSegments) throws IOException {
        this(basePath, prefix, true, segmentsSize, maxNbSegments);
    }

    public FileBackedBuffer(final String basePath, final String prefix, final boolean deleteFilesOnClose, final int segmentsSize, final int maxNbSegments) throws IOException {
        this.basePath = basePath;
        this.prefix = prefix;
        this.deleteFilesOnClose = deleteFilesOnClose;

        smileObjectMapper = new ObjectMapper(smileFactory);
        smileObjectMapper.registerModule(new JodaModule());
        smileObjectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        final MemBuffersForBytes bufs = new MemBuffersForBytes(segmentsSize, 1, maxNbSegments);
        inputBuffer = bufs.createStreamyBuffer(1, maxNbSegments);

        recycle();
    }

// Path: src/main/java/org/killbill/billing/plugin/meter/timeline/sources/SourceSamplesForTimestamp.java
// @SuppressWarnings("unchecked")
// public class SourceSamplesForTimestamp {
// 
//     private static final String KEY_SOURCE = "H";
//     private static final String KEY_CATEGORY = "V";
//     private static final String KEY_TIMESTAMP = "T";
//     private static final String KEY_SAMPLES = "S";
// 
//     private final Integer sourceId;
//     private final String category;
//     private final DateTime timestamp;
//     // A map from sample id to sample value for that timestamp
//     private final Map<Integer, ScalarSample> samples;
// 
//     public SourceSamplesForTimestamp(final int sourceId, final String category, final DateTime timestamp) {
//         this(sourceId, category, timestamp, new HashMap<Integer, ScalarSample>());
//     }
// 
//     @JsonCreator
//     public SourceSamplesForTimestamp(@JsonProperty(KEY_SOURCE) final Integer sourceId, @JsonProperty(KEY_CATEGORY) final String category,
//                                      @JsonProperty(KEY_TIMESTAMP) final DateTime timestamp, @JsonProperty(KEY_SAMPLES) final Map<Integer, ScalarSample> samples) {
//         this.sourceId = sourceId;
//         this.category = category;
//         this.timestamp = timestamp;
//         this.samples = samples;
//     }
// 
//     public int getSourceId() {
//         return sourceId;
//     }
// 
//     public String getCategory() {
//         return category;
//     }
// 
//     public DateTime getTimestamp() {
//         return timestamp;
//     }
// 
//     public Map<Integer, ScalarSample> getSamples() {
//         return samples;
//     }
// 
//     @Override
//     public String toString() {
//         final StringBuilder sb = new StringBuilder();
//         sb.append("SourceSamplesForTimestamp");
//         sb.append("{category='").append(category).append('\'');
//         sb.append(", sourceId=").append(sourceId);
//         sb.append(", timestamp=").append(timestamp);
//         sb.append(", samples=").append(samples);
//         sb.append('}');
// 
//         return sb.toString();
//     }
// 
//     @Override
//     public boolean equals(final Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (o == null || getClass() != o.getClass()) {
//             return false;
//         }
// 
//         final SourceSamplesForTimestamp that = (SourceSamplesForTimestamp) o;
// 
//         if (category != null ? !category.equals(that.category) : that.category != null) {
//             return false;
//         }
//         if (samples != null ? !samples.equals(that.samples) : that.samples != null) {
//             return false;
//         }
//         if (sourceId != null ? !sourceId.equals(that.sourceId) : that.sourceId != null) {
//             return false;
//         }
//         if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null) {
//             return false;
//         }
// 
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = sourceId != null ? sourceId.hashCode() : 0;
//         result = 31 * result + (category != null ? category.hashCode() : 0);
//         result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
//         result = 31 * result + (samples != null ? samples.hashCode() : 0);
//         return result;
//     }
// 
//     @JsonValue
//     public Map<String, Object> toMap() {
//         return ImmutableMap.of(KEY_SOURCE, sourceId, KEY_CATEGORY, category, KEY_TIMESTAMP, timestamp, KEY_SAMPLES, samples);
//     }
// }


// Path: src/main/java/org/killbill/billing/plugin/meter/timeline/persistent/FileBackedBuffer.java
import com.fasterxml.util.membuf.MemBuffersForBytes;
import com.fasterxml.util.membuf.StreamyBytesMemBuffer;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import org.killbill.billing.plugin.meter.timeline.sources.SourceSamplesForTimestamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import com.fasterxml.jackson.dataformat.smile.SmileGenerator;
import com.fasterxml.jackson.datatype.joda.JodaModule;


    private final String basePath;
    private final String prefix;
    private final boolean deleteFilesOnClose;
    private final AtomicLong samplesforTimestampWritten = new AtomicLong();
    private final Object recyclingMonitor = new Object();

    private final StreamyBytesMemBuffer inputBuffer;
    private StreamyBytesPersistentOutputStream out = null;
    private SmileGenerator smileGenerator;

    public FileBackedBuffer(final String basePath, final String prefix, final int segmentsSize, final int maxNbSegments) throws IOException {
        this(basePath, prefix, true, segmentsSize, maxNbSegments);
    }

    public FileBackedBuffer(final String basePath, final String prefix, final boolean deleteFilesOnClose, final int segmentsSize, final int maxNbSegments) throws IOException {
        this.basePath = basePath;
        this.prefix = prefix;
        this.deleteFilesOnClose = deleteFilesOnClose;

        smileObjectMapper = new ObjectMapper(smileFactory);
        smileObjectMapper.registerModule(new JodaModule());
        smileObjectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        final MemBuffersForBytes bufs = new MemBuffersForBytes(segmentsSize, 1, maxNbSegments);
        inputBuffer = bufs.createStreamyBuffer(1, maxNbSegments);

        recycle();
    }

    public boolean append(final SourceSamplesForTimestamp sourceSamplesForTimestamp) {