I need a specialized queue-like data structure. It can be used by multiple consumers, but each item in queue must be removed from queue after k consumers read it.
Is there any production ready implementation? Or Should I implement a queue with read-counter in each item, and handle item removal myself?
Thanks in advance.
I think this is what you are looking for. Derived from the source code for BlockingQueue. Caveat emptor, not tested.
I tried to find a way to wrap Queue, but Queue doesn't expose its concurrency members, so you can't get the right semantics.
public class CountingQueue<E> {
private class Entry {
Entry(int count, E element) {
this.count = count;
this.element = element;
}
int count;
E element;
}
public CountingQueue(int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException();
}
this.items = new Object[capacity];
this.lock = new ReentrantLock(false);
this.condition = this.lock.newCondition();
}
private final ReentrantLock lock;
private final Condition condition;
private final Object[] items;
private int takeIndex;
private int putIndex;
private int count;
final int inc(int i) {
return (++i == items.length) ? 0 : i;
}
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
/**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
private void insert(int count, E x) {
items[putIndex] = new Entry(count, x);
putIndex = inc(putIndex);
if (count++ == 0) {
// empty to non-empty
condition.signal();
}
}
private E extract() {
Entry entry = (Entry)items[takeIndex];
if (--entry.count <= 0) {
items[takeIndex] = null;
takeIndex = inc(takeIndex);
if (count-- == items.length) {
// full to not-full
condition.signal();
}
}
return entry.element;
}
private boolean waitNotEmpty(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
while (count == 0) {
if (nanos <= 0) {
return false;
}
nanos = this.condition.awaitNanos(nanos);
}
return true;
}
private boolean waitNotFull(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = condition.awaitNanos(nanos);
}
return true;
}
public boolean put(int count, E e) {
checkNotNull(e);
final ReentrantLock localLock = this.lock;
localLock.lock();
try {
if (count == items.length)
return false;
else {
insert(count, e);
return true;
}
} finally {
localLock.unlock();
}
}
public boolean put(int count, E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);
final ReentrantLock localLock = this.lock;
localLock.lockInterruptibly();
try {
if (!waitNotFull(timeout, unit)) {
return false;
}
insert(count, e);
return true;
} finally {
localLock.unlock();
}
}
public E get() {
final ReentrantLock localLock = this.lock;
localLock.lock();
try {
return (count == 0) ? null : extract();
} finally {
localLock.unlock();
}
}
public E get(long timeout, TimeUnit unit) throws InterruptedException {
final ReentrantLock localLock = this.lock;
localLock.lockInterruptibly();
try {
if (waitNotEmpty(timeout, unit)) {
return extract();
} else {
return null;
}
} finally {
localLock.unlock();
}
}
public int size() {
final ReentrantLock localLock = this.lock;
localLock.lock();
try {
return count;
} finally {
localLock.unlock();
}
}
public boolean isEmpty() {
final ReentrantLock localLock = this.lock;
localLock.lock();
try {
return count == 0;
} finally {
localLock.unlock();
}
}
public int remainingCapacity() {
final ReentrantLock lock= this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}
public boolean isFull() {
final ReentrantLock localLock = this.lock;
localLock.lock();
try {
return items.length - count == 0;
} finally {
localLock.unlock();
}
}
public void clear() {
final ReentrantLock localLock = this.lock;
localLock.lock();
try {
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
items[i] = null;
count = 0;
putIndex = 0;
takeIndex = 0;
condition.signalAll();
} finally {
localLock.unlock();
}
}
}
A memory efficient way that retains the info you need:
Each queue entry becomes a
Set<ConsumerID>
so that you ensure the k times are for k distinct consumers: your app logic checks if the
set.size()==k
and removes it from queue in that case.
In terms of storage: you will have tradeoffs of which Set implementation based on
size and type of the ConsumerID
speed of retrieval requirement
E.g if k is very small and your queue retrieval logic has access to a
Map<ID,ConsumerId>
then you could have simply an Int or even a Short or Byte depending on # distinct ConsumerID's and possibly store in an Array . This is slower than accessing a set since it would be traversed linearly - but for small K that may be reasonable.
Related
I'm using the filter to check user rights.
Problem in comparing session value to param value is occurred and resolution load is applied using wrapper.
However, the following error message came out.
List<Map<String,Object>> loginInfo = (List<Map<String,Object>>)session.getAttribute("loginSession");
if loginInfo.get(0).get("user_type").equals("1") || loginInfo.get(0).get("user_type").equals("2"))
{
chain.doFilter(req, res);
}
else
{
RereadableRequestWrapper wrapperRequest = new RereadableRequestWrapper(request);
String requestBody= IOUtils.toString(wrapperRequest.getInputStream(), "UTF-8");
Enumeration<String> reqeustNames = request.getParameterNames();
if(requestBody == null) {
}
Map<String,Object> param_map = new ObjectMapper().readValue(requestBody, HashMap.class);
String userId_param = String.valueOf(param_map.get("customer_id"));
System.out.println(userId_param);
if( userId_param == null || userId_param.isEmpty()) {
logger.debug("error, customer_id error");
}
if (!loginInfo.get(0).get("customer_id").equals(userId_param))
{
logger.debug("error, customer_id error");
}
chain.doFilter(wrapperRequest, res);
}
/////////////////////////
here is my wrapper Code.
private boolean parametersParsed = false;
private final Charset encoding;
private final byte[] rawData;
private final Map<String, ArrayList<String>> parameters = new LinkedHashMap<String, ArrayList<String>>();
ByteChunk tmpName = new ByteChunk();
ByteChunk tmpValue = new ByteChunk();
private class ByteChunk {
private byte[] buff;
private int start = 0;
private int end;
public void setByteChunk(byte[] b, int off, int len) {
buff = b;
start = off;
end = start + len;
}
public byte[] getBytes() {
return buff;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public void recycle() {
buff = null;
start = 0;
end = 0;
}
}
public RereadableRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String characterEncoding = request.getCharacterEncoding();
if (StringUtils.isBlank(characterEncoding)) {
characterEncoding = StandardCharsets.UTF_8.name();
}
this.encoding = Charset.forName(characterEncoding);
// Convert InputStream data to byte array and store it to this wrapper instance.
try {
InputStream inputStream = request.getInputStream();
this.rawData = IOUtils.toByteArray(inputStream);
} catch (IOException e) {
throw e;
}
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.rawData);
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
#Override
public boolean isFinished() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
#Override
public void setReadListener(ReadListener listener) {
// TODO Auto-generated method stub
}
};
return servletInputStream;
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream(), this.encoding));
}
#Override
public ServletRequest getRequest() {
return super.getRequest();
}
#Override
public String getParameter(String name) {
if (!parametersParsed) {
parseParameters();
}
ArrayList<String> values = this.parameters.get(name);
if (values == null || values.size() == 0)
return null;
return values.get(0);
}
public HashMap<String, String[]> getParameters() {
if (!parametersParsed) {
parseParameters();
}
HashMap<String, String[]> map = new HashMap<String, String[]>(this.parameters.size() * 2);
for (String name : this.parameters.keySet()) {
ArrayList<String> values = this.parameters.get(name);
map.put(name, values.toArray(new String[values.size()]));
}
return map;
}
#SuppressWarnings("rawtypes")
#Override
public Map getParameterMap() {
return getParameters();
}
#SuppressWarnings("rawtypes")
#Override
public Enumeration getParameterNames() {
return new Enumeration<String>() {
#SuppressWarnings("unchecked")
private String[] arr = (String[])(getParameterMap().keySet().toArray(new String[0]));
private int index = 0;
#Override
public boolean hasMoreElements() {
return index < arr.length;
}
#Override
public String nextElement() {
return arr[index++];
}
};
}
#Override
public String[] getParameterValues(String name) {
if (!parametersParsed) {
parseParameters();
}
ArrayList<String> values = this.parameters.get(name);
String[] arr = values.toArray(new String[values.size()]);
if (arr == null) {
return null;
}
return arr;
}
private void parseParameters() {
parametersParsed = true;
if (!("application/x-www-form-urlencoded".equalsIgnoreCase(super.getContentType()))) {
return;
}
int pos = 0;
int end = this.rawData.length;
while (pos < end) {
int nameStart = pos;
int nameEnd = -1;
int valueStart = -1;
int valueEnd = -1;
boolean parsingName = true;
boolean decodeName = false;
boolean decodeValue = false;
boolean parameterComplete = false;
do {
switch (this.rawData[pos]) {
case '=':
if (parsingName) {
// Name finished. Value starts from next character
nameEnd = pos;
parsingName = false;
valueStart = ++pos;
} else {
// Equals character in value
pos++;
}
break;
case '&':
if (parsingName) {
// Name finished. No value.
nameEnd = pos;
} else {
// Value finished
valueEnd = pos;
}
parameterComplete = true;
pos++;
break;
case '%':
case '+':
// Decoding required
if (parsingName) {
decodeName = true;
} else {
decodeValue = true;
}
pos++;
break;
default:
pos++;
break;
}
} while (!parameterComplete && pos < end);
if (pos == end) {
if (nameEnd == -1) {
nameEnd = pos;
} else if (valueStart > -1 && valueEnd == -1) {
valueEnd = pos;
}
}
if (nameEnd <= nameStart) {
continue;
// ignore invalid chunk
}
tmpName.setByteChunk(this.rawData, nameStart, nameEnd - nameStart);
if (valueStart >= 0) {
tmpValue.setByteChunk(this.rawData, valueStart, valueEnd - valueStart);
} else {
tmpValue.setByteChunk(this.rawData, 0, 0);
}
try {
String name;
String value;
if (decodeName) {
name = new String(URLCodec.decodeUrl(Arrays.copyOfRange(tmpName.getBytes(), tmpName.getStart(), tmpName.getEnd())), this.encoding);
} else {
name = new String(tmpName.getBytes(), tmpName.getStart(), tmpName.getEnd() - tmpName.getStart(), this.encoding);
}
if (valueStart >= 0) {
if (decodeValue) {
value = new String(URLCodec.decodeUrl(Arrays.copyOfRange(tmpValue.getBytes(), tmpValue.getStart(), tmpValue.getEnd())), this.encoding);
} else {
value = new String(tmpValue.getBytes(), tmpValue.getStart(), tmpValue.getEnd() - tmpValue.getStart(), this.encoding);
}
} else {
value = "";
}
if (StringUtils.isNotBlank(name)) {
ArrayList<String> values = this.parameters.get(name);
if (values == null) {
values = new ArrayList<String>(1);
this.parameters.put(name, values);
}
if (StringUtils.isNotBlank(value)) {
values.add(value);
}
}
} catch (DecoderException e) {
// ignore invalid chunk
}
tmpName.recycle();
tmpValue.recycle();
}
}
and Error Message is com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
I Don't know why this problem happened...
I'm trying to implement the logic for "Longest consecutive sequence in Binary tree". The logic I have implemented inside the method { longestConsecutivePath } is not working as expected for the tree structure. It is giving me the lognest path length as 5.
Output:
curLength : 5
BSTNode node = new BSTNode(1);
node.setRight(new BSTNode(2));
node.getRight().setRight(new BSTNode(3));
node.getRight().getRight().setRight(new BSTNode(4));
node.getRight().getRight().getRight().setRight(new BSTNode(5));
node.getRight().setLeft(new BSTNode(7));
node.getRight().getLeft().setLeft(new BSTNode(8));
node.getRight().getLeft().getLeft().setLeft(new BSTNode(9));
node.getRight().getLeft().getLeft().getLeft().setLeft(new BSTNode(10));
node.getRight().getLeft().getLeft().getLeft().getLeft().setLeft(new BSTNode(11));
node.getRight().getLeft().getLeft().getLeft().getLeft().getLeft().setLeft(new BSTNode(12));
Class implementing the Longest Consecutive sequence logic:
public class LongestConsecutivePath {
static BSTNode root = null;
public LongestConsecutivePath() {
root = createBinaryTree();
System.out.println("Before finding the longest consecutive path:");
inorder();
}
public void inorder() {
if (null == root) {
return;
}
inorder(root);
}
private void inorder(BSTNode node) {
if (null != node) {
inorder(node.getLeft());
System.out.print(node.getData() + " ");
inorder(node.getRight());
}
}
public BSTNode createBinaryTree() {
BSTNode node = new BSTNode(1);
node.setRight(new BSTNode(2));
node.getRight().setRight(new BSTNode(3));
node.getRight().getRight().setRight(new BSTNode(4));
node.getRight().getRight().getRight().setRight(new BSTNode(5));
node.getRight().setLeft(new BSTNode(7));
node.getRight().getLeft().setLeft(new BSTNode(8));
node.getRight().getLeft().getLeft().setLeft(new BSTNode(9));
node.getRight().getLeft().getLeft().getLeft().setLeft(new BSTNode(10));
node.getRight().getLeft().getLeft().getLeft().getLeft().setLeft(new BSTNode(11));
node.getRight().getLeft().getLeft().getLeft().getLeft().getLeft().setLeft(new BSTNode(12));
return node;
}
public int longestConsecutivePath() {
if (null == root) {
return 0;
}
return longestConsecutivePath(root, 0, root.getData() + 1);
}
public int longestConsecutivePath(BSTNode node, int curLength,
int targetLength) {
if (null == node) {
return curLength;
}
if (node.getData() == targetLength) {
System.out.println("\nnode data value: "+node.getData());
curLength += 1;
longestPath = curLength;
} else {
curLength = 1;
}
longestLeft = longestConsecutivePath(node.getLeft(), curLength,
node.getData() + 1);
longestRight = longestConsecutivePath(node.getRight(), curLength,
node.getData() + 1);
return Math.max(curLength, Math.max(longestLeft, longestRight));
}
public static void main(String[] args) {
LongestConsecutivePath consecutivePath = new LongestConsecutivePath();
int curLength = consecutivePath.longestConsecutivePath();
System.out.println("\ncurLength : " + curLength);
}
}
BSTNode.java
public class BSTNode {
BSTNode left, right;
int data;
/* Default constructor */
public BSTNode() {
left = null;
right = null;
data = 0;
}
/* Constructor */
public BSTNode(int data) {
left = null;
right = null;
this.data = data;
}
public BSTNode getLeft() {
return left;
}
public void setLeft(BSTNode left) {
this.left = left;
}
public BSTNode getRight() {
return right;
}
public void setRight(BSTNode right) {
this.right = right;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
Is there a built-in support for monad that deals with exception handling? Something similar to Scala's Try. I am asking because I don't like unchecked exceptions.
There are at least two generally available (e.g. on Maven Central) - Vavr and Cyclops both have Try implementations that take a slightly differing approach.
Vavr's Try follows Scala's Try very closely. It will catch all 'non-fatal' exceptions thrown during the execution of it's combinators.
Cyclops Try will only catch explicitly configured exceptions (of course you can, by default, also have it catch everything), and the default mode of operating is only to catch during the initial population method. The reasoning behind this is so that Try behaves in a somewhat similar way to Optional - Optional doesn't encapsulate unexpected Null values (i.e. bugs), just places where we reasonable expect to have no value.
Here is an example Try With Resources from Cyclops
Try t2 = Try.catchExceptions(FileNotFoundException.class,IOException.class)
.init(()->PowerTuples.tuple(new BufferedReader(new FileReader("file.txt")),new FileReader("hello")))
.tryWithResources(this::read2);
And another example 'lifting' an existing method (that might divide by zero) to support error handling.
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.*;
import static com.aol.cyclops.lambda.api.AsAnyM.anyM;
import lombok.val;
val divide = Monads.liftM2(this::divide);
AnyM<Integer> result = divide.apply(anyM(Try.of(2, ArithmeticException.class)), anyM(Try.of(0)));
assertThat(result.<Try<Integer,ArithmeticException>>unwrapMonad().isFailure(),equalTo(true));
private Integer divide(Integer a, Integer b){
return a/b;
}
The "better-java-monads" project on GitHub has a Try monad for Java 8 here.
You can do what you want by (ab)using CompletableFuture. Please don't do this in any sort of production code.
CompletableFuture<Scanner> sc = CompletableFuture.completedFuture(
new Scanner(System.in));
CompletableFuture<Integer> divident = sc.thenApply(Scanner::nextInt);
CompletableFuture<Integer> divisor = sc.thenApply(Scanner::nextInt);
CompletableFuture<Integer> result = divident.thenCombine(divisor, (a,b) -> a/b);
result.whenComplete((val, ex) -> {
if (ex == null) {
System.out.printf("%s/%s = %s%n", divident.join(), divisor.join(), val);
} else {
System.out.println("Something went wrong");
}
});
Firstly, let me apologise for answering instead of commenting - apparently I need 50 reputation to comment ...
#ncaralicea your implementation is similar to my own but the problem I had was how to reconcile the try ... catch in bind() with the identity laws. Specifically return x >>= f is equivalent to f x. When bind() catches the exception then f x differs because it throws.
Moreover the ITransformer appears to be a -> b instead of a -> M b. My current version of bind(), unsatisfactory though I find it, is
public <R> MException<R> bind(final Function<T, MException<R>> f) {
Validate.notNull(f);
if (value.isRight())
try {
return f.apply(value.right().get());
} catch (final Exception ex) {
return new MException<>(Either.<Exception, R>left(ex));
}
else
return new MException<>(Either.<Exception, R>left(value.left().get()));
}
where value is an
Either<? extends Exception,T>
The problem with the identity law is that it requires the function f to catch exceptions which defeats the whole purpose of the exercise.
What I think you might actually want is the Functor and not the Monad. That is the fmap : (a->b) -> f a -> f b function.
If you write
#Override
public <R> MException<R> fmap(final Function<T, R> fn) {
Validate.notNull(fn);
if (value.isRight())
try {
return new MException<>(Either.<Exception, R>right(fn.apply(value.right().get())));
} catch (final Exception ex) {
return new MException<>(Either.<Exception, R>left(ex));
}
else
return new MException<>(Either.<Exception, R>left(value.left().get()));
}
then you don't need to write explicit exception handling code, implement new interfaces or mess with the Monad laws.
Here there is an implementation that could be used as a model.
Further information can be found here:
Java with Try, Failure, and Success based computations
You can basically do something like this:
public class Test {
public static void main(String[] args) {
ITransformer < String > t0 = new ITransformer < String > () {#
Override
public String transform(String t) {
//return t + t;
throw new RuntimeException("some exception 1");
}
};
ITransformer < String > t1 = new ITransformer < String > () {#
Override
public String transform(String t) {
return "<" + t + ">";
//throw new RuntimeException("some exception 2");
}
};
ComputationlResult < String > res = ComputationalTry.initComputation("1").bind(t0).bind(t1).getResult();
System.out.println(res);
if (res.isSuccess()) {
System.out.println(res.getResult());
} else {
System.out.println(res.getError());
}
}
}
And here is the code:
public class ComputationalTry < T > {
final private ComputationlResult < T > result;
static public < P > ComputationalTry < P > initComputation(P argument) {
return new ComputationalTry < P > (argument);
}
private ComputationalTry(T param) {
this.result = new ComputationalSuccess < T > (param);
}
private ComputationalTry(ComputationlResult < T > result) {
this.result = result;
}
private ComputationlResult < T > applyTransformer(T t, ITransformer < T > transformer) {
try {
return new ComputationalSuccess < T > (transformer.transform(t));
} catch (Exception throwable) {
return new ComputationalFailure < T, Exception > (throwable);
}
}
public ComputationalTry < T > bind(ITransformer < T > transformer) {
if (result.isSuccess()) {
ComputationlResult < T > resultAfterTransf = this.applyTransformer(result.getResult(), transformer);
return new ComputationalTry < T > (resultAfterTransf);
} else {
return new ComputationalTry < T > (result);
}
}
public ComputationlResult < T > getResult() {
return this.result;
}
}
public class ComputationalFailure < T, E extends Throwable > implements ComputationlResult < T > {
public ComputationalFailure(E exception) {
this.exception = exception;
}
final private E exception;
#Override
public T getResult() {
return null;
}
#Override
public E getError() {
return exception;
}
#Override
public boolean isSuccess() {
return false;
}
}
public class ComputationalSuccess < T > implements ComputationlResult < T > {
public ComputationalSuccess(T result) {
this.result = result;
}
final private T result;
#Override
public T getResult() {
return result;
}
#Override
public Throwable getError() {
return null;
}
#Override
public boolean isSuccess() {
return true;
}
}
public interface ComputationlResult < T > {
T getResult();
< E extends Throwable > E getError();
boolean isSuccess();
}
public interface ITransformer < T > {
public T transform(T t);
}
public class Test {
public static void main(String[] args) {
ITransformer < String > t0 = new ITransformer < String > () {#
Override
public String transform(String t) {
//return t + t;
throw new RuntimeException("some exception 1");
}
};
ITransformer < String > t1 = new ITransformer < String > () {#
Override
public String transform(String t) {
return "<" + t + ">";
//throw new RuntimeException("some exception 2");
}
};
ComputationlResult < String > res = ComputationalTry.initComputation("1").bind(t0).bind(t1).getResult();
System.out.println(res);
if (res.isSuccess()) {
System.out.println(res.getResult());
} else {
System.out.println(res.getError());
}
}
}
I hope this might shade some light.
#Misha is onto something. Obviously you wouldn't do this exact thing in real code, but CompletableFuture provides Haskell-style monads like this:
return maps to CompletableFuture.completedFuture
>= maps to thenCompose
So you could rewrite #Misha's example like this:
CompletableFuture.completedFuture(new Scanner(System.in)).thenCompose(scanner ->
CompletableFuture.completedFuture(scanner.nextInt()).thenCompose(divident ->
CompletableFuture.completedFuture(scanner.nextInt()).thenCompose(divisor ->
CompletableFuture.completedFuture(divident / divisor).thenCompose(val -> {
System.out.printf("%s/%s = %s%n", divident, divisor, val);
return null;
}))));
which maps to the Haskell-ish:
(return (newScanner SystemIn)) >>= \scanner ->
(return (nextInt scanner)) >>= \divident ->
(return (nextInt scanner)) >>= \divisor ->
(return (divident / divisor)) >>= \val -> do
SystemOutPrintf "%s/%s = %s%n" divident divisor val
return Null
or with do syntax
do
scanner <- return (newScanner SystemIn)
divident <- return (nextInt scanner)
divisor <- return (nextInt scanner)
val <- return (divident / divisor)
do
SystemOutPrintf "%s/%s = %s%n" divident divisor val
return Null
Implementations of fmap and join
I got a little carried away. These are the standard fmap and join implemented in terms of CompletableFuture:
<T, U> CompletableFuture<U> fmap(Function<T, U> f, CompletableFuture<T> m) {
return m.thenCompose(x -> CompletableFuture.completedFuture(f.apply(x)));
}
<T> CompletableFuture<T> join(CompletableFuture<CompletableFuture<T>> n) {
return n.thenCompose(x -> x);
}
I want to create a Custom Load function for Pig UDF, I have created a SimpleTextLoader using the link
https://pig.apache.org/docs/r0.11.0/udf.html , I have successfully generate the jar file for this code, register in pig and run a Pig Script.I am getting the empty output. I don't know how to solve this issue, any help would be appreciated.
Below is my Java code
public class SimpleTextLoader extends LoadFunc{
protected RecordReader in = null;
private byte fieldDel = '\t';
private ArrayList<Object> mProtoTuple = null;
private TupleFactory mTupleFactory = TupleFactory.getInstance();
private static final int BUFFER_SIZE = 1024;
public SimpleTextLoader() {
}
public SimpleTextLoader(String delimiter)
{
this();
if (delimiter.length() == 1) {
this.fieldDel = (byte)delimiter.charAt(0);
} else if (delimiter.length() > 1 && delimiter.charAt(0) == '\\') {
switch (delimiter.charAt(1)) {
case 't':
this.fieldDel = (byte)'\t';
break;
case 'x':
fieldDel =
Integer.valueOf(delimiter.substring(2), 16).byteValue();
break;
case 'u':
this.fieldDel =
Integer.valueOf(delimiter.substring(2)).byteValue();
break;
default:
throw new RuntimeException("Unknown delimiter " + delimiter);
}
} else {
throw new RuntimeException("PigStorage delimeter must be a single character");
}
}
private void readField(byte[] buf, int start, int end) {
if (mProtoTuple == null) {
mProtoTuple = new ArrayList<Object>();
}
if (start == end) {
// NULL value
mProtoTuple.add(null);
} else {
mProtoTuple.add(new DataByteArray(buf, start, end));
}
} #Override
public Tuple getNext() throws IOException {
try {
boolean notDone = in.nextKeyValue();
if (notDone) {
return null;
}
Text value = (Text) in.getCurrentValue();
System.out.println("printing value" +value);
byte[] buf = value.getBytes();
int len = value.getLength();
int start = 0;
for (int i = 0; i < len; i++) {
if (buf[i] == fieldDel) {
readField(buf, start, i);
start = i + 1;
}
}
// pick up the last field
readField(buf, start, len);
Tuple t = mTupleFactory.newTupleNoCopy(mProtoTuple);
mProtoTuple = null;
System.out.println(t);
return t;
} catch (InterruptedException e) {
int errCode = 6018;
String errMsg = "Error while reading input";
throw new ExecException(errMsg, errCode,
PigException.REMOTE_ENVIRONMENT, e);
}
}
#Override
public void setLocation(String string, Job job) throws IOException {
FileInputFormat.setInputPaths(job,string);
}
#Override
public InputFormat getInputFormat() throws IOException {
return new TextInputFormat();
}
#Override
public void prepareToRead(RecordReader reader, PigSplit ps) throws IOException {
in=reader;
}
}
Below is my Pig Script
REGISTER /home/hadoop/netbeans/sampleloader/dist/sampleloader.jar
a= load '/input.txt' using sampleloader.SimpleTextLoader();
store a into 'output';
You are using sampleloader.SimpleTextLoader() that doesn't do anything as it is just an empty constructor.
Instead use sampleloader.SimpleTextLoader(String delimiter) which is performing the actual operation of split.
I'm playing around with CompletableFuture and streams in Java 8 and I get different printouts each time I run this. Just curious, why?
public class DoIt {
public static class My {
private long cur = 0;
public long next() {
return cur++;
}
}
public static long add() {
long sum = 0;
for (long i=0; i<=100;i++) {
sum += i;
}
return sum;
}
public static long getResult(CompletableFuture<Long> f) {
long l = 0;
try {
f.complete(42l);
l = f.get();
System.out.println(l);
} catch (Exception e) {
//...
}
return l;
}
public static void main(String[] args){
ExecutorService exec = Executors.newFixedThreadPool(2);
My my = new My();
long sum = Stream.generate(my::next).limit(20000).
map(x -> CompletableFuture.supplyAsync(()-> add(), exec)).
mapToLong(f->getResult(f)).sum();
System.out.println(sum);
exec.shutdown();
}
}
If I skip the f.complete(42l) call I always get the same result.
http://download.java.net/jdk8/docs/api/java/util/concurrent/CompletableFuture.html#complete-T-
by the time the complete(42l) call happens, some add()'s may have already completed.