/*
* Copyright (c) 2011 LinkedIn, Inc
*
* Licensed 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 com.flaptor.indextank.storage;
import java.io.IOException;
import java.util.List;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransportException;
import com.flaptor.indextank.rpc.LogRecord;
import com.flaptor.indextank.storage.Segment.MissingSegmentException;
import com.flaptor.indextank.util.FormatLogger;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public class RawLog {
private static final FormatLogger logger = new FormatLogger();
public static final int DEFAULT_SEGMENT_SIZE = 1024 * 1024 * 50;
private SegmentWriter writingHead;
private LogRoot root;
private final int segmentSize;
private int records;
private int segmentRecords;
private long lastTime;
public RawLog() {
this(new LogRoot(), DEFAULT_SEGMENT_SIZE);
}
public RawLog(LogRoot root, int segmentSize) {
this.root = root;
this.segmentSize = segmentSize;
this.root.getLiveLogPath().mkdirs();
this.root.getHistoryLogPath().mkdirs();
}
public synchronized void write(LogRecord record) throws TException, IOException {
Preconditions.checkState(!record.is_set_id(), "Can't insert records to the live log with an id");
Preconditions.checkState(record.is_set_index_code(), "Can't insert records to the live log without defining the index code");
if (writingHead == null) {
writingHead = Segment.createRawHead(root, root.getLiveLogPath(), System.currentTimeMillis());
}
record.set_timestamp_ms(System.currentTimeMillis());
writingHead.write(record);
records++;
segmentRecords++;
if (System.currentTimeMillis() - lastTime > 5000) {
logger.debug("%d records so far (current segment: %d, bytes: %d / %d)", records, segmentRecords, writingHead.length(), segmentSize);
lastTime = System.currentTimeMillis();
}
if (writingHead.length() > segmentSize) {
logger.info("Closing a segment with %d records", segmentRecords);
writingHead.release();
writingHead = null;
segmentRecords = 0;
}
}
public synchronized void flush() throws TTransportException {
if (writingHead != null) {
writingHead.flush();
}
}
public List<Segment> getLiveSegments() {
List<Segment> live = Segment.getSegments(root, root.getLiveLogPath());
for (Segment s : live) {
s.addAlternativeParent(root.getHistoryLogPath());
}
return live;
}
public List<Segment> getAllSegments() {
List<Segment> live = Segment.getSegments(root, root.getLiveLogPath());
List<Segment> history = Segment.getSegments(root, root.getHistoryLogPath());
for (Segment s : live) {
s.addAlternativeParent(root.getHistoryLogPath());
}
return Lists.newArrayList(Iterables.concat(history, live));
}
public Segment getSegment(long timestamp) {
Segment segment = Segment.getSegment(root, root.getLiveLogPath(), timestamp, false);
if (segment == null) {
segment = Segment.getSegment(root, root.getHistoryLogPath(), timestamp, false);
} else {
segment.addAlternativeParent(root.getHistoryLogPath());
}
return segment;
}
public Segment getFirstSegment() {
Segment segment = Iterables.get(Segment.iterateSegments(root, root.getHistoryLogPath()), 0, null);
if (segment == null) {
segment = Iterables.get(Segment.iterateSegments(root, root.getLiveLogPath()), 0, null);
}
return segment;
}
public Segment findFollowingSegment(long timestamp) throws MissingSegmentException {
Segment segment = Segment.findNextSegment(root, timestamp, root.getHistoryLogPath(), root.getLiveLogPath());
if (segment != null && segment.parent.equals(root.getLiveLogPath())) {
segment.addAlternativeParent(root.getHistoryLogPath());
}
return segment;
}
}