Home > Software design >  Issue with synchronization and getting collection count for id generation
Issue with synchronization and getting collection count for id generation

Time:11-27

I'm having an issue with nextMessageId(), it should return a new id for each message created. However, every once and a while it doesn't. It returns a value that has been used already, and I can't understand why. I've tried debugging it in the IDE, but it seems to work fine when I step through it.

I'm trying to learn how to work with multiple threads, how to properly synchronize methods, etc. I'm simulating the process of Users sending messages.

Basically each time a block is mined, messages are copied from the buffer to the current block and then the new block is added to blocks Collection. Everything seems to work fine except the nextMessageId(). Any help is appreciated.

I didn't want to post unnecessary code to keep this post as clean as possible, If further information is needed, please let me know.

UserService class:

public final class UserService extends Service<User, String> {
    ...

    @Override
    public void submit(String message, User user) {
        synchronized (Blockchain.class) {
            MessageEntry messageEntry = MessageEntry.newInstance(repo.nextMessageId(), message, user);
            repo.postMessage(messageEntry);
        }
    }
}

MinerService class:

public final class MinerService extends Service<Miner, Long> {
    ...

    public void submit(Long number, Miner miner) {
        if (repo.getCurrentBlock().hash(number).startsWith(repo.prefix())) {
            synchronized (Blockchain.class) {
                if (repo.getCurrentBlock().hash(number).startsWith(repo.prefix())) {
                    repo.createBlock(number, miner);
                }
            }
        }
    }
}

Blockchain.class

public class Blockchain {
    ...

    private Deque<Block> blocks;
    private Deque<DataEntry<?>> messageBuffer;
    private Block currentBlock;

    ...

    public long nextMessageId() {
        return blocks.stream()
                .mapToLong(block -> block.getData().size())
                .sum()   messageBuffer.size()   1L;
    }

    public void postMessage(DataEntry<?> dataEntry) {
        messageBuffer.offerLast(dataEntry);
    }

    public void createBlock(long number, Miner miner) {
        long duration = (new Date().getTime() - currentBlock.getTimestamp()) / 1000;
        Block.ProofOfWork proofOfWork = new Block.ProofOfWork(number, duration, updateN(duration), miner);
        currentBlock.setProofOfWork(proofOfWork);

        if (blocks.offerLast(currentBlock)) {
            currentBlock = generateBlock();
            currentBlock.setData(messageBuffer);
            messageBuffer.clear();
            stateManager.save();
        }
    }
    ...
}

Output of Message after generating 5 blocks:

Block:
Created by miner # 4
Id: 1
Timestamp: 1637995160818
Magic number: 6489039085832314491
Hash of the previous block: 
0
Hash of the block: 
7cecb0d73c5bbfa925f2c04fba90778c8431e43dc3abd1b0faf1dbc23400321c
Block data: no messages
Block was generating for 0 seconds
N was increased to 1

Block:
Created by miner # 6
Id: 2
Timestamp: 1637995160897
Magic number: 5017000130559711273
Hash of the previous block: 
7cecb0d73c5bbfa925f2c04fba90778c8431e43dc3abd1b0faf1dbc23400321c
Hash of the block: 
0ff1a96574cd8cf9db8c91eeb436df8efd084582251c081409e43e0f17069d51
Block data: 
1 Charles: Life is good
2 Aramys: How bout' those Dolphins?
3 Evelio: Life is good
4 Armando: I love Java
5 Evelio: I love Java
6 Armando: What is the meaning of life?
7 Aramys: I love basketball
8 Charles: How bout' those Dolphins?
Block was generating for 0 seconds
N was increased to 2

Block:
Created by miner # 3
Id: 3
Timestamp: 1637995160918
Magic number: -4429177738817892095
Hash of the previous block: 
0ff1a96574cd8cf9db8c91eeb436df8efd084582251c081409e43e0f17069d51
Hash of the block: 
007577aca398b8fa711229b95f2abb0f959aa73fbaa8939516ca1bea11a467fa
Block data: no messages
Block was generating for 0 seconds
N was increased to 3

Block:
Created by miner # 5
Id: 4
Timestamp: 1637995160932
Magic number: 2352460595297940125
Hash of the previous block: 
007577aca398b8fa711229b95f2abb0f959aa73fbaa8939516ca1bea11a467fa
Hash of the block: 
00053d5c5b0e958f828c12ae74469fdce1e840334cfa4a431504239133c7c612
Block data: 
9 Evelio: How are you?
Block was generating for 0 seconds
N was increased to 4

Block:
Created by miner # 5
Id: 5
Timestamp: 1637995160951
Magic number: 3338207044781263189
Hash of the previous block: 
00053d5c5b0e958f828c12ae74469fdce1e840334cfa4a431504239133c7c612
Hash of the block: 
000093d155de9a54e2143b97d752b7d57031056ec6eb07b9672c5c0815fd9272
Block data: 
9 Armando: This chat is garbage
10 Charles: Interesting...
11 Aramys: Will I ever make decent money?
Block was generating for 0 seconds
N was increased to 5

[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11]

EDIT: The issue was that I was not accounting for the DataEntry (messages) being held in the currentBlock. This fixed the issue:

public long nextMessageId() {
    return blocks.stream()
            .mapToLong(block -> block.getData().size())
            .sum()   currentBlock.getData().size()   messageBuffer.size()   1L;
}

CodePudding user response:

From your comment:

The nextMessageId() counts the size of the collection in each block

NextMessageId:

    public long nextMessageId() {
        return blocks.stream()
                .mapToLong(block -> block.getData().size())
                .sum()   messageBuffer.size()   1L;
    }

Didn’t you also add an additional messagebuffer size?

And in your createBlock method, you will clear this buffer. So the ID has become smaller again.

  • Related