apache / incubator-fury

A blazingly fast multi-language serialization framework powered by JIT and zero-copy.

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suggestion for some refactorying for MemoryBuffer class.

pushrsp opened this issue · comments

Can i do some refactor for MemoryBuffer class?
e.g

public void writeBoolean(boolean value) {
    final int writerIdx = writerIndex;
    final int newIdx = writerIdx + 1; // we can replace this number to static variable which make more understandable.
    ensure(newIdx);
    final long pos = address + writerIdx;
    UNSAFE.putByte(heapMemory, pos, (byte) (value ? 1 : 0));
    writerIndex = newIdx;
  }
public byte readByte() {
    int readerIdx = readerIndex;
   // every readX method use this for checking bound, so we can make short for it.
    if (BoundsChecking.BOUNDS_CHECKING_ENABLED && readerIdx > size - 1) { 
      throw new IndexOutOfBoundsException(
          String.format(
              "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, 1, size, this));
    }
    readerIndex = readerIdx + 1;
    return UNSAFE.getByte(heapMemory, address + readerIdx);
  }

Hi @pushrsp ,thanks for your suggession.

Regarding your first proposal, I think it is unnecessary, we use one byte to store the value of boolean type. We can also know it from the code UNSAFE.putByte(heapMemory, pos, (byte) (value ? 1 : 0)); below, so writerIdx + 1 itself is easy to understand.

Regarding the second suggestion, how to simplify it? Extract a function separately for the checked logic and call it in readXXX?

cc @chaokunyang

Regarding the second suggestion, how to simplify it? Extract a function separately for the checked logic and call it in readXXX?

i would simplify like this below.

public byte readByte() {
    int readerIdx = readerIndex;
    throwIfOutOfBound(readerIdx, 1);
    readerIndex = readerIdx + 1;
    return UNSAFE.getByte(heapMemory, address + readerIdx);
  }

public short readShort() {
    int readerIdx = readerIndex;
    throwIfOutOfBound(readerIdx, 2)
    readerIndex = readerIdx + 2;
    final long pos = address + readerIdx;
    if (LITTLE_ENDIAN) {
      return UNSAFE.getShort(heapMemory, pos);
    } else {
      return Short.reverseBytes(UNSAFE.getShort(heapMemory, pos));
    }
  }

...

private void throwIfOutOfBound(int readerIdx, int dataSize) {
    if(BoundsChecking.BOUNDS_CHECKING_ENABLED && readerIdx > size - dataSize) {
      throw new IndexOutOfBoundsException(
              String.format(
                      "readerIndex(%d) + length(%d) exceeds size(%d): %s", readerIdx, dataSize, size, this));
    }
  }

LGTM.

We don't have to worry about throwIfOutOfBound function not being inlined because throwIfOutOfBound is rarely executed.

BTW, we can also use throwIndexOutOfBoundsException function to replace throw new IndexOutOfBoundsException(...).

What do you think about this suggestion? @chaokunyang

I refactorized this code, it has been replaced by a StreamReader in pr #1451 .

For changes here, seems throwIfOutOfBound will be invoked every time. The method invocation is not ignorable in such primitives. Jvm inline doesn't happens sometimes.