lib/postgrex/pg_output/lsn.ex

defmodule Postgrex.PgOutput.Lsn do
  @moduledoc """
  LSN (Log Sequence Number) is a pointer to a location in the WAL.

  Internally, an LSN is a 64-bit integer, representing a byte position in the write-ahead log stream.
  It is printed as two hexadecimal numbers of up to 8 digits each, separated by a slash; for example, 16/B374D848.

  This module provides utility functions for encoding/decoding Lsn's
  """
  import Postgrex.BinaryUtils
  import Bitwise

  @type t :: {non_neg_integer(), non_neg_integer()} | binary()

  @spec decode(binary()) :: t()
  def decode(<<xlog_file::uint32(), xlog_offset::uint32()>>), do: {xlog_file, xlog_offset}

  @spec decode_string(binary()) :: t()
  def decode_string(lsn_string) do
    with [file_id, offset] <- String.split(lsn_string, "/", trim: true),
         {file_id, ""} when file_id >= 0 <- Integer.parse(file_id, 16),
         {offset, ""} when offset >= 0 <- Integer.parse(offset, 16) do
      {file_id, offset}
    end
  end

  @spec encode(t()) :: binary()
  def encode({xlog_file, xlog_offset}) do
    <<xlog_file::int32(), xlog_offset::int32()>>
  end

  @spec encode_int64(t()) :: integer()
  def encode_int64({xlog_file, xlog_offset}) do
    <<lsn::uint64()>> = <<xlog_file::uint32(), xlog_offset::uint32()>>
    lsn
  end

  @spec encode_string(t()) :: binary()
  def encode_string({xlog_file, xlog_offset}) do
    i = xlog_file <<< 32 ||| xlog_offset
    <<xf::32, xo::32>> = <<i::64>>
    Integer.to_string(xf, 16) <> "/" <> Integer.to_string(xo, 16)
  end
end