Skip to content

Commit

Permalink
Type.Map; unify highest_clock_* set of functions
Browse files Browse the repository at this point in the history
  • Loading branch information
point committed Apr 23, 2024
1 parent 1b47e58 commit 3b7187c
Show file tree
Hide file tree
Showing 13 changed files with 599 additions and 88 deletions.
2 changes: 1 addition & 1 deletion lib/y/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule Y.Decoder do
]
end

def decode(msg, transaction) do
def apply(msg, transaction) do
{_u, msg} = read_uint(msg)
{key_clock, msg} = read_uint_array(msg)
{client, msg} = read_uint_array(msg)
Expand Down
84 changes: 53 additions & 31 deletions lib/y/doc.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ defmodule Y.Doc do
GenServer.call(doc_name, {:get_array, array_name})
end

def get_map(doc_name, map_name \\ "") do
GenServer.call(doc_name, {:get_map, map_name})
end

def transact(doc_name, f, opts \\ []) do
GenServer.call(doc_name, {:transact, f, opts})
end
Expand Down Expand Up @@ -117,38 +121,51 @@ defmodule Y.Doc do
end
end

def highest_clock(transaction, client_id \\ nil)

def highest_clock(%Transaction{doc: doc}, :all) do
Enum.reduce(Map.values(doc.share), %{}, fn t, acc ->
Map.merge(acc, Type.highest_clock(t, :all), fn _k, v1, v2 ->
max(v1, v2)
end)
end)
def highest_clock(%Transaction{doc: doc}, client_id \\ nil) do
highest_clock!(doc, client_id)
end

def highest_clock(%Transaction{doc: doc}, client_id) do
client_id = client_id || doc.client_id

def highest_clock!(%Doc{} = doc, client_id \\ nil) do
Enum.reduce(Map.values(doc.share), 0, fn t, acc ->
max(acc, Type.highest_clock(t, client_id))
end)
end

def highest_clock_with_length(transaction, client_id \\ nil)
def highest_clock_by_client_id(%Transaction{doc: doc}), do: highest_clock_by_client_id!(doc)

def highest_clock_with_length(%Transaction{doc: doc}, :all) do
highest_clock_with_length!(doc)
def highest_clock_by_client_id!(%Doc{} = doc) do
Enum.reduce(Map.values(doc.share), %{}, fn t, acc ->
Map.merge(acc, Type.highest_clock_by_client_id(t), fn _k, v1, v2 ->
max(v1, v2)
end)
end)
end

def highest_clock_with_length(%Transaction{doc: doc}, client_id) do
client_id = client_id || doc.client_id
def highest_clock_with_length(%Transaction{doc: doc}, client_id \\ nil) do
highest_clock_with_length!(doc, client_id)
end

@doc """
Make sure that %Doc{} = doc is not stale.
Better to use highest_clock_with_length within transaction
"""
def highest_clock_with_length!(%Doc{} = doc, client_id) do
Enum.reduce(Map.values(doc.share), 0, fn t, acc ->
max(acc, Type.highest_clock_with_length(t, client_id))
end)
end

def highest_clock_with_length_by_client_id(%Transaction{doc: doc}),
do: highest_clock_with_length_by_client_id!(doc)

def highest_clock_with_length_by_client_id!(%Doc{} = doc) do
Enum.reduce(Map.values(doc.share), %{}, fn t, acc ->
Map.merge(acc, Type.highest_clock_with_length_by_client_id(t), fn _k, v1, v2 ->
max(v1, v2)
end)
end)
end

def find_item(transaction, type_name \\ nil, id, default \\ nil)

def find_item(%Transaction{doc: doc}, nil, %ID{} = id, default) do
Expand All @@ -169,18 +186,6 @@ defmodule Y.Doc do
|> Enum.find_value(fn t -> Type.find(t, id, default) end)
end

