/* * Copyright 2010 NCHOVY * * 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 org.krakenapps.logstorage.engine; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.krakenapps.logstorage.file.LogFileWriter; import org.krakenapps.logstorage.file.LogRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OnlineWriter { private final Logger logger = LoggerFactory.getLogger(OnlineWriter.class.getName()); /** * table id */ private int tableId; /** * is in closing state? */ private boolean closing; /** * only yyyy-MM-dd (excluding hour, min, sec, milli) */ private Date day; /** * maintain last write access time. idle writer should be evicted */ private Date lastAccess = new Date(); private AtomicLong nextId; /** * binary log file writer */ private LogFileWriter writer; public OnlineWriter(int tableId, Date day, int blockSize) throws IOException { this(tableId, day, blockSize, null); } public OnlineWriter(int tableId, Date day, int blockSize, String defaultLogVersion) throws IOException { this.tableId = tableId; this.day = day; File indexPath = DatapathUtil.getIndexFile(tableId, day); File dataPath = DatapathUtil.getDataFile(tableId, day); indexPath.getParentFile().mkdirs(); dataPath.getParentFile().mkdirs(); writer = LogFileWriter.getLogFileWriter(indexPath, dataPath, defaultLogVersion); nextId = new AtomicLong(writer.getLastKey()); } public boolean isOpen() { return writer != null && closing == false; } public boolean isClosed() { return closing == true && writer == null; } public int getTableId() { return tableId; } public Date getDay() { return day; } private long nextId() { // do NOT update last access here return nextId.incrementAndGet(); } public Date getLastAccess() { return lastAccess; } public Date getLastFlush() { return writer.getLastFlush(); } public void write(LogRecord record) throws IOException { synchronized (this) { if (writer == null) throw new IOException("file closed"); long nid = nextId(); record.setId(nid); writer.write(record); lastAccess = new Date(); } } public void write(Collection<LogRecord> logs) throws IOException { if (writer == null) throw new IllegalStateException("file closed"); for (LogRecord record : logs) { record.setId(nextId()); } synchronized (this) { writer.write(logs); lastAccess = new Date(); } } public List<LogRecord> getBuffer() { synchronized (this) { return new ArrayList<LogRecord>(writer.getBuffer()); } } public void flush() throws IOException { if (logger.isTraceEnabled()) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); logger.trace("kraken logstorage: flushing log table [{}], day [{}]", tableId, dateFormat.format(day)); } synchronized (this) { writer.flush(); notifyAll(); } } public void close() { if (closing) return; try { synchronized (this) { closing = true; flush(); writer.close(); notifyAll(); writer = null; } } catch (IOException e) { logger.error("cannot close online log writer", e); } } }