blob: 5dfa5b5d80a9d16e6d18b454f5779c69f619f540 [file] [log] [blame]
defmodule PartitionSizeTest do
use CouchTestCase
@moduledoc """
Test Partition size functionality
"""
@moduletag :partition
@moduletag kind: :cluster
setup do
db_name = random_db_name()
{:ok, _} = create_db(db_name, query: %{partitioned: true, q: 1})
on_exit(fn -> delete_db(db_name) end)
{:ok, [db_name: db_name]}
end
def get_db_info(dbname) do
resp = Couch.get("/#{dbname}")
assert resp.status_code == 200
%{:body => body} = resp
body
end
def get_partition_info(dbname, partition) do
resp = Couch.get("/#{dbname}/_partition/#{partition}")
assert resp.status_code == 200
%{:body => body} = resp
body
end
def mk_partition(i) do
i |> rem(10) |> Integer.to_string() |> String.pad_leading(3, "0")
end
def mk_docid(i) do
id = i |> Integer.to_string() |> String.pad_leading(4, "0")
"#{mk_partition(i)}:#{id}"
end
def mk_docs(db_name) do
docs =
for i <- 1..1000 do
group = Integer.to_string(rem(i, 3))
%{
:_id => mk_docid(i),
:value => i,
:some => "field",
:group => group
}
end
body = %{:w => 3, :docs => docs}
retry_until(fn ->
resp = Couch.post("/#{db_name}/_bulk_docs", body: body)
assert resp.status_code in [201, 202]
end)
end
def save_doc(db_name, doc) do
resp = Couch.post("/#{db_name}", query: [w: 3], body: doc)
assert resp.status_code in [201, 202]
%{:body => body} = resp
body["rev"]
end
test "get empty partition", context do
db_name = context[:db_name]
partition = "non_existent_partition"
info = get_partition_info(db_name, partition)
assert info["doc_count"] == 0
assert info["doc_del_count"] == 0
assert info["partition"] == partition
assert info["sizes"]["external"] == 0
assert info["sizes"]["active"] == 0
end
test "unknown partition return's zero", context do
db_name = context[:db_name]
mk_docs(db_name)
info = get_partition_info(db_name, "unknown")
assert info["doc_count"] == 0
assert info["doc_del_count"] == 0
assert info["sizes"]["external"] == 0
assert info["sizes"]["active"] == 0
end
test "simple partition size", context do
db_name = context[:db_name]
save_doc(db_name, %{_id: "foo:bar", val: 42})
info = get_partition_info(db_name, "foo")
assert info["doc_count"] == 1
assert info["doc_del_count"] == 0
assert info["sizes"]["external"] > 0
assert info["sizes"]["active"] > 0
end
test "adding docs increases partition sizes", context do
db_name = context[:db_name]
save_doc(db_name, %{_id: "foo:bar", val: 42})
pre_info = get_partition_info(db_name, "foo")
save_doc(db_name, %{_id: "foo:baz", val: 24})
post_info = get_partition_info(db_name, "foo")
assert post_info["doc_count"] == 2
assert post_info["doc_del_count"] == 0
assert post_info["sizes"]["external"] > pre_info["sizes"]["external"]
assert post_info["sizes"]["active"] > pre_info["sizes"]["active"]
end
test "updating docs affects partition sizes", context do
db_name = context[:db_name]
rev1 = save_doc(db_name, %{_id: "foo:bar", val: ""})
info1 = get_partition_info(db_name, "foo")
rev2 =
save_doc(db_name, %{
_id: "foo:bar",
_rev: rev1,
val: "this is a very long string that is so super long its beyond long"
})
info2 = get_partition_info(db_name, "foo")
save_doc(db_name, %{
_id: "foo:bar",
_rev: rev2,
val: "this string is shorter"
})
info3 = get_partition_info(db_name, "foo")
assert info3["doc_count"] == 1
assert info3["doc_del_count"] == 0
assert info3["sizes"]["external"] > info1["sizes"]["external"]
assert info2["sizes"]["external"] > info3["sizes"]["external"]
end
test "deleting a doc affects partition sizes", context do
db_name = context[:db_name]
rev1 = save_doc(db_name, %{_id: "foo:bar", val: "some stuff here"})
info1 = get_partition_info(db_name, "foo")
save_doc(db_name, %{_id: "foo:bar", _rev: rev1, _deleted: true})
info2 = get_partition_info(db_name, "foo")
assert info1["doc_count"] == 1
assert info1["doc_del_count"] == 0
assert info2["doc_count"] == 0
assert info2["doc_del_count"] == 1
assert info2["sizes"]["external"] < info1["sizes"]["external"]
end
test "design docs do not affect partition sizes", context do
db_name = context[:db_name]
mk_docs(db_name)
pre_infos =
0..9
|> Enum.map(fn i ->
get_partition_info(db_name, mk_partition(i))
end)
0..5
|> Enum.map(fn i ->
base = i |> Integer.to_string() |> String.pad_leading(5, "0")
docid = "_design/#{base}"
save_doc(db_name, %{_id: docid, value: "some stuff here"})
end)
post_infos =
0..9
|> Enum.map(fn i ->
get_partition_info(db_name, mk_partition(i))
end)
assert post_infos == pre_infos
end
@tag :skip_on_jenkins
test "get all partition sizes", context do
db_name = context[:db_name]
mk_docs(db_name)
{esum, asum} =
0..9
|> Enum.reduce({0, 0}, fn i, {esize, asize} ->
partition = mk_partition(i)
info = get_partition_info(db_name, partition)
assert info["doc_count"] == 100
assert info["doc_del_count"] == 0
assert info["sizes"]["external"] > 0
assert info["sizes"]["active"] > 0
{esize + info["sizes"]["external"], asize + info["sizes"]["active"]}
end)
db_info = get_db_info(db_name)
assert db_info["sizes"]["external"] >= esum
assert db_info["sizes"]["active"] >= asum
end
test "get partition size with attachment", context do
db_name = context[:db_name]
doc = %{
_id: "foo:doc-with-attachment",
_attachments: %{
"foo.txt": %{
content_type: "text/plain",
data: Base.encode64("This is a text document to save")
}
}
}
save_doc(db_name, doc)
db_info = get_db_info(db_name)
foo_info = get_partition_info(db_name, "foo")
assert foo_info["doc_count"] == 1
assert foo_info["doc_del_count"] == 0
assert foo_info["sizes"]["active"] > 0
assert foo_info["sizes"]["external"] > 0
assert foo_info["sizes"]["active"] <= db_info["sizes"]["active"]
assert foo_info["sizes"]["external"] <= db_info["sizes"]["external"]
end
test "attachments don't affect other partitions", context do
db_name = context[:db_name]
mk_docs(db_name)
pre_infos =
0..9
|> Enum.map(fn i ->
get_partition_info(db_name, mk_partition(i))
end)
doc = %{
_id: "foo:doc-with-attachment",
_attachments: %{
"foo.txt": %{
content_type: "text/plain",
data: Base.encode64("This is a text document to save")
}
}
}
save_doc(db_name, doc)
att_info = get_partition_info(db_name, "foo")
assert att_info["doc_count"] == 1
assert att_info["sizes"]["external"] > 0
post_infos =
0..9
|> Enum.map(fn i ->
get_partition_info(db_name, mk_partition(i))
end)
assert post_infos == pre_infos
esize =
([att_info] ++ post_infos)
|> Enum.reduce(0, fn info, acc ->
info["sizes"]["external"] + acc
end)
db_info = get_db_info(db_name)
assert esize == db_info["sizes"]["external"]
end
test "partition activity not affect other partition sizes", context do
db_name = context[:db_name]
mk_docs(db_name)
partition1 = "000"
partition2 = "001"
info2 = get_partition_info(db_name, partition2)
doc_id = "#{partition1}:doc-with-attachment"
doc = %{
_id: doc_id,
_attachments: %{
"foo.txt": %{
content_type: "text/plain",
data: Base.encode64("This is a text document to save")
}
}
}
doc_rev = save_doc(db_name, doc)
info2_attach = get_partition_info(db_name, partition2)
assert info2_attach == info2
doc =
Enum.into(
%{
another: "add another field",
_rev: doc_rev
},
doc
)
doc_rev = save_doc(db_name, doc)
info2_update = get_partition_info(db_name, partition2)
assert info2_update == info2
resp = Couch.delete("/#{db_name}/#{doc_id}", query: %{rev: doc_rev})
assert resp.status_code == 200
info2_delete = get_partition_info(db_name, partition2)
assert info2_delete == info2
end
test "purging docs decreases partition size", context do
db_name = context[:db_name]
mk_docs(db_name)
partition = "000"
query = [
start_key: "\"#{partition}:0000\"",
end_key: "\"#{partition}:9999\"",
limit: 50
]
resp = Couch.get("/#{db_name}/_all_docs", query: query)
assert resp.status_code == 200
%{body: body} = resp
pre_info = get_partition_info(db_name, partition)
pbody =
body["rows"]
|> Enum.reduce(%{}, fn row, acc ->
Map.put(acc, row["id"], [row["value"]["rev"]])
end)
resp = Couch.post("/#{db_name}/_purge", query: [w: 3], body: pbody)
assert resp.status_code in [201, 202]
post_info = get_partition_info(db_name, partition)
assert post_info["doc_count"] == pre_info["doc_count"] - 50
assert post_info["doc_del_count"] == 0
assert post_info["sizes"]["active"] < pre_info["sizes"]["active"]
assert post_info["sizes"]["external"] < pre_info["sizes"]["external"]
end
end