@doc """
Make sure that %Doc{} = doc is not stale.
Better to use highest_clock_with_length within transaction
"""
def highest_clock_with_length!(%Doc{} = doc) do
Enum.reduce(Map.values(doc.share), %{}, fn t, acc ->
Map.merge(acc, Type.highest_clock_with_length(t, :all), fn _k, v1, v2 ->
max(v1, v2)
end)
end)
end

def items_of_client!(%Doc{} = doc, client) do
doc.share
|> Map.values()
Expand All @@ -195,7 +200,7 @@ defmodule Y.Doc do
def type_with_id!(%Doc{} = doc, %ID{} = id) do
doc.share
|> Map.values()
|> Enum.filter(fn type -> Type.highest_clock_with_length(type, :all) >= id.clock end)
|> Enum.filter(fn type -> Type.highest_clock_with_length(type) >= id.clock end)
|> Enum.find(fn type ->
type
|> Type.to_list(as_items: true)
Expand Down Expand Up @@ -233,9 +238,9 @@ defmodule Y.Doc do
%{doc | share: share}
end

def apply_update(update, transaction) when is_bitstring(update) do
def apply_update(transaction, update) when is_bitstring(update) do
update
|> Decoder.decode(transaction)
|> Decoder.apply(transaction)
end

def put_pending_structs(
Expand Down Expand Up @@ -275,6 +280,23 @@ defmodule Y.Doc do
{:reply, {:ok, array}, %Doc{doc | share: Map.put_new(share, array_name, array)}}
end

def handle_call({:get_map, name}, _, %{share: share} = doc) when is_map_key(share, name) do
case share[name] do
%Unknown{} = u ->
map = Y.Type.Map.from_unknown(u)
{:reply, {:ok, map}, %{doc | share: Map.replace(share, name, map)}}

_ ->
{:reply, {:error, "Type with the name #{name} has already been added"}, doc}
end
end

def handle_call({:get_map, map_name}, _, %{share: share} = doc) do
map = Y.Type.Map.new(doc, map_name)

{:reply, {:ok, map}, %Doc{doc | share: Map.put_new(share, map_name, map)}}
end

def handle_call(
{:transact, f, opts},
_,
Expand Down
2 changes: 1 addition & 1 deletion lib/y/encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule Y.Encoder do
doc <- Doc.pack!(doc),
sm <-
doc
|> Doc.highest_clock_with_length!()
|> Doc.highest_clock_with_length_by_client_id!()
|> Enum.map(fn {k, _v} -> {k, 0} end)
|> Enum.into(%{}) do
Buffer.new()
Expand Down
10 changes: 6 additions & 4 deletions lib/y/item.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ defmodule Y.Item do
origin = Keyword.get(opts, :origin)
right_origin = Keyword.get(opts, :right_origin)
parent_name = Keyword.get(opts, :parent_name)
parent_sub = Keyword.get(opts, :parent_sub)

item = %Item{
id: id,
content: content,
origin: origin,
right_origin: right_origin,
parent_name: parent_name
parent_name: parent_name,
parent_sub: parent_sub
}

%{item | length: content_length(item)}
Expand Down Expand Up @@ -197,7 +199,7 @@ defmodule Y.Item do
{:invalid, transaction}

nil ->
case Type.add_before(type, Type.first(type), item) do
case Type.add_before(type, Type.first(type, item), item) do
{:ok, updated_type} ->
Transaction.update(transaction, updated_type)

Expand Down Expand Up @@ -315,13 +317,13 @@ defmodule Y.Item do
%Item{} = o <- Type.next(type, item_left) do
o
else
_ -> Type.first(type)
_ -> Type.first(type, item)
end

end_range =
case item_right do
%Item{} -> item_right
_ -> Type.last(type)
_ -> Type.last(type, item)
end

with %Item{} <- start_range,
Expand Down
2 changes: 1 addition & 1 deletion lib/y/transaction.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule Y.Transaction do
local: local
}

%{t | before_state: Doc.highest_clock_with_length(t, :all)}
%{t | before_state: Doc.highest_clock_with_length(t)}
end

def update(transaction, type) do
Expand Down
10 changes: 6 additions & 4 deletions lib/y/type.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
defprotocol Y.Type do
def highest_clock(type, client)
def highest_clock_with_length(type, client)
def highest_clock(type, client \\ nil)
def highest_clock_with_length(type, client \\ nil)
def highest_clock_by_client_id(type)
def highest_clock_with_length_by_client_id(type)
def pack(type)
def to_list(type, opts \\ [])
def find(type, id, default \\ nil)
Expand All @@ -10,7 +12,7 @@ defprotocol Y.Type do
def add_before(type, before_item, item)
def next(type, item)
def prev(type, item)
def first(type)
def last(type)
def first(type, reference_item)
def last(type, reference_item)
def delete(type, transaction, id)
end
12 changes: 9 additions & 3 deletions lib/y/type/array.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ defmodule Y.Type.Array do
def from_unknown(%Unknown{} = u) do
tree =
u
|> Type.to_list(as_items: true)
|> Type.to_list(as_items: true, with_deleted: true)
|> Enum.reduce(ArrayTree.new(), fn item, tree ->
ArrayTree.conj!(tree, item)
end)
Expand Down Expand Up @@ -141,6 +141,12 @@ defmodule Y.Type.Array do
def highest_clock_with_length(%Array{tree: tree}, client),
do: ArrayTree.highest_clock_with_length(tree, client)

def highest_clock_by_client_id(%Array{tree: tree}),
do: ArrayTree.highest_clock_by_client_id(tree)

def highest_clock_with_length_by_client_id(%Array{tree: tree}),
do: ArrayTree.highest_clock_with_length_by_client_id(tree)

def pack(%Array{tree: tree} = array) do
new_tree =
tree
Expand Down Expand Up @@ -236,11 +242,11 @@ defmodule Y.Type.Array do
ArrayTree.prev(tree, item)
end

def first(%Array{tree: tree}) do
def first(%Array{tree: tree}, _) do
ArrayTree.first(tree)
end

def last(%Array{tree: tree}) do
def last(%Array{tree: tree}, _) do
ArrayTree.last(tree)
end

Expand Down
20 changes: 18 additions & 2 deletions lib/y/type/array/array_tree.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ defmodule Y.Type.Array.ArrayTree do
%ArrayTree{ft: FingerTree.finger_tree(meter_object())}
end

def highest_clock_with_length(%ArrayTree{ft: tree}, :all) do
def highest_clock_with_length(%ArrayTree{ft: tree}, nil) do
%Meter{highest_clocks_with_length: cl} = FingerTree.measure(tree)

cl
|> Map.values()
|> Enum.max(fn -> 0 end)
end

def highest_clock_with_length(%ArrayTree{ft: tree}, client_id) do
Expand All @@ -31,9 +34,12 @@ defmodule Y.Type.Array.ArrayTree do
end
end

def highest_clock(%ArrayTree{ft: tree}, :all) do
def highest_clock(%ArrayTree{ft: tree}, nil) do
%Meter{highest_clocks: c} = FingerTree.measure(tree)

c
|> Map.values()
|> Enum.max(fn -> 0 end)
end

def highest_clock(%ArrayTree{ft: tree}, client_id) do
Expand All @@ -45,6 +51,16 @@ defmodule Y.Type.Array.ArrayTree do
end
end

def highest_clock_with_length_by_client_id(%ArrayTree{ft: tree}) do
%Meter{highest_clocks_with_length: cl} = FingerTree.measure(tree)
cl
end

def highest_clock_by_client_id(%ArrayTree{ft: tree}) do
%Meter{highest_clocks: c} = FingerTree.measure(tree)
c
end

def put(%ArrayTree{ft: %EmptyTree{} = tree} = array_tree, _index, %Item{} = item) do
items = Item.explode(item) |> Enum.reverse()

Expand Down
Loading

0 comments on commit 3b7187c

Please sign in to comment.