-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Pablo
committed
Jul 19, 2021
0 parents
commit 78a9349
Showing
14 changed files
with
564 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
name: nmaglev | ||
on: | ||
push: | ||
branches: | ||
- '*' | ||
pull_request: | ||
branches: | ||
- master | ||
|
||
jobs: | ||
build: | ||
strategy: | ||
matrix: | ||
include: | ||
- platform: ubuntu-20.04 | ||
lsb_release: focal | ||
otp-version: 23.1-1 | ||
- platform: ubuntu-20.04 | ||
lsb_release: focal | ||
otp-version: 22.3.4.8-1 | ||
- platform: ubuntu-20.04 | ||
lsb_release: focal | ||
otp-version: 24.0.2-1 | ||
runs-on: ${{ matrix.platform }} | ||
steps: | ||
|
||
# Setup | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
|
||
- name: Setup git | ||
env: | ||
SSH_AUTH_SOCK: /tmp/ssh_agent.sock | ||
run: | | ||
mkdir -p /home/runner/.ssh | ||
ssh-keyscan github.com >> /home/runner/.ssh/known_hosts | ||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > /home/runner/.ssh/id_rsa | ||
chmod 600 /home/runner/.ssh/id_rsa | ||
ssh-agent -a $SSH_AUTH_SOCK > /dev/null | ||
ssh-add /home/runner/.ssh/id_rsa | ||
# Install Erlang | ||
- name: Install Erlang/OTP | ||
run: | | ||
DEB_NAME="esl-erlang_${{ matrix.otp-version }}~ubuntu~${{ matrix.lsb_release }}_amd64.deb" | ||
curl -f https://packages.erlang-solutions.com/erlang/debian/pool/$DEB_NAME -o $DEB_NAME | ||
sudo dpkg --install $DEB_NAME | ||
# Inspect rebar3 version | ||
- name: Rebar version | ||
env: | ||
SSH_AUTH_SOCK: /tmp/ssh_agent.sock | ||
run: rebar3 --version | ||
|
||
# PRE Checks | ||
- name: Checks | ||
env: | ||
SSH_AUTH_SOCK: /tmp/ssh_agent.sock | ||
run: rebar3 fmt --check | ||
|
||
# Compile | ||
- name: Compile | ||
env: | ||
SSH_AUTH_SOCK: /tmp/ssh_agent.sock | ||
run: | | ||
git config --global user.email "[email protected]" | ||
git config --global user.name "GitHub actions" | ||
make | ||
# Tests | ||
- name: Run tests | ||
env: | ||
SSH_AUTH_SOCK: /tmp/ssh_agent.sock | ||
run: make test | ||
- name: Store test logs | ||
uses: actions/upload-artifact@v1 | ||
if: always() | ||
with: | ||
name: ct-logs | ||
path: _build/test/logs | ||
|
||
# Cover reports | ||
# - name: Create Cover Reports | ||
# env: | ||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
# run: rebar3 do cover,coveralls send |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
_build/ | ||
_checkouts/ | ||
.DS_Store | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
### INCLUDES | ||
include app.mk | ||
|
||
###----------------------------------------------------------------------------- | ||
### APPLICATION LAYOUT | ||
###----------------------------------------------------------------------------- | ||
APPSRC = $(patsubst src/%.app.src,%.app.src,$(wildcard src/*.app.src)) | ||
APP = $(APPSRC:.app.src=.app) | ||
APPNAME = $(basename $(APP)) | ||
ERLS = $(patsubst src/%.erl,%.erl,$(wildcard src/*.erl)) | ||
|
||
.PHONY: all clean doc test | ||
.SUFFIXES: .erl .hrl .app.src .app | ||
|
||
###----------------------------------------------------------------------------- | ||
### TARGETS | ||
###----------------------------------------------------------------------------- | ||
all: compile | ||
|
||
compile: | ||
@$(REBAR) compile | ||
|
||
clean: | ||
@$(REBAR) clean | ||
|
||
fmt: | ||
$(REBAR) fmt | ||
|
||
dialyze: | ||
@$(REBAR) dialyzer | ||
|
||
test: fmt | ||
@$(REBAR) ct --spec test/conf/test.spec --cover --readable true | ||
|
||
test-verbose: fmt | ||
@$(REBAR) ct --spec test/conf/test.spec --cover --readable true --verbose |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# nmaglev | ||
|
||
Erlang implementation of the consistent hashing maglev algorithm | ||
|
||
## Introduction | ||
|
||
MagLev is a [consistent hashing](https://en.wikipedia.org/wiki/Consistent_hashing) algorithm developed at Google and | ||
[published](https://static.googleusercontent.com/media/research.google.com/es//pubs/archive/44824.pdf) in 2016. | ||
|
||
It aims to be lightning fast and always accurate due to the use of a deterministic algorithm at the spend | ||
of needing more computational power when there is a change in the list of possible outputs as it needs | ||
to recalculate the internal hashing table. | ||
|
||
## How to use it | ||
|
||
1. Create your maglev table with the list of possible outputs: ```MaglevTable = nmaglev:create([a,b,c,d]).``` | ||
2. Use the table: ```Output = nmaglev:get(<<"some bin">>, MaglevTable).``` | ||
|
||
|
||
## About lookup table sizes | ||
|
||
By default the lookup table size is 65537 as it should be enough for a normal scenario. | ||
You can choose your own size using the nmaglev:create/2 function but please be aware that the size has to be | ||
a prime number. | ||
|
||
## Original paper | ||
|
||
[https://static.googleusercontent.com/media/research.google.com/es//pubs/archive/44824.pdf](https://static.googleusercontent.com/media/research.google.com/es//pubs/archive/44824.pdf) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
VSN = 1.1.0 | ||
|
||
### Special characters | ||
comma := , | ||
empty := | ||
space := $(empty) $(empty) | ||
|
||
### Erlang compiler | ||
ERL = erl | ||
ERLC = erlc | ||
|
||
### Flags | ||
DFLAGS = -I .. --src --verbose -c | ||
STUB_EFLAGS = -v -pz ../../vo/ebin/ -I ../.. -I .. -I ./stubs/ -W1 -o stubs | ||
|
||
### Default apps | ||
CD = cd | ||
CP = cp -vf | ||
ECHO = echo | ||
ERLDOC = ndoc | ||
MKDIR = mkdir | ||
MV = mv -vf | ||
RM = rm -vf | ||
SED = sed | ||
REBAR = rebar3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{erl_opts, [ | ||
debug_info, | ||
bin_opt_info, | ||
{i, "include"} | ||
]}. | ||
|
||
{plugins, [ | ||
{erlfmt, {git, "[email protected]:WhatsApp/erlfmt.git", {tag, "v1.0.0"}}} | ||
]}. | ||
|
||
{erlfmt, [write]}. | ||
|
||
{provider_hooks, [ | ||
{pre, [{compile, fmt}]} | ||
]}. | ||
|
||
{cover_enabled, true}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[]. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
%%% -*- mode:erlang -*- | ||
{application, nmaglev, [ | ||
{description, "Erlang implementation of the consistent hashing maglev algorithm"}, | ||
{vsn, "1.0.0"}, | ||
{registered, []}, | ||
{applications, [kernel, stdlib]}, | ||
{env, []} | ||
]}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
%%% Copyright (c) 2013 [Nomasystems, S.L. http://www.nomasystems.com] | ||
%%% | ||
%%% This file contains Original Code and/or Modifications of Original Code as | ||
%%% defined in and that are subject to the Nomasystems Public License version | ||
%%% 1.0 (the 'License'). You may not use this file except in compliance with | ||
%%% the License. BY USING THIS FILE YOU AGREE TO ALL TERMS AND CONDITIONS OF | ||
%%% THE LICENSE. A copy of the License is provided with the Original Code and | ||
%%% Modifications, and is also available at www.nomasystems.com/license.txt. | ||
%%% | ||
%%% The Original Code and all software distributed under the License are | ||
%%% distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | ||
%%% EXPRESS OR IMPLIED, AND NOMASYSTEMS AND ALL CONTRIBUTORS HEREBY DISCLAIM | ||
%%% ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF | ||
%%% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR | ||
%%% NON-INFRINGEMENT. Please see the License for the specific language | ||
%%% governing rights and limitations under the License. | ||
%%% | ||
-module(nmaglev). | ||
|
||
%%% INCLUDE FILES | ||
|
||
%%% EXTERNAL EXPORTS | ||
-export([create/1, create/2, get/2]). | ||
|
||
%%% MACROS | ||
-define(DEFAULT_LOOKUP_SIZE, 65537). | ||
|
||
%%% RECORDS | ||
|
||
%%%----------------------------------------------------------------------------- | ||
%%% EXTERNAL EXPORTS | ||
%%%----------------------------------------------------------------------------- | ||
create(Nodes) -> | ||
LookupSize = ?DEFAULT_LOOKUP_SIZE, | ||
create(Nodes, LookupSize). | ||
|
||
create(Nodes, LookupSize) -> | ||
NodesLen = length(Nodes), | ||
PermutationsTable = permutations(Nodes, LookupSize), | ||
lookup_map(PermutationsTable, NodesLen, LookupSize, {0, #{}, NodesLen}). | ||
|
||
get(Key, Lookup) -> | ||
Offset = erlang:phash2(Key, maps:size(Lookup)), | ||
maps:get(Offset, Lookup). | ||
|
||
%%%----------------------------------------------------------------------------- | ||
%%% INTERNAL FUNCTIONS | ||
%%%----------------------------------------------------------------------------- | ||
lookup_map(_PermutationsTable, _NodesLen, LookupSize, {Filled, FilledMap, _LastNodePos}) when | ||
Filled >= LookupSize | ||
-> | ||
FilledMap; | ||
lookup_map(PermutationsTable, NodesLen, LookupSize, {Filled, FilledMap, LastNodePos}) -> | ||
{Permutation, ChosenNode, ChosenNodePos, NewPermutationsTable} = choose_node( | ||
PermutationsTable, | ||
NodesLen, | ||
FilledMap, | ||
LastNodePos | ||
), | ||
lookup_map( | ||
NewPermutationsTable, | ||
NodesLen, | ||
LookupSize, | ||
{Filled + 1, FilledMap#{Permutation => ChosenNode}, ChosenNodePos} | ||
). | ||
|
||
choose_node(PermutationsTable, NodesLen, FilledMap, LastNodePos) -> | ||
NodePos = mod(LastNodePos, NodesLen) + 1, | ||
{Node, NodePermutations} = lists:nth(NodePos, PermutationsTable), | ||
[Permutation | RestNodePermutations] = NodePermutations, | ||
NewPermutationsTable = lists:keyreplace( | ||
Node, | ||
1, | ||
PermutationsTable, | ||
{Node, RestNodePermutations} | ||
), | ||
case maps:is_key(Permutation, FilledMap) of | ||
false -> | ||
{Permutation, Node, NodePos, NewPermutationsTable}; | ||
true -> | ||
choose_node(NewPermutationsTable, NodesLen, FilledMap, NodePos) | ||
end. | ||
|
||
permutations(Nodes, LookupSize) -> | ||
[{Node, node_permutations(Node, LookupSize)} || Node <- Nodes]. | ||
|
||
node_permutations(Node, LookupSize) -> | ||
Offset = mod(erlang:phash(Node, LookupSize), LookupSize), | ||
Skip = mod(erlang:phash2(Node, LookupSize), LookupSize - 1) + 1, | ||
[mod(Offset + (Pos * Skip), LookupSize) || Pos <- lists:seq(0, LookupSize - 1)]. | ||
|
||
mod(A, B) when A > 0 -> | ||
A rem B; | ||
mod(A, B) when A < 0 -> | ||
mod(A + B, B); | ||
mod(0, _) -> | ||
0. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
%%% -*- mode:erlang -*- | ||
{apps, [nmaglev]}. | ||
{paths, []}. | ||
{env, [{nmaglev, []}]}. | ||
%{tpl_cases, [{api, [ets]}]}. | ||
%{tp_cases, []}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
%%% -*- mode:erlang -*- | ||
{config, "test.conf"}. | ||
{alias, test, ".."}. | ||
{suites, test, all}. |
Oops, something went wrong.