/** * Create a new feedbackstore with the specified storeId and fileNumber. * * @param storeId * the storeId * @param fileNumber * the new sequence number for this storeID * @return a feedbackstore */ private FeedbackStore createStore(long storeId, int fileNumber) throws IOException { File storeFile = new File(m_baseDir, getStoreName(storeId, fileNumber)); m_storeFileIdx.get(storeId).add(Integer.valueOf(fileNumber)); return new FeedbackStore(storeFile, storeId); }
/** * Create a new File based Store. * * @param store * the file to use as backend. * @param id * the log id of the store * @throws java.io.IOException * in case the file is not rw. */ FeedbackStore(File store, long id) throws IOException { m_storeFile = store; m_store = new RandomAccessFile(store, "rw"); m_id = id; init(); }
private FeedbackStore setStore(FeedbackStore store) throws IOException { FeedbackStore old; do { old = m_currentStoreRef.get(); } while (!m_currentStoreRef.compareAndSet(old, store)); if (old != null) { old.close(); } return store; } }
private void verifyStoreContents(final FeedbackStore store, final int count, Writer... writers) throws IOException { store.reset(); store.init(); assertEquals(store.getFirstEventID(), 0, "First record ID is different"); assertEquals(store.getLastEventID(), count - 1, "Last record ID is different"); // Verify the written file... List<Record> records = store.getRecords(0, count - 1); Collections.sort(records); long expectedID = 0; for (Record record : records) { long id = record.m_id; byte[] expectedEntry = null; for (int i = 0; (expectedEntry == null) && i < writers.length; i++) { expectedEntry = writers[i].m_written.remove(id); } assertNotNull(expectedEntry, "Event ID #" + id + " never written?!"); // Test consistency of written data... assertEquals(record.m_entry, expectedEntry, "Entry mismatch?!"); // Test continuation of written data... assertEquals(record.m_id, expectedID++, "Entry ID mismatch?!"); } } }
for (FeedbackStore store : stores) { try { if (store.getFirstEventID() <= toEventID && store.getLastEventID() >= fromEventID) { records.addAll(store.getRecords(fromEventID, toEventID));
long storeID = currentStore.getId(); long nextEventId = currentStore.getLastEventID() + 1; currentStore.append(result.getID(), result.toRepresentation().getBytes());
@Test public void testTimedWrite() throws Exception { File storeFile = File.createTempFile("feedback", ".store"); storeFile.deleteOnExit(); final int recordCount = 1000000; final FeedbackStore store = new FeedbackStore(storeFile, 1); long start = System.nanoTime(); for (int i = 0; i < recordCount; i++) { store.append(i, "Hello World!".getBytes()); } long end = System.nanoTime(); System.out.printf("Writing %d records took %.3f ms.%n", recordCount, (end - start) / 1.0e6); }
m_store.init(); long id = m_store.getLastEventID(); if (id >= m_count) { throw new IOException(String.format("Invalid record ID: %1$d (0x%1$x)!%n", id));
/** * Give the highest eventId that is is present is the specified store * * @param the * storeId * @return the highest event present in the store, >= 0, or <tt>-1</tt> if this manager is already closed. * @throws IOException * in case of I/O problems accessing the store(s). */ public long getHighestEventID(long storeID) throws IOException { if (m_closed.get()) { return -1L; } FeedbackStore store = getLastStore(storeID); try { return store.getLastEventID(); } finally { closeIfNeeded(store); } }
@Override public void run() { try { m_start.await(); System.out.printf("Writer (%s) starts writing %d records...%n", getName(), m_count); for (int i = m_initValue; i < m_count; i += m_stepSize) { long id = i; byte[] entry = String.format("record-data-%d", i).getBytes(); m_store.append(id, entry); m_written.putIfAbsent(Long.valueOf(id), entry); } System.out.printf("Writer (%s) finished with %d records written...%n", getName(), m_written.size()); } catch (InterruptedException e) { // ok, stop... } catch (IOException exception) { exception.printStackTrace(); } finally { m_stop.countDown(); } } }
/** * Return all feedbackstores for a single storeId. * * @param storeId * the storeId * @return a list of all feedbackstores for this storeId */ private FeedbackStore[] getAllStores(long storeId) throws IOException { List<FeedbackStore> stores = new ArrayList<>(); SortedSet<Integer> storeFileNos = m_storeFileIdx.get(storeId); FeedbackStore currentStore = getCurrentStore(); if (currentStore.getId() == storeId) { // The last one is the current store... storeFileNos = storeFileNos.headSet(storeFileNos.last()); } for (Integer fileNo : storeFileNos) { stores.add(createStore(storeId, fileNo)); } if (currentStore.getId() == storeId) { stores.add(currentStore); } return stores.toArray(new FeedbackStore[stores.size()]); }
/** * Check if the maximum allowed size for the current store file is reached * * @return is the maximum reached */ private boolean isMaximumStoreSizeReached(FeedbackStore store) throws IOException { return store.getFileSize() >= m_maxFileSize; }
/** * Return the feedbackstore for the specified storeId. If there are multiple files for this storeId the last one is * returned * * @param the * storeId * @return the feedbackstore for that storeID */ private FeedbackStore getLastStore(long storeID) throws IOException { FeedbackStore currentStore = getCurrentStore(); if (currentStore != null && currentStore.getId() == storeID) { return currentStore; } int lastFileNo = getLastLogfileNumber(storeID); return createStore(storeID, lastFileNo); }
/** * Create a new empty feedbackstore with a new storeId. * * @return A new feedbackstore with a new storeID */ private FeedbackStore newFeedbackStore() throws IOException { long storeId = System.currentTimeMillis(); String storeFilename; File storeFile; do { storeFilename = getStoreName(storeId, 1); storeFile = new File(m_baseDir, storeFilename); if (storeFile.createNewFile()) { break; } storeId++; } while (true); m_storeFileIdx.put(storeId, new TreeSet<>(Arrays.asList(1))); return new FeedbackStore(storeFile, storeId); }
/** * Close all the feedbackstores if necessary * * @param stores * a list of stores */ private void closeIfNeeded(FeedbackStore... stores) { for (FeedbackStore store : stores) { if (store != getCurrentStore()) { try { store.close(); } catch (IOException ex) { // Not much we can do } } } }
/** * Tests that concurrent use of a {@link FeedbackStore} with a single reader and writer works as expected. */ @Test public void testConcurrentUseSingleReaderAndSingleWriter() throws Exception { File storeFile = File.createTempFile("feedback", ".store"); storeFile.deleteOnExit(); final int recordCount = 10000; final FeedbackStore store = new FeedbackStore(storeFile, 1); final CountDownLatch start = new CountDownLatch(1); final CountDownLatch stop = new CountDownLatch(2); Writer writer = new Writer(store, start, stop, recordCount); Reader reader = new Reader(store, start, stop, recordCount); // gents, start your engines... writer.start(); reader.start(); // 3, 2, 1... GO... start.countDown(); // waiting both threads to finish... assertTrue(stop.await(15, TimeUnit.SECONDS)); writer.join(); reader.join(); int writeCount = writer.m_written.size(); int readCount = reader.m_seen.size(); assertEquals(recordCount, writeCount, "Not all records were written?"); assertEquals(readCount, writeCount, "Not all records were seen?"); verifyStoreContents(store, recordCount, writer); }
final int writerCount = Runtime.getRuntime().availableProcessors() + 1; final FeedbackStore store = new FeedbackStore(storeFile, 1);
final int writerCount = Runtime.getRuntime().availableProcessors() + 1; final FeedbackStore store = new FeedbackStore(storeFile, 1);