/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.hadoop.chukwa.util; import java.util.Random; import java.util.regex.*; import org.apache.hadoop.chukwa.*; import org.apache.hadoop.chukwa.datacollection.*; import org.apache.hadoop.chukwa.datacollection.adaptor.*; import org.apache.hadoop.chukwa.datacollection.agent.AdaptorManager; import org.apache.hadoop.chukwa.datacollection.agent.AdaptorManager; import org.apache.hadoop.conf.Configuration; /** * Emits chunks at a roughly constant data rate. Chunks are in a very particular * format: the output data is verifiable, but sufficiently non-deterministic * that two different instances of this adaptor are very likely to have * distinct outputs. * * * Each chunk is full of random bytes; the randomness comes from * an instance of java.util.Random seeded with the offset xored * with the time-of-generation. The time of generation is stored, big-endian, * in the first eight bytes of each chunk. */ public class ConstRateAdaptor extends AbstractAdaptor implements Runnable { private int SLEEP_VARIANCE = 200; private int MIN_SLEEP = 300; private long offset; private int bytesPerSec; Random timeCoin; long seed; private volatile boolean stopping = false; public String getCurrentStatus() { return type.trim() + " " + bytesPerSec + " " + seed; } public void start(long offset) throws AdaptorException { this.offset = offset; Configuration conf = control.getConfiguration(); MIN_SLEEP = conf.getInt("constAdaptor.minSleep", MIN_SLEEP); SLEEP_VARIANCE = conf.getInt("constAdaptor.sleepVariance", SLEEP_VARIANCE); timeCoin = new Random(seed); long o =0; while(o < offset) o += (int) ((timeCoin.nextInt(SLEEP_VARIANCE) + MIN_SLEEP) * (long) bytesPerSec / 1000L) + 8; new Thread(this).start(); // this is a Thread.start } public String parseArgs(String bytesPerSecParam) { try { Matcher m = Pattern.compile("([0-9]+)(?:\\s+([0-9]+))?\\s*").matcher(bytesPerSecParam); if(!m.matches()) return null; bytesPerSec = Integer.parseInt(m.group(1)); String rate = m.group(2); if(rate != null) seed = Long.parseLong(m.group(2)); else seed = System.currentTimeMillis(); } catch (NumberFormatException e) { //("bad argument to const rate adaptor: [" + bytesPerSecParam + "]"); return null; } return bytesPerSecParam; } public void run() { try { while (!stopping) { int MSToSleep = timeCoin.nextInt(SLEEP_VARIANCE) + MIN_SLEEP; int arraySize = (int) (MSToSleep * (long) bytesPerSec / 1000L) + 8; ChunkImpl evt = nextChunk(arraySize ); dest.add(evt); Thread.sleep(MSToSleep); } // end while } catch (InterruptedException ie) { } // abort silently } public ChunkImpl nextChunk(int arraySize) { byte[] data = new byte[arraySize]; Random dataPattern = new Random(offset ^ seed); long s = this.seed; offset += data.length; dataPattern.nextBytes(data); for(int i=0; i < 8; ++i) { data[7-i] = (byte) (s & 0xFF); s >>= 8; } ChunkImpl evt = new ChunkImpl(type, "random ("+ this.seed+")", offset, data, this); return evt; } public String toString() { return "const rate " + type; } @Override public long shutdown(AdaptorShutdownPolicy shutdownPolicy) { stopping = true; return offset; } public static boolean checkChunk(Chunk chunk) { byte[] data = chunk.getData(); byte[] correctData = new byte[data.length]; long seed = 0; for(int i=0; i < 8; ++i) seed = (seed << 8) | (0xFF & data[i] ); seed ^= (chunk.getSeqID() - data.length); Random dataPattern = new Random(seed); dataPattern.nextBytes(correctData); for(int i=8; i < data.length ; ++i) if(data [i] != correctData[i]) return false; return true; } void test_init(String type) { this.type = type; seed = System.currentTimeMillis(); } }