/* * Copyright 2012 Future Systems * * 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.eventstorage.engine.file; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.krakenapps.api.DateFormat; import org.krakenapps.eventstorage.EventRecord; import org.krakenapps.eventstorage.engine.DatapathUtil; import org.krakenapps.eventstorage.engine.DatapathUtil.FileType; public class EventWriter extends FileWriter { private static final int IDX_SIZE = 20; private static final int DEFAULT_CACHE_SIZE = 50000; private Date day; private FileHandlerManager fileman; private RandomAccessFile idx; @SuppressWarnings("unused") private EventFileHeader idxhdr; private ByteBuffer idxbuf; private Set<EventRecord> cache; private int cacheSize; private Object cachelock = new Object(); public EventWriter(int tableId, Date day, FileHandlerManager fileman) throws IOException { this(tableId, day, fileman, DEFAULT_CACHE_SIZE); } public EventWriter(int tableId, Date day, FileHandlerManager fileman, int cacheSize) throws IOException { super(tableId, DatapathUtil.getFilePath(tableId, day, FileType.Index)); boolean success = false; try { this.day = day; this.fileman = fileman; this.idx = new RandomAccessFile(getFile(), "rw"); this.idxhdr = getHeader(EventFileHeader.MAGIC_STRING_INDEX); this.idxbuf = ByteBuffer.allocate(cacheSize * IDX_SIZE + 4); idx.seek(idx.length()); this.cache = new TreeSet<EventRecord>(new Comparator<EventRecord>() { @Override public int compare(EventRecord o1, EventRecord o2) { return (int) (o1.getId() - o2.getId()); } }); this.cacheSize = cacheSize; success = true; } finally { if (!success) close(); } } public Date getDay() { return day; } @Override protected void doWrite(EventRecord record) throws IOException { synchronized (cachelock) { cache.add(record); } EventPointerFile ptr = fileman.getPointerFile(getTableId(), record.getId(), true); ptr.write(record); if (cache.size() >= cacheSize) flush(true); } public List<EventRecord> getCache() { ArrayList<EventRecord> records = null; synchronized (cachelock) { records = new ArrayList<EventRecord>(cache); } Collections.sort(records, new Comparator<EventRecord>() { @Override public int compare(EventRecord o1, EventRecord o2) { return o2.getDate().compareTo(o1.getDate()); } }); return records; } @Override protected void doFlush(boolean sync) throws IOException { List<EventRecord> idxs = null; if (sync) { synchronized (cachelock) { idxs = new ArrayList<EventRecord>(cache); cache.clear(); } } else { idxs = new ArrayList<EventRecord>(cache); } idxbuf.clear(); idxbuf.putInt(idxs.size()); for (EventRecord index : idxs) { idxbuf.putLong(index.getId()); idxbuf.putLong(index.getDate().getTime()); idxbuf.putInt(index.getCount()); } long before = idx.getFilePointer(); idx.write(idxbuf.array(), 0, idxs.size() * IDX_SIZE + 4); if (sync) idx.getFD().sync(); else idx.seek(before); } @Override protected void doClose() { try { if (idx != null) idx.close(); } catch (IOException e) { } } @Override public String toString() { return "EventWriter [tableId=" + getTableId() + ", day=" + DateFormat.format("yyyy-MM-dd", day) + "]"; } }