florinpatrascu / bolt_sips

Neo4j driver for Elixir
Apache License 2.0
256 stars 49 forks source link

Optimize internals #79

Closed kristofka closed 4 years ago

kristofka commented 4 years ago

Hi I did some work optimizing internals (encoding/decoding). I've removed all the expensive calls to Kernel.apply and used iolists allowing to encode data in a more efficient fashion. It might require a bit more polish but it's promising since we get around 2x improvement for decoding and much more when encoding long lists.

sourcelevel-bot[bot] commented 4 years ago

Hello, @kristofka! This is your first Pull Request that will be reviewed by SourceLevel, an automatic Code Review service. It will leave comments on this diff with potential issues and style violations found in the code as you push new commits. You can also see all the issues found on this Pull Request on its review page. Please check our documentation for more information.

sourcelevel-bot[bot] commented 4 years ago

SourceLevel has finished reviewing this Pull Request and has found:

See more details about this review.

florinpatrascu commented 4 years ago

This is so awesome. Thank you so much for this PR.

dominique-vassard commented 4 years ago

Hi, The performance improvement is welcome, everything that makes bolt_sips faster is great!f

However, I've 2 remarks:

dominique-vassard commented 4 years ago

I don't know if this could work, but what about something like this?

# Define the functions list
defmodule BoltSips.EncodingFunctionsV3 do
  defmacro __using__(_opts) do
    quote do
      def encode(:atom, data) do
        #Override EncodingFunctionsV2 encoding
      end

    end

    use BoltSips.EncodingFunctionsV1

    def encode(:new_type, data) do
      ...
    end
  end

end

defmodule BoltSips.EncodingFunctionsV2 do
  use BoltSips.EncodingFunctionsV1

  defmacro __using__(_opts) do
    quote do
      def encode(:date, data) do
        ....
      end

    end
  end
end

defmodule BoltSips.EncodingFunctionsV1 do
  defmacro __using__(_opts) do
    quote do
      def encode(:atom, data) do
        ....
      end

      def encode(:list, data) do
        ...
      end
    end
  end
end

# Build fully fleshed encoders with all required functions
# No need to fallback to a previous encoder anymore
defmodule BoltSips.EncoderV1 do
  use BoltSips.EncodingFunctionsV1
end

defmodule BoltSips.EncoderV2 do
  use BoltSips.EncodingFunctionsV2
end

defmodule BoltSips.EncoderV3 do
  use BoltSips.EncodingFunctionsV3
end

# EncoderHelper just needs to dispatch the calls
defmodule BoltSips.EncoderHelper do
  def call_encode(data_type, data, bolt_version) when bolt_version == 3 do
    BoltSips.EncoderV3.encode(data_type, data)
  end

  def call_encode(data_type, data, bolt_version) when bolt_version == 2 do
    BoltSips.EncoderV2.encode(data_type, data)
  end
  def call_encode(data_type, data, bolt_version) do
    BoltSips.EncoderV1.encode(data_type, data)
  end

end
kristofka commented 4 years ago

Regarding readability, I've moved the implementation in macro modules in this branch (see internals/packstream/v1.ex ...) . This gives us both more readable code and the benefits that the functions are called locally at runtime.

Regarding the first issue, I'm not sure I understand :

If the map is encoded with bolt v >=2 then the version will be passed along and dates will properly be encoded with v2 while the map itself will use v1. If the map is encoded with v1 then there shouldn't be date encoding. Am I missing something?

I can make a new pull request with the code moved in macros.

dominique-vassard commented 4 years ago

Regarding readability, I've moved the implementation in macro modules in this branch (see internals/packstream/v1.ex ...) . This gives us both more readable code and the benefits that the functions are called locally at runtime.

That's really nice :+1:

Regarding the first issue, I'm not sure I understand :

If the map is encoded with bolt v >=2 then the version will be passed along and dates will properly be encoded with v2 while the map itself will use v1. If the map is encoded with v1 then there shouldn't be date encoding. Am I missing something?

You're not missing anything, I was stuck in my fallback-to-previous-version mindset and didn't realize that wasn't the approach here. There is no problem, sorry for the misunderstanding.

I can make a new pull request with the code moved in macros.

Sure, thanks. @florinpatrascu will have the final on the PR but I think he will be pleased :)

One last thing about v1.ex and v2.ex would be to replace:

Thanks for your great work. It's nice to have more people contributing to bolt_sips!

kristofka commented 4 years ago

With the latest commits I believe I have addressed most concerns from @dominique-vassard , let me know if you think I should change anything

florinpatrascu commented 4 years ago

Thank you both, for ideas and implementation! This is an awesome contribution. I will try to take a shot at streaming server responses, after I return from vacation, and this new code makes all that work easier. ❤️