apache / plc4x

PLC4X The Industrial IoT adapter

Home Page:https://plc4x.apache.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PLCJ-0.10.0 Concurrency problem : RequestTransactionManager workLog.remove()

cptjackwu opened this issue · comments

What happened?

private void processWorklog() {
while (runningRequests.size() < getNumberOfConcurrentRequests() && !workLog.isEmpty()) {
RequestTransaction next = workLog.remove();
this.runningRequests.add(next);
Future<?> completionFuture = executor.submit(next.operation);
next.setCompletionFuture(completionFuture);
}
}

RequestTransactionManager workLog.remove()

When I write a connection to multiple points at the same time, each point is written once a second, there is a concurrency problem, this time the content in the worklog is empty, and the error is reported when remove

===============================================================

static Map<String, Boolean> map = new HashMap<>();

static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2);

public static void main(String[] args) throws Exception{



        PlcClient plcClient = new S7Client("s7://**.**.*.***");
        plcClient.connect();


    Map m1 = new HashMap();
    m1.put("stationCode","OP010");
    m1.put("address","%DB1150:0.0:BOOL");


    Map m2 = new HashMap();
    m2.put("stationCode","OP020");
    m2.put("address","%DB1100:0.0:BOOL");


    Map m3 = new HashMap();
    m3.put("stationCode","OP030");
    m3.put("address","%DB1200:0.0:BOOL");

    List<Map>  mapList = Stream.of(m1,m2,m3).collect(Collectors.toList());

    mapList.forEach(v->
        executorService.scheduleAtFixedRate(()-> {
            boolean value = map.get(v.get("stationCode")) == null ? true : map.get(v.get("stationCode"));
            plcClient.writeBOOL(new NodeId((String) v.get("address"), value));
            map.put((String) v.get("stationCode"), !value);
        },0, 1000, TimeUnit.MILLISECONDS)
    );

====================================================================================
The error content is as follows:

2023-11-03 00:20:25.432 WARN 7 --- [ nioEventLoopGroup-9-1] io.netty.channel.DefaultChannelPipeline : An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.

io.netty.handler.codec.DecoderException: java.util.NoSuchElementException
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:98)
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at io.netty.handler.codec.ByteToMessageCodec.channelRead(ByteToMessageCodec.java:103)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.NoSuchElementException: null
at java.util.AbstractQueue.remove(AbstractQueue.java:117)
at org.apache.plc4x.java.spi.transaction.RequestTransactionManager.processWorklog(RequestTransactionManager.java:104)
at org.apache.plc4x.java.spi.transaction.RequestTransactionManager.endRequest(RequestTransactionManager.java:133)
at org.apache.plc4x.java.spi.transaction.RequestTransactionManager.access$200(RequestTransactionManager.java:46)
at org.apache.plc4x.java.spi.transaction.RequestTransactionManager$RequestTransaction.endRequest(RequestTransactionManager.java:160)
at org.apache.plc4x.java.s7.readwrite.protocol.S7ProtocolLogic.lambda$readInternal$18(S7ProtocolLogic.java:272)
at org.apache.plc4x.java.spi.Plc4xNettyWrapper.decode(Plc4xNettyWrapper.java:187)
at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:88)
... 23 common frames omitted

So, How do I fix that concurrent problem

Version

v0.10.0

Programming Languages

  • plc4j
  • plc4go
  • plc4c
  • plc4net

Protocols

  • AB-Ethernet
  • ADS /AMS
  • BACnet/IP
  • CANopen
  • DeltaV
  • DF1
  • EtherNet/IP
  • Firmata
  • KNXnet/IP
  • Modbus
  • OPC-UA
  • S7

Admittedly I habe absolutely no idea what you are doing ... it looks as if you're trying to write something to a number of S7 devices. Well we definitely don't support that type of operation in PLC4X ... if you've implemented something fancy inside S7Client, I can't tell you what's going wrong without the full code.

I have changed workLog.remove(); to workLog.poll(), and then judged it and solved the problem。

private void processWorklog() {
while (runningRequests.size() < getNumberOfConcurrentRequests() && !workLog.isEmpty()) {
RequestTransaction next = workLog.poll();
if(next!-null){
this.runningRequests.add(next);
Future<?> completionFuture = executor.submit(next.operation);
next.setCompletionFuture(completionFuture);
}
}
}

the worklog processing changes were integrated at some point of time. If you are running 0.10 (which is over year old) you might need to backport fixes from 0.11 release.