diff --git a/_head.html b/_head.html new file mode 100644 index 00000000..3be00201 --- /dev/null +++ b/_head.html @@ -0,0 +1,2 @@ + + diff --git a/chunks/khepri.chunk b/chunks/khepri.chunk new file mode 100644 index 00000000..14248981 Binary files /dev/null and b/chunks/khepri.chunk differ diff --git a/chunks/khepri_adv.chunk b/chunks/khepri_adv.chunk new file mode 100644 index 00000000..fc3a300f Binary files /dev/null and b/chunks/khepri_adv.chunk differ diff --git a/chunks/khepri_app.chunk b/chunks/khepri_app.chunk new file mode 100644 index 00000000..b02a0f97 Binary files /dev/null and b/chunks/khepri_app.chunk differ diff --git a/chunks/khepri_cluster.chunk b/chunks/khepri_cluster.chunk new file mode 100644 index 00000000..1a059017 Binary files /dev/null and b/chunks/khepri_cluster.chunk differ diff --git a/chunks/khepri_condition.chunk b/chunks/khepri_condition.chunk new file mode 100644 index 00000000..01b2a1d5 Binary files /dev/null and b/chunks/khepri_condition.chunk differ diff --git a/chunks/khepri_event_handler.chunk b/chunks/khepri_event_handler.chunk new file mode 100644 index 00000000..f3257b2d Binary files /dev/null and b/chunks/khepri_event_handler.chunk differ diff --git a/chunks/khepri_evf.chunk b/chunks/khepri_evf.chunk new file mode 100644 index 00000000..86267918 Binary files /dev/null and b/chunks/khepri_evf.chunk differ diff --git a/chunks/khepri_export_erlang.chunk b/chunks/khepri_export_erlang.chunk new file mode 100644 index 00000000..f4a63a2e Binary files /dev/null and b/chunks/khepri_export_erlang.chunk differ diff --git a/chunks/khepri_import_export.chunk b/chunks/khepri_import_export.chunk new file mode 100644 index 00000000..980208ff Binary files /dev/null and b/chunks/khepri_import_export.chunk differ diff --git a/chunks/khepri_machine.chunk b/chunks/khepri_machine.chunk new file mode 100644 index 00000000..25213c03 Binary files /dev/null and b/chunks/khepri_machine.chunk differ diff --git a/chunks/khepri_machine_v0.chunk b/chunks/khepri_machine_v0.chunk new file mode 100644 index 00000000..9a486e63 Binary files /dev/null and b/chunks/khepri_machine_v0.chunk differ diff --git a/chunks/khepri_path.chunk b/chunks/khepri_path.chunk new file mode 100644 index 00000000..fd534e42 Binary files /dev/null and b/chunks/khepri_path.chunk differ diff --git a/chunks/khepri_pattern_tree.chunk b/chunks/khepri_pattern_tree.chunk new file mode 100644 index 00000000..d64ea1a4 Binary files /dev/null and b/chunks/khepri_pattern_tree.chunk differ diff --git a/chunks/khepri_payload.chunk b/chunks/khepri_payload.chunk new file mode 100644 index 00000000..3b4c44d5 Binary files /dev/null and b/chunks/khepri_payload.chunk differ diff --git a/chunks/khepri_prefix_tree.chunk b/chunks/khepri_prefix_tree.chunk new file mode 100644 index 00000000..2a148b80 Binary files /dev/null and b/chunks/khepri_prefix_tree.chunk differ diff --git a/chunks/khepri_projection.chunk b/chunks/khepri_projection.chunk new file mode 100644 index 00000000..7a8f8494 Binary files /dev/null and b/chunks/khepri_projection.chunk differ diff --git a/chunks/khepri_sproc.chunk b/chunks/khepri_sproc.chunk new file mode 100644 index 00000000..6169a06b Binary files /dev/null and b/chunks/khepri_sproc.chunk differ diff --git a/chunks/khepri_sup.chunk b/chunks/khepri_sup.chunk new file mode 100644 index 00000000..6edbef92 Binary files /dev/null and b/chunks/khepri_sup.chunk differ diff --git a/chunks/khepri_tree.chunk b/chunks/khepri_tree.chunk new file mode 100644 index 00000000..6458c6b5 Binary files /dev/null and b/chunks/khepri_tree.chunk differ diff --git a/chunks/khepri_tx.chunk b/chunks/khepri_tx.chunk new file mode 100644 index 00000000..797118fc Binary files /dev/null and b/chunks/khepri_tx.chunk differ diff --git a/chunks/khepri_tx_adv.chunk b/chunks/khepri_tx_adv.chunk new file mode 100644 index 00000000..88f0d73e Binary files /dev/null and b/chunks/khepri_tx_adv.chunk differ diff --git a/chunks/khepri_utils.chunk b/chunks/khepri_utils.chunk new file mode 100644 index 00000000..c1ca6f4b Binary files /dev/null and b/chunks/khepri_utils.chunk differ diff --git a/edoc-extensions.css b/edoc-extensions.css new file mode 100644 index 00000000..c120569e --- /dev/null +++ b/edoc-extensions.css @@ -0,0 +1,66 @@ +@import url("github-markdown.css"); +@import url("prism.css"); +@import url("stylesheet.css"); + +body { + box-sizing: border-box; + min-width: 200px; + max-width: 980px; + margin: 0 auto; + padding: 45px; +} +@media (max-width: 767px) { + body { + padding: 15px; + } +} +/* Don't apply the table style to the top-level navigation bar. */ +.navbar table { + display: table; + width: 100%; +} +.navbar table tr, +.navbar table th, +.navbar table td { + border: 0; +} +/* Keep the same font side inside code blocks than everywhere else. */ +.markdown-body pre code, +code[class*="language-"] { + font-size: 85%; +} +/* Force the color for link on code blocks used for @see tags. */ +.markdown-body a code, +.markdown-body a code span.token { + color: var(--color-accent-fg); +} +/* Copy the style of code blocks. */ +.markdown-body .spec { + background: #f5f2f0; + padding: 1em; + margin: .5em 0; + overflow: auto; + border-radius: 6px; +} +/* Improve margins inside function spec blocks so that: + - empty paragraphs don't add useless margins + - the final top and bottom margins are equal */ +.markdown-body .spec p, +.markdown-body .spec ul { + margin-top: 16px; + margin-bottom: 0; +} +.markdown-body .spec p:first-child, +.markdown-body .spec p:empty { + margin-top: 0; +} +/* Put the function prototype in bold characters. */ +.markdown-body .spec > p > code:first-child { + font-weight: bold; +} +/* Add some margin below the module short description between the table + of contents in the Description section. This text isn't in a +
. */ +.index + p { + margin-top: 16px; +} diff --git a/edoc-info b/edoc-info new file mode 100644 index 00000000..8a04e133 --- /dev/null +++ b/edoc-info @@ -0,0 +1,6 @@ +%% encoding: UTF-8 +{application,khepri}. +{modules,[khepri,khepri_adv,khepri_cluster,khepri_condition,khepri_evf, + khepri_export_erlang,khepri_import_export,khepri_machine, + khepri_path,khepri_payload,khepri_prefix_tree,khepri_projection, + khepri_tx,khepri_tx_adv]}. diff --git a/erlang.png b/erlang.png new file mode 100644 index 00000000..987a618e Binary files /dev/null and b/erlang.png differ diff --git a/github-markdown.css b/github-markdown.css new file mode 100644 index 00000000..b7afaa41 --- /dev/null +++ b/github-markdown.css @@ -0,0 +1,1221 @@ +.markdown-body { + --base-size-4: 0.25rem; + --base-size-8: 0.5rem; + --base-size-16: 1rem; + --base-size-24: 1.5rem; + --base-size-40: 2.5rem; + --base-text-weight-normal: 400; + --base-text-weight-medium: 500; + --base-text-weight-semibold: 600; + --fontStack-monospace: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; + --fgColor-accent: Highlight; +} +@media (prefers-color-scheme: dark) { + .markdown-body, [data-theme="dark"] { + /* dark */ + color-scheme: dark; + --focus-outlineColor: #1f6feb; + --fgColor-default: #f0f6fc; + --fgColor-muted: #9198a1; + --fgColor-accent: #4493f8; + --fgColor-success: #3fb950; + --fgColor-attention: #d29922; + --fgColor-danger: #f85149; + --fgColor-done: #ab7df8; + --bgColor-default: #0d1117; + --bgColor-muted: #151b23; + --bgColor-neutral-muted: #656c7633; + --bgColor-attention-muted: #bb800926; + --borderColor-default: #3d444d; + --borderColor-muted: #3d444db3; + --borderColor-neutral-muted: #3d444db3; + --borderColor-accent-emphasis: #1f6feb; + --borderColor-success-emphasis: #238636; + --borderColor-attention-emphasis: #9e6a03; + --borderColor-danger-emphasis: #da3633; + --borderColor-done-emphasis: #8957e5; + --color-prettylights-syntax-comment: #9198a1; + --color-prettylights-syntax-constant: #79c0ff; + --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; + --color-prettylights-syntax-entity: #d2a8ff; + --color-prettylights-syntax-storage-modifier-import: #f0f6fc; + --color-prettylights-syntax-entity-tag: #7ee787; + --color-prettylights-syntax-keyword: #ff7b72; + --color-prettylights-syntax-string: #a5d6ff; + --color-prettylights-syntax-variable: #ffa657; + --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; + --color-prettylights-syntax-brackethighlighter-angle: #9198a1; + --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; + --color-prettylights-syntax-invalid-illegal-bg: #8e1519; + --color-prettylights-syntax-carriage-return-text: #f0f6fc; + --color-prettylights-syntax-carriage-return-bg: #b62324; + --color-prettylights-syntax-string-regexp: #7ee787; + --color-prettylights-syntax-markup-list: #f2cc60; + --color-prettylights-syntax-markup-heading: #1f6feb; + --color-prettylights-syntax-markup-italic: #f0f6fc; + --color-prettylights-syntax-markup-bold: #f0f6fc; + --color-prettylights-syntax-markup-deleted-text: #ffdcd7; + --color-prettylights-syntax-markup-deleted-bg: #67060c; + --color-prettylights-syntax-markup-inserted-text: #aff5b4; + --color-prettylights-syntax-markup-inserted-bg: #033a16; + --color-prettylights-syntax-markup-changed-text: #ffdfb6; + --color-prettylights-syntax-markup-changed-bg: #5a1e02; + --color-prettylights-syntax-markup-ignored-text: #f0f6fc; + --color-prettylights-syntax-markup-ignored-bg: #1158c7; + --color-prettylights-syntax-meta-diff-range: #d2a8ff; + --color-prettylights-syntax-sublimelinter-gutter-mark: #3d444d; + } +} +@media (prefers-color-scheme: light) { + .markdown-body, [data-theme="light"] { + /* light */ + color-scheme: light; + --focus-outlineColor: #0969da; + --fgColor-default: #1f2328; + --fgColor-muted: #59636e; + --fgColor-accent: #0969da; + --fgColor-success: #1a7f37; + --fgColor-attention: #9a6700; + --fgColor-danger: #d1242f; + --fgColor-done: #8250df; + --bgColor-default: #ffffff; + --bgColor-muted: #f6f8fa; + --bgColor-neutral-muted: #818b981f; + --bgColor-attention-muted: #fff8c5; + --borderColor-default: #d1d9e0; + --borderColor-muted: #d1d9e0b3; + --borderColor-neutral-muted: #d1d9e0b3; + --borderColor-accent-emphasis: #0969da; + --borderColor-success-emphasis: #1a7f37; + --borderColor-attention-emphasis: #9a6700; + --borderColor-danger-emphasis: #cf222e; + --borderColor-done-emphasis: #8250df; + --color-prettylights-syntax-comment: #59636e; + --color-prettylights-syntax-constant: #0550ae; + --color-prettylights-syntax-constant-other-reference-link: #0a3069; + --color-prettylights-syntax-entity: #6639ba; + --color-prettylights-syntax-storage-modifier-import: #1f2328; + --color-prettylights-syntax-entity-tag: #0550ae; + --color-prettylights-syntax-keyword: #cf222e; + --color-prettylights-syntax-string: #0a3069; + --color-prettylights-syntax-variable: #953800; + --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; + --color-prettylights-syntax-brackethighlighter-angle: #59636e; + --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; + --color-prettylights-syntax-invalid-illegal-bg: #82071e; + --color-prettylights-syntax-carriage-return-text: #f6f8fa; + --color-prettylights-syntax-carriage-return-bg: #cf222e; + --color-prettylights-syntax-string-regexp: #116329; + --color-prettylights-syntax-markup-list: #3b2300; + --color-prettylights-syntax-markup-heading: #0550ae; + --color-prettylights-syntax-markup-italic: #1f2328; + --color-prettylights-syntax-markup-bold: #1f2328; + --color-prettylights-syntax-markup-deleted-text: #82071e; + --color-prettylights-syntax-markup-deleted-bg: #ffebe9; + --color-prettylights-syntax-markup-inserted-text: #116329; + --color-prettylights-syntax-markup-inserted-bg: #dafbe1; + --color-prettylights-syntax-markup-changed-text: #953800; + --color-prettylights-syntax-markup-changed-bg: #ffd8b5; + --color-prettylights-syntax-markup-ignored-text: #d1d9e0; + --color-prettylights-syntax-markup-ignored-bg: #0550ae; + --color-prettylights-syntax-meta-diff-range: #8250df; + --color-prettylights-syntax-sublimelinter-gutter-mark: #818b98; + } +} + +.markdown-body { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + margin: 0; + color: var(--fgColor-default); + background-color: var(--bgColor-default); + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; + font-size: 16px; + line-height: 1.5; + word-wrap: break-word; + scroll-behavior: auto !important; +} + +.markdown-body .octicon { + display: inline-block; + fill: currentColor; + vertical-align: text-bottom; +} + +.markdown-body h1:hover .anchor .octicon-link:before, +.markdown-body h2:hover .anchor .octicon-link:before, +.markdown-body h3:hover .anchor .octicon-link:before, +.markdown-body h4:hover .anchor .octicon-link:before, +.markdown-body h5:hover .anchor .octicon-link:before, +.markdown-body h6:hover .anchor .octicon-link:before { + width: 16px; + height: 16px; + content: ' '; + display: inline-block; + background-color: currentColor; + -webkit-mask-image: url("data:image/svg+xml,"); + mask-image: url("data:image/svg+xml,"); +} + +.markdown-body details, +.markdown-body figcaption, +.markdown-body figure { + display: block; +} + +.markdown-body summary { + display: list-item; +} + +.markdown-body [hidden] { + display: none !important; +} + +.markdown-body a { + background-color: transparent; + color: var(--fgColor-accent); + text-decoration: none; +} + +.markdown-body abbr[title] { + border-bottom: none; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +.markdown-body b, +.markdown-body strong { + font-weight: var(--base-text-weight-semibold, 600); +} + +.markdown-body dfn { + font-style: italic; +} + +.markdown-body h1 { + margin: .67em 0; + font-weight: var(--base-text-weight-semibold, 600); + padding-bottom: .3em; + font-size: 2em; + border-bottom: 1px solid var(--borderColor-muted); +} + +.markdown-body mark { + background-color: var(--bgColor-attention-muted); + color: var(--fgColor-default); +} + +.markdown-body small { + font-size: 90%; +} + +.markdown-body sub, +.markdown-body sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +.markdown-body sub { + bottom: -0.25em; +} + +.markdown-body sup { + top: -0.5em; +} + +.markdown-body img { + border-style: none; + max-width: 100%; + box-sizing: content-box; +} + +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp { + font-family: monospace; + font-size: 1em; +} + +.markdown-body figure { + margin: 1em var(--base-size-40); +} + +.markdown-body hr { + box-sizing: content-box; + overflow: hidden; + background: transparent; + border-bottom: 1px solid var(--borderColor-muted); + height: .25em; + padding: 0; + margin: var(--base-size-24) 0; + background-color: var(--borderColor-default); + border: 0; +} + +.markdown-body input { + font: inherit; + margin: 0; + overflow: visible; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +.markdown-body [type=button], +.markdown-body [type=reset], +.markdown-body [type=submit] { + -webkit-appearance: button; + appearance: button; +} + +.markdown-body [type=checkbox], +.markdown-body [type=radio] { + box-sizing: border-box; + padding: 0; +} + +.markdown-body [type=number]::-webkit-inner-spin-button, +.markdown-body [type=number]::-webkit-outer-spin-button { + height: auto; +} + +.markdown-body [type=search]::-webkit-search-cancel-button, +.markdown-body [type=search]::-webkit-search-decoration { + -webkit-appearance: none; + appearance: none; +} + +.markdown-body ::-webkit-input-placeholder { + color: inherit; + opacity: .54; +} + +.markdown-body ::-webkit-file-upload-button { + -webkit-appearance: button; + appearance: button; + font: inherit; +} + +.markdown-body a:hover { + text-decoration: underline; +} + +.markdown-body ::placeholder { + color: var(--fgColor-muted); + opacity: 1; +} + +.markdown-body hr::before { + display: table; + content: ""; +} + +.markdown-body hr::after { + display: table; + clear: both; + content: ""; +} + +.markdown-body table { + border-spacing: 0; + border-collapse: collapse; + display: block; + width: max-content; + max-width: 100%; + overflow: auto; +} + +.markdown-body td, +.markdown-body th { + padding: 0; +} + +.markdown-body details summary { + cursor: pointer; +} + +.markdown-body a:focus, +.markdown-body [role=button]:focus, +.markdown-body input[type=radio]:focus, +.markdown-body input[type=checkbox]:focus { + outline: 2px solid var(--focus-outlineColor); + outline-offset: -2px; + box-shadow: none; +} + +.markdown-body a:focus:not(:focus-visible), +.markdown-body [role=button]:focus:not(:focus-visible), +.markdown-body input[type=radio]:focus:not(:focus-visible), +.markdown-body input[type=checkbox]:focus:not(:focus-visible) { + outline: solid 1px transparent; +} + +.markdown-body a:focus-visible, +.markdown-body [role=button]:focus-visible, +.markdown-body input[type=radio]:focus-visible, +.markdown-body input[type=checkbox]:focus-visible { + outline: 2px solid var(--focus-outlineColor); + outline-offset: -2px; + box-shadow: none; +} + +.markdown-body a:not([class]):focus, +.markdown-body a:not([class]):focus-visible, +.markdown-body input[type=radio]:focus, +.markdown-body input[type=radio]:focus-visible, +.markdown-body input[type=checkbox]:focus, +.markdown-body input[type=checkbox]:focus-visible { + outline-offset: 0; +} + +.markdown-body kbd { + display: inline-block; + padding: var(--base-size-4); + font: 11px var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace); + line-height: 10px; + color: var(--fgColor-default); + vertical-align: middle; + background-color: var(--bgColor-muted); + border: solid 1px var(--borderColor-neutral-muted); + border-bottom-color: var(--borderColor-neutral-muted); + border-radius: 6px; + box-shadow: inset 0 -1px 0 var(--borderColor-neutral-muted); +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + margin-top: var(--base-size-24); + margin-bottom: var(--base-size-16); + font-weight: var(--base-text-weight-semibold, 600); + line-height: 1.25; +} + +.markdown-body h2 { + font-weight: var(--base-text-weight-semibold, 600); + padding-bottom: .3em; + font-size: 1.5em; + border-bottom: 1px solid var(--borderColor-muted); +} + +.markdown-body h3 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: 1.25em; +} + +.markdown-body h4 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: 1em; +} + +.markdown-body h5 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: .875em; +} + +.markdown-body h6 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: .85em; + color: var(--fgColor-muted); +} + +.markdown-body p { + margin-top: 0; + margin-bottom: 10px; +} + +.markdown-body blockquote { + margin: 0; + padding: 0 1em; + color: var(--fgColor-muted); + border-left: .25em solid var(--borderColor-default); +} + +.markdown-body ul, +.markdown-body ol { + margin-top: 0; + margin-bottom: 0; + padding-left: 2em; +} + +.markdown-body ol ol, +.markdown-body ul ol { + list-style-type: lower-roman; +} + +.markdown-body ul ul ol, +.markdown-body ul ol ol, +.markdown-body ol ul ol, +.markdown-body ol ol ol { + list-style-type: lower-alpha; +} + +.markdown-body dd { + margin-left: 0; +} + +.markdown-body tt, +.markdown-body code, +.markdown-body samp { + font-family: var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace); + font-size: 12px; +} + +.markdown-body pre { + margin-top: 0; + margin-bottom: 0; + font-family: var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace); + font-size: 12px; + word-wrap: normal; +} + +.markdown-body .octicon { + display: inline-block; + overflow: visible !important; + vertical-align: text-bottom; + fill: currentColor; +} + +.markdown-body input::-webkit-outer-spin-button, +.markdown-body input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; + appearance: none; +} + +.markdown-body .mr-2 { + margin-right: var(--base-size-8, 8px) !important; +} + +.markdown-body::before { + display: table; + content: ""; +} + +.markdown-body::after { + display: table; + clear: both; + content: ""; +} + +.markdown-body>*:first-child { + margin-top: 0 !important; +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important; +} + +.markdown-body a:not([href]) { + color: inherit; + text-decoration: none; +} + +.markdown-body .absent { + color: var(--fgColor-danger); +} + +.markdown-body .anchor { + float: left; + padding-right: var(--base-size-4); + margin-left: -20px; + line-height: 1; +} + +.markdown-body .anchor:focus { + outline: none; +} + +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body pre, +.markdown-body details { + margin-top: 0; + margin-bottom: var(--base-size-16); +} + +.markdown-body blockquote>:first-child { + margin-top: 0; +} + +.markdown-body blockquote>:last-child { + margin-bottom: 0; +} + +.markdown-body h1 .octicon-link, +.markdown-body h2 .octicon-link, +.markdown-body h3 .octicon-link, +.markdown-body h4 .octicon-link, +.markdown-body h5 .octicon-link, +.markdown-body h6 .octicon-link { + color: var(--fgColor-default); + vertical-align: middle; + visibility: hidden; +} + +.markdown-body h1:hover .anchor, +.markdown-body h2:hover .anchor, +.markdown-body h3:hover .anchor, +.markdown-body h4:hover .anchor, +.markdown-body h5:hover .anchor, +.markdown-body h6:hover .anchor { + text-decoration: none; +} + +.markdown-body h1:hover .anchor .octicon-link, +.markdown-body h2:hover .anchor .octicon-link, +.markdown-body h3:hover .anchor .octicon-link, +.markdown-body h4:hover .anchor .octicon-link, +.markdown-body h5:hover .anchor .octicon-link, +.markdown-body h6:hover .anchor .octicon-link { + visibility: visible; +} + +.markdown-body h1 tt, +.markdown-body h1 code, +.markdown-body h2 tt, +.markdown-body h2 code, +.markdown-body h3 tt, +.markdown-body h3 code, +.markdown-body h4 tt, +.markdown-body h4 code, +.markdown-body h5 tt, +.markdown-body h5 code, +.markdown-body h6 tt, +.markdown-body h6 code { + padding: 0 .2em; + font-size: inherit; +} + +.markdown-body summary h1, +.markdown-body summary h2, +.markdown-body summary h3, +.markdown-body summary h4, +.markdown-body summary h5, +.markdown-body summary h6 { + display: inline-block; +} + +.markdown-body summary h1 .anchor, +.markdown-body summary h2 .anchor, +.markdown-body summary h3 .anchor, +.markdown-body summary h4 .anchor, +.markdown-body summary h5 .anchor, +.markdown-body summary h6 .anchor { + margin-left: -40px; +} + +.markdown-body summary h1, +.markdown-body summary h2 { + padding-bottom: 0; + border-bottom: 0; +} + +.markdown-body ul.no-list, +.markdown-body ol.no-list { + padding: 0; + list-style-type: none; +} + +.markdown-body ol[type="a s"] { + list-style-type: lower-alpha; +} + +.markdown-body ol[type="A s"] { + list-style-type: upper-alpha; +} + +.markdown-body ol[type="i s"] { + list-style-type: lower-roman; +} + +.markdown-body ol[type="I s"] { + list-style-type: upper-roman; +} + +.markdown-body ol[type="1"] { + list-style-type: decimal; +} + +.markdown-body div>ol:not([type]) { + list-style-type: decimal; +} + +.markdown-body ul ul, +.markdown-body ul ol, +.markdown-body ol ol, +.markdown-body ol ul { + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body li>p { + margin-top: var(--base-size-16); +} + +.markdown-body li+li { + margin-top: .25em; +} + +.markdown-body dl { + padding: 0; +} + +.markdown-body dl dt { + padding: 0; + margin-top: var(--base-size-16); + font-size: 1em; + font-style: italic; + font-weight: var(--base-text-weight-semibold, 600); +} + +.markdown-body dl dd { + padding: 0 var(--base-size-16); + margin-bottom: var(--base-size-16); +} + +.markdown-body table th { + font-weight: var(--base-text-weight-semibold, 600); +} + +.markdown-body table th, +.markdown-body table td { + padding: 6px 13px; + border: 1px solid var(--borderColor-default); +} + +.markdown-body table td>:last-child { + margin-bottom: 0; +} + +.markdown-body table tr { + background-color: var(--bgColor-default); + border-top: 1px solid var(--borderColor-muted); +} + +.markdown-body table tr:nth-child(2n) { + background-color: var(--bgColor-muted); +} + +.markdown-body table img { + background-color: transparent; +} + +.markdown-body img[align=right] { + padding-left: 20px; +} + +.markdown-body img[align=left] { + padding-right: 20px; +} + +.markdown-body .emoji { + max-width: none; + vertical-align: text-top; + background-color: transparent; +} + +.markdown-body span.frame { + display: block; + overflow: hidden; +} + +.markdown-body span.frame>span { + display: block; + float: left; + width: auto; + padding: 7px; + margin: 13px 0 0; + overflow: hidden; + border: 1px solid var(--borderColor-default); +} + +.markdown-body span.frame span img { + display: block; + float: left; +} + +.markdown-body span.frame span span { + display: block; + padding: 5px 0 0; + clear: both; + color: var(--fgColor-default); +} + +.markdown-body span.align-center { + display: block; + overflow: hidden; + clear: both; +} + +.markdown-body span.align-center>span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: center; +} + +.markdown-body span.align-center span img { + margin: 0 auto; + text-align: center; +} + +.markdown-body span.align-right { + display: block; + overflow: hidden; + clear: both; +} + +.markdown-body span.align-right>span { + display: block; + margin: 13px 0 0; + overflow: hidden; + text-align: right; +} + +.markdown-body span.align-right span img { + margin: 0; + text-align: right; +} + +.markdown-body span.float-left { + display: block; + float: left; + margin-right: 13px; + overflow: hidden; +} + +.markdown-body span.float-left span { + margin: 13px 0 0; +} + +.markdown-body span.float-right { + display: block; + float: right; + margin-left: 13px; + overflow: hidden; +} + +.markdown-body span.float-right>span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: right; +} + +.markdown-body code, +.markdown-body tt { + padding: .2em .4em; + margin: 0; + font-size: 85%; + white-space: break-spaces; + background-color: var(--bgColor-neutral-muted); + border-radius: 6px; +} + +.markdown-body code br, +.markdown-body tt br { + display: none; +} + +.markdown-body del code { + text-decoration: inherit; +} + +.markdown-body samp { + font-size: 85%; +} + +.markdown-body pre code { + font-size: 100%; +} + +.markdown-body pre>code { + padding: 0; + margin: 0; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; +} + +.markdown-body .highlight { + margin-bottom: var(--base-size-16); +} + +.markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal; +} + +.markdown-body .highlight pre, +.markdown-body pre { + padding: var(--base-size-16); + overflow: auto; + font-size: 85%; + line-height: 1.45; + color: var(--fgColor-default); + background-color: var(--bgColor-muted); + border-radius: 6px; +} + +.markdown-body pre code, +.markdown-body pre tt { + display: inline; + max-width: auto; + padding: 0; + margin: 0; + overflow: visible; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; +} + +.markdown-body .csv-data td, +.markdown-body .csv-data th { + padding: 5px; + overflow: hidden; + font-size: 12px; + line-height: 1; + text-align: left; + white-space: nowrap; +} + +.markdown-body .csv-data .blob-num { + padding: 10px var(--base-size-8) 9px; + text-align: right; + background: var(--bgColor-default); + border: 0; +} + +.markdown-body .csv-data tr { + border-top: 0; +} + +.markdown-body .csv-data th { + font-weight: var(--base-text-weight-semibold, 600); + background: var(--bgColor-muted); + border-top: 0; +} + +.markdown-body [data-footnote-ref]::before { + content: "["; +} + +.markdown-body [data-footnote-ref]::after { + content: "]"; +} + +.markdown-body .footnotes { + font-size: 12px; + color: var(--fgColor-muted); + border-top: 1px solid var(--borderColor-default); +} + +.markdown-body .footnotes ol { + padding-left: var(--base-size-16); +} + +.markdown-body .footnotes ol ul { + display: inline-block; + padding-left: var(--base-size-16); + margin-top: var(--base-size-16); +} + +.markdown-body .footnotes li { + position: relative; +} + +.markdown-body .footnotes li:target::before { + position: absolute; + top: calc(var(--base-size-8)*-1); + right: calc(var(--base-size-8)*-1); + bottom: calc(var(--base-size-8)*-1); + left: calc(var(--base-size-24)*-1); + pointer-events: none; + content: ""; + border: 2px solid var(--borderColor-accent-emphasis); + border-radius: 6px; +} + +.markdown-body .footnotes li:target { + color: var(--fgColor-default); +} + +.markdown-body .footnotes .data-footnote-backref g-emoji { + font-family: monospace; +} + +.markdown-body .pl-c { + color: var(--color-prettylights-syntax-comment); +} + +.markdown-body .pl-c1, +.markdown-body .pl-s .pl-v { + color: var(--color-prettylights-syntax-constant); +} + +.markdown-body .pl-e, +.markdown-body .pl-en { + color: var(--color-prettylights-syntax-entity); +} + +.markdown-body .pl-smi, +.markdown-body .pl-s .pl-s1 { + color: var(--color-prettylights-syntax-storage-modifier-import); +} + +.markdown-body .pl-ent { + color: var(--color-prettylights-syntax-entity-tag); +} + +.markdown-body .pl-k { + color: var(--color-prettylights-syntax-keyword); +} + +.markdown-body .pl-s, +.markdown-body .pl-pds, +.markdown-body .pl-s .pl-pse .pl-s1, +.markdown-body .pl-sr, +.markdown-body .pl-sr .pl-cce, +.markdown-body .pl-sr .pl-sre, +.markdown-body .pl-sr .pl-sra { + color: var(--color-prettylights-syntax-string); +} + +.markdown-body .pl-v, +.markdown-body .pl-smw { + color: var(--color-prettylights-syntax-variable); +} + +.markdown-body .pl-bu { + color: var(--color-prettylights-syntax-brackethighlighter-unmatched); +} + +.markdown-body .pl-ii { + color: var(--color-prettylights-syntax-invalid-illegal-text); + background-color: var(--color-prettylights-syntax-invalid-illegal-bg); +} + +.markdown-body .pl-c2 { + color: var(--color-prettylights-syntax-carriage-return-text); + background-color: var(--color-prettylights-syntax-carriage-return-bg); +} + +.markdown-body .pl-sr .pl-cce { + font-weight: bold; + color: var(--color-prettylights-syntax-string-regexp); +} + +.markdown-body .pl-ml { + color: var(--color-prettylights-syntax-markup-list); +} + +.markdown-body .pl-mh, +.markdown-body .pl-mh .pl-en, +.markdown-body .pl-ms { + font-weight: bold; + color: var(--color-prettylights-syntax-markup-heading); +} + +.markdown-body .pl-mi { + font-style: italic; + color: var(--color-prettylights-syntax-markup-italic); +} + +.markdown-body .pl-mb { + font-weight: bold; + color: var(--color-prettylights-syntax-markup-bold); +} + +.markdown-body .pl-md { + color: var(--color-prettylights-syntax-markup-deleted-text); + background-color: var(--color-prettylights-syntax-markup-deleted-bg); +} + +.markdown-body .pl-mi1 { + color: var(--color-prettylights-syntax-markup-inserted-text); + background-color: var(--color-prettylights-syntax-markup-inserted-bg); +} + +.markdown-body .pl-mc { + color: var(--color-prettylights-syntax-markup-changed-text); + background-color: var(--color-prettylights-syntax-markup-changed-bg); +} + +.markdown-body .pl-mi2 { + color: var(--color-prettylights-syntax-markup-ignored-text); + background-color: var(--color-prettylights-syntax-markup-ignored-bg); +} + +.markdown-body .pl-mdr { + font-weight: bold; + color: var(--color-prettylights-syntax-meta-diff-range); +} + +.markdown-body .pl-ba { + color: var(--color-prettylights-syntax-brackethighlighter-angle); +} + +.markdown-body .pl-sg { + color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); +} + +.markdown-body .pl-corl { + text-decoration: underline; + color: var(--color-prettylights-syntax-constant-other-reference-link); +} + +.markdown-body [role=button]:focus:not(:focus-visible), +.markdown-body [role=tabpanel][tabindex="0"]:focus:not(:focus-visible), +.markdown-body button:focus:not(:focus-visible), +.markdown-body summary:focus:not(:focus-visible), +.markdown-body a:focus:not(:focus-visible) { + outline: none; + box-shadow: none; +} + +.markdown-body [tabindex="0"]:focus:not(:focus-visible), +.markdown-body details-dialog:focus:not(:focus-visible) { + outline: none; +} + +.markdown-body g-emoji { + display: inline-block; + min-width: 1ch; + font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; + font-size: 1em; + font-style: normal !important; + font-weight: var(--base-text-weight-normal, 400); + line-height: 1; + vertical-align: -0.075em; +} + +.markdown-body g-emoji img { + width: 1em; + height: 1em; +} + +.markdown-body .task-list-item { + list-style-type: none; +} + +.markdown-body .task-list-item label { + font-weight: var(--base-text-weight-normal, 400); +} + +.markdown-body .task-list-item.enabled label { + cursor: pointer; +} + +.markdown-body .task-list-item+.task-list-item { + margin-top: var(--base-size-4); +} + +.markdown-body .task-list-item .handle { + display: none; +} + +.markdown-body .task-list-item-checkbox { + margin: 0 .2em .25em -1.4em; + vertical-align: middle; +} + +.markdown-body ul:dir(rtl) .task-list-item-checkbox { + margin: 0 -1.6em .25em .2em; +} + +.markdown-body ol:dir(rtl) .task-list-item-checkbox { + margin: 0 -1.6em .25em .2em; +} + +.markdown-body .contains-task-list:hover .task-list-item-convert-container, +.markdown-body .contains-task-list:focus-within .task-list-item-convert-container { + display: block; + width: auto; + height: 24px; + overflow: visible; + clip: auto; +} + +.markdown-body ::-webkit-calendar-picker-indicator { + filter: invert(50%); +} + +.markdown-body .markdown-alert { + padding: var(--base-size-8) var(--base-size-16); + margin-bottom: var(--base-size-16); + color: inherit; + border-left: .25em solid var(--borderColor-default); +} + +.markdown-body .markdown-alert>:first-child { + margin-top: 0; +} + +.markdown-body .markdown-alert>:last-child { + margin-bottom: 0; +} + +.markdown-body .markdown-alert .markdown-alert-title { + display: flex; + font-weight: var(--base-text-weight-medium, 500); + align-items: center; + line-height: 1; +} + +.markdown-body .markdown-alert.markdown-alert-note { + border-left-color: var(--borderColor-accent-emphasis); +} + +.markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title { + color: var(--fgColor-accent); +} + +.markdown-body .markdown-alert.markdown-alert-important { + border-left-color: var(--borderColor-done-emphasis); +} + +.markdown-body .markdown-alert.markdown-alert-important .markdown-alert-title { + color: var(--fgColor-done); +} + +.markdown-body .markdown-alert.markdown-alert-warning { + border-left-color: var(--borderColor-attention-emphasis); +} + +.markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title { + color: var(--fgColor-attention); +} + +.markdown-body .markdown-alert.markdown-alert-tip { + border-left-color: var(--borderColor-success-emphasis); +} + +.markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title { + color: var(--fgColor-success); +} + +.markdown-body .markdown-alert.markdown-alert-caution { + border-left-color: var(--borderColor-danger-emphasis); +} + +.markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title { + color: var(--fgColor-danger); +} + +.markdown-body>*:first-child>.heading-element:first-child { + margin-top: 0 !important; +} + diff --git a/index.html b/index.html new file mode 100644 index 00000000..7eef48eb --- /dev/null +++ b/index.html @@ -0,0 +1,19 @@ + + + +Khepri database API.
+ +This module exposes the database API to manipulate data.
+ +The API is mainly made of the functions used to perform simple direct atomic
+ operations and queries on the database: get/1
, put/2
, delete/1
and so on. In addition to that, transaction/1
is the
+ starting point to run transaction functions. However the API to use inside
+ transaction functions is provided by khepri_tx
.
Functions in this module have simplified return values to cover most
+ frequent use cases. If you need more details about the queried or modified
+ tree nodes, like the ability to distinguish a non-existent tree node from a
+ tree node with no payload, you can use the khepri_adv
module.
This module also provides functions to start and stop a simple unclustered
+ Khepri store. For more advanced setup and clustering, see khepri_cluster
.
A Khepri store is one instance of Khepri running inside a Ra cluster (which +could be made of a single Erlang node). It is possible to run multiple +Khepri stores in parallel by creating multiple Ra clusters.
+ +A Khepri store is started and configured with start/0
, start/1
or start/3
. To setup a cluster, see khepri_cluster
.
When a store is started, a store ID store_id()
is returned. This
+store ID is then used by the rest of this module's API. The returned store
+ID currently corresponds exactly to the Ra cluster name. It must be an atom
+though; other types are unsupported.
get/1
, exists/1
, has_data/1
, etc.put/2
, delete/1
, etc.transaction/1
, etc.:
+ khepri:transaction(
+ fun() ->
+ khepri_tx:put(Path, Value)
+ end).
+
+ Simple operations are more efficient than transactions, but transactions are
+ more flexible.
+async_option() = boolean() | ra_server:command_correlation() | ra_server:command_priority() | {ra_server:command_correlation(), ra_server:command_priority()}
Option to indicate if the command should be synchronous or asynchronous.
+ + Values are: +true
to perform an asynchronous command without a correlation
+ ID.false
to perform a synchronous command.async_ret() = khepri_adv:single_result() | khepri_adv:many_results() | khepri_tx:tx_fun_result() | khepri:error({not_leader, ra:server_id()})
The value returned from of a command function which was executed +asynchronously.
+ +When a caller includes a correlation ID (ra_server:command_correlation()
) async_option()
in their khepri:command_options()
on a command function, the caller will receive a
+ ra_event
message. Handling the notification with khepri:handle_async_ret/2
will return a list of pairs of correlation IDs
+ (ra_server:command_correlation()
) and the return values of the
+ commands which were applied, or {error, {not_leader, LeaderId}}
if the
+commands could not be applied since they were sent to a non-leader member.
Note that when commands are successfully applied, the return values are in
+ the khepri_adv
formats - khepri_adv:single_result()
or
+ khepri_adv:many_results()
- rather than khepri:minimal_ret()
, even if the command was sent using a function from
+ the khepri
API such as khepri:put/4
.
khepri:handle_async_ret/2
.
+
+child_list_length() = non_neg_integer()
Number of direct child nodes under a tree node.
+ +child_list_version() = pos_integer()
Number of changes made to the list of child nodes of a tree node (child +nodes added or removed).
+ + The child list version starts at 1 when a tree node is created. It is + increased by 1 each time a child is added or removed. Changes made to + existing nodes are not reflected in this version. + +command_options() = #{timeout => timeout(), async => async_option(), reply_from => reply_from_option(), protect_against_dups => boolean()}
Options used in commands.
+ +Commands are put/4
, delete/3
and read-write transaction/4
.
timeout
is passed to Ra command processing function.async
indicates the synchronous or asynchronous nature of the
+ command; see async_option()
.reply_from
indicates which cluster member should reply to the
+ command request; see reply_from_option()
.protect_against_dups
indicates if the deduplication mechanism should
+ be used for the command. This mechanism helps to avoid the same command to
+ be processed multiple times if there is a Ra cluster member stopping or a
+ change of leadership occurring at the same time. It is disabled by default,
+ except for R/W transactions.data() = any()
Data stored in a tree node's payload.
+ +error() = error(any())
The error tuple returned by a function after a failure.
+ +error(Type) = {error, Type}
Return value of a failed command or query.
+ +favor_option() = consistency | low_latency
Option to indicate where to put the cursor between freshness of the +returned data and low latency of queries.
+ + Values are: +low_latency
means that a local query is used. It is the fastest and
+ have the lowest latency. However, the returned data is whatever the local Ra
+ server has. It could be out-of-date if the local Ra server did not get or
+ applied the latest updates yet. The chance of blocking and timing out is
+ very small.consistency
means that a local query is used. However the query uses
+ the fence mechanism to ensure that the previous updates from the calling
+ process are applied locally before the query is evaluated. It will return
+ the most up-to-date piece of data the cluster agreed on. Note that it could
+ block and eventually time out if there is no quorum in the Ra cluster.filter_fun() = fun((khepri_path:native_path(), khepri:node_props()) -> boolean())
Function passed to khepri:filter/4
.
fold_acc() = any()
Term passed to and returned by a fold_fun/0
.
fold_fun() = fun((khepri_path:native_path(), khepri:node_props(), khepri:fold_acc()) -> khepri:fold_acc())
Function passed to khepri:fold/5
.
foreach_fun() = fun((khepri_path:native_path(), khepri:node_props()) -> any())
Function passed to khepri:foreach/4
.
many_payloads_ret() = many_payloads_ret(undefined)
The return value of query functions in the khepri
module that work
+on a many nodes.
undefined
is returned if a tree node has no payload attached to it.
+
+many_payloads_ret(Default) = khepri:ok(#{khepri_path:path() => khepri:data() | horus:horus_fun() | Default}) | khepri:error()
The return value of query functions in the khepri
module that work
+on many nodes.
Default
is the value to return if a tree node has no payload attached to
+ it.
+
+map_fun() = fun((khepri_path:native_path(), khepri:node_props()) -> khepri:map_fun_ret())
Function passed to khepri:map/4
.
map_fun_ret() = any()
Value returned by khepri:map_fun/0
.
minimal_ret() = ok | khepri:error()
The return value of update functions in the khepri
module.
node_props() = #{data => khepri:data(), has_data => boolean(), sproc => horus:horus_fun(), is_sproc => boolean(), payload_version => khepri:payload_version(), child_list_version => khepri:child_list_version(), child_list_length => khepri:child_list_length(), child_names => [khepri_path:node_id()]}
Structure used to return properties, payload and child nodes for a specific +tree node.
+ +The payload in data
or sproc
is only returned if the tree node carries
+something. If that key is missing from the returned properties map, it means
+the tree node has no payload.
khepri_adv
. The list of returned properties can be
+ configured using the props_to_return
option (see tree_options()
).
+
+ok(Type) = {ok, Type}
The result of a function after a successful call, wrapped in an "ok" tuple.
+ +payload_ret() = payload_ret(undefined)
The return value of query functions in the khepri
module that work
+on a single tree node.
undefined
is returned if a tree node has no payload attached to it.
+
+payload_ret(Default) = khepri:ok(khepri:data() | horus:horus_fun() | Default) | khepri:error()
The return value of query functions in the khepri
module that work
+on a single tree node.
Default
is the value to return if a tree node has no payload attached to
+ it.
+
+payload_version() = pos_integer()
Number of changes made to the payload of a tree node.
+ + The payload version starts at 1 when a tree node is created. It is increased + by 1 each time the payload is added, modified or removed. + +put_options() = #{keep_while => khepri_condition:keep_while()}
Options specific to updates.
+ +keep_while
allows to define keep-while conditions on the
+ created/updated tree node.query_options() = #{condition => ra:query_condition(), timeout => timeout(), favor => favor_option()}
Options used in queries.
+ +condition
indicates the condition on which the Ra server should wait
+ for before it executes the query.timeout
is passed to Ra query processing function.favor
indicates where to put the cursor between freshness of the
+ returned data and low latency of queries; see favor_option()
.favor
computes a condition
internally. Therefore if both options are
+ set, condition
takes precedence and favor
is ignored.
+
+reply_from_option() = leader | local | {member, ra:server_id()}
Options to indicate which member of the cluster should reply to a command +request.
+ +Note that commands are always handled by the leader. This option only +controls which member of the cluster carries out the reply.
+ +leader
: the cluster leader will reply. This is the default value.{member, Member}
: the given cluster member will reply.local
: a member of the cluster on the same Erlang node as the caller
+ will perform the reply.reply_from
is {member, Member}
and the given member is not part of
+ the cluster or when reply_from
is local
and there is no member local to
+ the caller, the leader member will perform the reply. This mechanism uses
+ the cluster membership information to decide which member should reply: if
+ the given Member
or local member is a member of the cluster but is offline
+ or unreachable, no reply may be sent even though the leader may have
+ successfully handled the command.
+
+store_id() = atom()
ID of a Khepri store.
+ + This is the same as the Ra cluster name hosting the Khepri store. + +tree_options() = #{expect_specific_node => boolean(), props_to_return => [payload_version | child_list_version | child_list_length | child_names | payload | has_payload | raw_payload], include_root_props => boolean()}
Options used during tree traversal.
+ +expect_specific_node
indicates if the path is expected to point to a
+ specific tree node or could match many nodes.props_to_return
indicates the list of properties to include in the
+ returned tree node properties map. The default is [payload,
+ payload_version]
. Note that payload
and has_payload
are a bit special:
+ the actually returned properties will be data
/sproc
and
+ has_data
/is_sproc
respectively. raw_payload
is for internal use
+ only.include_root_props
indicates if root properties and payload should be
+ returned as well.trigger_id() = atom()
An ID to identify a registered trigger.
+ +unwrapped_many_payloads_ret() = unwrapped_many_payloads_ret(undefined)
unwrapped_many_payloads_ret(Default) = #{khepri_path:path() => khepri:data() | horus:horus_fun() | Default}
unwrapped_minimal_ret() = khepri:minimal_ret()
unwrapped_payload_ret() = unwrapped_payload_ret(undefined)
unwrapped_payload_ret(Default) = khepri:data() | horus:horus_fun() | Default
start/0 | Starts a store. |
start/1 | Starts a store. |
start/2 | Starts a store. |
start/3 | Starts a store. |
reset/0 | Resets the store on this Erlang node. |
reset/1 | Resets the store on this Erlang node. |
reset/2 | Resets the store on this Erlang node. |
stop/0 | Stops a store. |
stop/1 | Stops a store. |
get_store_ids/0 | Returns the list of running stores. |
is_empty/0 | Indicates if the store is empty or not. |
is_empty/1 | Indicates if the store is empty or not. |
is_empty/2 | Indicates if the store is empty or not. |
get/1 | Returns the payload of the tree node pointed to by the given path +pattern. |
get/2 | Returns the payload of the tree node pointed to by the given path +pattern. |
get/3 | Returns the payload of the tree node pointed to by the given path +pattern. |
get_or/2 | Returns the payload of the tree node pointed to by the given path +pattern, or a default value. |
get_or/3 | Returns the payload of the tree node pointed to by the given path +pattern, or a default value. |
get_or/4 | Returns the payload of the tree node pointed to by the given path +pattern, or a default value. |
get_many/1 | Returns payloads of all the tree nodes matching the given path +pattern. |
get_many/2 | Returns payloads of all the tree nodes matching the given path +pattern. |
get_many/3 | Returns payloads of all the tree nodes matching the given path +pattern. |
get_many_or/2 | Returns payloads of all the tree nodes matching the given path +pattern, or a default payload. |
get_many_or/3 | Returns payloads of all the tree nodes matching the given path +pattern, or a default payload. |
get_many_or/4 | Returns payloads of all the tree nodes matching the given path +pattern, or a default payload. |
exists/1 | Indicates if the tree node pointed to by the given path exists or not. |
exists/2 | Indicates if the tree node pointed to by the given path exists or not. |
exists/3 | Indicates if the tree node pointed to by the given path exists or not. |
has_data/1 | Indicates if the tree node pointed to by the given path has data or +not. |
has_data/2 | Indicates if the tree node pointed to by the given path has data or +not. |
has_data/3 | Indicates if the tree node pointed to by the given path has data or +not. |
is_sproc/1 | Indicates if the tree node pointed to by the given path holds a stored +procedure or not. |
is_sproc/2 | Indicates if the tree node pointed to by the given path holds a stored +procedure or not. |
is_sproc/3 | Indicates if the tree node pointed to by the given path holds a stored +procedure or not. |
count/1 | Counts all tree nodes matching the given path pattern. |
count/2 | Counts all tree nodes matching the given path pattern. |
count/3 | Counts all tree nodes matching the given path pattern. |
fold/3 | Calls Fun on successive tree nodes matching the given path pattern,
+ starting with Acc . |
fold/4 | Calls Fun on successive tree nodes matching the given path pattern,
+ starting with Acc . |
fold/5 | Calls Fun on successive tree nodes matching the given path pattern,
+ starting with Acc . |
foreach/2 | Calls Fun for each tree node matching the given path pattern. |
foreach/3 | Calls Fun for each tree node matching the given path pattern. |
foreach/4 | Calls Fun for each tree node matching the given path pattern. |
map/2 | Produces a new map by calling Fun for each tree node matching the
+given path pattern. |
map/3 | Produces a new map by calling Fun for each tree node matching the
+given path pattern. |
map/4 | Produces a new map by calling Fun for each tree node matching the
+given path pattern. |
filter/2 | Returns a map for which predicate Pred holds true in tree nodes
+matching the given path pattern. |
filter/3 | Returns a map for which predicate Pred holds true in tree nodes
+matching the given path pattern. |
filter/4 | Returns a map for which predicate Pred holds true in tree nodes
+matching the given path pattern. |
run_sproc/2 | Runs the stored procedure pointed to by the given path and returns the +result. |
run_sproc/3 | Runs the stored procedure pointed to by the given path and returns the +result. |
run_sproc/4 | Runs the stored procedure pointed to by the given path and returns the +result. |
put/2 | Sets the payload of the tree node pointed to by the given path +pattern. |
put/3 | Sets the payload of the tree node pointed to by the given path +pattern. |
put/4 | Sets the payload of the tree node pointed to by the given path +pattern. |
put_many/2 | Sets the payload of all the tree nodes matching the given path pattern. |
put_many/3 | Sets the payload of all the tree nodes matching the given path pattern. |
put_many/4 | Sets the payload of all the tree nodes matching the given path pattern. |
create/2 | Creates a tree node with the given payload. |
create/3 | Creates a tree node with the given payload. |
create/4 | Creates a tree node with the given payload. |
update/2 | Updates an existing tree node with the given payload. |
update/3 | Updates an existing tree node with the given payload. |
update/4 | Updates an existing tree node with the given payload. |
compare_and_swap/3 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
compare_and_swap/4 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
compare_and_swap/5 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
delete/1 | Deletes the tree node pointed to by the given path pattern. |
delete/2 | Deletes the tree node pointed to by the given path pattern. |
delete/3 | Deletes the tree node pointed to by the given path pattern. |
delete_many/1 | Deletes all tree nodes matching the given path pattern. |
delete_many/2 | Deletes all tree nodes matching the given path pattern. |
delete_many/3 | Deletes all tree nodes matching the given path pattern. |
clear_payload/1 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_payload/2 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_payload/3 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_many_payloads/1 | Deletes the payload of all tree nodes matching the given path pattern. |
clear_many_payloads/2 | Deletes the payload of all tree nodes matching the given path pattern. |
clear_many_payloads/3 | Deletes the payload of all tree nodes matching the given path pattern. |
register_trigger/3 | Registers a trigger. |
register_trigger/4 | Registers a trigger. |
register_trigger/5 | Registers a trigger. |
register_projection/2 | Registers a projection. |
register_projection/3 | Registers a projection. |
register_projection/4 | Registers a projection. |
unregister_projections/1 | Removes the given projections from the store. |
unregister_projections/2 | Removes the given projections from the store. |
unregister_projections/3 | Removes the given projections from the store. |
has_projection/1 | Determines whether the store has a projection registered with the given +name. |
has_projection/2 | Determines whether the store has a projection registered with the given +name. |
has_projection/3 | Determines whether the store has a projection registered with the given + name. |
transaction/1 | Runs a transaction and returns its result. |
transaction/2 | Runs a transaction and returns its result. |
transaction/3 | Runs a transaction and returns its result. |
transaction/4 | Runs a transaction and returns its result. |
transaction/5 | Runs a transaction and returns its result. |
fence/0 | Blocks until all updates received by the cluster leader are applied +locally. |
fence/1 | Blocks until all updates received by the cluster leader are applied +locally. |
fence/2 | Blocks until all updates received by the cluster leader are applied +locally. |
handle_async_ret/1 | Handles the Ra event sent for asynchronous call results. |
handle_async_ret/2 | Handles the Ra event sent for asynchronous call results. |
'get!'/1 | |
'get!'/2 | |
'get!'/3 | |
'get_or!'/2 | |
'get_or!'/3 | |
'get_or!'/4 | |
'get_many!'/1 | |
'get_many!'/2 | |
'get_many!'/3 | |
'get_many_or!'/2 | |
'get_many_or!'/3 | |
'get_many_or!'/4 | |
'exists!'/1 | |
'exists!'/2 | |
'exists!'/3 | |
'has_data!'/1 | |
'has_data!'/2 | |
'has_data!'/3 | |
'is_sproc!'/1 | |
'is_sproc!'/2 | |
'is_sproc!'/3 | |
'count!'/1 | |
'count!'/2 | |
'count!'/3 | |
'put!'/2 | |
'put!'/3 | |
'put!'/4 | |
'put_many!'/2 | |
'put_many!'/3 | |
'put_many!'/4 | |
'create!'/2 | |
'create!'/3 | |
'create!'/4 | |
'update!'/2 | |
'update!'/3 | |
'update!'/4 | |
'compare_and_swap!'/3 | |
'compare_and_swap!'/4 | |
'compare_and_swap!'/5 | |
'delete!'/1 | |
'delete!'/2 | |
'delete!'/3 | |
'delete_many!'/1 | |
'delete_many!'/2 | |
'delete_many!'/3 | |
'clear_payload!'/1 | |
'clear_payload!'/2 | |
'clear_payload!'/3 | |
'clear_many_payloads!'/1 | |
'clear_many_payloads!'/2 | |
'clear_many_payloads!'/3 | |
export/2 | Exports a Khepri store using the Module callback module. |
export/3 | Exports a Khepri store using the Module callback module. |
export/4 | Exports a Khepri store using the Module callback module. |
import/2 | Imports a previously exported set of tree nodes using the Module
+callback module. |
import/3 | Imports a previously exported set of tree nodes using the Module
+callback module. |
info/0 | Lists the running stores on stdout. |
info/1 | Lists the content of specified store on stdout. |
info/2 | Lists the content of specified store on stdout. |
start() -> Ret
+
Ret = khepri:ok(StoreId) | khepri:error()
StoreId = khepri:store_id()
Starts a store. +
+See also: khepri_cluster:start/0.
+ +start(RaSystemOrDataDir::RaSystem | DataDir) -> Ret
+
RaSystem = atom()
DataDir = file:filename_all()
Ret = khepri:ok(StoreId) | khepri:error()
StoreId = khepri:store_id()
Starts a store. +
+See also: khepri_cluster:start/1.
+ +start(RaSystemOrDataDir::RaSystem | DataDir, StoreIdOrRaServerConfig::StoreId | RaServerConfig) -> Ret
+
RaSystem = atom()
DataDir = file:filename_all()
StoreId = store_id()
RaServerConfig = khepri_cluster:incomplete_ra_server_config()
Ret = khepri:ok(StoreId) | khepri:error()
StoreId = khepri:store_id()
Starts a store. +
+See also: khepri_cluster:start/2.
+ +start(RaSystemOrDataDir::RaSystem | DataDir, StoreIdOrRaServerConfig::StoreId | RaServerConfig, Timeout) -> Ret
+
RaSystem = atom()
DataDir = file:filename_all()
StoreId = store_id()
RaServerConfig = khepri_cluster:incomplete_ra_server_config()
Timeout = timeout()
Ret = khepri:ok(StoreId) | khepri:error()
StoreId = khepri:store_id()
Starts a store. +
+See also: khepri_cluster:start/3.
+ +reset() -> Ret
+
Ret = ok | error()
Resets the store on this Erlang node. +
+See also: khepri_cluster:reset/0.
+ +reset(StoreIdOrTimeout::StoreId | Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
Resets the store on this Erlang node. +
+See also: khepri_cluster:reset/1.
+ +reset(StoreId, Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | error()
Resets the store on this Erlang node. +
+See also: khepri_cluster:reset/2.
+ +stop() -> Ret
+
Ret = ok | khepri:error()
Stops a store. +
+See also: khepri_cluster:stop/0.
+ +stop(StoreId) -> Ret
+
StoreId = khepri:store_id()
Ret = ok | khepri:error()
Stops a store. +
+See also: khepri_cluster:stop/1.
+ +get_store_ids() -> [StoreId]
+
StoreId = store_id()
Returns the list of running stores. +
+See also: khepri_cluster:get_store_ids/0.
+ +is_empty() -> IsEmpty | Error
+
IsEmpty = boolean()
Error = khepri:error()
Indicates if the store is empty or not.
+ + Calling this function is the same as callingis_empty(StoreId)
with the
+ default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: is_empty/1, is_empty/2.
+ +is_empty(StoreId) -> IsEmpty | Error
+
StoreId = khepri:store_id()
IsEmpty = boolean()
Error = khepri:error()
is_empty(Options) -> IsEmpty | Error
+
Options = khepri:query_options() | khepri:tree_options()
IsEmpty = boolean()
Error = khepri:error()
Indicates if the store is empty or not.
+ + This function accepts the following two forms: +is_empty(StoreId)
. Calling it is the same as calling
+ is_empty(StoreId, #{})
.is_empty(Options)
. Calling it is the same as calling
+ is_empty(StoreId, Options)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: is_empty/2.
+ +is_empty(StoreId, Options) -> IsEmpty | Error
+
StoreId = khepri:store_id()
Options = khepri:query_options() | khepri:tree_options()
IsEmpty = boolean()
Error = khepri:error()
StoreId
: the name of the Khepri store.
+Options
: query options such as favor
.
+
+
returns: true
if the store is empty, false
if it is not, or an {error,
+ Reason}
tuple.
Indicates if the store is empty or not. +
+ +get(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:payload_ret()
Returns the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingget(StoreId, PathPattern)
+ with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+get(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri:payload_ret()
get(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:payload_ret()
Returns the payload of the tree node pointed to by the given path +pattern.
+ + This function accepts the following two forms: +get(StoreId, PathPattern)
. Calling it is the same as calling
+ get(StoreId, PathPattern, #{})
.get(PathPattern, Options)
. Calling it is the same as calling
+ get(StoreId, PathPattern, Options)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: get/3.
+ +get(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:payload_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to get.
+Options
: query options.
+
+
returns: an {ok, Payload | undefined}
tuple or an {error, Reason}
+ tuple.
+
Returns the payload of the tree node pointed to by the given path +pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+updating many nodes with the same payload is denied. That fact is checked
+before the tree node is looked up: so if a condition in the path could
+potentially match several nodes, an exception is raised, even though only
+one tree node would match at the time.
The returned {ok, Payload}
tuple contains the payload of the targeted
+ tree node, or {ok, undefined}
if the tree node had no payload.
value
+ %% Query the tree node at `/:foo/:bar'.
+{ok, value} = khepri:get(StoreId, [foo, bar]).
+
+ Example: query an existing tree node with no payload
+ %% Query the tree node at `/:no_payload'.
+{ok, undefined} = khepri:get(StoreId, [no_payload]).
+
+ Example: query a non-existent tree node
+ %% Query the tree node at `/:non_existent'.
+{error, ?khepri_error(node_not_found, _)} = khepri:get(
+ StoreId, [non_existent]).
+
+See also: get_many/3, get_or/3, khepri_adv:get/3.
+ +get_or(PathPattern, Default) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Ret = khepri:payload_ret(Default)
Returns the payload of the tree node pointed to by the given path +pattern, or a default value.
+ + Calling this function is the same as callingget_or(StoreId, PathPattern,
+ Default)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+get_or(StoreId, PathPattern, Default) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Ret = khepri:payload_ret(Default)
get_or(PathPattern, Default, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:payload_ret(Default)
Returns the payload of the tree node pointed to by the given path +pattern, or a default value.
+ + This function accepts the following two forms: +get_or(StoreId, PathPattern, Default)
. Calling it is the same as
+ calling get_or(StoreId, PathPattern, Default, #{})
.get_or(PathPattern, Default, Options)
. Calling it is the same as
+ calling get_or(StoreId, PathPattern, Default, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: get_or/4.
+ +get_or(StoreId, PathPattern, Default, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:payload_ret(Default)
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to get.
+Default
: the default value to return in case the tree node has no
+ payload or does not exist.
+Options
: query options.
+
+
returns: an {ok, Payload | Default}
tuple or an {error, Reason}
tuple.
+
Returns the payload of the tree node pointed to by the given path +pattern, or a default value.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+updating many nodes with the same payload is denied. That fact is checked
+before the tree node is looked up: so if a condition in the path could
+potentially match several nodes, an exception is raised, even though only
+one tree node would match at the time.
The returned {ok, Payload}
tuple contains the payload of the targeted
+ tree node, or {ok, Default}
if the tree node had no payload or was not
+found.
value
+ %% Query the tree node at `/:foo/:bar'.
+{ok, value} = khepri:get_or(StoreId, [foo, bar], default).
+
+ Example: query an existing tree node with no payload
+ %% Query the tree node at `/:no_payload'.
+{ok, default} = khepri:get_or(StoreId, [no_payload], default).
+
+ Example: query a non-existent tree node
+ %% Query the tree node at `/:non_existent'.
+{ok, default} = khepri:get_or(StoreId, [non_existent], default).
+
+See also: get/3, get_many_or/4, khepri_adv:get/3.
+ +get_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:many_payloads_ret()
Returns payloads of all the tree nodes matching the given path +pattern.
+ + Calling this function is the same as callingget_many(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: get_many/2, get_many/3.
+ +get_many(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri:many_payloads_ret()
get_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:many_payloads_ret()
Returns payloads of all the tree nodes matching the given path +pattern.
+ + This function accepts the following two forms: +get_many(StoreId, PathPattern)
. Calling it is the same as calling
+ get_many(StoreId, PathPattern, #{})
.get_many(PathPattern, Options)
. Calling it is the same as calling
+ get_many(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: get_many/3.
+ +get_many(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:many_payloads_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Options
: query options.
+
+
returns: an {ok, PayloadsMap}
tuple or an {error, Reason}
tuple.
+
Returns payloads of all the tree nodes matching the given path +pattern.
+ +Calling this function is the same as calling get_many_or(StoreId,
+ PathPattern, undefined, Options)
.
The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The returned {ok, PayloadsMap}
tuple contains a map where keys correspond
+ to the path to a tree node matching the path pattern. Each key then points
+ to the payload of that matching tree node, or Default
if the tree node
+had no payload.
%% Get all nodes in the tree. The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+{ok, #{[foo] := undefined,
+ [foo, bar] := value}} = khepri:get_many(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR]).
+
+See also: get/3, get_many_or/4, khepri_adv:get_many/3.
+ +get_many_or(PathPattern, Default) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Ret = khepri:many_payloads_ret(Default)
Returns payloads of all the tree nodes matching the given path +pattern, or a default payload.
+ + Calling this function is the same as callingget_many_or(StoreId,
+ PathPattern, Default)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: get_many_or/3, get_many_or/4.
+ +get_many_or(StoreId, PathPattern, Default) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Ret = khepri:many_payloads_ret(Default)
get_many_or(PathPattern, Default, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:many_payloads_ret(Default)
Returns payloads of all the tree nodes matching the given path +pattern, or a default payload.
+ + This function accepts the following two forms: +get_many_or(StoreId, PathPattern, Default)
. Calling it is the same as
+ calling get_many_or(StoreId, PathPattern, Default, #{})
.get_many_or(PathPattern, Default, Options)
. Calling it is the same as
+ calling get_many_or(StoreId, PathPattern, Default, Options)
with the
+ default store ID (see khepri_cluster:get_default_store_id/0
).See also: get_many_or/4.
+ +get_many_or(StoreId, PathPattern, Default, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:many_payloads_ret(Default)
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Default
: the default value to set in PayloadsMap
for tree nodes
+ with no payload.
+Options
: query options.
+
+
returns: an {ok, PayloadsMap}
tuple or an {error, Reason}
tuple.
+
Returns payloads of all the tree nodes matching the given path +pattern, or a default payload.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The returned {ok, PayloadsMap}
tuple contains a map where keys correspond
+ to the path to a tree node matching the path pattern. Each key then points
+ to the payload of that matching tree node, or Default
if the tree node
+had no payload.
%% Get all nodes in the tree. The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+{ok, #{[foo] := default,
+ [foo, bar] := value}} = khepri:get_many_or(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR],
+ default).
+
+See also: get_many/3, get_or/4, khepri_adv:get_many/3.
+ +exists(PathPattern) -> Exists | Error
+
PathPattern = khepri_path:pattern()
Exists = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path exists or not.
+ + Calling this function is the same as callingexists(StoreId, PathPattern)
+ with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+exists(StoreId, PathPattern) -> Exists | Error
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Exists = boolean()
Error = khepri:error()
exists(PathPattern, Options) -> Exists | Error
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Exists = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path exists or not.
+ + This function accepts the following two forms: +exists(StoreId, PathPattern)
. Calling it is the same as calling
+ exists(StoreId, PathPattern, #{})
.exists(PathPattern, Options)
. Calling it is the same as calling
+ exists(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: exists/3.
+ +exists(StoreId, PathPattern, Options) -> Exists | Error
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Exists = boolean()
Error = khepri:error()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to check.
+Options
: query options such as favor
.
+
+
returns: true
if the tree node exists, false
if it does not, or an
+ {error, Reason}
tuple.
+
Indicates if the tree node pointed to by the given path exists or not.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
PathPattern
must target a specific tree node. In other words,
+ updating many nodes with the same payload is denied. That fact is checked
+ before the tree node is looked up: so if a condition in the path could
+ potentially match several nodes, an exception is raised, even though only
+ one tree node would match at the time.
+
+See also: get/3.
+ +has_data(PathPattern) -> HasData | Error
+
PathPattern = khepri_path:pattern()
HasData = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path has data or +not.
+ + Calling this function is the same as callinghas_data(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: has_data/2, has_data/3.
+ +has_data(StoreId, PathPattern) -> HasData | Error
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
HasData = boolean()
Error = khepri:error()
has_data(PathPattern, Options) -> HasData | Error
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
HasData = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path has data or +not.
+ + This function accepts the following two forms: +has_data(StoreId, PathPattern)
. Calling it is the same as calling
+ has_data(StoreId, PathPattern, #{})
.has_data(PathPattern, Options)
. Calling it is the same as calling
+ has_data(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: has_data/3.
+ +has_data(StoreId, PathPattern, Options) -> HasData | Error
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
HasData = boolean()
Error = khepri:error()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to check.
+Options
: query options such as favor
.
+
+
returns: true
if tree the node holds data, false
if it does not exist,
+ has no payload or holds a stored procedure, or an {error, Reason}
tuple.
+
Indicates if the tree node pointed to by the given path has data or +not.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
PathPattern
must target a specific tree node. In other words,
+ updating many nodes with the same payload is denied. That fact is checked
+ before the tree node is looked up: so if a condition in the path could
+ potentially match several nodes, an exception is raised, even though only
+ one tree node would match at the time.
+
+See also: get/3.
+ +is_sproc(PathPattern) -> IsSproc | Error
+
PathPattern = khepri_path:pattern()
IsSproc = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path holds a stored +procedure or not.
+ + Calling this function is the same as callingis_sproc(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: is_sproc/2, is_sproc/3.
+ +is_sproc(StoreId, PathPattern) -> IsSproc | Error
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
IsSproc = boolean()
Error = khepri:error()
is_sproc(PathPattern, Options) -> IsSproc | Error
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
IsSproc = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path holds a stored +procedure or not.
+ + This function accepts the following two forms: +is_sproc(StoreId, PathPattern)
. Calling it is the same as calling
+ is_sproc(StoreId, PathPattern, #{})
.is_sproc(PathPattern, Options)
. Calling it is the same as calling
+ is_sproc(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: is_sproc/3.
+ +is_sproc(StoreId, PathPattern, Options) -> IsSproc | Error
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
IsSproc = boolean()
Error = khepri:error()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to check.
+Options
: query options such as favor
.
+
+
returns: true
if the tree node holds a stored procedure, false
if it
+ does not exist, has no payload or holds data, or an {error, Reason}
+ tuple.
+
Indicates if the tree node pointed to by the given path holds a stored +procedure or not.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
PathPattern
must target a specific tree node. In other words,
+ updating many nodes with the same payload is denied. That fact is checked
+ before the tree node is looked up: so if a condition in the path could
+ potentially match several nodes, an exception is raised, even though only
+ one tree node would match at the time.
+
+See also: get/3.
+ +count(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = ok(Count) | error()
Count = non_neg_integer()
Counts all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingcount(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+count(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = ok(Count) | error()
Count = non_neg_integer()
count(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = ok(Count) | error()
Count = non_neg_integer()
Counts all tree nodes matching the given path pattern.
+ + This function accepts the following two forms: +count(StoreId, PathPattern)
. Calling it is the same as calling
+ count(StoreId, PathPattern, #{})
.count(PathPattern, Options)
. Calling it is the same as calling
+ count(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: count/3.
+ +count(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = ok(Count) | error()
Count = non_neg_integer()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to count.
+Options
: query options such as favor
.
+
+
returns: an {ok, Count}
tuple with the number of matching tree nodes, or
+ an {error, Reason}
tuple.
Counts all tree nodes matching the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The root node is not included in the count.
+ + Example: +%% Query the tree node at `/:foo/:bar'.
+{ok, 3} = khepri:count(StoreId, [foo, ?KHEPRI_WILDCARD_STAR]).
+
+
+fold(PathPattern, Fun, Acc) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
Calls Fun
on successive tree nodes matching the given path pattern,
+ starting with Acc
.
fold(StoreId, PathPattern,
+ Fun, Acc)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+fold(StoreId, PathPattern, Fun, Acc) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
fold(PathPattern, Fun, Acc, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
Calls Fun
on successive tree nodes matching the given path pattern,
+ starting with Acc
.
fold(StoreId, PathPattern, Fun, Acc)
. Calling it is the same as
+ calling fold(StoreId, PathPattern, Fun, Acc, #{})
.fold(PathPattern, Fun, Acc, Options)
. Calling it is the same as
+ calling fold(StoreId, PathPattern, Fun, Acc, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: fold/5.
+ +fold(StoreId, PathPattern, Fun, Acc, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Fun
: the function to call for each matching tree node.
+Acc
: the Erlang term to pass to the first call to Fun
.
+Options
: query options.
+
+
returns: an {ok, NewAcc}
tuple or an {error, Reason}
tuple.
Calls Fun
on successive tree nodes matching the given path pattern,
+ starting with Acc
.
The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
maps:fold/3
, Fun
must accept the
+ following arguments:
+ Acc
for the first matched tree node, or
+ the return value of the previous call to Fun
The returned {ok, NewAcc}
tuple contains the return value of the last call
+ to Fun
, or Acc
if no tree nodes matched the given path pattern.
%% List all tree node paths in the tree. The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+{ok, [[foo], [foo, bar]]} = khepri:fold(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR],
+ fun(Path, _NodeProps, Acc) ->
+ [Path | Acc]
+ end, []).
+
+
+foreach(PathPattern, Fun) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:foreach_fun()
Ret = ok | khepri:error()
Calls Fun
for each tree node matching the given path pattern.
foreach(StoreId, PathPattern,
+ Fun)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: foreach/3, foreach/4.
+ +foreach(StoreId, PathPattern, Fun) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:foreach_fun()
Ret = ok | khepri:error()
foreach(PathPattern, Fun, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:foreach_fun()
Options = khepri:query_options() | khepri:tree_options()
Ret = ok | khepri:error()
Calls Fun
for each tree node matching the given path pattern.
foreach(StoreId, PathPattern, Fun)
. Calling it is the same as
+ calling foreach(StoreId, PathPattern, Fun, #{})
.foreach(PathPattern, Fun, Options)
. Calling it is the same as
+ calling foreach(StoreId, PathPattern, Fun, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: foreach/4.
+ +foreach(StoreId, PathPattern, Fun, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:foreach_fun()
Options = khepri:query_options() | khepri:tree_options()
Ret = ok | khepri:error()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Fun
: the function to call for each matching tree node.
+Options
: query options.
+
+
returns: ok
or an {error, Reason}
tuple.
Calls Fun
for each tree node matching the given path pattern.
The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
maps:foreach/2
, Fun
must accept the
+ following arguments:
+ %% Print all tree node paths in the tree. The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+ok = khepri:foreach(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR],
+ fun(Path, _NodeProps) ->
+ io:format("Path ~0p~n", [Path])
+ end).
+
+
+map(PathPattern, Fun) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:map_fun()
Ret = khepri:ok(Map) | khepri:error()
Map = #{khepri_path:native_path() => khepri:map_fun_ret()}
Produces a new map by calling Fun
for each tree node matching the
+given path pattern.
map(StoreId, PathPattern,
+ Fun)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+map(StoreId, PathPattern, Fun) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:map_fun()
Ret = khepri:ok(Map) | khepri:error()
Map = #{khepri_path:native_path() => khepri:map_fun_ret()}
map(PathPattern, Fun, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:map_fun()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:ok(Map) | khepri:error()
Map = #{khepri_path:native_path() => khepri:map_fun_ret()}
Produces a new map by calling Fun
for each tree node matching the
+given path pattern.
map(StoreId, PathPattern, Fun)
. Calling it is the same as
+ calling map(StoreId, PathPattern, Fun, #{})
.map(PathPattern, Fun, Options)
. Calling it is the same as
+ calling map(StoreId, PathPattern, Fun, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: map/4.
+ +map(StoreId, PathPattern, Fun, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:map_fun()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:ok(Map) | khepri:error()
Map = #{khepri_path:native_path() => khepri:map_fun_ret()}
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Fun
: the function to call for each matching tree node.
+Options
: query options.
+
+
returns: {ok, Map}
or an {error, Reason}
tuple.
Produces a new map by calling Fun
for each tree node matching the
+given path pattern.
The produced map uses the tree node path as the key, like get_many/3
+ and the return value of Fun
as the value.
The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
maps:map/2
, Fun
must accept the
+ following arguments:
+ %% The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+{ok, #{[foo] => "/:foo",
+ [foo, bar] => "/:foo/:bar"}} = khepri:map(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR],
+ fun(Path, _NodeProps) ->
+ khepri_path:to_string(Path)
+ end).
+
+
+filter(PathPattern, Pred) -> Ret
+
PathPattern = khepri_path:pattern()
Pred = khepri:filter_fun()
Ret = khepri:many_payloads_ret()
Returns a map for which predicate Pred
holds true in tree nodes
+matching the given path pattern.
filter(StoreId, PathPattern,
+ Pred)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+filter(StoreId, PathPattern, Pred) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Pred = khepri:filter_fun()
Ret = khepri:many_payloads_ret()
filter(PathPattern, Pred, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Pred = khepri:filter_fun()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:many_payloads_ret()
Returns a map for which predicate Pred
holds true in tree nodes
+matching the given path pattern.
filter(StoreId, PathPattern, Pred)
. Calling it is the same as
+ calling filter(StoreId, PathPattern, Pred, #{})
.filter(PathPattern, Pred, Options)
. Calling it is the same as
+ calling filter(StoreId, PathPattern, Pred, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: filter/4.
+ +filter(StoreId, PathPattern, Pred, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Pred = khepri:filter_fun()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:many_payloads_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Pred
: the function to call for each matching tree node.
+Options
: query options.
+
+
returns: {ok, Map}
or an {error, Reason}
tuple.
Returns a map for which predicate Pred
holds true in tree nodes
+matching the given path pattern.
The produced map only contains tree nodes for which Pred
returned true.
+ The map has the same form as the one returned by get_many/3
+otherwise.
The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
maps:filter/2
, Pred
must accept the
+ following arguments:
+ /:foo
+ %% The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+{ok, #{[foo] => undefined,
+ [foo, bar] => value}} = khepri:filter(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR],
+ fun
+ ([foo | _], _NodeProps) -> true;
+ (_Path, _NodeProps) -> false
+ end).
+
+
+run_sproc(PathPattern, Args) -> Ret
+
PathPattern = khepri_path:pattern()
Args = list()
Ret = any()
Runs the stored procedure pointed to by the given path and returns the +result.
+ + Calling this function is the same as callingrun_sproc(StoreId,
+ PathPattern, Args)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: run_sproc/3, run_sproc/4.
+ +run_sproc(StoreId, PathPattern, Args) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Args = list()
Ret = any()
run_sproc(PathPattern, Args, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Args = list()
Options = khepri:query_options() | khepri:tree_options()
Ret = any()
Runs the stored procedure pointed to by the given path and returns the +result.
+ + This function accepts the following two forms: +run_sproc(StoreId, PathPattern, Args)
. Calling it is the same as
+ calling run_sproc(StoreId, PathPattern, Args, #{})
.run_sproc(PathPattern, Args, Options)
. Calling it is the same as
+ calling run_sproc(StoreId, PathPattern, Args, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: run_sproc/4.
+ +run_sproc(StoreId, PathPattern, Args, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Args = list()
Options = khepri:query_options()
Ret = any()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node holding the
+ stored procedure.
+Args
: the list of args to pass to the stored procedure; its length
+ must be equal to the stored procedure arity.
+Options
: query options.
+
+
returns: the result of the stored procedure execution, or throws an + exception if the tree node does not exist, does not hold a stored procedure + or if there was an error. +
+Runs the stored procedure pointed to by the given path and returns the +result.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+updating many nodes with the same payload is denied. That fact is checked
+before the tree node is looked up: so if a condition in the path could
+potentially match several nodes, an exception is raised, even though only
+one tree node would match at the time.
Args
list must match the number of arguments expected by
+ the stored procedure.
+
+See also: is_sproc/3.
+ +put(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingput(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+put(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingput(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: put/4.
+ +put(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to create or
+ modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Sets the payload of the tree node pointed to by the given path +pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+updating many nodes with the same payload is denied. That fact is checked
+before the tree node is looked up: so if a condition in the path could
+potentially match several nodes, an exception is raised, even though only
+one tree node would match at the time.
When using a simple path (i.e. without conditions), if the targeted tree +node does not exist, it is created using the given payload. If the +targeted tree node exists, it is updated with the given payload and its +payload version is increased by one. Missing parent nodes are created on +the way.
+ +When using a path pattern, the behavior is the same. However if a condition +in the path pattern is not met, an error is returned and the tree structure +is not modified.
+ + The payload must be one of the following form: +khepri_payload:no_payload()
),
+ using the marker returned by khepri_payload:none/0
, meaning there
+ will be no payload attached to the tree node and the existing payload will
+ be discarded if anykhepri_payload:sproc()
recordkhepri_payload:data()
+ recordIt is possible to wrap the payload in its internal structure explicitly
+ using the khepri_payload
module directly.
The Options
map may specify command-level options; see khepri:command_options()
, khepri:tree_options()
and khepri:put_options()
.
When doing an asynchronous update, the handle_async_ret/2
+function can be used to handle the message received from Ra.
%% Insert a tree node at `/:foo/:bar', overwriting the previous value.
+ok = khepri:put(StoreId, [foo, bar], new_value).
+
+See also: compare_and_swap/5, create/4, put_many/4, update/4, khepri_adv:put/4.
+ +put_many(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Sets the payload of all the tree nodes matching the given path pattern.
+ + Calling this function is the same as callingput_many(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: put_many/3, put_many/4.
+ +put_many(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Sets the payload of all the tree nodes matching the given path pattern.
+ + Calling this function is the same as callingput_many(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: put_many/4.
+ +put_many(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to create or
+ modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Sets the payload of all the tree nodes matching the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
When using a simple path (i.e. without conditions), if the targeted tree +node does not exist, it is created using the given payload. If the +targeted tree node exists, it is updated with the given payload and its +payload version is increased by one. Missing parent nodes are created on +the way.
+ +When using a path pattern, the behavior is the same. However if a condition +in the path pattern is not met, an error is returned and the tree structure +is not modified.
+ + The payload must be one of the following form: +khepri_payload:no_payload()
),
+ using the marker returned by khepri_payload:none/0
, meaning there
+ will be no payload attached to the tree node and the existing payload will
+ be discarded if anykhepri_payload:sproc()
recordkhepri_payload:data()
+ recordIt is possible to wrap the payload in its internal structure explicitly
+ using the khepri_payload
module directly.
The Options
map may specify command-level options; see khepri:command_options()
, khepri:tree_options()
and khepri:put_options()
.
When doing an asynchronous update, the handle_async_ret/2
+function can be used to handle the message received from Ra.
%% Insert a tree node at `/:foo/:bar', overwriting the previous value.
+ok = khepri:put(StoreId, [foo, bar], new_value).
+
+See also: put/4, khepri_adv:put_many/4.
+ +create(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Creates a tree node with the given payload.
+ + Calling this function is the same as callingcreate(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+create(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Creates a tree node with the given payload.
+ + Calling this function is the same as callingcreate(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: create/4.
+ +create(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to create.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Creates a tree node with the given payload.
+ +The behavior is the same as put/4
except that if the tree node
+ already exists, an {error, ?khepri_error(mismatching_node, Info)}
tuple is
+returned.
PathPattern
is modified to include an
+ #if_node_exists{exists = false}
condition on its last component.
+
+See also: compare_and_swap/5, put/4, update/4, khepri_adv:create/4.
+ +update(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload.
+ + Calling this function is the same as callingupdate(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+update(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload.
+ + Calling this function is the same as callingupdate(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: update/4.
+ +update(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Updates an existing tree node with the given payload.
+ +The behavior is the same as put/4
except that if the tree node
+ already exists, an {error, ?khepri_error(mismatching_node, Info)}
tuple is
+returned.
PathPattern
is modified to include an
+ #if_node_exists{exists = true}
condition on its last component.
+
+See also: compare_and_swap/5, create/4, put/4, khepri_adv:update/4.
+ +compare_and_swap(PathPattern, DataPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + Calling this function is the same as callingcompare_and_swap(StoreId,
+ PathPattern, DataPattern, Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: compare_and_swap/4, compare_and_swap/5.
+ +compare_and_swap(StoreId, PathPattern, DataPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + Calling this function is the same as callingcompare_and_swap(StoreId,
+ PathPattern, DataPattern, Data, #{})
.
+
+See also: compare_and_swap/5.
+ +compare_and_swap(StoreId, PathPattern, DataPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ +The behavior is the same as put/4
except that if the tree node
+ already exists, an {error, ?khepri_error(mismatching_node, Info)}
tuple is
+returned.
PathPattern
is modified to include an
+ #if_data_matches{pattern = DataPattern}
condition on its last component.
+
+See also: create/4, put/4, update/4, khepri_adv:compare_and_swap/5.
+ +delete(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the tree node pointed to by the given path pattern.
+ + Calling this function is the same as callingdelete(StoreId, PathPattern)
+ with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+delete(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
delete(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri:minimal_ret()
Deletes the tree node pointed to by the given path pattern.
+ + This function accepts the following two forms: +delete(StoreId, PathPattern)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, #{})
.delete(PathPattern, Options)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: delete/3.
+ +delete(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the node to delete.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Deletes the tree node pointed to by the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words, deleting
+ many nodes is denied. That fact is checked before the tree node is looked
+ up: so if a condition in the path could potentially match several nodes, an
+ exception is raised, even though only one tree node would match at the time.
+ If you want to delete multiple nodes at once, use delete_many/3
.
%% Delete the tree node at `/:foo/:bar'.
+ok = khepri:delete(StoreId, [foo, bar]).
+
+See also: delete_many/3, khepri_adv:delete/3.
+ +delete_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingdelete_many(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: delete_many/2, delete_many/3.
+ +delete_many(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
delete_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri:minimal_ret()
Deletes all tree nodes matching the given path pattern.
+ + This function accepts the following two forms: +delete_many(StoreId, PathPattern)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, #{})
.delete_many(PathPattern, Options)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: delete_many/3.
+ +delete_many(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to delete.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Deletes all tree nodes matching the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
%% Delete all nodes in the tree.
+ok = khepri:delete_many(StoreId, [?KHEPRI_WILDCARD_STAR]).
+
+See also: delete/3.
+ +clear_payload(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingclear_payload(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: clear_payload/2, clear_payload/3.
+ +clear_payload(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingclear_payload(StoreId,
+ PathPattern, #{})
.
+
+See also: clear_payload/3.
+ +clear_payload(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to modify.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + In other words, the payload is set tokhepri_payload:no_payload()
.
+ Otherwise, the behavior is that of put/4
.
+
+See also: put/4, khepri_adv:clear_payload/3.
+ +clear_many_payloads(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the payload of all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingclear_many_payloads(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: clear_many_payloads/2, clear_many_payloads/3.
+ +clear_many_payloads(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the payload of all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingclear_many_payloads(StoreId,
+ PathPattern, #{})
.
+
+See also: clear_many_payloads/3.
+ +clear_many_payloads(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to modify.
+Options
: command options.
+
+
returns: in the case of a synchronous call, ok
or an {error, Reason}
+ tuple; in the case of an asynchronous call, always ok
(the actual return
+ value may be sent by a message if a correlation ID was specified).
+
Deletes the payload of all tree nodes matching the given path pattern.
+ + In other words, the payload is set tokhepri_payload:no_payload()
.
+ Otherwise, the behavior is that of put/4
.
+
+See also: delete_many/3, put/4, khepri_adv:clear_many_payloads/3.
+ +register_trigger(TriggerId, EventFilter, StoredProcPath) -> Ret
+
TriggerId = trigger_id()
EventFilter = khepri_evf:event_filter() | khepri_path:pattern()
StoredProcPath = khepri_path:path()
Ret = ok | error()
Registers a trigger.
+ + Calling this function is the same as callingregister_trigger(StoreId,
+ TriggerId, EventFilter, StoredProcPath)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).
+
+See also: register_trigger/4.
+ +register_trigger(StoreId, TriggerId, EventFilter, StoredProcPath) -> Ret
+
StoreId = khepri:store_id()
TriggerId = trigger_id()
EventFilter = khepri_evf:event_filter() | khepri_path:pattern()
StoredProcPath = khepri_path:path()
Ret = ok | error()
register_trigger(TriggerId, EventFilter, StoredProcPath, Options) -> Ret
+
TriggerId = trigger_id()
EventFilter = khepri_evf:event_filter() | khepri_path:pattern()
StoredProcPath = khepri_path:path()
Options = command_options() | khepri:tree_options()
Ret = ok | error()
Registers a trigger.
+ + This function accepts the following two forms: +register_trigger(StoreId, TriggerId, EventFilter, StoredProcPath)
.
+ Calling it is the same as calling register_trigger(StoreId, TriggerId,
+ EventFilter, StoredProcPath, #{})
.register_trigger(TriggerId, EventFilter, StoredProcPath, Options)
.
+ Calling it is the same as calling register_trigger(StoreId, TriggerId,
+ EventFilter, StoredProcPath, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: register_trigger/5.
+ +register_trigger(StoreId, TriggerId, EventFilter, StoredProcPath, Options) -> Ret
+
StoreId = khepri:store_id()
TriggerId = trigger_id()
EventFilter = khepri_evf:event_filter() | khepri_path:pattern()
StoredProcPath = khepri_path:path()
Options = command_options() | khepri:tree_options()
Ret = ok | error()
StoreId
: the name of the Khepri store.
+TriggerId
: the name of the trigger.
+EventFilter
: the event filter used to associate an event with a
+ stored procedure.
+StoredProcPath
: the path to the stored procedure to execute when the
+ corresponding event occurs.
+
+
returns: ok
if the trigger was registered, an {error, Reason}
tuple
+ otherwise.
Registers a trigger.
+ +A trigger is based on an event filter. It associates an event with a stored +procedure. When an event matching the event filter is emitted, the stored +procedure is executed.
+ +The following event filters are documented by khepri_evf:event_filter()
.
Here are examples of event filters:
+ +%% An event filter can be explicitly created using the `khepri_evf'
+%% module. This is possible to specify properties at the same time.
+EventFilter = khepri_evf:tree([stock, wood, <<"oak">>], %% Required
+ #{on_actions => [delete], %% Optional
+ priority => 10}). %% Optional
+ %% For ease of use, some terms can be automatically converted to an event
+%% filter. In this example, a Unix-like path can be used as a tree event
+%% filter.
+EventFilter = "/:stock/:wood/oak".
+
+ The stored procedure is expected to accept a single argument. This argument +is a map containing the event properties. Here is an example:
+ +my_stored_procedure(Props) ->
+ #{path := Path},
+ on_action => Action} = Props.
+
+ The stored procedure is executed on the leader's Erlang node.
+ + It is guaranteed to run at least once. It could be executed multiple times + if the Ra leader changes, therefore the stored procedure must be + idempotent. + + +register_projection(PathPattern, Projection) -> Ret
+
PathPattern = khepri_path:pattern()
Projection = khepri_projection:projection()
Ret = ok | khepri:error()
Registers a projection.
+ + Calling this function is the same as calling +register_projection(StoreId, PathPattern, Projection)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: register_projection/3.
+ +register_projection(StoreId, PathPattern, Projection) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Projection = khepri_projection:projection()
Ret = ok | khepri:error()
register_projection(PathPattern, Projection, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Projection = khepri_projection:projection()
Options = khepri:command_options()
Ret = ok | khepri:error()
Registers a projection.
+ + This function accepts the following two forms: +register_projection(StoreId, PathPattern, Projection)
. Calling it is
+ the same as calling register_projection(StoreId, PathPattern, Projection,
+ #{})
.register_projection(PathPattern, Projection, Options)
. Calling it is
+ the same as calling register_projection(StoreId, PathPattern, Projection,
+ Options)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: register_projection/4.
+ +register_projection(StoreId, PathPattern, Projection, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Projection = khepri_projection:projection()
Options = khepri:command_options()
Ret = ok | khepri:error()
StoreId
: the name of the Khepri store.
+PathPattern
: the pattern of tree nodes which the projection should
+ watch.
+Projection
: the projection resource, created with
+ khepri_projection:new/3
.
+Options
: command options for registering the projection.
+
returns: ok
if the projection was registered, an {error, Reason}
tuple
+ otherwise.
Registers a projection.
+ +A projection is a replicated ETS cache which is kept up to date by
+ Khepri. See the khepri_projection
module-docs for more information
+about projections.
This function associates a projection created with khepri_projection:new/3
with a pattern. Any changes to tree nodes matching
+ the provided pattern will be turned into records using the projection's
+ khepri_projection:projection_fun()
and then applied to the
+projection's ETS table.
PathPattern
and are already in the store.
+
+
+unregister_projections(Names) -> Ret
+
Names = all | [khepri_projection:name()]
Ret = ok | khepri:error()
Removes the given projections from the store.
+ + Calling this function is the same as calling +unregister_projections(StoreId, Names)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).
+
+See also: unregister_projections/2.
+ +unregister_projections(StoreId, Names) -> Ret
+
StoreId = khepri:store_id()
Names = all | [khepri_projection:name()]
Ret = ok | khepri:error()
unregister_projections(Names, Options) -> Ret
+
Names = all | [khepri_projection:name()]
Options = khepri:command_options()
Ret = ok | khepri:error()
Removes the given projections from the store.
+ + This function accepts the following two forms: +unregister_projections(StoreId, Names)
. Calling it is the same as
+ calling unregister_projections(StoreId, Names, #{})
.unregister_projections(Names, Options)
. Calling it is the same as
+ calling unregister_projections(StoreId, Names, Options)
with
+ the default store ID (see khepri_cluster:get_default_store_id/0
).
+ See also: unregister_projections/3.
+ +unregister_projections(StoreId, Names, Options) -> Ret
+
StoreId = khepri:store_id()
Names = all | [khepri_projection:name()]
Options = khepri:command_options()
Ret = ok | khepri:error()
StoreId
: the name of the Khepri store.
+Names
: the names of projections to unregister or the atom all
to
+ remove all projections.
+Options
: command options for unregistering the projections.
+
returns: ok
if the projections were unregistered, an {error, Reason}
+ tuple otherwise.
+
Removes the given projections from the store.
+ +Names
may either be a list of projection names to remove or the atom
+ all
. When all
is passed, every projection in the store is removed.
+
+See also: khepri_adv:unregister_projections/3.
+ +has_projection(ProjectionName) -> Ret
+
ProjectionName = khepri_projection:name()
Ret = boolean() | khepri:error()
Determines whether the store has a projection registered with the given +name.
+ + Calling this function is the same as calling +has_projection(StoreId, ProjectionName)
with the default store ID
+ (see khepri_cluster:get_default_store_id/0
).
+
+See also: has_projection/2.
+ +has_projection(StoreId, ProjectionName) -> Ret
+
StoreId = khepri:store_id()
ProjectionName = khepri_projection:name()
Ret = boolean() | khepri:error()
has_projection(ProjectionName, Options) -> Ret
+
ProjectionName = khepri_projection:name()
Options = khepri:query_options()
Ret = boolean() | khepri:error()
Determines whether the store has a projection registered with the given +name.
+ + This function accepts the following two forms: +has_projection(StoreId, ProjectionName)
. Calling it is the same
+ as calling has_projection(StoreId, ProjectionName, #{})
.has_projection(ProjectionName, Options)
. Calling it is the same
+ as calling has_projection(StoreId, ProjectionName, Options)
with
+ the default store ID (see khepri_cluster:get_default_store_id/0
).
+ See also: has_projection/3.
+ +has_projection(StoreId, ProjectionName, Options) -> Ret
+
StoreId = khepri:store_id()
ProjectionName = khepri_projection:name()
Options = khepri:query_options()
Ret = boolean() | khepri:error()
StoreId
: the name of the Khepri store.
+ProjectionName
: the name of the projection to has as passed to
+ khepri_projection:new/3
.
+Options
: query options.
+
returns: true
if the store contains a projection registered with the given
+ name, false
if it does not, or an {error, Reason}
tuple if the query
+ failed.
Determines whether the store has a projection registered with the given + name. +
+ +transaction(FunOrPath) -> Ret
+
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Ret = khepri_machine:tx_ret()
Runs a transaction and returns its result.
+ + Calling this function is the same as callingtransaction(FunOrPath, [])
+ with the default store ID.
+
+See also: transaction/2.
+ +transaction(StoreId, FunOrPath) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Ret = khepri_machine:tx_ret()
transaction(FunOrPath, Args) -> Ret
+
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
Ret = khepri_machine:tx_ret()
transaction(FunOrPath, ReadWriteOrOptions) -> Ret
+
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
ReadWriteOrOptions = ReadWrite | Options
ReadWrite = ro | rw | auto
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
Runs a transaction and returns its result.
+ + This function accepts the following two forms: +transaction(StoreId, FunOrPath)
. Calling it is the same as calling
+ transaction(StoreId, FunOrPath, [])
.transaction(FunOrPath, Args)
. Calling it is the same as calling
+ transaction(StoreId, FunOrPath, Args)
with the default store ID.transaction(FunOrPath, ReadWriteOrOptions)
. Calling it is the same as
+ calling transaction(StoreId, FunOrPath, [], ReadWriteOrOptions)
with the
+ default store ID.See also: transaction/3.
+ +transaction(StoreId, FunOrPath, Args) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
Ret = khepri_machine:tx_ret()
transaction(StoreId, FunOrPath, ReadWriteOrOptions) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
ReadWriteOrOptions = ReadWrite | Options
ReadWrite = ro | rw | auto
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
transaction(FunOrPath, Args, ReadWriteOrOptions) -> Ret
+
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
ReadWriteOrOptions = ReadWrite | Options
ReadWrite = ro | rw | auto
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
transaction(FunOrPath, ReadWrite, Options) -> Ret
+
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
ReadWrite = ro | rw | auto
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
Runs a transaction and returns its result.
+ + This function accepts the following two forms: +transaction(StoreId, FunOrPath, Args)
. Calling it is the same as
+ calling transaction(StoreId, FunOrPath, Args, auto)
.transaction(StoreId, FunOrPath, ReadWriteOrOptions)
. Calling it is
+ the same as calling transaction(StoreId, FunOrPath, [],
+ ReadWriteOrOptions)
.transaction(FunOrPath, Args, ReadWriteOrOptions)
. Calling it is the
+ same as calling transaction(StoreId, FunOrPath, Args, ReadWriteOrOptions)
+ with the default store ID.See also: transaction/4.
+ +transaction(StoreId, FunOrPath, Args, ReadWrite) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
ReadWrite = ro | rw | auto
Ret = khepri_machine:tx_ret()
transaction(StoreId, FunOrPath, Args, Options) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
transaction(StoreId, FunOrPath, ReadWrite, Options) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
ReadWrite = ro | rw | auto
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
transaction(FunOrPath, Args, ReadWrite, Options) -> Ret
+
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
ReadWrite = ro | rw | auto
Options = command_options() | query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
Runs a transaction and returns its result.
+ + This function accepts the following three forms: +transaction(StoreId, FunOrPath, Args, ReadWrite)
. Calling it is the
+ same as calling transaction(StoreId, FunOrPath, Args, ReadWrite,
+ #{})
.transaction(StoreId, FunOrPath, Args, Options)
. Calling it is the
+ same as calling transaction(StoreId, FunOrPath, Args, auto,
+ Options)
.transaction(FunOrPath, Args, ReadWrite, Options)
. Calling it is the
+ same as calling transaction(StoreId, FunOrPath, Args, ReadWrite, Options)
+ with the default store ID.See also: transaction/5.
+ +transaction(StoreId, FunOrPath, Args, ReadWrite, Options) -> Ret
+
StoreId = store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
ReadWrite = ro | rw | auto
Options = khepri:command_options() | khepri:query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+FunOrPath
: an arbitrary anonymous function or a path pattern pointing
+ to a stored procedure.
+Args
: a list of arguments to pass to FunOrPath
.
+ReadWrite
: the read/write or read-only nature of the transaction.
+Options
: command options such as the command type.
+
+
returns: in the case of a synchronous transaction, {ok, Result}
where
+ Result
is the return value of FunOrPath
, or {error, Reason}
if the
+ anonymous function was aborted; in the case of an asynchronous transaction,
+ always ok
(the actual return value may be sent by a message if a
+ correlation ID was specified).
Runs a transaction and returns its result.
+ +Fun
is an arbitrary anonymous function which takes the content of Args
+ as its arguments. In other words, the length of Args
must correspond to
+ the arity of Fun
.
Instead of Fun
, PathPattern
can be passed. It must point to an existing
+ stored procedure. The length to Args
must correspond to the arity of that
+stored procedure.
The ReadWrite
flag determines what the Fun
anonymous function is
+allowed to do and in which context it runs:
ReadWrite
is ro
, Fun
can do whatever it wants, except modify
+ the content of the store. In other words, uses of khepri_tx:put/2
+ or khepri_tx:delete/1
are forbidden and will abort the function.
+ Fun
is executed from a process on the leader Ra member.ReadWrite
is rw
, Fun
can use the khepri_tx
transaction
+ API as well as any calls to other modules as long as those functions or what
+ they do is permitted. See khepri_tx
for more details. If Fun
does
+ or calls something forbidden, the transaction will be aborted. Fun
is
+ executed in the context of the state machine process on each Ra
+ members.ReadWrite
is auto
, Fun
is analyzed to determine if it calls
+ khepri_tx:put/2
or khepri_tx:delete/1
, or uses any denied
+ operations for a read/write transaction. If it does, this is the same as
+ setting ReadWrite
to true. Otherwise, this is the equivalent of setting
+ ReadWrite
to false.When using PathPattern
, a ReadWrite
of auto
is synonymous of rw
.
Options
is relevant for both read-only and read-write transactions
+(including audetected ones). However note that both types expect different
+options.
FunOrPath
can be any term. That result is returned in an
+ {ok, Result}
tuple if the transaction is synchronous. The result is sent
+ by message if the transaction is asynchronous and a correlation ID was
+ specified.
+
+
+fence() -> Ret
+
Ret = ok | khepri:error()
Blocks until all updates received by the cluster leader are applied +locally.
+ + Calling this function is the same as callingfence(StoreId)
with the
+ default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+fence(Timeout::StoreId | Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
Blocks until all updates received by the cluster leader are applied +locally.
+ + This function accepts the following two forms: +fence(StoreId)
. Calling it is the same as calling fence(StoreId,
+ Timeout)
with the default timeout (see khepri_app:get_default_timeout/0
).fence(Timeout)
. Calling it is the same as calling fence(StoreId,
+ Timeout)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: fence/2.
+ +fence(StoreId, Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
StoreId
: the name of the Khepri store.
+Timeout
: the time limit after which the call returns with an error.
+
+
returns: ok
or an {error, Reason}
tuple.
Blocks until all updates received by the cluster leader are applied +locally.
+ +This ensures that a subsequent query will see the result of synchronous and +asynchronous updates.
+ + This can't work however if: +reply_from => local
command option is overridden by
+ something else.handle_async_ret(RaEvent) -> Ret
+
RaEvent = ra_server_proc:ra_event()
Ret = [{CorrelationId, AsyncRet}, ...]
CorrelationId = ra_server:command_correlation()
AsyncRet = khepri:async_ret()
Handles the Ra event sent for asynchronous call results.
+ + Calling this function is the same as calling +handle_async_ret(StoreId, RaEvent)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: handle_async_ret/2.
+ +handle_async_ret(StoreId, RaEvent) -> Ret
+
StoreId = khepri:store_id()
RaEvent = ra_server_proc:ra_event()
Ret = [{CorrelationId, AsyncRet}, ...]
CorrelationId = ra_server:command_correlation()
AsyncRet = khepri:async_ret()
Handles the Ra event sent for asynchronous call results.
+ +When sending commands with async
command_options()
, the calling
+process will receive Ra events with the following structure:
{ra_event, CurrentLeader, {applied, [{Correlation1, Reply1}, ...]}}
or
+ +{ra_event,
+ FromId,
+ {rejected, {not_leader, Leader | undefined, Correlation}}}
The first event acknowledges all commands handled in a batch while the +second is sent per-command when commands are sent against a non-leader +member.
+ +These events should be passed to this function in order to map the return +values from the async commands and to update leader information. This +function does not handle retrying rejected commands or return values from +applied commands - the caller is responsible for those tasks.
+ + Example: +ok = khepri:put(StoreId, [stock, wood, <<"oak">>], 200, #{async => 1}),
+ok = khepri:put(StoreId, [stock, wood, <<"maple">>], 150, #{async => 2}),
+RaEvent = receive {ra_event, _, _} = Event -> Event end,
+?assertMatch(
+ [{1, {ok, #{[stock, wood, <<"oak">>] => _}}},
+ {2, {ok, #{[stock, wood, <<"maple">>] => _}}}],
+ khepri:handle_async_ret(RaEvent)).
+
+See also: async_option(), ra:pipeline_command/4.
+ +'get!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_payload_ret()
'get!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_payload_ret()
'get!'(PathPattern, Options) -> Payload
+
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_payload_ret()
'get!'(StoreId, PathPattern, Options) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_payload_ret()
'get_or!'(PathPattern, Default) -> Payload
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Payload = khepri:unwrapped_payload_ret()
'get_or!'(StoreId, PathPattern, Default) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Payload = khepri:unwrapped_payload_ret()
'get_or!'(PathPattern, Default, Options) -> Payload
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_payload_ret()
'get_or!'(StoreId, PathPattern, Default, Options) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_payload_ret()
'get_many!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many!'(PathPattern, Options) -> Payload
+
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many!'(StoreId, PathPattern, Options) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many_or!'(PathPattern, Default) -> Payload
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many_or!'(StoreId, PathPattern, Default) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many_or!'(PathPattern, Default, Options) -> Payload
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_many_payloads_ret()
'get_many_or!'(StoreId, PathPattern, Default, Options) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_many_payloads_ret()
'exists!'(PathPattern) -> Exists
+
PathPattern = khepri_path:pattern()
Exists = boolean()
'exists!'(StoreId, PathPattern) -> Exists
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Exists = boolean()
'exists!'(PathPattern, Options) -> Exists
+
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Exists = boolean()
'exists!'(StoreId, PathPattern, Options) -> Exists
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Exists = boolean()
'has_data!'(PathPattern) -> HasData
+
PathPattern = khepri_path:pattern()
HasData = boolean()
'has_data!'(StoreId, PathPattern) -> HasData
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
HasData = boolean()
'has_data!'(PathPattern, Options) -> HasData
+
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
HasData = boolean()
'has_data!'(StoreId, PathPattern, Options) -> HasData
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
HasData = boolean()
'is_sproc!'(PathPattern) -> IsSproc
+
PathPattern = khepri_path:pattern()
IsSproc = boolean()
'is_sproc!'(StoreId, PathPattern) -> IsSproc
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
IsSproc = boolean()
'is_sproc!'(PathPattern, Options) -> IsSproc
+
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
IsSproc = boolean()
'is_sproc!'(StoreId, PathPattern, Options) -> IsSproc
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
IsSproc = boolean()
'count!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_payload_ret()
'count!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_payload_ret()
'count!'(PathPattern, Options) -> Payload
+
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_payload_ret()
'count!'(StoreId, PathPattern, Options) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = query_options() | khepri:tree_options()
Payload = khepri:unwrapped_payload_ret()
'put!'(PathPattern, Data) -> Payload
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'put!'(StoreId, PathPattern, Data) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'put!'(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'put_many!'(PathPattern, Data) -> Payload
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'put_many!'(StoreId, PathPattern, Data) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'put_many!'(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'create!'(PathPattern, Data) -> Payload
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'create!'(StoreId, PathPattern, Data) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'create!'(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'update!'(PathPattern, Data) -> Payload
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'update!'(StoreId, PathPattern, Data) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'update!'(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'compare_and_swap!'(PathPattern, DataPattern, Data) -> Payload
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'compare_and_swap!'(StoreId, PathPattern, DataPattern, Data) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | data() | function()
Payload = khepri:unwrapped_minimal_ret()
'compare_and_swap!'(StoreId, PathPattern, DataPattern, Data, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'delete!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'delete!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'delete!'(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = command_options() | khepri:tree_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'delete!'(StoreId, PathPattern, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = command_options() | khepri:tree_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'delete_many!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'delete_many!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'delete_many!'(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = command_options() | khepri:tree_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'delete_many!'(StoreId, PathPattern, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = command_options() | khepri:tree_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'clear_payload!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'clear_payload!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'clear_payload!'(StoreId, PathPattern, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
'clear_many_payloads!'(PathPattern) -> Payload
+
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'clear_many_payloads!'(StoreId, PathPattern) -> Payload
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Payload = khepri:unwrapped_minimal_ret()
'clear_many_payloads!'(StoreId, PathPattern, Options) -> Ret
+
StoreId = store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:unwrapped_minimal_ret() | khepri_machine:async_ret()
export(Module, ModulePriv) -> Ret
+
Module = module()
ModulePriv = khepri_import_export:module_priv()
Ret = ok | {ok, ModulePriv} | {error, any()}
Exports a Khepri store using the Module
callback module.
export(StoreId, Module,
+ ModulePriv)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+export(StoreId::StoreId | PathPattern, Module, ModulePriv) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Module = module()
ModulePriv = khepri_import_export:module_priv()
Ret = ok | {ok, ModulePriv} | {error, any()}
Exports a Khepri store using the Module
callback module.
export(StoreId, Module, ModulePriv)
. Calling it is the same as
+ calling export(StoreId, "**", Module, ModulePriv)
.export(PathPattern, Module, ModulePriv)
. Calling it is the same as
+ calling export(StoreId, PathPattern, Module, ModulePriv)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: export/4.
+ +export(StoreId, PathPattern, Module, ModulePriv) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Module = module()
ModulePriv = khepri_import_export:module_priv()
Ret = ok | {ok, ModulePriv} | {error, any()}
StoreId
: the name of the Khepri store.
+PathPattern
: the path pattern matching the tree nodes to export.
+Module
: the callback module to use to export.
+ModulePriv
: arguments passed to Module:open_write/1
.
+
+
returns: ok
or an {ok, Term}
tuple if the export succeeded (the actual
+ return value depends on whether the callback module wants to return anything
+ to the caller), or an {error, Reason}
tuple if it failed.
+
Exports a Khepri store using the Module
callback module.
The PathPattern
allows to filter which tree nodes are exported. The path
+ pattern can be provided as a native path pattern (a list of tree node names
+ and conditions) or as a string. See khepri_path:from_string/1
.
Module
is the callback module called to perform the actual export. It
+ must conform to the Mnesia Backup & Restore API. See khepri_import_export
for more details.
ModulePriv
is the term passed to Module:open_write/1
.
khepri_export_erlang
as
+ the callback module
+ ok = khepri:export(StoreId, khepri_export_erlang, "export-1.erl").
+
+ Example: export a subset of the Khepri store
+ ok = khepri:export(
+ StoreId,
+ "/:stock/:wood/**",
+ khepri_export_erlang,
+ "export-wood-stock-1.erl").
+
+See also: import/3.
+ +import(Module, ModulePriv) -> Ret
+
Module = module()
ModulePriv = khepri_import_export:module_priv()
Ret = ok | {ok, ModulePriv} | {error, any()}
Imports a previously exported set of tree nodes using the Module
+callback module.
import(StoreId, Module,
+ ModulePriv)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: import/3.
+ +import(StoreId, Module, ModulePriv) -> Ret
+
StoreId = khepri:store_id()
Module = module()
ModulePriv = khepri_import_export:module_priv()
Ret = ok | {ok, ModulePriv} | {error, any()}
StoreId
: the name of the Khepri store.
+Module
: the callback module to use to import.
+ModulePriv
: arguments passed to Module:open_read/1
.
+
+
returns: ok
or an {ok, Term}
tuple if the import succeeded (the actual
+ return value depends on whether the callback module wants to return anything
+ to the caller), or an {error, Reason}
tuple if it failed.
+
Imports a previously exported set of tree nodes using the Module
+callback module.
Module
is the callback module called to perform the actual import. It
+ must conform to the Mnesia Backup & Restore API. See khepri_import_export
for more details.
ModulePriv
is the term passed to Module:open_read/1
.
Importing something doesn't delete existing tree nodes. The caller is +responsible for deleting the existing content of a store if he needs to.
+ + Example: import a set of tree nodes usingkhepri_export_erlang
as
+ the callback module
+ ok = khepri:import(StoreId, khepri_export_erlang, "export-1.erl").
+
+See also: export/3.
+ +info() -> ok
Lists the running stores on stdout.
+ +Lists the content of specified store on stdout. +
+ +info(StoreId, Options) -> ok
+
StoreId = khepri:store_id()
Options = khepri:query_options()
StoreId
: the name of the Khepri store.
+Options
: query options.
+
Lists the content of specified store on stdout. +
+Generated by EDoc
+ + diff --git a/khepri_adv.html b/khepri_adv.html new file mode 100644 index 00000000..689941ac --- /dev/null +++ b/khepri_adv.html @@ -0,0 +1,888 @@ + + + + +Khepri database advanced API.
+ +This module exposes variants of the functions in khepri
which
+return more detailed return values for advanced use cases. Here are some
+examples of what can be achieved with this module:
undefined
atom as its payload, from
+ a tree node with no payload, from a non-existing tree node.put/4
which can be useful to perform transactional operations without
+ using khepri:transaction/4
.khepri
are implemented on top of this module
+ and simplify the return value for the more common use cases.
+many_results() = khepri_machine:common_ret()
Return value of a query or synchronous command targeting many tree nodes.
+ +node_props_map() = #{khepri_path:native_path() => khepri:node_props()}
Structure used to return a map of nodes and their associated properties, + payload and child nodes.
+ +single_result() = khepri:ok(khepri:node_props() | #{}) | khepri:error()
Return value of a query or synchronous command targeting one specific tree + node.
+ +get/1 | Returns the properties and payload of the tree node pointed to by the +given path pattern. |
get/2 | Returns the properties and payload of the tree node pointed to by the +given path pattern. |
get/3 | Returns the properties and payload of the tree node pointed to by the +given path pattern. |
get_many/1 | Returns properties and payloads of all the tree nodes matching the +given path pattern. |
get_many/2 | Returns properties and payloads of all the tree nodes matching the +given path pattern. |
get_many/3 | Returns properties and payloads of all the tree nodes matching the +given path pattern. |
put/2 | Sets the payload of the tree node pointed to by the given path +pattern. |
put/3 | Sets the payload of the tree node pointed to by the given path +pattern. |
put/4 | Sets the payload of the tree node pointed to by the given path +pattern. |
put_many/2 | Sets the payload of all the tree nodes matching the given path pattern. |
put_many/3 | Sets the payload of all the tree nodes matching the given path pattern. |
put_many/4 | Sets the payload of all the tree nodes matching the given path pattern. |
create/2 | Creates a tree node with the given payload. |
create/3 | Creates a tree node with the given payload. |
create/4 | Creates a tree node with the given payload. |
update/2 | Updates an existing tree node with the given payload. |
update/3 | Updates an existing tree node with the given payload. |
update/4 | Updates an existing tree node with the given payload. |
compare_and_swap/3 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
compare_and_swap/4 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
compare_and_swap/5 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
delete/1 | Deletes the tree node pointed to by the given path pattern. |
delete/2 | Deletes the tree node pointed to by the given path pattern. |
delete/3 | Deletes the tree node pointed to by the given path pattern. |
delete_many/1 | Deletes all tree nodes matching the given path pattern. |
delete_many/2 | Deletes all tree nodes matching the given path pattern. |
delete_many/3 | Deletes all tree nodes matching the given path pattern. |
clear_payload/1 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_payload/2 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_payload/3 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_many_payloads/1 | Deletes the payload of all tree nodes matching the given path pattern. |
clear_many_payloads/2 | Deletes the payload of all tree nodes matching the given path pattern. |
clear_many_payloads/3 | Deletes the payload of all tree nodes matching the given path pattern. |
unregister_projections/1 | Removes the given projections from the store. |
unregister_projections/2 | Removes the given projections from the store. |
unregister_projections/3 | Removes the given projections from the store. |
get(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Returns the properties and payload of the tree node pointed to by the +given path pattern.
+ + Calling this function is the same as callingget(StoreId, PathPattern)
+ with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+get(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
get(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri_adv:single_result()
Returns the properties and payload of the tree node pointed to by the +given path pattern.
+ + This function accepts the following two forms: +get(StoreId, PathPattern)
. Calling it is the same as calling
+ get(StoreId, PathPattern, #{})
.get(PathPattern, Options)
. Calling it is the same as calling
+ get(StoreId, PathPattern, Options)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: get/3.
+ +get(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri_adv:single_result()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to get.
+Options
: query options.
+
+
returns: an {ok, NodeProps}
tuple or an {error, Reason}
tuple.
+
Returns the properties and payload of the tree node pointed to by the +given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+ updating many nodes with the same payload is denied. That fact is checked
+ before the tree node is looked up: so if a condition in the path could
+ potentially match several nodes, an exception is raised, even though only
+ one tree node would match at the time. If you want to get multiple nodes at
+ once, use get_many/3
.
The returned {ok, NodeProps}
tuple contains a map with the properties and
+ payload (if any) of the targeted tree node. If the tree node is not found,
+ {error, ?khepri_error(node_not_found, Info)}
is returned.
value
+ %% Query the tree node at `/:foo/:bar'.
+{ok, #{data := value,
+ payload_version := 1}} = khepri_adv:get(StoreId, [foo, bar]).
+
+ Example: query an existing tree node with no payload
+ %% Query the tree node at `/:no_payload'.
+{ok, #{payload_version := 1}} = khepri_adv:get(StoreId, [no_payload]).
+
+ Example: query a non-existent tree node
+ %% Query the tree node at `/:non_existent'.
+{error, ?khepri_error(node_not_found, _)} = khepri_adv:get(
+ StoreId, [non_existent]).
+
+See also: get_many/3, khepri:get/3.
+ +get_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Returns properties and payloads of all the tree nodes matching the +given path pattern.
+ + Calling this function is the same as callingget_many(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: get_many/2, get_many/3.
+ +get_many(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
get_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri_adv:many_results()
Returns properties and payloads of all the tree nodes matching the +given path pattern.
+ + This function accepts the following two forms: +get_many(StoreId, PathPattern)
. Calling it is the same as calling
+ get_many(StoreId, PathPattern, #{})
.get_many(PathPattern, Options)
. Calling it is the same as calling
+ get_many(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: get_many/3.
+ +get_many(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri_adv:many_results()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to get.
+Options
: query options such as favor
.
+
+
returns: an {ok, NodePropsMap}
tuple or an {error, Reason}
tuple.
+
Returns properties and payloads of all the tree nodes matching the +given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The returned {ok, NodePropsMap}
tuple contains a map where keys correspond
+to the path to a tree node matching the path pattern. Each key then points
+to a map containing the properties and payload (if any) of that matching
+tree node.
%% Get all nodes in the tree. The tree is:
+%% <root>
+%% `-- foo
+%% `-- bar = value
+{ok, #{[foo] :=
+ #{payload_version := 1},
+ [foo, bar] :=
+ #{data := value,
+ payload_version := 1}}} = khepri_adv:get_many(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR_STAR]).
+
+See also: get/3, khepri:get_many/3.
+ +put(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret() | khepri_adv:single_result()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingput(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+put(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret() | khepri_adv:single_result()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingput(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: put/4.
+ +put(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret() | khepri_adv:single_result() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to create or
+ modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodeProps}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Sets the payload of the tree node pointed to by the given path +pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+updating many nodes with the same payload is denied. That fact is checked
+before the tree node is looked up: so if a condition in the path could
+potentially match several nodes, an exception is raised, even though only
+one tree node would match at the time.
When using a simple path (i.e. without conditions), if the targeted tree +node does not exist, it is created using the given payload. If the +targeted tree node exists, it is updated with the given payload and its +payload version is increased by one. Missing parent nodes are created on +the way.
+ +When using a path pattern, the behavior is the same. However if a condition +in the path pattern is not met, an error is returned and the tree structure +is not modified.
+ +The returned {ok, NodeProps}
tuple contains a map with the properties and
+ payload (if any) of the targeted tree node: the payload was the one before
+ the update, other properties like the payload version correspond to the
+ updated node. If the targeted tree node didn't exist, NodeProps
will be
+an empty map.
khepri_payload:no_payload()
),
+ using the marker returned by khepri_payload:none/0
, meaning there
+ will be no payload attached to the tree node and the existing payload will
+ be discarded if anykhepri_payload:sproc()
recordkhepri_payload:data()
+ recordIt is possible to wrap the payload in its internal structure explicitly
+ using the khepri_payload
module directly.
The Options
map may specify command-level options; see khepri:command_options()
, khepri:tree_options()
and khepri:put_options()
.
When doing an asynchronous update, the handle_async_ret/1
+function should be used to handle the message received from Ra.
The returned {ok, NodeProps}
tuple contains a map with the properties and
+payload (if any) of the targeted tree node as they were before the put.
%% Insert a tree node at `/:foo/:bar', overwriting the previous value.
+{ok, #{data := value,
+ payload_version := 1}} = khepri_adv:put(
+ StoreId, [foo, bar], new_value).
+
+See also: compare_and_swap/5, create/4, update/4, khepri:put/4.
+ +put_many(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:many_results()
Sets the payload of all the tree nodes matching the given path pattern.
+ + Calling this function is the same as callingput_many(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: put_many/3, put_many/4.
+ +put_many(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:many_results()
Sets the payload of all the tree nodes matching the given path pattern.
+ + Calling this function is the same as callingput_many(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: put_many/4.
+ +put_many(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:many_results() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to create or
+ modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodePropsMap}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always ok
+ (the actual return value may be sent by a message if a correlation ID was
+ specified).
+
Sets the payload of all the tree nodes matching the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
When using a simple path (i.e. without conditions), if the targeted tree +node does not exist, it is created using the given payload. If the +targeted tree node exists, it is updated with the given payload and its +payload version is increased by one. Missing parent nodes are created on +the way.
+ +When using a path pattern, the behavior is the same. However if a condition +in the path pattern is not met, an error is returned and the tree structure +is not modified.
+ +The returned {ok, NodePropsMap}
tuple contains a map where keys
+correspond to the path to a tree node matching the path pattern. Each key
+then points to a map containing the properties and payload (if any) of the
+targeted tree node: the payload was the one before the update, other
+properties like the payload version correspond to the updated node.
khepri_payload:no_payload()
),
+ using the marker returned by khepri_payload:none/0
, meaning there
+ will be no payload attached to the tree node and the existing payload will
+ be discarded if anykhepri_payload:sproc()
recordkhepri_payload:data()
+ recordIt is possible to wrap the payload in its internal structure explicitly
+ using the khepri_payload
module directly.
The Options
map may specify command-level options; see khepri:command_options()
, khepri:tree_options()
and khepri:put_options()
.
When doing an asynchronous update, the handle_async_ret/1
+function should be used to handle the message received from Ra.
%% Set value of all tree nodes matching `/*/:bar', to `new_value'.
+{ok, #{[foo, bar] :=
+ #{data := value,
+ payload_version := 1},
+ [baz, bar] :=
+ #{payload_version := 1}}} = khepri_adv:put_many(
+ StoreId,
+ [?KHEPRI_WILDCARD_STAR, bar],
+ new_value).
+
+See also: put/4, khepri:put_many/4.
+ +create(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Creates a tree node with the given payload.
+ + Calling this function is the same as callingcreate(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+create(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Creates a tree node with the given payload.
+ + Calling this function is the same as callingcreate(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: create/4.
+ +create(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to create.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodeProps}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Creates a tree node with the given payload.
+ +The behavior is the same as put/4
except that if the tree node
+ already exists, an {error, ?khepri_error(mismatching_node, Info)}
tuple
+is returned.
PathPattern
is modified to include an
+ #if_node_exists{exists = false}
condition on its last component.
+
+See also: put/4, update/4, khepri:create/4.
+ +update(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload.
+ + Calling this function is the same as callingupdate(StoreId, PathPattern,
+ Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+update(StoreId, PathPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload.
+ + Calling this function is the same as callingupdate(StoreId, PathPattern,
+ Data, #{})
.
+
+See also: update/4.
+ +update(StoreId, PathPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodeProps}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Updates an existing tree node with the given payload.
+ +The behavior is the same as put/4
except that if the tree node
+ already exists, an {error, ?khepri_error(mismatching_node, Info)}
tuple
+is returned.
PathPattern
is modified to include an
+ #if_node_exists{exists = true}
condition on its last component.
+
+See also: create/4, put/4, khepri:update/4.
+ +compare_and_swap(PathPattern, DataPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + Calling this function is the same as callingcompare_and_swap(StoreId,
+ PathPattern, DataPattern, Data)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: compare_and_swap/4, compare_and_swap/5.
+ +compare_and_swap(StoreId, PathPattern, DataPattern, Data) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + Calling this function is the same as callingcompare_and_swap(StoreId,
+ PathPattern, DataPattern, Data, #{})
.
+
+See also: compare_and_swap/5.
+ +compare_and_swap(StoreId, PathPattern, DataPattern, Data, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to modify.
+Data
: the Erlang term or function to store, or a khepri_payload:payload()
structure.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodeProps}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ +The behavior is the same as put/4
except that if the tree node
+ already exists, an {error, ?khepri_error(mismatching_node, Info)}
tuple
+is returned.
PathPattern
is modified to include an
+ #if_data_matches{pattern = DataPattern}
condition on its last component.
+
+See also: put/4, khepri:compare_and_swap/5.
+ +delete(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Deletes the tree node pointed to by the given path pattern.
+ + Calling this function is the same as callingdelete(StoreId, PathPattern)
+ with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+delete(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
delete(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri_adv:single_result()
Deletes the tree node pointed to by the given path pattern.
+ + This function accepts the following two forms: +delete(StoreId, PathPattern)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, #{})
.delete(PathPattern, Options)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: delete/3.
+ +delete(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri_adv:single_result() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to delete.
+Options
: command options such as the command type.
+
+
returns: in the case of a synchronous call, an {ok, NodeProps}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Deletes the tree node pointed to by the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The PathPattern
must target a specific tree node. In other words,
+ updating many nodes with the same payload is denied. That fact is checked
+ before the tree node is looked up: so if a condition in the path could
+ potentially match several nodes, an exception is raised, even though only
+ one tree node would match at the time. If you want to delete multiple nodes
+ at once, use delete_many/3
.
The returned {ok, NodeProps}
tuple contains a map with the properties and
+ payload (if any) of the targeted tree node as they were before the delete.
+ If the targeted tree node didn't exist, NodeProps
will be an empty map.
When doing an asynchronous update, the handle_async_ret/1
+function should be used to handle the message received from Ra.
%% Delete the tree node at `/:foo/:bar'.
+{ok, #{data := value,
+ payload_version := 1}} = khepri_adv:delete(StoreId, [foo, bar]).
+
+See also: delete_many/3, khepri:delete/3.
+ +delete_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Deletes all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingdelete_many(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: delete_many/2, delete_many/3.
+ +delete_many(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
delete_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri_adv:many_results()
Deletes all tree nodes matching the given path pattern.
+ + This function accepts the following two forms: +delete_many(StoreId, PathPattern)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, #{})
.delete_many(PathPattern, Options)
. Calling it is the same as calling
+ delete(StoreId, PathPattern, Options)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).See also: delete_many/3.
+ +delete_many(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri_adv:many_results() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the nodes to delete.
+Options
: command options such as the command type.
+
+
returns: in the case of a synchronous call, an {ok, NodePropsMap}
tuple
+ or an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Deletes all tree nodes matching the given path pattern.
+ +The PathPattern
can be provided as a native path pattern (a list of tree
+ node names and conditions) or as a string. See khepri_path:from_string/1
.
The returned {ok, NodePropsMap}
tuple contains a map where keys
+correspond to the path to a deleted tree node. Each key then points to a
+map containing the properties and payload (if any) of that deleted tree
+node as they were before the delete.
When doing an asynchronous update, the handle_async_ret/1
+function should be used to handle the message received from Ra.
%% Delete the tree node at `/:foo/:bar'.
+{ok, #{[foo, bar] := #{data := value,
+ payload_version := 1},
+ [baz, bar] := #{payload_version := 1}}} = khepri_adv:delete_many(
+ StoreId, [foo, bar]).
+
+See also: delete/3, khepri:delete/3.
+ +clear_payload(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingclear_payload(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: clear_payload/2, clear_payload/3.
+ +clear_payload(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + Calling this function is the same as callingclear_payload(StoreId,
+ PathPattern, #{})
.
+
+See also: clear_payload/3.
+ +clear_payload(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree node to modify.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodeProps}
tuple or
+ an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + In other words, the payload is set tokhepri_payload:no_payload()
.
+ Otherwise, the behavior is that of update/4
.
+
+See also: update/4, khepri:clear_payload/3.
+ +clear_many_payloads(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Deletes the payload of all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingclear_many_payloads(StoreId,
+ PathPattern)
with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: clear_many_payloads/2, clear_many_payloads/3.
+ +clear_many_payloads(StoreId, PathPattern) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Deletes the payload of all tree nodes matching the given path pattern.
+ + Calling this function is the same as callingclear_many_payloads(StoreId,
+ PathPattern, #{})
.
+
+See also: clear_many_payloads/3.
+ +clear_many_payloads(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:many_results() | khepri_machine:async_ret()
StoreId
: the name of the Khepri store.
+PathPattern
: the path (or path pattern) to the tree nodes to modify.
+Options
: command options.
+
+
returns: in the case of a synchronous call, an {ok, NodePropsMap}
tuple
+ or an {error, Reason}
tuple; in the case of an asynchronous call, always
+ ok
(the actual return value may be sent by a message if a correlation ID
+ was specified).
+
Deletes the payload of all tree nodes matching the given path pattern.
+ + In other words, the payload is set tokhepri_payload:no_payload()
.
+ Otherwise, the behavior is that of put/4
.
+
+See also: delete_many/3, put/4, khepri:clear_many_payloads/3.
+ +unregister_projections(Names) -> Ret
+
Names = all | [khepri_projection:name()]
Ret = khepri:ok(khepri_machine:projection_map()) | khepri:error()
Removes the given projections from the store.
+ + Calling this function is the same as calling +unregister_projections(StoreId, Names)
with the default store ID (see
+ khepri_cluster:get_default_store_id/0
).
+
+See also: unregister_projections/2.
+ +unregister_projections(StoreId, Names) -> Ret
+
StoreId = khepri:store_id()
Names = all | [khepri_projection:name()]
Ret = khepri:ok(khepri_machine:projection_map()) | khepri:error()
unregister_projections(Names, Options) -> Ret
+
Names = all | [khepri_projection:name()]
Options = khepri:command_options()
Ret = khepri:ok(khepri_machine:projection_map()) | khepri:error()
Removes the given projections from the store.
+ + This function accepts the following two forms: +unregister_projections(StoreId, Names)
. Calling it is the same as
+ calling unregister_projections(StoreId, Names, #{})
.unregister_projections(Names, Options)
. Calling it is the same as
+ calling unregister_projections(StoreId, Names, Options)
with the default
+ store ID (see khepri_cluster:get_default_store_id/0
).See also: unregister_projections/3.
+ +unregister_projections(StoreId, Names, Options) -> Ret
+
StoreId = khepri:store_id()
Names = all | [khepri_projection:name()]
Options = khepri:command_options()
Ret = khepri:ok(khepri_machine:projection_map()) | khepri:error()
StoreId
: the name of the Khepri store.
+Names
: the names of projections to unregister or the atom all
to
+ remove all projections.
+Options
: command options for unregistering the projections.
+
returns: ok
if the projections were unregistered, an {error, Reason}
+ tuple otherwise.
Removes the given projections from the store.
+ +Names
may either be a list of projection names to remove or the atom
+ all
. When all
is passed, every projection in the store is removed.
+
+Generated by EDoc
+ + diff --git a/khepri_cluster.html b/khepri_cluster.html new file mode 100644 index 00000000..cb135124 --- /dev/null +++ b/khepri_cluster.html @@ -0,0 +1,494 @@ + + + + +Khepri service and cluster management API.
+ +This module provides the public API for the service and cluster management.
+ For convenience, some functions of this API are repeated in the khepri
module for easier access.
A Khepri store is a Ra server inside a Ra cluster. The Khepri store and the +Ra cluster share the same name in fact. The only constraint is that the name +must be an atom, even though Ra accepts other Erlang types as cluster names.
+ +By default, Khepri uses khepri
as the store ID (and thus Ra cluster name).
+ This default can be overridden using an argument to the start()
functions
+ or the default_store_id
application environment variable.
{ok, khepri} = khepri:start().
{ok, my_store} = khepri:start("/var/lib/khepri", my_store).
ok = application:set_env(
+ khepri, default_store_id, my_store, [{persistent, true}]),
+
+{ok, my_store} = khepri:start().
A Ra server relies on a Ra system to provide various functions and to +configure the directory where the data should be stored on disk.
+ +By default, Khepri will configure its own Ra system to write data under
+ khepri#Nodename
in the current working directory, where Nodename
is
+the name of the Erlang node.
{ok, StoreId} = khepri:start().
+
+%% If the Erlang node was started without distribution (the default), the
+%% statement above will start a Ra system called like the store (`khepri')
+%% and will use the `khepri#nonode@nohost' directory.
+
+ The default data directory or Ra system name can be overridden using an
+ argument to the start()
or the default_ra_system
application environment
+variable. Both a directory (string or binary) or the name of an already
+running Ra system are accepted.
{ok, StoreId} = khepri:start(my_ra_system).
ok = application:set_env(
+ khepri, default_ra_system, "/var/lib/khepri", [{persistent, true}]),
+
+{ok, StoreId} = khepri:start().
Please refer to Ra + documentation to learn more about Ra systems and Ra clusters.
+ +A Khepri/Ra cluster can be expanded by telling a node to join a remote +cluster. Note that the Khepri store/Ra server to add to the cluster must run +before it can join.
+ +%% Start the local Khepri store.
+{ok, StoreId} = khepri:start().
+
+%% Join a remote cluster.
+ok = khepri_cluster:join(RemoteNode).
+
+ To remove the local Khepri store node from the cluster, it must be reset.
+ +%% Start the local Khepri store.
+ok = khepri_cluster:reset().
+incomplete_ra_server_config() = map()
A Ra server config map.
+ + This configuration map can lack the required parameters, Khepri will fill + them if necessary. Important parameters for Khepri (e.g.machine
) will be
+ overridden anyway.
+
+
+start/0 | Starts a store. |
start/1 | Starts a store. |
start/2 | Starts a store. |
start/3 | Starts a store. |
stop/0 | Stops a store. |
stop/1 | Stops a store. |
join/1 | Adds the local running Khepri store to a remote cluster. |
join/2 | Adds the local running Khepri store to a remote cluster. |
reset/0 | Resets the store on this Erlang node. |
reset/1 | Resets the store on this Erlang node. |
reset/2 | Resets the store on this Erlang node. |
get_default_ra_system_or_data_dir/0 | Returns the default Ra system name or data directory. |
get_default_store_id/0 | Returns the default Khepri store ID. |
members/0 | Returns the list of Ra members that are part of the cluster. |
members/1 | Returns the list of Ra members that are part of the cluster. |
members/2 | Returns the list of Ra members that are part of the cluster. |
nodes/0 | Returns the list of Erlang nodes that are part of the cluster. |
nodes/1 | Returns the list of Erlang nodes that are part of the cluster. |
nodes/2 | Returns the list of Erlang nodes that are part of the cluster. |
wait_for_leader/0 | Waits for a leader to be elected. |
wait_for_leader/1 | Waits for a leader to be elected. |
wait_for_leader/2 | Waits for a leader to be elected. |
get_store_ids/0 | Returns the list of running stores. |
is_store_running/1 | Indicates if StoreId is running or not. |
start() -> Ret
+
Ret = khepri:ok(StoreId) | khepri:error()
StoreId = khepri:store_id()
Starts a store.
+ + Calling this function is the same as callingstart(DefaultRaSystem)
where
+ DefaultRaSystem
is returned by get_default_ra_system_or_data_dir/0
.
+
+See also: start/1, ra_server:ra_server_config().
+ +start(RaSystemOrDataDir::RaSystem | DataDir) -> Ret
+
RaSystem = atom()
DataDir = file:filename_all()
Ret = khepri:ok(StoreId) | khepri:error()
StoreId = khepri:store_id()
Starts a store.
+ + Calling this function is the same as callingstart(RaSystemOrDataDir,
+ DefaultStoreId)
where DefaultStoreId
is returned by get_default_store_id/0
.
+
+See also: start/2.
+ +start(RaSystemOrDataDir::RaSystem | DataDir, StoreIdOrRaServerConfig::StoreId | RaServerConfig) -> Ret
+
RaSystem = atom()
DataDir = file:filename_all()
StoreId = khepri:store_id()
RaServerConfig = incomplete_ra_server_config()
Ret = khepri:ok(StoreId) | khepri:error()
Starts a store.
+ + Calling this function is the same as callingstart(RaSystemOrDataDir,
+ StoreIdOrRaServerConfig, DefaultTimeout)
where DefaultTimeout
is
+ returned by khepri_app:get_default_timeout/0
.
+
+See also: start/3.
+ +start(RaSystemOrDataDir::RaSystem | DataDir, StoreIdOrRaServerConfig::StoreId | RaServerConfig, Timeout) -> Ret
+
RaSystem = atom()
DataDir = file:filename_all()
StoreId = khepri:store_id()
RaServerConfig = incomplete_ra_server_config()
Timeout = timeout()
Ret = khepri:ok(StoreId) | khepri:error()
returns: the ID of the started store in an "ok" tuple, or an error tuple if + the store couldn't be started.
+Starts a store.
+ +It accepts either a Ra system name (atom) or a data directory (string or +binary) as its first argument. If a Ra system name is given, that Ra system +must be running when this function is called. If a data directory is given, +a new Ra system will be started, using this directory. The directory will +be created automatically if it doesn't exist. The Ra system will use the +same name as the Khepri store.
+ +It accepts a Khepri store ID or a Ra server configuration as its second +argument. If a store ID is given, a Ra server configuration will be created +based on it. If a Ra server configuration is given, the name of the Khepri +store will be derived from it.
+ +If this is a new store, the Ra server is started and an election is +triggered so that it becomes its own leader and is ready to process +commands and queries.
+ + If the store was started in the past and stopped, it will be restarted. In + this case,RaServerConfig
will be ignored. Ra will take care of the
+ eletion automatically.
+
+
+stop() -> Ret
+
Ret = ok | khepri:error()
Stops a store.
+ + Calling this function is the same as callingstop(DefaultStoreId)
+ where DefaultStoreId
is returned by get_default_store_id/0
.
+
+See also: stop/1.
+ +stop(StoreId) -> Ret
+
StoreId = khepri:store_id()
Ret = ok | khepri:error()
StoreId
: the ID of the store to stop.
+
+
returns: ok
if it succeeds, an error tuple otherwise.
Stops a store. +
+ +join(RemoteNode::RemoteMember | RemoteNode) -> Ret
+
RemoteMember = ra:server_id()
RemoteNode = node()
Ret = ok | khepri:error()
Adds the local running Khepri store to a remote cluster.
+ + This function accepts the following forms: +join(RemoteNode)
. Calling it is the same as calling
+ join(DefaultStoreId, RemoteNode)
where DefaultStoreId
is
+ returned by get_default_store_id/0
.join(RemoteMember)
. Calling it is the same as calling
+ join(StoreId, RemoteNode)
where StoreId
and RemoteNode
are
+ derived from RemoteMember
.See also: join/2.
+ +join(RemoteNode::RemoteMember | RemoteNode | StoreId, Timeout::Timeout | RemoteNode) -> Ret
+
RemoteMember = ra:server_id()
RemoteNode = node()
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
Adds the local running Khepri store to a remote cluster.
+ + This function accepts the following forms: +join(RemoteNode, Timeout)
. Calling it is the same as calling
+ join(DefaultStoreId, RemoteNode, Timeout)
where DefaultStoreId
+ is returned by get_default_store_id/0
.join(StoreId, RemoteNode)
. Calling it is the same as calling
+ join(StoreId, RemoteNode, DefaultTimeout)
where DefaultTimeout
is
+ returned by khepri_app:get_default_timeout/0
.join(RemoteMember, Timeout)
. Calling it is the same as calling
+ join(StoreId, RemoteNode, Timeout)
where StoreId
and
+ RemoteNode
are derived from RemoteMember
.See also: join/3.
+ +reset() -> Ret
+
Ret = ok | khepri:error()
Resets the store on this Erlang node.
+ +reset(Timeout::StoreId | Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
Resets the store on this Erlang node.
+ +reset(StoreId, Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
StoreId
: the name of the Khepri store.
+
Resets the store on this Erlang node.
+ +It does that by force-deleting the Ra local server.
+ + This function is also used to gracefully remove the local Khepri store node + from a cluster. + + +get_default_ra_system_or_data_dir() -> RaSystem | DataDir
+
RaSystem = atom()
DataDir = file:filename_all()
returns: the value of the default_ra_system
application environment
+ variable.
Returns the default Ra system name or data directory.
+ +This is based on Khepri's default_ra_system` application environment
+ variable. The variable can be set to:
+ <ul>
+ <li>A directory (a string or binary) where data should be stored. A new Ra
+ system called `khepri` will be initialized with this directory.</li>
+ <li>A Ra system name (an atom). In this case, the user is expected to
+ configure and start the Ra system before starting Khepri.</li>
+ </ul>
+
+ If this application environment variable is unset, the default is to
+ configure a Ra system called `khepri
which will write data in
+ "khepri-$NODE"
in the current working directory where $NODE
is the
+Erlang node name.
{khepri, [{default_ra_system, "/var/db/khepri"}]}.
+
+
+get_default_store_id() -> StoreId
+
StoreId = khepri:store_id()
returns: the value of the default_store_id
application environment
+ variable.
Returns the default Khepri store ID.
+ + This is based on Khepri'sdefault_store_id
application environment
+ variable. The variable can be set to an atom. The default is khepri
.
+
+
+members() -> Ret
+
Ret = khepri:ok(Members) | khepri:error()
Members = [ra:server_id(), ...]
Returns the list of Ra members that are part of the cluster.
+ + Calling this function is the same as callingmembers(StoreId)
with the
+ default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: members/1, members/2.
+ +members(StoreId::StoreId | Options) -> Ret
+
StoreId = khepri:store_id()
Options = khepri:query_options()
Ret = khepri:ok(Members) | khepri:error()
Members = [ra:server_id(), ...]
Returns the list of Ra members that are part of the cluster.
+ + This function accepts the following two forms: +members(StoreId)
. Calling it is the same as calling members(StoreId,
+ #{})
.members(Options)
. Calling it is the same as calling members(StoreId,
+ Options)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: members/2.
+ +members(StoreId, Options) -> Ret
+
StoreId = khepri:store_id()
Options = khepri:query_options()
Ret = khepri:ok(Members) | khepri:error()
Members = [ra:server_id(), ...]
StoreId
: the ID of the store to stop.
+Options
: query options such as favor
.
+
+
returns: an {ok, Members}
tuple or an {error, Reason}
tuple. Members
+ is a non-empty list of Ra server IDs.
Returns the list of Ra members that are part of the cluster.
+ +If the favor
option is set to consistency
, the Ra leader is queried for
+the list of members, therefore the membership view is consistent with the
+rest of the cluster.
If the favor
option is set to low_latency
, the local Ra server is
+queried. The query will be faster at the cost of returning a possibly
+out-of-date result.
condition
query option is unsupported.
+
+
+nodes() -> Ret
+
Ret = khepri:ok(Nodes) | khepri:error()
Nodes = [node(), ...]
Returns the list of Erlang nodes that are part of the cluster.
+ + Calling this function is the same as callingnodes(StoreId)
with the
+ default store ID (see khepri_cluster:get_default_store_id/0
).
+
+
+
+nodes(StoreIdOrOptions::StoreId | Options) -> Ret
+
StoreId = khepri:store_id()
Options = khepri:query_options()
Ret = khepri:ok(Nodes) | khepri:error()
Nodes = [node(), ...]
Returns the list of Erlang nodes that are part of the cluster.
+ + This function accepts the following two forms: +nodes(StoreId)
. Calling it is the same as calling nodes(StoreId,
+ #{})
.nodes(Options)
. Calling it is the same as calling nodes(StoreId,
+ Options)
with the default store ID (see khepri_cluster:get_default_store_id/0
).See also: nodes/2.
+ +nodes(StoreId, Options) -> Ret
+
StoreId = khepri:store_id()
Options = khepri:query_options()
Ret = khepri:ok(Nodes) | khepri:error()
Nodes = [node(), ...]
Returns the list of Erlang nodes that are part of the cluster.
+ +If the favor
option is set to consistency
, the Ra leader is queried for
+the list of members, therefore the membership view is consistent with the
+rest of the cluster.
If the favor
option is set to low_latency
, the local Ra server is
+queried. The query will be faster at the cost of returning a possibly
+out-of-date result.
condition
query option is unsupported.
+
+See also: members/2.
+ +wait_for_leader() -> Ret
+
Ret = ok | khepri:error()
Waits for a leader to be elected.
+ + Calling this function is the same as callingwait_for_leader(StoreId)
+ with the default store ID (see khepri_cluster:get_default_store_id/0
).
+
+See also: wait_for_leader/1, wait_for_leader/2.
+ +wait_for_leader(StoreIdOrRaServer) -> Ret
+
StoreIdOrRaServer = StoreId | RaServer
StoreId = khepri:store_id()
RaServer = ra:server_id()
Ret = ok | khepri:error()
Waits for a leader to be elected.
+ + Calling this function is the same as callingwait_for_leader(StoreId,
+ DefaultTimeout)
where DefaultTimeout
is returned by khepri_app:get_default_timeout/0
.
+
+See also: wait_for_leader/2.
+ +wait_for_leader(StoreIdOrRaServer, Timeout) -> Ret
+
StoreIdOrRaServer = StoreId | RaServer
StoreId = khepri:store_id()
RaServer = ra:server_id()
Timeout = timeout()
Ret = ok | khepri:error()
Timeout
: the timeout.
+
+
returns: ok
if a leader was elected or an {error, Reason}
tuple.
Waits for a leader to be elected.
+ + This is useful if you want to be sure the clustered store is ready before + issueing writes and queries. Note that there are obviously no guaranties + that the Raft quorum will be lost just after this call. + + +get_store_ids() -> [StoreId]
+
StoreId = khepri:store_id()
Returns the list of running stores.
+ +is_store_running(StoreId) -> IsRunning
+
StoreId = khepri:store_id()
IsRunning = boolean()
Indicates if StoreId
is running or not.
Generated by EDoc
+ + diff --git a/khepri_condition.html b/khepri_condition.html new file mode 100644 index 00000000..1720dc79 --- /dev/null +++ b/khepri_condition.html @@ -0,0 +1,320 @@ + + + + +Condition support.
+ +Conditions can be used in path patterns and keep_while
conditions. They
+allow to point to a specific node only if conditions are met, or to match
+several tree nodes with a single path pattern.
A condition is an Erlang record defining a specific property. Some of them +have arguments to further define the condition.
+ +Path components (atoms and binaries) also act as conditions which check
+ equality with the path of the tested node. This can be useful for
+ conditions which compose other conditions: if_not()
,
+ if_all()
and if_any()
.
Example:
+ +%% Matches `[stock, wood, <<"birch">>]' but not `[stock, wood, <<"oak">>]'
+[stock, wood, #if_not{condition = <<"oak">>}]
+
+ All supported conditions are described in the Data Types
+ section.
+comparison_op(Type) = {eq, Type} | {ne, Type} | {lt, Type} | {le, Type} | {gt, Type} | {ge, Type}
Comparison operator in some condition()
.
condition() = if_name_matches() | if_path_matches() | if_has_payload() | if_has_data() | if_has_sproc() | if_data_matches() | if_node_exists() | if_payload_version() | if_child_list_version() | if_child_list_length() | if_not() | if_all() | if_any()
All supported conditions.
+ +if_all() = #if_all{conditions = [khepri_path:pattern_component()]}
Condition. Evaluates to true if all inner conditions evaluate to true.
+ + Record fields: +conditions
: a list of inner conditions to evaluate.#if_all{conditions = [#if_name_matches{regex = "^a"},
+ #if_has_data{has_data = true}]}.
+
+if_any() = #if_any{conditions = [khepri_path:pattern_component()]}
Condition. Evaluates to true if any of the inner conditions evaluate to +true.
+ + Record fields: +conditions
: a list of inner conditions to evaluate.#if_any{conditions = [#if_name_matches{regex = "^a"},
+ #if_has_data{has_data = true}]}.
+
+if_child_list_length() = #if_child_list_length{count = non_neg_integer() | khepri_condition:comparison_op(non_neg_integer())}
Condition. Evaluates to true if the tested node's child list size +corresponds to the expected value.
+ + Record fields: +version
: integer or comparison_op()
to compare to the actual
+ child list child.#if_child_list_length{count = 1}.
+#if_child_list_length{count = {gt, 10}}.
+
+if_child_list_version() = #if_child_list_version{version = khepri:child_list_version() | khepri_condition:comparison_op(khepri:child_list_version())}
Condition. Evaluates to true if the tested node's child list version +corresponds to the expected value.
+ + Record fields: +version
: integer or comparison_op()
to compare to the actual
+ child list version.#if_child_list_version{version = 1}.
+#if_child_list_version{version = {gt, 10}}.
+
+if_data_matches() = #if_data_matches{pattern = ets:match_pattern() | term(), conditions = [any()], compiled = ets:comp_match_spec() | undefined}
Condition. Evaluates to true if the tested node has a data payload and the
+ data payload term matches the given pattern
and all conditions
evaluates
+to true.
pattern
: an ETS-like match pattern. The match pattern can define
+ variables to be used in the conditions
below.conditions
: a list of guard expressions. All guard expressions must
+ evaluate to true to consider a match. The default is an empty list of
+ conditions which means that only the pattern matching is
+ considered.%% The data must be of the form `{user, _}', so a tuple of arity 2 with the
+%% first element being the `user' atom. The second element can be anything.
+#if_data_matches{pattern = {user, '_'}}.
+ %% The data must be of the form `{age, Age}' and `Age' must be an
+%% integer greater than or equal to 18.
+#if_data_matches{pattern = {age, '$1'},
+ conditions = [{is_integer, '$1'},
+ {'>=', '$1', 18}]}.
+
+ See Match
+ Specifications in Erlang for a detailed documentation of how it works.
+
+if_has_data() = #if_has_data{has_data = boolean()}
Condition. Evaluates to true if the tested node's data payload presence +corresponds to the expected state.
+ + Record fields: +has_data
: boolean set to the expected presence of a data
+ payload.Data absence is either no payload or a non-data type of payload.
+ + Example: +#if_has_data{has_data = false}.
+
+if_has_payload() = #if_has_payload{has_payload = boolean()}
Condition. Evaluates to true if the tested node has any kind of payload.
+ + Record fields: +has_payload
: boolean set to the expected presence of any kind of
+ payload.#if_has_payload{has_payload = true}.
+
+if_has_sproc() = #if_has_sproc{has_sproc = boolean()}
Condition. Evaluates to true if the tested node's stored procedure payload +presence corresponds to the expected state.
+ + Record fields: +has_sproc
: boolean set to the expected presence of a stored procedure
+ payload.Stored procedure absence is either no payload or a non-sproc type of +payload.
+ + Example: +#if_has_sproc{has_sproc = false}.
+
+if_name_matches() = #if_name_matches{regex = any | iodata() | unicode:charlist(), compiled = khepri_condition:re_compile_ret() | undefined}
Condition. Evaluates to true if the name of the tested node matches the +condition pattern.
+ + Record fields: +regex
: defines the condition pattern. It can be either:
+ any
to match any node names; the equivalent of the ".*"
+ regular expression but more efficient#if_name_matches{regex = "^user_"}.
+#if_name_matches{regex = any}.
+
+if_node_exists() = #if_node_exists{exists = boolean()}
Condition. Evaluates to true if the tested node existence corresponds to +the expected state.
+ + Record fields: +exists
: boolean set to the expected presence of the node.#if_node_exists{exists = false}.
+
+if_not() = #if_not{condition = khepri_path:pattern_component()}
Condition. Evaluates to true if the inner condition evaluates to false.
+ + Record fields: +condition
: the inner condition to evaluate.#if_not{condition = #if_name_matches{regex = "^a"}}.
+
+if_path_matches() = #if_path_matches{regex = any | iodata() | unicode:charlist(), compiled = khepri_condition:re_compile_ret() | undefined}
Condition. Evaluates to true if the name of the tested node matches the +condition pattern. If it does not match, child node names are tested +recursively.
+ + Record fields: +regex
: defines the condition pattern. It can be either:
+ any
to match any node names; the equivalent of the ".*"
+ regular expression but more efficient#if_path_matches{regex = "^user_"}.
+#if_path_matches{regex = any}.
+
+if_payload_version() = #if_payload_version{version = khepri:payload_version() | khepri_condition:comparison_op(khepri:payload_version())}
Condition. Evaluates to true if the tested node's payload version +corresponds to the expected value.
+ + Record fields: +version
: integer or comparison_op()
to compare to the actual
+ payload version.#if_payload_version{version = 1}.
+#if_payload_version{version = {gt, 10}}.
+
+keep_while() = #{khepri_path:path() => condition()}
An association between a path and a condition. As long as the condition +evaluates to true, the tree node is kept. Once the condition evaluates to +false, the tree node is deleted.
+ +If the keep_while
conditions are false at the time of the insert, the
+ insert fails. The only exception to that is if the keep_while
condition
+is on the inserted node itself.
Paths in the map can be native paths or Unix-like paths. However, having +two entries that resolve to the same node (one native path entry and one +Unix-like path entry for instance) is undefined behavior: one of them will +overwrite the other.
+ + Example: +khepri:put(
+ StoreId,
+ [foo],
+ Payload,
+ #{keep_while => #{
+ %% The node `[foo]' will be removed as soon as `[bar]' is removed
+ %% because the condition associated with `[bar]' will not be true
+ %% anymore.
+ [bar] => #if_node_exists{exists = true}
+ }}
+).
+
+native_keep_while() = #{khepri_path:native_path() => condition()}
An association between a native path and a condition.
+ + This is the same askeep_while()
but the paths in the map keys were
+ converted to native paths if necessary.
+
+re_compile_ret() = {ok, {re_pattern, term(), term(), term(), term()}} | {error, {string(), non_neg_integer()}}
Return value of re:compile/1
.
re:mp()
, is unfortunately not
+ exported by re
, neither is the error tuple (at least up to
+ Erlang/OTP 25.1).
+
+ensure_native_keep_while/1 |
ensure_native_keep_while(KeepWhile) -> NativeKeepWhile
+
KeepWhile = keep_while()
NativeKeepWhile = native_keep_while()
Generated by EDoc
+ + diff --git a/khepri_evf.html b/khepri_evf.html new file mode 100644 index 00000000..746f3dde --- /dev/null +++ b/khepri_evf.html @@ -0,0 +1,134 @@ + + + + +event_filter() = tree_event_filter()
An event filter.
+ + The following event filters are supported: +tree_event_filter()
priority() = integer()
An event filter priority.
+ +This is an integer to prioritize event filters: the greater the priority, +the more it is prioritized. Negative integers are allowed.
+ + The default priority is 0. + +tree_event_filter() = #evf_tree{path = khepri_path:native_pattern(), props = khepri_evf:tree_event_filter_props()}
A tree event filter.
+ + It takes a path pattern to monitor and optionally properties. + +tree_event_filter_props() = #{on_actions => [create | update | delete], priority => khepri_evf:priority()}
Tree event filter properties.
+ + The properties are: +on_actions
: a list of actions to filter among create
, update
and
+ delete
; the default is to react to all of them.priority
: a priority()
tree/1 | Constructs a tree event filter. |
tree/2 | Constructs a tree event filter. |
wrap/1 | Automatically detects the event filter type and ensures it is wrapped + in one of the internal types. |
get_priority/1 | Returns the priority of the event filter. |
set_priority/2 | Sets the priority of the event filter. |
tree(PathPattern) -> EventFilter
+
PathPattern = khepri_path:pattern() | string()
EventFilter = tree_event_filter()
Constructs a tree event filter. +
+See also: tree/2.
+ +tree(PathPattern, Props) -> EventFilter
+
PathPattern = khepri_path:pattern() | string()
Props = tree_event_filter_props()
EventFilter = tree_event_filter()
Constructs a tree event filter. +
+See also: tree_event_filter().
+ +wrap(Input) -> EventFilter
+
Input = event_filter() | khepri_path:pattern() | string()
EventFilter = event_filter()
Input
: an already created event filter, or any term which can be
+ automatically converted to an event filter.
+
+
returns: the created event filter.
+Automatically detects the event filter type and ensures it is wrapped + in one of the internal types. +
+ +get_priority(EventFilter) -> Priority
+
EventFilter = event_filter()
Priority = priority()
EventFilter
: the event filter to update.
+
+
returns: the priority.
+Returns the priority of the event filter. +
+ +set_priority(EventFilter, Priority) -> EventFilter
+
EventFilter = event_filter()
Priority = priority()
EventFilter
: the event filter to update.
+Priority
: the new priority.
+
+
returns: the updated event filter.
+Sets the priority of the event filter. +
+Generated by EDoc
+ + diff --git a/khepri_export_erlang.html b/khepri_export_erlang.html new file mode 100644 index 00000000..ffeb271d --- /dev/null +++ b/khepri_export_erlang.html @@ -0,0 +1,40 @@ + + + + +Khepri import/export callback module using Erlang terms formatted as +plain text as its external format.
+ +The exported file could be read using file:consult/1
to get back
+the list of backup items.
This callback module takes a filename or an opened file descriptor as its
+ private data passed to khepri:export/4
and khepri:import/3
.
ok = khepri:put(StoreId, "/:stock/:wood/Oak", 100).
+ok = khepri:put(StoreId, "/:stock/:wood/Mapple", 55).
+ok = khepri:export(StoreId, khepri_export_erlang, "export.erl").
+
+ Content of export.erl
:
+ {put,[stock,wood,<<"Mapple">>],{p_data,55},#{},#{}}.
+{put,[stock,wood,<<"Oak">>],{p_data,100},#{},#{}}.
Generated by EDoc
+ + diff --git a/khepri_import_export.html b/khepri_import_export.html new file mode 100644 index 00000000..4b5bc903 --- /dev/null +++ b/khepri_import_export.html @@ -0,0 +1,142 @@ + + + + +This module defines the khepri_import_export
behaviour.
Required callback functions: open_write/1
, write/2
, commit_write/1
, abort_write/1
, open_read/1
, read/1
, close_read/1
.
Wrapper around Mnesia Backup & Restore callback modules.
+ +Khepri uses the same callback module as Mnesia to implement its import and + export feature. The Mnesia Backup + & Restore API is described in the Mnesia documentation.
+ + Mnesia doesn't provide an Erlang behavior module to ease development. This + module can be used as the behavior instead. For example: +-module(my_export_module).
+-behavior(khepri_import_export).
+
+-export([open_write/1,
+ write/2,
+ commit_write/1,
+ abort_write/1,
+
+ open_read/1,
+ read/1,
+ close_read/1]).
+
+ There are two sets of callback functions to implement: one used during +export (or "backup" in Mnesia terms), one used during import (or "restore" +in Mnesia terms).
+ +Module:open_write(Args)
This function is called at the beginning of an export. It is responsible
+ for any initialization and must return an {ok, ModulePriv}
tuple.
+ ModulePriv
is a private state passed to the following functions.
Module:write(ModulePriv, BackupItems)
This function is called for each subset of the items to export.
+BackupItems
is a list of opaque Erlang terms. The callback module
+ can't depend on the structure of these Erlang terms. Only the fact that it
+ is a list is guarantied.
An empty list of BackupItems
means this is the last call to
+ Module:write/2
. Otherwise, the way all items to export are split into
+ several subsets and thus several calls to Module:write/2
is
+ undefined.
At the end of each call, the function must return {ok, NewModulePriv}
.
+ This new private state is passed to the subsequent calls.
Module:commit_write(ModulePriv)
This function is called after successful calls to Module:write/2
. It
+ is responsible for doing any cleanup.
This function can return ok
or {ok, Ret}
if it wants to return some
+ Erlang terms to the caller.
Module:abort_write(ModulePriv)
This function is called after failed call to Module:write/2
, or if
+ reading from the Khepri store fails. It is responsible for doing any
+ cleanup.
This function can return ok
or {ok, Ret}
if it wants to return some
+ Erlang terms to the caller.
Module:open_read(Args)
This function is called at the beginning of an import. It is responsible
+ for any initialization and must return an {ok, ModulePriv}
tuple.
+ ModulePriv
is a private state passed to the following functions.
Module:read(ModulePriv)
This function is one or more times until there is nothing left to + import.
+The function must return {ok, BackupItems, NewModulePriv}
. This new
+ private state is passed to the subsequent calls.
BackupItems
is a list of opaque Erlang terms. The callback module
+ can't depend on the structure of these Erlang terms. The backup items must
+ be returned exactly as they were at the time of the export and in the same
+ order.
An empty list of BackupItems
means this is the last batch.
+ Module:read/1
won't be called anymore. Module:close_read/1
will be
+ called next instead.
Module:close_read(ModulePriv)
This function is called after the last call to Module:read/1
,
+ successful or not, or if the actual import into the Khepri store fails. It
+ is responsible for doing any cleanup.
This function can return ok
or {ok, Ret}
if it wants to return some
+ Erlang terms to the caller.
khepri_export_erlang
. This module offers to
+ export Khepri tree nodes in a plain text file where backup items are
+ formatted as Erlang terms.
+backup_item() = term()
An opaque term passed in a list to Module:write/2
and returned by
+ Module:read/1
.
module_priv() = any()
Private data passed to Module:open_write/1
or Module:open_read/1
+initially.
Generated by EDoc
+ + diff --git a/khepri_machine.html b/khepri_machine.html new file mode 100644 index 00000000..2d21bcc1 --- /dev/null +++ b/khepri_machine.html @@ -0,0 +1,299 @@ + + + + +Behaviours: ra_machine
.
+Khepri private low-level API.
+ +This module exposes the private "low-level" API to the Khepri database and
+ state machine. Main functions correspond to Ra commands implemented by the
+ state machine. All functions in khepri
are built on top of this
+module.
This module is private. The documentation is still visible because it may +help understand some implementation details. However, this module should +never be called directly outside of Khepri.
+ +Version | What changed |
---|---|
0 | +Initial version | +
1 | +
+
|
+
2 | +
+
|
+
async_ret() = ok
command() = #put{path = khepri_path:native_pattern(), payload = khepri_payload:payload(), options = khepri:tree_options() | khepri:put_options()} | #delete{path = khepri_path:native_pattern(), options = khepri:tree_options()} | #tx{'fun' = horus:horus_fun() | khepri_path:pattern(), args = list()} | #register_trigger{id = khepri:trigger_id(), event_filter = khepri_evf:event_filter(), sproc = khepri_path:native_path()} | #ack_triggered{triggered = [khepri_machine:triggered()]} | #register_projection{pattern = khepri_path:native_pattern(), projection = khepri_projection:projection()} | #unregister_projections{names = all | [khepri_projection:name()]} | #dedup{ref = reference(), expiry = integer(), command = khepri_machine:command()} | #dedup_ack{ref = reference()}
Commands specific to this Ra machine.
+ +common_ret() = khepri:ok(khepri_adv:node_props_map()) | khepri:error()
dedups_map() = #{reference() => {any(), integer()}}
Map to handle command deduplication.
+ +machine_config() = #config{store_id = khepri:store_id(), member = ra:server_id(), snapshot_interval = non_neg_integer()}
Configuration record, holding read-only or rarely changing fields.
+ +machine_init_args() = #{store_id := khepri:store_id(), member := ra:server_id(), snapshot_interval => non_neg_integer(), commands => [command()], atom() => any()}
Structure passed to init/1
.
metrics() = #{applied_command_count => non_neg_integer()}
Internal state machine metrics.
+ +old_command() = #unregister_projection{name = khepri_projection:name()}
Old commands that are still accepted by the Ra machine but never created.
+ +Even though Khepri no longer creates these commands, they may still be +present in existing Ra log files and thus be applied after an ugprade of +Khepri.
+ + We keep them supported for backward-compatibility. + +projection_map() = #{khepri_projection:name() => khepri_path:pattern()}
A mapping between the names of projections and patterns to which each + projection is registered.
+ +projection_tree() = khepri_pattern_tree:tree([khepri_projection:projection()])
A pattern tree that holds all registered projections in the machine's state.
+ +props() = #{payload_version := khepri:payload_version(), child_list_version := khepri:child_list_version()}
Properties attached to each node in the tree structure.
+ +state() = state_v1() | khepri_machine_v0:state()
State of this Ra state machine.
+ +abstract datatype: state_v1()
State of this Ra state machine, version 1.
+ + Note that this type is used also for machine version 2. Machine version 2 + changes the type of an opaque member of thekhepri_tree
record and
+ doesn't need any changes to the khepri_machine
type. See the moduledoc of
+ this module for more information about version 2.
+
+triggered() = #triggered{id = khepri:trigger_id(), event_filter = khepri_evf:event_filter(), sproc = horus:horus_fun(), props = map()}
triggers_map() = #{khepri:trigger_id() => #{sproc := khepri_path:native_path(), event_filter := khepri_evf:event_filter()}}
Internal triggers map in the machine state.
+ +tx_ret() = khepri:ok(khepri_tx:tx_fun_result()) | khepri_tx:tx_abort() | no_return()
fold/5 | Returns all tree nodes matching the given path pattern. |
fence/2 | Blocks until all updates received by the cluster leader are applied + locally. |
delete/3 | Deletes all tree nodes matching the path pattern. |
transaction/5 | Runs a transaction and returns the result. |
handle_tx_exception/1 | |
register_trigger/5 | Registers a trigger. |
register_projection/4 | Registers a projection. |
unregister_projections/3 | Removes the given projections from the store. |
version/0 | Returns the state machine version. |
which_module/1 | Returns the state machine module corresponding to the given version. |
fold(StoreId, PathPattern, Fun, Acc, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Options = khepri:query_options() | khepri:tree_options()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
StoreId
: the name of the Ra cluster.
+PathPattern
: the path (or path pattern) to the nodes to get.
+Options
: query options such as favor
.
+
+
returns: an {ok, NodePropsMap}
tuple with a map with zero, one or more
+ entries, or an {error, Reason}
tuple.
Returns all tree nodes matching the given path pattern. +
+ +fence(StoreId, Timeout) -> Ret
+
StoreId = khepri:store_id()
Timeout = timeout()
Ret = ok | khepri:error()
StoreId
: the name of the Ra cluster
+Timeout
: the time limit after which the call returns with an error.
+
+
returns: ok
or an {error, Reason}
tuple.
Blocks until all updates received by the cluster leader are applied + locally. +
+ +delete(StoreId, PathPattern, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Options = khepri:command_options() | khepri:tree_options()
Ret = khepri_machine:common_ret() | khepri_machine:async_ret()
StoreId
: the name of the Ra cluster.
+PathPattern
: the path (or path pattern) to the nodes to delete.
+Options
: command options such as the command type.
+
+
returns: in the case of a synchronous delete, an {ok, NodePropsMap}
tuple
+ with a map with zero, one or more entries, or an {error, Reason}
tuple;
+ in the case of an asynchronous put, always ok
(the actual return value
+ may be sent by a message if a correlation ID was specified).
Deletes all tree nodes matching the path pattern. +
+ +transaction(StoreId, FunOrPath, Args, ReadWrite, Options) -> Ret
+
StoreId = khepri:store_id()
FunOrPath = Fun | PathPattern
Fun = khepri_tx:tx_fun()
PathPattern = khepri_path:pattern()
Args = list()
ReadWrite = ro | rw | auto
Options = khepri:command_options() | khepri:query_options()
Ret = khepri_machine:tx_ret() | khepri_machine:async_ret()
StoreId
: the name of the Ra cluster.
+FunOrPath
: an arbitrary anonymous function or a path pattern pointing
+ to a stored procedure.
+Args
: a list of arguments to pass to FunOrPath
.
+ReadWrite
: the read/write or read-only nature of the transaction.
+Options
: command options such as the command type.
+
+
returns: in the case of a synchronous transaction, {ok, Result}
where
+ Result
is the return value of FunOrPath
, or {error, Reason}
if the
+ anonymous function was aborted; in the case of an asynchronous transaction,
+ always ok
(the actual return value may be sent by a message if a
+ correlation ID was specified).
Runs a transaction and returns the result. +
+ +handle_tx_exception(X1) -> any()
register_trigger(StoreId, TriggerId, EventFilter, StoredProcPath, Options) -> Ret
+
StoreId = khepri:store_id()
TriggerId = khepri:trigger_id()
EventFilter = khepri_evf:event_filter() | khepri_path:pattern()
StoredProcPath = khepri_path:path()
Options = khepri:command_options()
Ret = ok | khepri:error()
StoreId
: the name of the Ra cluster.
+TriggerId
: the name of the trigger.
+EventFilter
: the event filter used to associate an event with a
+ stored procedure.
+StoredProcPath
: the path to the stored procedure to execute when the
+ corresponding event occurs.
+
+
returns: ok
if the trigger was registered, an {error, Reason}
tuple
+ otherwise.
Registers a trigger. +
+ +register_projection(StoreId, PathPattern, Projection, Options) -> Ret
+
StoreId = khepri:store_id()
PathPattern = khepri_path:pattern()
Projection = khepri_projection:projection()
Options = khepri:command_options()
Ret = ok | khepri:error()
StoreId
: the name of the Ra cluster.
+PathPattern
: the pattern of tree nodes which should be projected.
+Projection
: the projection record created with khepri_projection:new/3
.
+Options
: command options such as the command type.
+
+
returns: ok
if the projection was registered, an {error, Reason}
tuple
+ otherwise.
Registers a projection. +
+ +unregister_projections(StoreId, Names, Options) -> Ret
+
StoreId = khepri:store_id()
Names = all | [khepri_projection:name()]
Options = khepri:command_options()
Ret = khepri:ok(khepri_machine:projection_map()) | khepri:error()
StoreId
: the name of the Ra cluster.
+Names
: the names of projections to unregister or the atom all
to
+ remove all projections.
+Options
: command options such as the command type.
+
+
returns: {ok, ProjectionMap}
if the command succeeds, {error, Reason}
+ otherwise. The ProjectionMap
is a map with projection names (khepri_projection:name()
keys associated to the pattern to which each
+ projection was registered.
Removes the given projections from the store.
+ +Names
may either be a list of projection names to remove or the atom
+ all
. When all
is passed, every projection in the store is removed.
+
+
+version() -> MacVer
+
MacVer = 2
Returns the state machine version.
+ +which_module(MacVer) -> Module
+
MacVer = 0..2
Module = khepri_machine
Returns the state machine module corresponding to the given version.
+Generated by EDoc
+ + diff --git a/khepri_path.html b/khepri_path.html new file mode 100644 index 00000000..54ec8059 --- /dev/null +++ b/khepri_path.html @@ -0,0 +1,280 @@ + + + + +Khepri path API.
+ +A path is the type used by Khepri to reference nodes in the tree structure. +A path describes how to reach a node from the root node.
+ +A path, or native path, is a list of components. Components can be +Erlang atoms and binaries. Example:
+ +%% Native path.
+Path = [stock, wood, <<"oak">>].
+
+ A path may contain conditions to tune how a node is matched or to match
+ multiple nodes at once. This is called a path pattern. A path
+ pattern may contain conditions in addition to regular components (Erlang
+ atoms and binaries). See khepri_condition
to learn more about
+conditions. Example:
%% Path pattern with a condition on `wood'.
+PathPattern = [stock,
+ #if_all{conditions = [wood,
+ #if_node_exists{exists = true}]},
+ oak].
+
+ To be user-friendly, string-based and binary-based Unix-like paths
+ are accepted by most functions. The syntax of these Unix paths is
+ described in the unix_path()
type documentation. Example:
%% Unix path, equivalent of the first native path example.
+UnixPath = "/:stock/:wood/oak".
+component() = node_id() | 47 | 46 | 94
Component name in a path to a node.
+ +native_path() = [component()]
Native path to a node.
+ +A native path is a list of atoms, binaries and special components.
+ +It is called native because it requires no further processing
+ (unlike unix_path()
) and is the format used internally by the state
+machine.
?KHEPRI_ROOT_NODE
to explicitly mark the root node. A path is absolute
+ by default. Using ?KHEPRI_ROOT_NODE
is only useful when manipulating the
+ root node itself (querying it or storing something in the root node).?THIS_KHEPRI_NODE
to make a relative path (the default being an
+ absolute path). This is mostly useful for khepri_condition:keep_while()
to make it easy to put a condition on the
+ node itself.?PARENT_KHEPRI_NODE
to target the parent of a node, with the same
+ benefits and use cases as ?THIS_KHEPRI_NODE
.Example:
+ +%% Native path.
+Path = [stock, wood, <<"oak">>].
+
+native_pattern() = [pattern_component()]
Path pattern which may match zero, one or more nodes.
+ +A native pattern is a list of atoms, binaries, special components and +conditions.
+ +It is called native because it requires no further processing
+ (unlike unix_pattern()
) and is the format used internally by the
+state machine.
See native_path()
for a description of special components.
Conditions are any condition defined by khepri_condition:condition()
.
Example:
+ +%% Path pattern with a condition on `wood'.
+PathPattern = [stock,
+ #if_all{conditions = [wood,
+ #if_node_exists{exists = true}]},
+ oak].
+
+node_id() = atom() | binary()
A node name.
+ +path() = native_path() | unix_path()
Path to a node.
+ +pattern() = native_pattern() | unix_pattern()
Path pattern which may match zero, one or more nodes.
+ +pattern_component() = component() | khepri_condition:condition()
Path pattern component which may match zero, one or more nodes.
+ +unix_path() = string() | binary()
Unix-like path to a node.
+ +These Unix paths have the following syntax:
+ +/
.:
character: :wood
.oak
./
, otherwise it is considered a
+ relative path.
and ..
represent ?THIS_KHEPRI_NODE
and ?PARENT_KHEPRI_NODE
+ respectivelyabc*def
is the same as #if_name_matches{regex = "^abc.*def$"}
*
is the same as ?KHEPRI_WILDCARD_STAR
or #if_name_matches{regex =
+ any}
**
is the same as ?KHEPRI_WILDCARD_STAR_STAR
or
+ if_path_matches{regex = any}
Warning: There is no special handling of Unicode in tree +node names. To use Unicode, it is recommended to either use a native path or +a binary-based Unix-like path. If using a string-based Unix-like path, the +behavior is undefined and the call may crash. Matching against node names is +also undefined behavior and may crash, regardless of the type of path being +used. It will be improved in the future.
+ + Example: +%% Unix path, equivalent of the first native path example.
+UnixPath = "/:stock/:wood/oak".
+
+unix_pattern() = string() | binary()
Unix-like path pattern to a node.
+ + It accepts the following special characters: +*
anywhere in a path component behaves like a khepri_condition:if_name_matches()
.**
as a path component behaves like a khepri_condition:if_path_matches()
.A Unix-like path pattern can't express all the conditions of a native path +pattern currently.
+ +Otherwise it works as a unix_path()
and has the same syntax and
+limitations.
%% Unix path pattern, matching multiple types of oak.
+UnixPathPattern = "/:stock/:wood/*oak".
+
+from_string/1 | Converts a Unix-like path to a native path. |
from_binary/1 | Converts a Unix-like path to a native path. |
to_string/1 | Converts a native path to a string. |
to_binary/1 | Converts a native path to a binary. |
combine_with_conditions/2 | |
targets_specific_node/1 | |
is_valid/1 | |
ensure_is_valid/1 | |
abspath/2 | |
realpath/1 | |
pattern_includes_root_node/1 |
from_string(String) -> PathPattern
+
String = pattern()
PathPattern = native_pattern()
Converts a Unix-like path to a native path.
+ +The Unix-like string can be either an Erlang string or an Erlang binary.
+ + For convenience, a native path is also accepted and returned as-is. + +from_binary(String) -> PathPattern
+
String = pattern()
PathPattern = native_pattern()
Converts a Unix-like path to a native path.
+ + This is the same as callingfrom_string(String)
. Therefore, it accepts
+ Erlang strings or binaries and native paths.
+
+See also: from_string/1.
+ +to_string(NativePath) -> UnixPath
+
NativePath = native_path()
UnixPath = string()
Converts a native path to a string.
+ +to_binary(NativePath) -> UnixPath
+
NativePath = native_path()
UnixPath = binary()
Converts a native path to a binary.
+ +combine_with_conditions(PathPattern, Conditions) -> PathPattern
+
PathPattern = native_pattern()
Conditions = [khepri_condition:condition()]
targets_specific_node(PathPattern) -> Ret
+
PathPattern = native_pattern()
Ret = {true, Path} | false
Path = native_path()
is_valid(PathPattern) -> IsValid
+
PathPattern = native_pattern()
IsValid = true | {false, ComponentPattern}
ComponentPattern = pattern_component()
ensure_is_valid(PathPattern) -> ok | no_return()
+
PathPattern = native_pattern()
abspath(Path, BasePath) -> Path
+
Path = native_pattern()
BasePath = native_pattern()
realpath(Path) -> Path
+
Path = native_pattern()
pattern_includes_root_node(Path) -> any()
Generated by EDoc
+ + diff --git a/khepri_payload.html b/khepri_payload.html new file mode 100644 index 00000000..9bb678e7 --- /dev/null +++ b/khepri_payload.html @@ -0,0 +1,118 @@ + + + + +Khepri payloads.
+ + Payloads are the structure used to attach something to a tree node in the + store. Khepri supports the following payloads: +no_payload()
data()
)sproc()
)wrap/1
function already
+ called internally.
+data() = #p_data{data = khepri:data()}
Internal structure to wrap any Erlang term before it can be stored in a +tree node.
+ + The only constraint is the conversion to an Erlang binary must be supported + by this term. + +no_payload() = '$__NO_PAYLOAD__'
Internal value used to mark that a tree node has no payload attached.
+ +payload() = no_payload() | data() | sproc()
All types of payload stored in the nodes of the tree structure.
+ + Beside the absence of payload, the only type of payload supported is data. + +sproc() = #p_sproc{sproc = horus:horus_fun(), is_valid_as_tx_fun = ro | rw | false}
Internal structure to wrap an anonymous function before it can be stored in + a tree node and later executed.
+ +none/0 | Returns the internal value used to mark that a tree node has no + payload attached. |
data/1 | Returns the same term wrapped into an internal structure ready to be + stored in the tree. |
sproc/1 | Returns the same function wrapped into an internal structure ready to + be stored in the tree. |
wrap/1 | Automatically detects the payload type and ensures it is wrapped in +one of the internal types. |
none() -> no_payload()
Returns the internal value used to mark that a tree node has no + payload attached. +
+See also: no_payload().
+ +data(Term) -> Payload
+
Term = khepri:data()
Payload = data()
Returns the same term wrapped into an internal structure ready to be + stored in the tree. +
+See also: data().
+ +sproc(Fun) -> Payload
+
Fun = horus:horus_fun() | function()
Payload = sproc()
Returns the same function wrapped into an internal structure ready to + be stored in the tree. +
+See also: sproc().
+ +wrap(Payload) -> WrappedPayload
+
Payload = payload() | khepri:data() | function()
WrappedPayload = payload()
Payload
: an already wrapped payload, or any term which needs to be
+ wrapped.
+
+
returns: the wrapped payload.
+Automatically detects the payload type and ensures it is wrapped in +one of the internal types.
+ + The internal types make sure we avoid any collision between any + user-provided terms and internal structures. + +Generated by EDoc
+ + diff --git a/khepri_prefix_tree.html b/khepri_prefix_tree.html new file mode 100644 index 00000000..a9a86350 --- /dev/null +++ b/khepri_prefix_tree.html @@ -0,0 +1,99 @@ + + + + +abstract datatype: tree(Payload)
empty/0 | Returns a new empty tree. |
is_prefix_tree/1 | Determines whether the given term is a prefix tree. |
from_map/1 | Converts a map of paths to payloads into a prefix tree. |
fold_prefixes_of/4 | Folds over all nodes in the tree which are prefixed by the given Path
+ building an accumulated value with the given fold function and initial
+ accumulator. |
find_path/2 | Returns the payload associated with a path in the tree. |
update/3 | Updates a given path in the tree. |
empty() -> tree(term())
Returns a new empty tree. +
+See also: tree().
+ +is_prefix_tree(Prefix_tree::tree(term())) -> true
is_prefix_tree(Prefix_tree::term()) -> false
Determines whether the given term is a prefix tree.
+ +from_map(Map) -> Tree
+
Map = #{khepri_path:native_path() => Payload}
Tree = khepri_prefix_tree:tree(Payload)
Payload = term()
Converts a map of paths to payloads into a prefix tree.
+ +fold_prefixes_of(Fun, Acc, Path, Tree) -> Ret
+
Fun = fun((Payload, Acc) -> Acc1)
Acc = term()
Acc1 = term()
Path = khepri_path:native_path()
Tree = khepri_prefix_tree:tree(Payload)
Payload = term()
Ret = Acc1
Folds over all nodes in the tree which are prefixed by the given Path
+ building an accumulated value with the given fold function and initial
+ accumulator.
find_path(Path, Tree) -> Ret
+
Path = khepri_path:native_path()
Tree = khepri_prefix_tree:tree(Payload)
Payload = term()
Ret = {ok, Payload} | error
returns: {ok, Payload}
where Payload
is associated with the given path
+ or error
if the path is not associated with a payload in the given tree.
Returns the payload associated with a path in the tree. +
+ +update(Fun, Path, Tree) -> Ret
+
Fun = fun((Payload | '$__NO_PAYLOAD__') -> Payload | '$__NO_PAYLOAD__')
Path = khepri_path:native_path()
Tree = khepri_prefix_tree:tree(Payload)
Payload = term()
Ret = khepri_prefix_tree:tree(Payload)
Updates a given path in the tree.
+ +This function can be used to create, update or delete tree nodes. If the
+ tree node does not exist for the given path, the update function is passed
+ ?NO_PAYLOAD
. If the update function returns ?NO_PAYLOAD
then the tree
+node and all of its ancestors which do not have a payload or children are
+removed.
?NO_PAYLOAD
if a tree node exists
+ but does not have a payload: being passed ?NO_PAYLOAD
is not a reliable
+ sign that a tree node did not exist prior to an update.
+Generated by EDoc
+ + diff --git a/khepri_projection.html b/khepri_projection.html new file mode 100644 index 00000000..42a068bb --- /dev/null +++ b/khepri_projection.html @@ -0,0 +1,163 @@ + + + + +Khepri projections
+ +Projections build a replicated ETS table using tree nodes from the store
+ which match a khepri_path:pattern()
. When a tree node matching a
+ projection's pattern is changed in the store, the tree node is passed
+ through the projection's projection_fun()
to create record(s).
+These records are then stored in the projection's ETS table for all members
+in a Khepri cluster.
Projections provide a way to query the store as fast as possible and are +appropriate for lookups which require low latency and/or high throughput. +Projection tables contain all records matching the pattern, though, so the +memory footprint of a projection table grows with the number of tree nodes +in the store matching the pattern.
+ +Projection ETS tables are owned by the Khepri cluster and are deleted when +the cluster stops.
+ + Updates to projection tables are immediately consistent for the member of + the cluster on which the change to the store is made and the leader member + but are eventually consistent for all other followers. +extended_projection_fun() = fun((Table::ets:tid(), Path::khepri_path:native_path(), OldPayload::khepri:node_props(), NewPayload::khepri:node_props()) -> any())
An extended projection function.
+ +In some cases, a tree node in the store might correspond to many objects in +a projection table. Extended projection functions are allowed to call ETS +functions directly in order to build the projection table.
+ +OldPayload
or NewPayload
are empty maps if there is no tree node. For
+ example, a newly created tree node will have an empty map for OldPayload
+ and a khepri:node_props()
map with values for NewPayload
.
This function is compiled like a transaction function except that calls
+ to the ets
module are allowed.
name() = atom()
The name of a projection. +
+ +options() = #{type => ets:table_type(), keypos => pos_integer(), read_concurrency => boolean(), write_concurrency => boolean() | auto, compressed => boolean(), standalone_fun_options => horus:options()}
Options which control the created ETS table.
+ +If provided, standalone_fun_options
are merged with defaults and passed to
+ horus:to_standalone_fun/2
. The remaining options are a subset of the
+ options available to ets:new/2
. Refer to the ets:new/2
+documentation for a reference on each type and available values.
simple_projection_fun()
, the
+ type
option may only be set
or ordered_set
: bag
types are not
+ allowed. extended_projection_fun()
s may use any valid ets:table_type()
.
+
+projection() = #khepri_projection{name = atom(), projection_fun = copy | horus:horus_fun(), ets_options = [atom() | tuple()]}
A projection resource. +
+ +projection_fun() = copy | simple_projection_fun() | extended_projection_fun()
A function that formats an entry in the tree into a record to be stored in a +projection.
+ + Projection functions may either be: +simple_projection_fun()
.extended_projection_fun()
.simple_projection_fun() = fun((Path::khepri_path:native_path(), Payload::khepri:data()) -> Record::tuple())
A simple projection function.
+ +Simple projection functions only take the path and payload for a tree node +in the store. The record produced by the function is used to create and +delete objects in the ETS table.
+ + This function is compiled the same way as a transaction function: all + side-effects are not allowed. Additionally, for anyPath
and Payload
+ inputs, this function must consistently return the same Record
.
+
+new/2 | |
new/3 | Creates a new projection data structure. |
name/1 | Returns the name of the given Projection . |
new(Name, ProjectionFun) -> Projection
+
Name = khepri_projection:name()
ProjectionFun = khepri_projection:projection_fun()
Projection = khepri_projection:projection()
See also: khepri:register_projection/4, khepri_projection:new/3, khepri_projection:new/3.
+ +new(Name, ProjectionFun, Options) -> Projection
+
Name = khepri_projection:name()
ProjectionFun = khepri_projection:projection_fun()
Options = khepri_projection:options()
Projection = khepri_projection:projection()
Name
: the name of the projection. This corresponds to the name of
+ the ETS table which is created when the projection is registered.
+ProjectionFun
: the function which turns paths and data into records
+ to be stored in the projection table.
+Options
: options which control properties of the projection table.
+
+
returns: a projection()
resource.
Creates a new projection data structure.
+ + This function throws an error in the shape of{unexpected_option, Key,
+ Value}
when an unknown or invalid option()
is passed. For example,
+ if the passed ProjectionFun
is a simple_projection_fun()
and the
+ Options
map sets the type
to bag
, this function throws
+ {unexpected_option, type, bag}
since bag
is not valid for simple
+ projection funs.
+
+
+name(Projection) -> Name
+
Projection = projection()
Name = khepri_projection:name()
Returns the name of the given Projection
.
Generated by EDoc
+ + diff --git a/khepri_tx.html b/khepri_tx.html new file mode 100644 index 00000000..9396322f --- /dev/null +++ b/khepri_tx.html @@ -0,0 +1,723 @@ + + + + +Khepri API for transactional queries and updates.
+ +Transactions are anonymous functions which take no arguments, much like +what Mnesia supports. However, unlike with Mnesia, transaction functions in +Khepri are restricted:
+ +khepri_tx_adv:is_remote_call_valid/3
for the complete
+ list.The reason is that the transaction function must always have the exact same +outcome given its inputs. Indeed, the transaction function is executed on +every Ra cluster members participating in the consensus. The function must +therefore modify the Khepri state (the database) identically on all Ra +members. This is also true for Ra members joining the cluster later or +catching up after a network partition.
+ + To achieve that: +khepri_tx_adv
module.
+tx_abort() = khepri:error(any())
Return value after a transaction function aborted.
+ +tx_fun() = function()
Transaction function signature.
+ +tx_fun_result() = any() | no_return()
Return value of a transaction function.
+ +is_empty/0 | Indicates if the store is empty or not. |
is_empty/1 | Indicates if the store is empty or not. |
get/1 | Returns the payload of the tree node pointed to by the given path +pattern. |
get/2 | Returns the payload of the tree node pointed to by the given path +pattern. |
get_or/2 | Returns the payload of the tree node pointed to by the given path +pattern, or a default value. |
get_or/3 | Returns the payload of the tree node pointed to by the given path +pattern, or a default value. |
get_many/1 | Returns payloads of all the tree nodes matching the given path +pattern. |
get_many/2 | Returns payloads of all the tree nodes matching the given path +pattern. |
get_many_or/2 | Returns payloads of all the tree nodes matching the given path +pattern, or a default payload. |
get_many_or/3 | Returns payloads of all the tree nodes matching the given path +pattern, or a default payload. |
exists/1 | Indicates if the tree node pointed to by the given path exists or not. |
exists/2 | Indicates if the tree node pointed to by the given path exists or not. |
has_data/1 | Indicates if the tree node pointed to by the given path has data or +not. |
has_data/2 | Indicates if the tree node pointed to by the given path has data or +not. |
is_sproc/1 | Indicates if the tree node pointed to by the given path holds a stored +procedure or not. |
is_sproc/2 | Indicates if the tree node pointed to by the given path holds a stored +procedure or not. |
count/1 | Counts all tree nodes matching the given path pattern. |
count/2 | Counts all tree nodes matching the given path pattern. |
fold/3 | Calls Fun on successive tree nodes matching the given path pattern,
+ starting with Acc . |
fold/4 | Calls Fun on successive tree nodes matching the given path pattern,
+ starting with Acc . |
foreach/2 | Calls Fun for each tree node matching the given path pattern. |
foreach/3 | Calls Fun for each tree node matching the given path pattern. |
map/2 | Produces a new map by calling Fun for each tree node matching the
+given path pattern. |
map/3 | Produces a new map by calling Fun for each tree node matching the
+given path pattern. |
filter/2 | Returns a map for which predicate Pred holds true in tree nodes
+matching the given path pattern. |
filter/3 | Returns a map for which predicate Pred holds true in tree nodes
+matching the given path pattern. |
put/2 | Sets the payload of the tree node pointed to by the given path +pattern. |
put/3 | Sets the payload of the tree node pointed to by the given path +pattern. |
put_many/2 | Sets the payload of all the tree nodes matching the given path pattern. |
put_many/3 | Sets the payload of all the tree nodes matching the given path pattern. |
create/2 | Creates a tree node with the given payload. |
create/3 | Creates a tree node with the given payload. |
update/2 | Updates an existing tree node with the given payload. |
update/3 | Updates an existing tree node with the given payload. |
compare_and_swap/3 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
compare_and_swap/4 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
delete/1 | Deletes the tree node pointed to by the given path pattern. |
delete/2 | Deletes the tree node pointed to by the given path pattern. |
delete_many/1 | Deletes all tree nodes matching the given path pattern. |
delete_many/2 | Deletes all tree nodes matching the given path pattern. |
clear_payload/1 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_payload/2 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_many_payloads/1 | Deletes the payload of all tree nodes matching the given path pattern. |
clear_many_payloads/2 | Deletes the payload of all tree nodes matching the given path pattern. |
abort/1 | Aborts the transaction. |
is_transaction/0 | Indicates if the calling function runs in the context of a transaction + function. |
is_empty() -> IsEmpty | Error
+
IsEmpty = boolean()
Error = khepri:error()
Indicates if the store is empty or not.
+ + This is the same askhepri:is_empty/1
but inside the context of a
+ transaction function.
+
+See also: is_empty/1, khepri:is_empty/2.
+ +is_empty(Options) -> IsEmpty | Error
+
Options = khepri:tree_options()
IsEmpty = boolean()
Error = khepri:error()
Indicates if the store is empty or not.
+ + This is the same askhepri:is_empty/2
but inside the context of a
+ transaction function.
+
+See also: khepri:is_empty/2.
+ +get(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:payload_ret()
Returns the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri:get/2
but inside the context of a
+ transaction function.
+
+See also: khepri:get/2.
+ +get(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri:payload_ret()
Returns the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri:get/3
but inside the context of a
+ transaction function.
+
+See also: khepri:get/3.
+ +get_or(PathPattern, Default) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Ret = khepri:payload_ret()
Returns the payload of the tree node pointed to by the given path +pattern, or a default value.
+ + This is the same askhepri:get_or/3
but inside the context of a
+ transaction function.
+
+See also: khepri:get_or/3.
+ +get_or(PathPattern, Default, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = khepri:tree_options()
Ret = khepri:payload_ret()
Returns the payload of the tree node pointed to by the given path +pattern, or a default value.
+ + This is the same askhepri:get_or/4
but inside the context of a
+ transaction function.
+
+See also: khepri:get_or/4.
+ +get_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:many_payloads_ret()
Returns payloads of all the tree nodes matching the given path +pattern.
+ + This is the same askhepri:get_many/2
but inside the context of a
+ transaction function.
+
+See also: khepri:get_many/2.
+ +get_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri:many_payloads_ret()
Returns payloads of all the tree nodes matching the given path +pattern.
+ + This is the same askhepri:get_many/3
but inside the context of a
+ transaction function.
+
+See also: khepri:get_many/3.
+ +get_many_or(PathPattern, Default) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Ret = khepri:many_payloads_ret()
Returns payloads of all the tree nodes matching the given path +pattern, or a default payload.
+ + This is the same askhepri:get_many_or/3
but inside the context of a
+ transaction function.
+
+See also: khepri:get_many_or/3.
+ +get_many_or(PathPattern, Default, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Default = khepri:data()
Options = khepri:tree_options()
Ret = khepri:many_payloads_ret()
Returns payloads of all the tree nodes matching the given path +pattern, or a default payload.
+ + This is the same askhepri:get_many_or/4
but inside the context of a
+ transaction function.
+
+See also: khepri:get_many_or/4.
+ +exists(PathPattern) -> Exists
+
PathPattern = khepri_path:pattern()
Exists = boolean()
Indicates if the tree node pointed to by the given path exists or not.
+ + This is the same askhepri:exists/2
but inside the context of a
+ transaction function.
+
+See also: khepri:exists/2.
+ +exists(PathPattern, Options) -> Exists
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Exists = boolean()
Indicates if the tree node pointed to by the given path exists or not.
+ + This is the same askhepri:exists/3
but inside the context of a
+ transaction function.
+
+See also: khepri:exists/3.
+ +has_data(PathPattern) -> HasData | Error
+
PathPattern = khepri_path:pattern()
HasData = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path has data or +not.
+ + This is the same askhepri:has_data/2
but inside the context of a
+ transaction function.
+
+See also: khepri:has_data/2.
+ +has_data(PathPattern, Options) -> HasData | Error
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
HasData = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path has data or +not.
+ + This is the same askhepri:has_data/3
but inside the context of a
+ transaction function.
+
+See also: khepri:has_data/3.
+ +is_sproc(PathPattern) -> IsSproc | Error
+
PathPattern = khepri_path:pattern()
IsSproc = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path holds a stored +procedure or not.
+ + This is the same askhepri:is_sproc/2
but inside the context of a
+ transaction function.
+
+See also: khepri:is_sproc/2.
+ +is_sproc(PathPattern, Options) -> IsSproc | Error
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
IsSproc = boolean()
Error = khepri:error()
Indicates if the tree node pointed to by the given path holds a stored +procedure or not.
+ + This is the same askhepri:is_sproc/3
but inside the context of a
+ transaction function.
+
+See also: khepri:is_sproc/3.
+ +count(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:ok(Count) | khepri:error()
Count = non_neg_integer()
Counts all tree nodes matching the given path pattern.
+ + This is the same askhepri:count/2
but inside the context of a
+ transaction function.
+
+See also: khepri:count/2.
+ +count(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri:ok(Count) | khepri:error()
Count = non_neg_integer()
Counts all tree nodes matching the given path pattern.
+ + This is the same askhepri:count/3
but inside the context of a
+ transaction function.
+
+See also: khepri:count/3.
+ +fold(PathPattern, Fun, Acc) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
Calls Fun
on successive tree nodes matching the given path pattern,
+ starting with Acc
.
khepri:fold/4
but inside the context of a
+ transaction function.
+
+See also: khepri:fold/4.
+ +fold(PathPattern, Fun, Acc, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:fold_fun()
Acc = khepri:fold_acc()
Options = khepri:tree_options()
Ret = khepri:ok(NewAcc) | khepri:error()
NewAcc = Acc
Calls Fun
on successive tree nodes matching the given path pattern,
+ starting with Acc
.
khepri:fold/5
but inside the context of a
+ transaction function.
+
+See also: khepri:fold/5.
+ +foreach(PathPattern, Fun) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:foreach_fun()
Ret = ok | khepri:error()
Calls Fun
for each tree node matching the given path pattern.
khepri:foreach/3
but inside the context of a
+ transaction function.
+
+See also: khepri:foreach/3.
+ +foreach(PathPattern, Fun, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:foreach_fun()
Options = khepri:tree_options()
Ret = ok | khepri:error()
Calls Fun
for each tree node matching the given path pattern.
khepri:foreach/4
but inside the context of a
+ transaction function.
+
+See also: khepri:foreach/4.
+ +map(PathPattern, Fun) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:map_fun()
Ret = khepri:ok(Map) | khepri:error()
Map = #{khepri_path:native_path() => khepri:map_fun_ret()}
Produces a new map by calling Fun
for each tree node matching the
+given path pattern.
khepri:map/3
but inside the context of a
+ transaction function.
+
+See also: khepri:map/3.
+ +map(PathPattern, Fun, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Fun = khepri:map_fun()
Options = khepri:tree_options()
Ret = khepri:ok(Map) | khepri:error()
Map = #{khepri_path:native_path() => khepri:map_fun_ret()}
Produces a new map by calling Fun
for each tree node matching the
+given path pattern.
khepri:map/4
but inside the context of a
+ transaction function.
+
+See also: khepri:map/4.
+ +filter(PathPattern, Pred) -> Ret
+
PathPattern = khepri_path:pattern()
Pred = khepri:filter_fun()
Ret = khepri:many_payloads_ret()
Returns a map for which predicate Pred
holds true in tree nodes
+matching the given path pattern.
khepri:filter/3
but inside the context of a
+ transaction function.
+
+See also: khepri:filter/3.
+ +filter(PathPattern, Pred, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Pred = khepri:filter_fun()
Options = khepri:tree_options()
Ret = khepri:many_payloads_ret()
Returns a map for which predicate Pred
holds true in tree nodes
+matching the given path pattern.
khepri:filter/4
but inside the context of a
+ transaction function.
+
+See also: khepri:filter/4.
+ +put(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri:put/3
but inside the context of a
+ transaction function.
+
+See also: khepri:put/3.
+ +put(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri:put/4
but inside the context of a
+ transaction function.
+
+See also: khepri:put/4.
+ +put_many(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Sets the payload of all the tree nodes matching the given path pattern.
+ + This is the same askhepri:put_many/3
but inside the context of a
+ transaction function.
+
+See also: khepri:put_many/3.
+ +put_many(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Sets the payload of all the tree nodes matching the given path pattern.
+ + This is the same askhepri:put_many/4
but inside the context of a
+ transaction function.
+
+See also: khepri:put_many/4.
+ +create(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Creates a tree node with the given payload.
+ + This is the same askhepri:create/3
but inside the context of a
+ transaction function.
+
+See also: khepri:create/3.
+ +create(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Creates a tree node with the given payload.
+ + This is the same askhepri:create/4
but inside the context of a
+ transaction function.
+
+See also: khepri:create/4.
+ +update(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload.
+ + This is the same askhepri:update/3
but inside the context of a
+ transaction function.
+
+See also: khepri:update/3.
+ +update(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload.
+ + This is the same askhepri:update/4
but inside the context of a
+ transaction function.
+
+See also: khepri:update/4.
+ +compare_and_swap(PathPattern, DataPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + This is the same askhepri:compare_and_swap/4
but inside the context
+ of a transaction function.
+
+See also: khepri:compare_and_swap/4.
+ +compare_and_swap(PathPattern, DataPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + This is the same askhepri:compare_and_swap/5
but inside the context
+ of a transaction function.
+
+See also: khepri:compare_and_swap/5.
+ +delete(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the tree node pointed to by the given path pattern.
+ + This is the same askhepri:delete/2
but inside the context
+ of a transaction function.
+
+See also: khepri:delete/2.
+ +delete(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri:minimal_ret()
Deletes the tree node pointed to by the given path pattern.
+ + This is the same askhepri:delete/3
but inside the context
+ of a transaction function.
+
+See also: khepri:delete/3.
+ +delete_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes all tree nodes matching the given path pattern.
+ + This is the same askhepri:delete_many/2
but inside the context
+ of a transaction function.
+
+See also: khepri:delete_many/2.
+ +delete_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri:minimal_ret()
Deletes all tree nodes matching the given path pattern.
+ + This is the same askhepri:delete_many/3
but inside the context
+ of a transaction function.
+
+See also: khepri:delete_many/3.
+ +clear_payload(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri:clear_payload/2
but inside the context
+ of a transaction function.
+
+See also: khepri:clear_payload/2.
+ +clear_payload(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri:clear_payload/3
but inside the context
+ of a transaction function.
+
+See also: khepri:clear_payload/3.
+ +clear_many_payloads(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri:minimal_ret()
Deletes the payload of all tree nodes matching the given path pattern.
+ + This is the same askhepri:clear_many_payloads/2
but inside the
+ context of a transaction function.
+
+See also: khepri:clear_many_payloads/2.
+ +clear_many_payloads(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri:minimal_ret()
Deletes the payload of all tree nodes matching the given path pattern.
+ + This is the same askhepri:clear_many_payloads/3
but inside the
+ context of a transaction function.
+
+See also: khepri:clear_many_payloads/3.
+ +abort(Reason) -> no_return()
+
Reason = any()
Reason
: term to return to caller of the transaction.
+
Aborts the transaction.
+ +Any changes so far are not committed to the store.
+ +khepri:transaction/1
and friends will return tx_abort()
.
+
+
+is_transaction() -> boolean()
returns: true
if the calling code runs inside a transaction function,
+ false
otherwise.
Indicates if the calling function runs in the context of a transaction + function. +
+Generated by EDoc
+ + diff --git a/khepri_tx_adv.html b/khepri_tx_adv.html new file mode 100644 index 00000000..c8dc9982 --- /dev/null +++ b/khepri_tx_adv.html @@ -0,0 +1,365 @@ + + + + +Khepri advanced API for transactional queries and updates.
+ + This module exposes variants of the functions inkhepri_tx
which
+ return more detailed return values for advanced use cases. See khepri_adv
for examples of use cases where this module could be useful.
+get/1 | Returns the payload of the tree node pointed to by the given path +pattern. |
get/2 | Returns the payload of the tree node pointed to by the given path +pattern. |
get_many/1 | Returns payloads of all the tree nodes matching the given path +pattern. |
get_many/2 | Returns payloads of all the tree nodes matching the given path +pattern. |
do_get_many/4 | |
put/2 | Sets the payload of the tree node pointed to by the given path +pattern. |
put/3 | Sets the payload of the tree node pointed to by the given path +pattern. |
put_many/2 | Sets the payload of all the tree nodes matching the given path pattern. |
put_many/3 | Sets the payload of all the tree nodes matching the given path pattern. |
create/2 | Creates a tree node with the given payload. |
create/3 | Creates a tree node with the given payload. |
update/2 | Updates an existing tree node with the given payload. |
update/3 | Updates an existing tree node with the given payload. |
compare_and_swap/3 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
compare_and_swap/4 | Updates an existing tree node with the given payload only if its data +matches the given pattern. |
delete/1 | Deletes the tree node pointed to by the given path pattern. |
delete/2 | Deletes the tree node pointed to by the given path pattern. |
delete_many/1 | Deletes all tree nodes matching the given path pattern. |
delete_many/2 | Deletes all tree nodes matching the given path pattern. |
clear_payload/1 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_payload/2 | Deletes the payload of the tree node pointed to by the given path +pattern. |
clear_many_payloads/1 | Deletes the payload of all tree nodes matching the given path pattern. |
clear_many_payloads/2 | Deletes the payload of all tree nodes matching the given path pattern. |
ensure_instruction_is_permitted/1 | |
should_process_function/4 | |
is_standalone_fun_still_needed/2 |
get(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Returns the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri_adv:get/2
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:get/2.
+ +get(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri_adv:single_result()
Returns the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri_adv:get/3
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:get/3.
+ +get_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Returns payloads of all the tree nodes matching the given path +pattern.
+ + This is the same askhepri_adv:get_many/2
but inside the context of
+ a transaction function.
+
+See also: khepri_adv:get_many/2.
+ +get_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri_adv:many_results()
Returns payloads of all the tree nodes matching the given path +pattern.
+ + This is the same askhepri_adv:get_many/3
but inside the context of
+ a transaction function.
+
+See also: khepri_adv:get_many/3.
+ +do_get_many(PathPattern, Fun, Acc, Options) -> any()
put(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri_adv:put/3
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:put/3.
+ +put(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result()
Sets the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri_adv:put/4
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:put/4.
+ +put_many(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:many_results()
Sets the payload of all the tree nodes matching the given path pattern.
+ + This is the same askhepri_adv:put_many/3
but inside the context of
+ a transaction function.
+
+See also: khepri_adv:put_many/3.
+ +put_many(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:many_results()
Sets the payload of all the tree nodes matching the given path pattern.
+ + This is the same askhepri_adv:put_many/4
but inside the context of
+ a transaction function.
+
+See also: khepri_adv:put_many/4.
+ +create(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Creates a tree node with the given payload.
+ + This is the same askhepri_adv:create/3
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:create/3.
+ +create(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result()
Creates a tree node with the given payload.
+ + This is the same askhepri_adv:create/4
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:create/4.
+ +update(PathPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload.
+ + This is the same askhepri_adv:update/3
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:update/3.
+ +update(PathPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload.
+ + This is the same askhepri_adv:update/4
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:update/4.
+ +compare_and_swap(PathPattern, DataPattern, Data) -> Ret
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + This is the same askhepri_adv:compare_and_swap/4
but inside the
+ context of a transaction function.
+
+See also: khepri_adv:compare_and_swap/4.
+ +compare_and_swap(PathPattern, DataPattern, Data, Options) -> Ret
+
PathPattern = khepri_path:pattern()
DataPattern = ets:match_pattern()
Data = khepri_payload:payload() | khepri:data() | function()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result()
Updates an existing tree node with the given payload only if its data +matches the given pattern.
+ + This is the same askhepri_adv:compare_and_swap/5
but inside the
+ context of a transaction function.
+
+See also: khepri_adv:compare_and_swap/5.
+ +delete(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Deletes the tree node pointed to by the given path pattern.
+ + This is the same askhepri_adv:delete/2
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:delete/2.
+ +delete(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri_adv:single_result()
Deletes the tree node pointed to by the given path pattern.
+ + This is the same askhepri_adv:delete/3
but inside the context of a
+ transaction function.
+
+See also: khepri_adv:delete/3.
+ +delete_many(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Deletes all tree nodes matching the given path pattern.
+ + This is the same askhepri_adv:delete_many/2
but inside the context
+ of a transaction function.
+
+See also: khepri_adv:delete_many/2.
+ +delete_many(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options()
Ret = khepri_adv:many_results()
Deletes all tree nodes matching the given path pattern.
+ + This is the same askhepri_adv:delete_many/3
but inside the context
+ of a transaction function.
+
+See also: khepri_adv:delete_many/3.
+ +clear_payload(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:single_result()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri_adv:clear_payload/2
but inside the
+ context of a transaction function.
+
+See also: khepri_adv:clear_payload/2.
+ +clear_payload(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:single_result()
Deletes the payload of the tree node pointed to by the given path +pattern.
+ + This is the same askhepri_adv:clear_payload/3
but inside the
+ context of a transaction function.
+
+See also: khepri_adv:clear_payload/3.
+ +clear_many_payloads(PathPattern) -> Ret
+
PathPattern = khepri_path:pattern()
Ret = khepri_adv:many_results()
Deletes the payload of all tree nodes matching the given path pattern.
+ + This is the same askhepri_adv:clear_many_payloads/2
but inside the
+ context of a transaction function.
+
+See also: khepri_adv:clear_many_payloads/2.
+ +clear_many_payloads(PathPattern, Options) -> Ret
+
PathPattern = khepri_path:pattern()
Options = khepri:tree_options() | khepri:put_options()
Ret = khepri_adv:many_results()
Deletes the payload of all tree nodes matching the given path pattern.
+ + This is the same askhepri_adv:clear_many_payloads/3
but inside the
+ context of a transaction function.
+
+See also: khepri_adv:clear_many_payloads/3.
+ +ensure_instruction_is_permitted(Unknown) -> any()
should_process_function(Module, Name, Arity, FromModule) -> any()
is_standalone_fun_still_needed(X1, X2) -> any()
Generated by EDoc
+ + diff --git a/modules-frame.html b/modules-frame.html new file mode 100644 index 00000000..118a4562 --- /dev/null +++ b/modules-frame.html @@ -0,0 +1,64 @@ + + + +Copyright © 2021-2024 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
+Version: Development branch +
+Authors: Jean-Sébastien Pédron (jean-sebastien.pedron@dumbbell.fr
), Michael Davis (mcarsondavis@gmail.com
), Diana Parra Corbacho (dparracorbac@vmware.com
), Karl Nilsson (nkarl@vmware.com
), The RabbitMQ team (rabbitmq-core@groups.vmware.com
).
+Khepri is a tree-like replicated on-disk database library for Erlang and +Elixir.
+ +Data are stored in a tree structure. Each node in the tree is +referenced by its path from the root node. A path is a list of Erlang atoms +and/or binaries. For ease of use, Unix-like path strings are accepted as well.
+ +For consistency and replication and to manage data on disk, +Khepri relies on Ra, an Erlang +implementation of the Raft consensus +algorithm. In Ra parlance, Khepri is a state machine in a Ra cluster.
+ +This page describes all the concepts in Khepri and points the +reader to the modules' documentation for more details.
+ + + +This started as an experiment to replace how data (other than message bodies) +are stored in the RabbitMQ messaging +broker. Before Khepri, those data were stored and replicated to cluster +members using Mnesia.
+ +Mnesia is very handy and powerful: +However, recovering from any network partitions is quite difficult. This was +the primary reason why the RabbitMQ team started to explore other options.
+ +Because RabbitMQ already uses an implementation of the Raft consensus algorithm +for its quorum queues, it was decided to leverage that library for all +metadata. That's how Khepri was borne.
+ +Thanks to Ra and Raft, it is clear how Khepri will behave during a +network partition and recover from it. This makes it more comfortable +for the RabbitMQ team and users, thanks to the absence of unknowns.
+ ++At the time of this writing, RabbitMQ does not use Khepri in a production +release yet because this library and its integration into RabbitMQ are still a +work in progress. ++ +
khepri_machine:tree_node()
) in a tree structure. Every tree node has:
+o
+|
++-- orders
+|
+`-- stock
+ |
+ `-- wood
+ |-- <<"mapple">> = 12
+ `-- <<"oak">> = 41
+
+A tree node name is either an Erlang atom or an Erlang binary (khepri_path:node_id()
).
A tree node may or may not have a payload. Khepri supports two types of +payload, the data payload and the stored procedure payload. +More payload types may be added in the future.
+ +When passed tokhepri:put/2
, the type of the payload is autodetected.
+However if you need to prepare the payload before passing it to Khepri, you can
+use the following functions:
+
+
+khepri:payload_version()
).khepri:child_list_version()
).khepri:child_list_count()
).The equivalent of a key in a key/value store is a path
+(khepri_path:path()
) in Khepri.
khepri_path:path()
). For instance:
+%% Points to "/:stock/:wood/oak" in the tree shown above:
+Path = [stock, wood, <<"oak">>].
+
+It is possible to target multiple tree nodes at once by using a path
+pattern (khepri_path:pattern()
). In addition to node IDs, path
+patterns have conditions (khepri_condition:condition()
). Conditions
+allow things like:
+%% Matches all varieties of wood in the stock:
+PathPattern = [stock, wood, #if_node_matches{regex = any}].
+
+%% Matches the supplier of oak if there is an active order:
+PathPattern = [order,
+ wood,
+ #if_all{conditions = [
+ <<"oak">>,
+ #if_data_matches{pattern = {active, true}}]},
+ supplier].
+
+Finally, a path can use some special path component names, handy when using
+relative paths:
+?THIS_NODE
to point to self?PARENT_NODE
to point to the parent tree node?ROOT_NODE
to explicitly point to the root unnamed nodeRelative paths are useful when putting conditions on +tree node lifetimes.
+ +A tree node's lifetime starts when it is inserted the first time and ends when +it is removed from the tree. However, intermediary tree nodes created on the +way remain in the tree long after the leaf node was removed.
+ +For instance, when [stock, wood, <<"walnut">>]
was inserted, the intermediary
+tree nodes stock
and wood
were created if they were missing. After
+<<"walnut">>
is removed, they will stay in the tree with possibly neither
+payload nor child nodes.
Khepri has the concept of keep_while
conditions. A keep_while
+condition is like the conditions which can be used inside path pattern. When a
+node is inserted or updated, it is possible to set keep_while
conditions:
+when these conditions evaluate to false, the tree node is removed from the
+tree.
[stock, wood]
+to make sure it is removed after its last child node is removed:
+%% We keep [stock, wood] as long as its child nodes count is strictly greater
+%% than zero.
+KeepWhileCondition = #{[stock, wood] => #if_child_list_length{count = {gt, 0}}}.
+
+keep_while
conditions on self (like the example above) are not evaluated on
+the first insert though.
A Khepri store corresponds to one Ra cluster. In fact, the name of the Ra +cluster is the name of the Khepri store. It is possible to have multiple +database instances running on the same Erlang node or cluster by starting +multiple Ra clusters. Note that it is called a "cluster" but it can have a +single member.
+ +You can start a Khepri store using start/0
up to start/3
. See
+those functions to learn more about the configuration settings.
To expand or shrink a cluster, khepri_cluster:join/1
and khepri_cluster:reset/0
allow a Khepri store node to join or leave a cluster.
The essential part of the public API is provided by the khepri
module.
+It covers most common use cases and should be straightforward to use.
ok = khepri:put([stock, wood, <<"lime tree">>], 150),
+
+{ok, 150} = khepri:get([stock, wood, <<"lime tree">>]),
+
+true = khepri:exists([stock, wood, <<"lime tree">>]),
+
+ok = khepri:delete([stock, wood, <<"lime tree">>]).
+
+Inside transaction functions, khepri_tx
must be used instead of khepri
. The former provides the same API, except for functions which don't
+make sense in the context of a transaction function.
khepri
and khepri_tx
both have counterparts for more advanced
+use cases, khepri_adv
and khepri_tx_adv
. The return values of
+the *_adv
modules are maps giving more details about what was queried or
+modified.
The public API is built on top of a low-level internal API, provided by the
+private khepri_machine
module.
On the surface, Khepri transactions look like Mnesia ones: they are anonymous +functions which can do any arbitrary operations on the data and return any +result. If something goes wrong or the anonymous function aborts, nothing is +committed and the database is left untouched as if the transaction code was +never called.
+ +Under the hood, there are several restrictions and caveats that need to be +understood in order to use transactions in Khepri: +The nature of the anonymous function is passed as the ReadWrite
argument to
+khepri:transaction/3
.
The Raft algorithm is used to achieve consensus among Khepri members +participating in the database. Khepri is a state machine executed on each Ra +node and all instances of that Khepri state machine start with the same state +and modify it identically. The goal is that, after the same list of Ra +commands, all instances have the same state.
+ +When a new Ra node joins the cluster and therefore participates to the Khepri +database, it starts a new Khepri state machine instance. This instance needs to +apply all Ra commands from an initial state to be on the same page as other +existing instances.
+ +Likewise, if for any reason, one of the Khepri state machine instance looses +the connection to other members and can't apply Ra commands, then when the link +comes back, it has to catch up.
+ +All this means that the code to modify the state of the state machines (i.e. +the tree) needs to run on all instances, possibly not at the same time, and +give the exact same result everywhere.
+ +To achieve that, Horus and khepri_tx
extract the assembly
+code of the anonymous function and create a standalone Erlang module based on
+it. This module can be stored in Ra's log and executed anywhere without the
+presence of the initial anonymous function's module.
The consequence of the above constraints is that a transaction function can't +depend on anything else than the tree and it can't have any side effects +outside of the changes to the tree nodes.
+ +If the transaction needs to have side effects, there are two options: +khepri:put/3
with khepri_condition:if_payload_version()
+conditions in the path and retry if the put fails because the version changed
+in between.Here is an example of the second option:
+ +Path = [stock, wood, <<"lime tree">>],
+{ok, #{data := Term,
+ payload_version := PayloadVersion}} =
+ khepri_adv:get(StoredId, Path),
+
+%% Do anything with `Term` that depend on external factors and could have side
+%% effects.
+Term1 = do_something_with_side_effects(Term),
+
+PathPattern = [stock,
+ wood,
+ #if_all{
+ conditions = [
+ <<"lime tree">>,
+ #if_payload_version{version = PayloadVersion}]}],
+case khepri:put(StoredId, PathPattern, Term1) of
+ ok ->
+ ok; %% `Term1` was stored successfully.
+ {error, ?khepri_error(mismatching_node, _)} ->
+ loop() %% Restart the whole function to read/modify/write again.
+end.
+
+To backup and restore a Khepri store, you can use khepri:export/4
and
+khepri:import/3
.
They both rely on a backend module which follows the Mnesia Backup &
+Restore API. Khepri comes with one backend module called khepri_export_erlang
. It uses plaintext files containing opaque Erlang terms
+formatted as text. It is possible to provide your own backend module obviously.
To export the content of a running store:
+ +ok = khepri:export(StoreId, khepri_export_erlang, "export.erl").
+
+This will export the entire store. It is possible to export a part of it by +passing a path patterns to select the tree nodes you want to export.
+ +Later, to import to a running store:
+ +ok = khepri:import(StoreId, khepri_export_erlang, "export.erl").
+
+Importing a backup does not touch unrelated tree nodes. In other words, the +content of the exported store is imported but whatever exists in the target +store remains (except if the import overwrites some tree nodes of course). In +particular, the target store is not reset.
+ +You can learn more about this import/export feature in the khepri_import_export
module documentation.
You can lean more about the provide backend module by reading the documentation
+of khepri_export_erlang
.
It is possible to associate events with an anonymous function to trigger its +execution when something happens. This is what is usually called a +trigger in databases and Khepri supports this feature.
+ +Currently, Khepri supports a single type of event, tree changes. This +event is emitted whenever a tree node is being created, updated or deleted.
+ +Here is a summary of what happens when such an event is emitted: +The indicated stored procedure must have been stored in the tree first.
+ +This is possible to store an anonymous function as the payload of a tree node:
+ +khepri:put(
+ StoreId,
+ StoredProcPath,
+ fun() -> do_something() end).
+
+The StoredProcPath
can be any path in the
+tree.
Unlike transaction functions, a stored procedure has no restrictions on what +it is allowed to do. Therefore, a stored procedure can send or receive +messages, read or write from a disk, generate random numbers and so on.
+ +A stored procedure can accept any numbers of arguments too.
+ +It is possible to execute a stored procedure directly without configuring any
+triggers. To execute a stored procedure, you can call khepri:run_sproc/3
. Here is an example:
Ret = khepri:run_sproc(
+ StoreId,
+ StoredProcPath,
+ [] = _Args).
+
+This works exactly like erlang:apply/2
. The list of arguments passed
+to khepri:run_sproc/3
must correspond to the stored procedure
+arity.
Khepri uses event filters to associate a type of events with a stored
+procedure. Khepri supports tree changes events and thus only supports a single
+event filter called khepri_evf:tree_event_filter()
.
An event filter is registered using khepri:register_trigger/4
:
%% An event filter can be explicitly created using the `khepri_evf'
+%% module. This is possible to specify properties at the same time.
+EventFilter = khepri_evf:tree([stock, wood, <<"oak">>], %% Required
+ #{on_actions => [delete], %% Optional
+ priority => 10}), %% Optional
+
+%% For ease of use, some terms can be automatically converted to an event
+%% filter. Here, a Unix-like path could be used as a tree event filter, though
+%% it would have default properties unlike the previous line:
+EventFilter = "/:stock/:wood/oak".
+
+ok = khepri:register_trigger(
+ StoreId,
+ TriggerId,
+ EventFilter,
+ StoredProcPath).
+
+In this example, the khepri_evf:tree_event_filter()
structure only
+requires the path to monitor. The path can be any path pattern and thus can
+have conditions to monitor several nodes at once.
The on_actions
property is optional. By default the event filter matches all
+tree changes (create
, update
or delete
).
The priority
property is also optional and defaults to 0. When several event
+filters match a given event, they are sorted by priority (a greater integer
+means the event filter will be considered first), then by TriggerId
in
+alphabetical order.
Neither the monitored path nor the stored procedure (pointed to by
+StoredProcPath
) need to exist when the event filter is registered. If the
+stored procedure doesn't exist when an event occurs, the event filter is
+simply ignored. A stored procedure can change after an event filter is
+registered as well.
The stored procedure used for a trigger must accept a single argument, a map +containing properties of the emitted event:
+ +my_stored_procedure(Props) ->
+ #{path := Path,
+ on_action := Action} = Props.
+
+Path
is the path to the tree node created, updated or deleted.
Action
is the nature of the change (create
, update
or delete
).
The return value of this stored procedure is ignored in the context of a +trigger.
+ +The stored procedure associated with a trigger (event filter) is executed on +the Ra leader node.
+ +If the stored procedure throws an exception, it is logged and there is no +retry.
+ +There is an internal ack mechanism to make sure the stored procedure is +executed at least once. Therefore, if the Ra leader changes before the +execution of the stored procedure could be confirmed to the Khepri state +machine, the execution will be retried on the new Ra leader.
+ +This means that the stored procedure could be executed multiple times. +Therefore it is important it is idempotent.
+ +As described earlier, the rationale for triggers in Khepri is that sometimes, +one needs to execute some code with side effects (e.g. sending a message to a +process) after a record was modified in the database. This can't happen in a +transaction because side effects are forbidden. The caller could handle that +after he modifies the record, but the record could be indirectly modified +(deleted) as a consequence of another record being modified or deleted. In +this case, the caller can't do anything.
+ +Because of the freedom they need, triggers are not allowed to mess +with the database directly. In other words, they must go through the +regular Khepri API like any caller. Triggers do not have any privileges or +blanket approvals to tamper with the data.
+ +So even though Khepri uses the same naming than many RDBMS, triggers in Khepri +can't have unexpected consequences.
+ +Projections are a system within Khepri for maintaining replicated ETS caches +for tree nodes matching a given path pattern.
+ +Projection resources are created with the khepri_projection:new/3
+function and are registered in a store with khepri:register_projection/4
:
ProjectionName = wood_stocks,
+ProjectionFun = fun([stock, wood, Kind], Stock) -> {Kind, Stock} end,
+Options = #{type => set, read_concurrency => true},
+Projection = khepri_projection:new(ProjectionName, ProjectionFun, Options).
+
+StoreId = stock,
+PathPattern = "/:stock/:wood/*",
+khepri:register_projection(StoreId, PathPattern, Projection).
+
+When a path within the store which matches PathPattern
changes, the changed
+path and data are passed to the given ProjectionFun
to create ETS objects
+which are then stored in the projection's ETS table.
Projection tables may be queried directly with functions from the ets
+module.
khepri:put(StoreId, "/:stock/:wood/oak", 100),
+ets:lookup(ProjectionName, <<"oak">>, 2).
+%%=> [{<<"oak">>,100}]
+
+khepri:put(StoreId, "/:stock/:wood/oak", 80),
+ets:lookup(ProjectionName, <<"oak">>, 2).
+%%=> [{<<"oak">>,80}]
+
+khepri:delete(StoreId, "/:stock/:wood/oak"),
+ets:member(ProjectionName, <<"oak">>).
+%%=> false
+
+Use projections to maximize query throughput and/or minimize query latency.
+ +Projections have some costs though. Expect some increased memory consumption +since information in the projection tables is duplicated between the Khepri +store and ETS. Khepri may also take longer to accomplish writes since +projections are updated by Khepri synchronously when writing to the store. + +Generated by EDoc
+ + diff --git a/overview.edoc b/overview.edoc new file mode 100644 index 00000000..d6132be6 --- /dev/null +++ b/overview.edoc @@ -0,0 +1,589 @@ +@author Jean-Sébastien Pédron+At the time of this writing, RabbitMQ does not use Khepri in a production +release yet because this library and its integration into RabbitMQ are still a +work in progress. ++ +== The tree structure == + +=== Tree nodes === + +Data in Khepri are organized as tree nodes ({@link +khepri_machine:tree_node()}) in a tree structure. Every tree node has: +