├── .eqc_ci ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── Dockerfiles ├── dcos-runner ├── epmd ├── erlang ├── lasp ├── lasp-base ├── lasp-bootler ├── lasp-dev ├── lasp-dev-no-clone ├── lasp-divergence ├── lasp-exp ├── lasp-gce-workflow-v2 ├── lasp-hipe-dev ├── lasp-unstable └── packager ├── LICENSE ├── Makefile ├── README.md ├── Vagrantfile ├── bin ├── azure-start.sh ├── azure-stop.sh ├── bench-types.erl ├── dcos-deploy.sh ├── elb-host.sh ├── env ├── event-interval ├── gce-start.sh ├── gce-stop.sh ├── helpers.sh ├── ienv ├── kube-divergence ├── kube-divergence-automation ├── kube-divergence-simulation ├── kube-throughput ├── kube-throughput-simulation ├── launch-instances-m3-2xlarge.sh ├── launch-instances-m4-4xlarge.sh ├── launch-instances.sh ├── open-ui.sh ├── start-dcos-runner.sh ├── sync-redis.erl └── transmission.sh ├── circle.yml ├── config ├── .vm.args.swp ├── sys.config └── vm.args ├── docker-compose.yml ├── experiments ├── activity.md ├── experiments.md ├── launch.md └── manual-launch.md ├── images ├── fast_spinning_3.gif ├── lasp-logo-large-square.jpg ├── lasp-logo-large-square.pxm ├── lasp-logo-large.png ├── lasp-logo-text-large.png ├── lasp-logo-text-small.png ├── lasp-logo-tiny.png ├── netnow3.gif └── packagecloud-logo-dark.png ├── include ├── lasp.hrl └── sprinter.hrl ├── pkg.vars.config ├── priv ├── favicon.ico ├── images │ ├── lasp-logo-large.png │ └── lasp-logo-tiny.png ├── index.html ├── js │ ├── main.js │ ├── pdfobject.js │ └── viz.min.js └── ssh │ ├── evaluation │ └── wrapper ├── rebar.config ├── rebar.lock ├── rel ├── before-install ├── etc │ ├── default │ │ └── lasp │ └── lasp │ │ └── lasp.config ├── init └── var │ ├── lib │ └── lasp │ │ └── .gitkeep │ └── log │ └── lasp │ └── .gitkeep ├── samples ├── docker.sh └── map.erl ├── scripts └── hex.sh ├── simulations ├── lasp_advertisement_counter_client.erl ├── lasp_advertisement_counter_server.erl ├── lasp_dag_resource.erl ├── lasp_game_tournament_client.erl ├── lasp_game_tournament_server.erl ├── lasp_gui_resource.erl ├── lasp_health_check_resource.erl ├── lasp_instrumentation.erl ├── lasp_kubernetes_simulations.erl ├── lasp_kv_resource.erl ├── lasp_logs_resource.erl ├── lasp_plots_resource.erl ├── lasp_simulation.erl ├── lasp_simulation_support.erl └── lasp_status_resource.erl ├── src ├── lasp.app.src ├── lasp.erl ├── lasp_app.erl ├── lasp_config.erl ├── lasp_console.erl ├── lasp_core.erl ├── lasp_delta_based_synchronization_backend.erl ├── lasp_dependence_dag.erl ├── lasp_dets_storage_backend.erl ├── lasp_distribution_backend.erl ├── lasp_divergence_client.erl ├── lasp_divergence_server.erl ├── lasp_dt.erl ├── lasp_eqc.erl ├── lasp_ets_storage_backend.erl ├── lasp_logger.erl ├── lasp_marathon_simulations.erl ├── lasp_membership.erl ├── lasp_memory_utilization_report.erl ├── lasp_mochiglobal.erl ├── lasp_operations.erl ├── lasp_partisan_peer_service.erl ├── lasp_peer_service.erl ├── lasp_plumtree_backend.erl ├── lasp_plumtree_memory_report.erl ├── lasp_process.erl ├── lasp_process_sup.erl ├── lasp_redis_storage_backend.erl ├── lasp_sql_lexer.xrl ├── lasp_sql_materialized_view.erl ├── lasp_sql_parser.yrl ├── lasp_state_based_synchronization_backend.erl ├── lasp_storage_backend.erl ├── lasp_sup.erl ├── lasp_support.erl ├── lasp_synchronization_backend.erl ├── lasp_throughput_client.erl ├── lasp_throughput_server.erl ├── lasp_type.erl ├── lasp_unique.erl ├── lasp_vclock.erl ├── lasp_workflow.erl ├── state_awset_ps_ext.erl └── state_orset_ext.erl ├── test ├── lasp_SUITE.erl ├── lasp_advertisement_counter_overcounting_SUITE.erl ├── lasp_advertisement_counter_partition_overcounting_SUITE.erl ├── lasp_client_server_advertisement_counter_SUITE.erl ├── lasp_client_server_divergence_SUITE.erl ├── lasp_client_server_game_tournament_SUITE.erl ├── lasp_client_server_throughput_SUITE.erl ├── lasp_peer_to_peer_advertisement_counter_SUITE.erl ├── lasp_peer_to_peer_game_tournament_SUITE.erl └── lasp_peer_to_peer_throughput_SUITE.erl └── tools.mk /.eqc_ci: -------------------------------------------------------------------------------- 1 | {build, "make"}. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.beam 2 | *.swp 3 | .eunit 4 | deps/* 5 | ebin/* 6 | dev 7 | bin/*.swp 8 | priv/*.swp 9 | src/*.swp 10 | test/*.swp 11 | tags 12 | .qc/ 13 | riak_test/ebin/*.beam 14 | .eqc-info 15 | current_counterexample.eqc 16 | dialyzer_warnings 17 | .rebar/ 18 | distdir 19 | package 20 | deps.test/ 21 | rt/ 22 | .combo_dialyzer_plt 23 | .local_dialyzer_plt 24 | build 25 | .vagrant 26 | _build/ 27 | TEST-* 28 | data/ 29 | *.deb 30 | log/ 31 | _checkouts/ 32 | fprof.trace 33 | .rebar3/ 34 | .eqc/ 35 | dcos/ 36 | priv/ssh/*id_rsa* 37 | priv/evaluation 38 | priv/lager 39 | src/lasp_sql_lexer.erl 40 | src/lasp_sql_parser.erl 41 | bin/a 42 | dcos.pem 43 | logs/ 44 | erl_crash.dump 45 | rebar3.crashdump 46 | dump.rdb -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | otp_release: 3 | - 21.2.5 4 | - 20.3 5 | - 19.3 6 | install: 7 | - wget https://s3.amazonaws.com/rebar3/rebar3 && chmod u+x rebar3 8 | - REBAR=./rebar3 make 9 | - ./rebar3 update 10 | before_script: 11 | - epmd -daemon 12 | services: 13 | - redis-server 14 | script: 15 | - REBAR=./rebar3 make eunit 16 | - REBAR=./rebar3 make xref 17 | - REBAR=./rebar3 make ct 18 | - REBAR=./rebar3 make peer-to-peer-ad-counter-simulation 19 | - REBAR=./rebar3 make client-server-ad-counter-simulation 20 | - REBAR=./rebar3 make peer-to-peer-game-tournament-simulation 21 | - REBAR=./rebar3 make client-server-game-tournament-simulation 22 | notifications: 23 | email: christopher.meiklejohn@gmail.com 24 | slack: lasp-lang:hiPRNnbUa3zdGrrXZfGRAF7D 25 | irc: "irc.freenode.org#lasp-lang" 26 | webhooks: 27 | urls: 28 | - https://webhooks.gitter.im/e/1382c852fbaf2633033a 29 | sudo: false 30 | env: 31 | global: 32 | - OMIT_HIGH_ULIMIT=true 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.8.2 2 | 3 | * Fix packaging. 4 | 5 | # 0.8.1 6 | 7 | * Bump partisan dependencies. 8 | 9 | # 0.8.0 10 | 11 | * Delta dissemination supports forced propagation after update. 12 | * Added experimental Redis backend. 13 | 14 | # 0.7.2 15 | 16 | * Add partial replication support to the reverse topological sort behavior. 17 | 18 | # 0.7.1 19 | 20 | * Fix bad plumtree dependency. 21 | 22 | # 0.7.0: 23 | 24 | * Prototype support for partial replication if you're using the default peer service manager with no broadcast trees. This feature adds the ability to make nodes interested in certain replication topics using `interested/1` and `disinterested/1`, and tag objects accordingly using `set_topic/2` and `remove_topic/2`. Objects that have topics not matching the node interests will be not replicated during the normal anti-entropy process using an algorithms inspired by the Footloose protocol. This dissemination mechanism is *experimental* and not supported when broadcast trees are enabled, nor under any of the partially connected overlays. 25 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at christopher.meiklejohn@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lasplang/erlang:19.3 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot 8 | 9 | RUN cd /opt && \ 10 | (git clone https://github.com/lasp-lang/lasp.git -b $LASP_BRANCH && cd lasp && make exp-stage); 11 | 12 | CMD cd /opt/lasp && \ 13 | /opt/lasp/_build/exp/rel/lasp/bin/env -------------------------------------------------------------------------------- /Dockerfiles/dcos-runner: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | MAINTAINER Vitor Enes Duarte 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget curl build-essential make gcc ruby-dev git expect gnuplot python && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang 12 | 13 | CMD cd /opt && \ 14 | git clone https://github.com/lasp-lang/lasp.git -b $LASP_BRANCH && \ 15 | cd lasp/bin && \ 16 | ./transmission.sh 17 | -------------------------------------------------------------------------------- /Dockerfiles/epmd: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get -y install wget && \ 7 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 8 | dpkg -i erlang-solutions_1.0_all.deb && \ 9 | apt-get update && \ 10 | apt-get -y install erlang 11 | 12 | CMD epmd -d 13 | -------------------------------------------------------------------------------- /Dockerfiles/erlang: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang 12 | 13 | CMD bash 14 | -------------------------------------------------------------------------------- /Dockerfiles/lasp: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN apt-get update && \ 6 | apt-get -y install curl && \ 7 | curl -s https://packagecloud.io/install/repositories/cmeiklejohn/lasp/script.deb.sh | sudo bash && \ 8 | apt-get install lasp 9 | 10 | CMD sh -C "/opt/lasp/bin/env" 11 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-base: -------------------------------------------------------------------------------- 1 | FROM erlang:19.3-slim 2 | 3 | MAINTAINER Vitor Enes Duarte 4 | 5 | RUN apt-get update && apt-get install -y git make 6 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-bootler: -------------------------------------------------------------------------------- 1 | FROM lasplang/lasp-base 2 | 3 | MAINTAINER Vitor Enes Duarte 4 | 5 | ARG BRANCH=bootler 6 | 7 | RUN cd /opt && \ 8 | git clone https://github.com/lasp-lang/lasp.git -b $BRANCH && \ 9 | cd lasp && \ 10 | make stage 11 | 12 | CMD /opt/lasp/_build/exp/rel/lasp/bin/env 13 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-dev: -------------------------------------------------------------------------------- 1 | FROM lasplang/erlang:19.3 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot 8 | 9 | CMD cd /opt && \ 10 | git clone https://github.com/lasp-lang/lasp.git -b $LASP_BRANCH && \ 11 | cd lasp && \ 12 | make stage && \ 13 | /opt/lasp/_build/default/rel/lasp/bin/env 14 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-dev-no-clone: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang 12 | 13 | RUN cd /opt && \ 14 | git clone https://github.com/lasp-lang/lasp.git -b dcos_again && \ 15 | cd lasp && \ 16 | make stage 17 | 18 | CMD /opt/lasp/_build/default/rel/lasp/bin/env 19 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-divergence: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang && \ 12 | cd /opt && \ 13 | git clone https://github.com/lasp-lang/lasp.git -b divergence && \ 14 | cd lasp && \ 15 | make stage 16 | 17 | CMD /opt/lasp/_build/default/rel/lasp/bin/env 18 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-exp: -------------------------------------------------------------------------------- 1 | FROM lasplang/erlang:19.3 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot 8 | 9 | CMD cd /opt && \ 10 | git clone https://github.com/lasp-lang/lasp.git -b $LASP_BRANCH && \ 11 | cd lasp && \ 12 | make exp-stage && \ 13 | /opt/lasp/_build/exp/rel/lasp/bin/env -------------------------------------------------------------------------------- /Dockerfiles/lasp-gce-workflow-v2: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang && \ 12 | cd /opt && \ 13 | git clone https://github.com/lasp-lang/lasp.git -b workflow-v2 && \ 14 | cd lasp && \ 15 | make stage 16 | 17 | CMD /opt/lasp/_build/default/rel/lasp/bin/env 18 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-hipe-dev: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang && \ 12 | apt-get -y install erlang-base-hipe 13 | 14 | CMD cd /opt && \ 15 | git clone https://github.com/lasp-lang/lasp.git -b unstable && \ 16 | cd lasp && \ 17 | make stage && \ 18 | /opt/lasp/_build/default/rel/lasp/bin/env 19 | -------------------------------------------------------------------------------- /Dockerfiles/lasp-unstable: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | MAINTAINER Christopher Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git expect gnuplot && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang && \ 12 | cd /opt && \ 13 | git clone https://github.com/lasp-lang/lasp.git -b unstable && \ 14 | cd lasp && \ 15 | make stage 16 | 17 | CMD /opt/lasp/_build/default/rel/lasp/bin/env 18 | -------------------------------------------------------------------------------- /Dockerfiles/packager: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | MAINTAINER Christopher S. Meiklejohn 4 | 5 | RUN cd /tmp && \ 6 | apt-get update && \ 7 | apt-get -y install wget build-essential make gcc ruby-dev git && \ 8 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ 9 | dpkg -i erlang-solutions_1.0_all.deb && \ 10 | apt-get update && \ 11 | apt-get -y install erlang && \ 12 | apt-get clean && apt-get update && apt-get install -y locales && \ 13 | locale-gen en_US.UTF-8 && \ 14 | gem install rake && \ 15 | gem install package_cloud && \ 16 | gem install fpm 17 | 18 | CMD cd /tmp && \ 19 | git clone https://github.com/lasp-lang/lasp.git && \ 20 | cd lasp && make && VERSION="0.8.2" make package && \ 21 | locale-gen en_US en_US.UTF-8 && \ 22 | dpkg-reconfigure locales && \ 23 | LC_ALL="en_US.UTF-8" package_cloud push cmeiklejohn/lasp/ubuntu/trusty `find /tmp/lasp -name *.deb | tail -1` 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE ?= lasp 2 | VERSION ?= $(shell git describe --tags) 3 | BASE_DIR = $(shell pwd) 4 | ERLANG_BIN = $(shell dirname $(shell which erl)) 5 | REBAR ?= rebar3 6 | VERSION = "0.8.2" 7 | MAKE = make 8 | 9 | .PHONY: rel deps test plots dcos logs fpm 10 | 11 | all: compile 12 | 13 | ## 14 | ## Compilation targets 15 | ## 16 | 17 | compile: 18 | $(REBAR) compile 19 | 20 | clean: packageclean 21 | $(REBAR) clean 22 | 23 | packageclean: 24 | rm -fr *.deb 25 | rm -fr *.tar.gz 26 | 27 | ## 28 | ## Test targets 29 | ## 30 | 31 | kill: 32 | pkill -9 beam.smp; \ 33 | pkill -9 epmd; \ 34 | exit 0 35 | 36 | check: kill test xref dialyzer 37 | 38 | test: ct eunit ad-counter-simulations game-tournament-simulations 39 | 40 | lint: 41 | ${REBAR} as lint lint 42 | 43 | eunit: 44 | ${REBAR} eunit 45 | 46 | ct: 47 | ${REBAR} ct --suite=lasp_SUITE 48 | 49 | ad-counter-simulations: client-server-ad-counter-simulation peer-to-peer-ad-counter-simulation ad-counter-overcounting ad-counter-partition-overcounting 50 | game-tournament-simulations: client-server-game-tournament-simulation peer-to-peer-game-tournament-simulation 51 | 52 | peer-to-peer-ad-counter-simulation: 53 | ${REBAR} ct --suite=lasp_peer_to_peer_advertisement_counter_SUITE 54 | 55 | client-server-ad-counter-simulation: 56 | ${REBAR} ct --suite=lasp_client_server_advertisement_counter_SUITE 57 | 58 | ad-counter-overcounting: 59 | #${REBAR} ct --suite=lasp_advertisement_counter_overcounting_SUITE 60 | 61 | ad-counter-partition-overcounting: 62 | ${REBAR} ct --suite=lasp_advertisement_counter_partition_overcounting_SUITE 63 | 64 | peer-to-peer-game-tournament-simulation: 65 | ${REBAR} ct --suite=lasp_peer_to_peer_game_tournament_SUITE 66 | 67 | client-server-game-tournament-simulation: 68 | ${REBAR} ct --suite=lasp_client_server_game_tournament_SUITE 69 | 70 | peer-to-peer-throughput-simulation: 71 | ${REBAR} ct --suite=lasp_peer_to_peer_throughput_SUITE 72 | 73 | client-server-throughput-simulation: 74 | ${REBAR} ct --suite=lasp_client_server_throughput_SUITE 75 | 76 | client-server-divergence-simulation: 77 | ${REBAR} as test ct --suite=lasp_client_server_divergence_SUITE 78 | 79 | ## 80 | ## Release targets 81 | ## 82 | 83 | rel: 84 | ${REBAR} release 85 | 86 | stage: 87 | ${REBAR} release -d 88 | 89 | exp-rel: 90 | ${REBAR} as exp release 91 | 92 | exp-stage: 93 | ${REBAR} as exp release -d 94 | 95 | ## 96 | ## Packaging targets 97 | ## 98 | 99 | fpm: 100 | gem install --no-ri --no-rdoc fpm 101 | 102 | package: rel fpm 103 | fpm -s dir -t deb -n $(PACKAGE) -v $(VERSION) \ 104 | --deb-user $(PACKAGE) \ 105 | --deb-group $(PACKAGE) \ 106 | --before-install=rel/before-install \ 107 | _build/default/rel/$(PACKAGE)=/opt/ \ 108 | rel/init=/etc/init.d/$(PACKAGE) \ 109 | rel/var/lib/$(PACKAGE)/=/var/lib/$(PACKAGE)/ \ 110 | rel/var/log/$(PACKAGE)/=/var/log/$(PACKAGE)/ \ 111 | rel/etc/$(PACKAGE)/$(PACKAGE).config=/etc/$(PACKAGE)/$(PACKAGE).config \ 112 | rel/etc/default/$(PACKAGE)=/etc/default/$(PACKAGE) 113 | 114 | package_cloud: package 115 | docker build -f Dockerfiles/packager -t cmeiklejohn/packager . 116 | docker run -i -t -v ~/.packagecloud:/root/.packagecloud cmeiklejohn/packager 117 | 118 | cut: 119 | ${REBAR} as package hex cut 120 | 121 | publish: 122 | ${REBAR} as package hex publish 123 | 124 | shell: 125 | ${REBAR} shell --apps lasp --name lasp@localhost 126 | 127 | ## 128 | ## Evaluation related targets 129 | ## 130 | plots: 131 | pkill -9 beam.smp; \ 132 | clear; \ 133 | rm -rf priv/lager/ priv/evaluation; \ 134 | (cd priv/ && git clone https://github.com/lasp-lang/evaluation); \ 135 | ./rebar3 ct --readable=false --suite=test/lasp_peer_to_peer_advertisement_counter_SUITE; \ 136 | ./rebar3 ct --readable=false --suite=test/lasp_client_server_advertisement_counter_SUITE; \ 137 | cd priv/evaluation && make plots 138 | 139 | div: 140 | pkill -9 beam.smp; \ 141 | clear; \ 142 | ./rebar3 ct --readable=false --suite=test/lasp_advertisement_counter_overcounting_SUITE 143 | 144 | part-div: 145 | pkill -9 beam.smp; \ 146 | clear; \ 147 | ./rebar3 ct --readable=false --suite=test/lasp_advertisement_counter_partition_overcounting_SUITE 148 | 149 | tail-logs: 150 | tail -F priv/lager/*/*/log/*.log 151 | 152 | logs: 153 | cat priv/lager/*/*/log/*.log 154 | 155 | DIALYZER_APPS = kernel stdlib erts sasl eunit syntax_tools compiler crypto 156 | 157 | include tools.mk 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Lasp 2 | ======================================================= 3 | 4 | [![Build Status](https://travis-ci.org/lasp-lang/lasp.svg?branch=master)](https://travis-ci.org/lasp-lang/lasp) 5 | 6 | ## Overview 7 | 8 | Lasp is a programming model for synchronization-free computations. 9 | 10 | ## Installing 11 | 12 | Lasp requires Erlang 19 or greater. Once you have Erlang installed, do 13 | the following to install and build Lasp. 14 | 15 | ``` 16 | $ git clone git@github.com:lasp-lang/lasp.git 17 | $ cd lasp 18 | $ make 19 | ``` 20 | 21 | ## Creating a small cluster 22 | Clone Lasp: 23 | ``` 24 | $ git clone https://github.com/lasp-lang/lasp.git 25 | ``` 26 | 27 | Run two shells 28 | ``` 29 | $ rebar3 shell --name a@127.0.0.1 30 | $ rebar3 shell --name b@127.0.0.1 31 | ``` 32 | 33 | Exceute to node a: 34 | ```erlang 35 | 1> lasp_peer_service:join('a@127.0.0.1'). 36 | ok 37 | 2> lasp_peer_service:members(). 38 | {ok,['a@127.0.0.1','b@127.0.0.1']} 39 | ``` 40 | 41 | Execute node b: 42 | ```erlang 43 | 1> lasp_peer_service:members(). 44 | {ok,['a@127.0.0.1','b@127.0.0.1']} 45 | ``` 46 | 47 | Go back to node a and run: 48 | ```erlang 49 | 3> Content = #{what => i_am_an_awmap_value}. 50 | 51 | % create a lasp CRDT 52 | AwMapVarName = <<"awmap">>. 53 | Key1 = <<"key1">>. 54 | AwMapType = {state_awmap, [state_mvregister]}. 55 | {ok, {AwMap, _, _, _}} = lasp:declare({AwMapVarName, AwMapType}, AwMapType). 56 | 57 | % Update the CRDT with the content 58 | {ok, _} = lasp:update(AwMap, {apply, Key1, {set, nil, Content}}, term_to_binary(self())). 59 | ``` 60 | 61 | Go to node b and retrieve the content of the CRDT: 62 | ```erlang 63 | 2> {ok,[{_, AwMapSet}]} = lasp:query({<<"awmap">>,{state_awmap,[state_mvregister]}}). 64 | 65 | 3> sets:to_list(AwMapSet). 66 | % [#{what => i_am_an_awmap_value}] 67 | ``` 68 | 69 | ## Running a shell 70 | 71 | You can run a Erlang shell where you can interact with a Lasp node by 72 | doing the following: 73 | 74 | ``` 75 | $ make shell 76 | ``` 77 | 78 | ## Running the test suite 79 | 80 | To run the test suite, which will execute all of the Lasp scenarios, use 81 | the following command. 82 | 83 | ```bash 84 | $ make check 85 | ``` 86 | 87 | ## Notes 88 | 89 | If using the Distributed Erlang backend, make sure that all nodes are configured to use the same cookie. 90 | 91 | ## Code examples 92 | 93 | [This blog post](http://marianoguerra.org/posts/playing-with-lasp-and-crdts.html) by [@marianoguerra](https://github.com/marianoguerra) contains concise sample code. 94 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | config.ssh.forward_agent = true 14 | 15 | config.vm.define "trusty64" do |trusty64| 16 | trusty64.vm.box = "ubuntu/trusty64" 17 | 18 | trusty64.vm.hostname = "localhost.tld" 19 | 20 | trusty64.vm.provider :virtualbox do |vb| 21 | vb.customize ["modifyvm", :id, "--memory", "2048"] 22 | vb.customize ["modifyvm", :id, "--cpus", "2"] 23 | end 24 | 25 | trusty64.vm.provision "shell", inline: <<-SHELL 26 | # Packages 27 | sudo apt-get update 28 | sudo apt-get install -y build-essential git devscripts debhelper 29 | 30 | # Use Erlang Solutions packages for Erlang 18. 31 | wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb 32 | sudo dpkg -i erlang-solutions_1.0_all.deb 33 | sudo apt-get update 34 | sudo apt-get install -y erlang 35 | rm erlang-solutions_1.0_all.deb 36 | 37 | # Install fpm 38 | sudo apt-get install -y ruby-dev gcc make 39 | sudo gem install fpm 40 | SHELL 41 | end 42 | 43 | # Every Vagrant development environment requires a box. You can search for 44 | # boxes at https://atlas.hashicorp.com/search. 45 | # config.vm.box = "hashicorp/precise64" 46 | 47 | # Disable automatic box update checking. If you disable this, then 48 | # boxes will only be checked for updates when the user runs 49 | # `vagrant box outdated`. This is not recommended. 50 | # config.vm.box_check_update = false 51 | 52 | # Create a forwarded port mapping which allows access to a specific port 53 | # within the machine from a port on the host machine. In the example below, 54 | # accessing "localhost:8080" will access port 80 on the guest machine. 55 | # config.vm.network "forwarded_port", guest: 80, host: 8080 56 | 57 | # Create a private network, which allows host-only access to the machine 58 | # using a specific IP. 59 | # config.vm.network "private_network", ip: "192.168.33.10" 60 | 61 | # Create a public network, which generally matched to bridged network. 62 | # Bridged networks make the machine appear as another physical device on 63 | # your network. 64 | # config.vm.network "public_network" 65 | 66 | # Share an additional folder to the guest VM. The first argument is 67 | # the path on the host to the actual folder. The second argument is 68 | # the path on the guest to mount the folder. And the optional third 69 | # argument is a set of non-required options. 70 | # config.vm.synced_folder "../data", "/vagrant_data" 71 | 72 | # Provider-specific configuration so you can fine-tune various 73 | # backing providers for Vagrant. These expose provider-specific options. 74 | # Example for VirtualBox: 75 | # 76 | # config.vm.provider "virtualbox" do |vb| 77 | # # Display the VirtualBox GUI when booting the machine 78 | # vb.gui = true 79 | # 80 | # # Customize the amount of memory on the VM: 81 | # vb.memory = "1024" 82 | # end 83 | # 84 | # View the documentation for the provider you are using for more 85 | # information on available options. 86 | 87 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies 88 | # such as FTP and Heroku are also available. See the documentation at 89 | # https://docs.vagrantup.com/v2/push/atlas.html for more information. 90 | # config.push.define "atlas" do |push| 91 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" 92 | # end 93 | 94 | # Enable provisioning with a shell script. Additional provisioners such as 95 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the 96 | # documentation for more information about their specific syntax and use. 97 | # config.vm.provision "shell", inline: <<-SHELL 98 | # sudo apt-get update 99 | # sudo apt-get install -y build-essential erlang git 100 | # SHELL 101 | end 102 | -------------------------------------------------------------------------------- /bin/azure-start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Configure the environment. 4 | CLUSTER_NAME=lasp 5 | RESOURCE_GROUP=lasp 6 | 7 | ## Create the resource group. 8 | az group create --name ${RESOURCE_GROUP} --location eastus 9 | 10 | ## Create the Kubernetes cluster. 11 | az acs create --orchestrator-type=kubernetes --resource-group ${RESOURCE_GROUP} --name=${CLUSTER_NAME} --generate-ssh-keys 12 | 13 | ## Get credentials. 14 | az acs kubernetes get-credentials --resource-group=${RESOURCE_GROUP} --name=${CLUSTER_NAME} 15 | -------------------------------------------------------------------------------- /bin/azure-stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Configure environment. 4 | RESOURCE_GROUP=lasp 5 | 6 | ## Terminate resource group. 7 | az group delete --name ${RESOURCE_GROUP} --yes --no-wait 8 | -------------------------------------------------------------------------------- /bin/bench-types.erl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | 3 | %%! -pa _build/default/lib/types/ebin/ 4 | 5 | -define(OPS, 1000000). 6 | 7 | main(_) -> 8 | SetFun = fun() -> 9 | lists:foldl(fun(_X, Acc) -> 10 | {ok, State} = state_gset:mutate({add, self()}, self(), Acc), 11 | State 12 | end, state_gset:new(), lists:seq(1, ?OPS)) 13 | end, 14 | {SetTime, _} = timer:tc(SetFun), 15 | io:format("G-Set Time: ~p~n", [SetTime]), 16 | 17 | BooleanFun = fun() -> 18 | lists:foldl(fun(_X, Acc) -> 19 | {ok, State} = state_boolean:mutate(true, self(), Acc), 20 | State 21 | end, state_boolean:new(), lists:seq(1, ?OPS)) 22 | end, 23 | {BooleanTime, _} = timer:tc(BooleanFun), 24 | io:format("Boolean Time: ~p~n", [BooleanTime]), 25 | 26 | CounterFun = fun() -> 27 | lists:foldl(fun(_X, Acc) -> 28 | {ok, State} = state_gcounter:mutate(increment, self(), Acc), 29 | State 30 | end, state_gcounter:new(), lists:seq(1, ?OPS)) 31 | end, 32 | {CounterTime, _} = timer:tc(CounterFun), 33 | io:format("G-Counter Time: ~p~n", [CounterTime]), 34 | 35 | ok. 36 | -------------------------------------------------------------------------------- /bin/dcos-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source helpers.sh 4 | 5 | TIMESTAMP_FILE=/tmp/.LAST_TIMESTAMP 6 | 7 | ENV_VARS=( 8 | LASP_BRANCH 9 | DCOS 10 | ELB_HOST 11 | PEER_SERVICE 12 | MODE 13 | BROADCAST 14 | SIMULATION 15 | EVAL_ID 16 | EVAL_TIMESTAMP 17 | CLIENT_NUMBER 18 | HEAVY_CLIENT 19 | REACTIVE_SERVER 20 | PARTITION_PROBABILITY 21 | STATE_INTERVAL 22 | DELTA_INTERVAL 23 | INSTRUMENTATION 24 | LOGS 25 | EXTENDED_LOGGING 26 | MAILBOX_LOGGING 27 | AWS_ACCESS_KEY_ID 28 | AWS_SECRET_ACCESS_KEY 29 | ) 30 | 31 | for ENV_VAR in "${ENV_VARS[@]}" 32 | do 33 | if [ -z "${!ENV_VAR}" ]; then 34 | echo ">>> ${ENV_VAR} is not configured; please export it." 35 | exit 1 36 | fi 37 | done 38 | 39 | echo ">>> Beginning deployment!" 40 | 41 | if [ -e "$TIMESTAMP_FILE" ]; then 42 | # Last timestamp used to deploy an experiment 43 | LAST_TIMESTAMP=$(cat $TIMESTAMP_FILE) 44 | 45 | echo ">>> Removing lasp-server-$LAST_TIMESTAMP from Marathon" 46 | curl -s -k -H 'Content-type: application/json' -X DELETE $DCOS/service/marathon/v2/apps/lasp-server-$LAST_TIMESTAMP > /dev/null 47 | sleep 2 48 | 49 | echo ">>> Removing lasp-client-$LAST_TIMESTAMP from Marathon" 50 | curl -s -k -H 'Content-type: application/json' -X DELETE $DCOS/service/marathon/v2/apps/lasp-client-$LAST_TIMESTAMP > /dev/null 51 | sleep 2 52 | 53 | echo ">>> Waiting for Mesos to kill all tasks." 54 | wait_for_completion $LAST_TIMESTAMP 55 | else 56 | echo ">>> No apps to be removed from Marathon" 57 | fi 58 | 59 | echo ">>> Configuring Lasp" 60 | cd /tmp 61 | 62 | # Memory of each VM. 63 | SERVER_MEMORY=4096.0 64 | CLIENT_MEMORY=1024.0 65 | 66 | # CPU of each VM. 67 | SERVER_CPU=2 68 | CLIENT_CPU=0.5 69 | 70 | # Docker image 71 | IMAGE=vitorenesduarte/lasp-dev 72 | 73 | cat < lasp-server.json 74 | { 75 | "acceptedResourceRoles": [ 76 | "slave_public" 77 | ], 78 | "id": "lasp-server-$EVAL_TIMESTAMP", 79 | "dependencies": [], 80 | "constraints": [["hostname", "UNIQUE", ""]], 81 | "cpus": $SERVER_CPU, 82 | "mem": $SERVER_MEMORY, 83 | "instances": 1, 84 | "container": { 85 | "type": "DOCKER", 86 | "docker": { 87 | "image": "$IMAGE", 88 | "network": "HOST", 89 | "forcePullImage": true, 90 | "parameters": [ 91 | { "key": "oom-kill-disable", "value": "true" } 92 | ] 93 | } 94 | }, 95 | "ports": [0, 0], 96 | "env": { 97 | "LASP_BRANCH": "$LASP_BRANCH", 98 | "AD_COUNTER_SIM_SERVER": "true", 99 | "TAG": "server", 100 | "DCOS": "$DCOS", 101 | "PEER_SERVICE": "$PEER_SERVICE", 102 | "MODE": "$MODE", 103 | "BROADCAST": "$BROADCAST", 104 | "SIMULATION": "$SIMULATION", 105 | "EVAL_ID": "$EVAL_ID", 106 | "EVAL_TIMESTAMP": "$EVAL_TIMESTAMP", 107 | "CLIENT_NUMBER": "$CLIENT_NUMBER", 108 | "HEAVY_CLIENT": "$HEAVY_CLIENT", 109 | "REACTIVE_SERVER": "$REACTIVE_SERVER", 110 | "PARTITION_PROBABILITY": "$PARTITION_PROBABILITY", 111 | "STATE_INTERVAL": "$STATE_INTERVAL", 112 | "DELTA_INTERVAL": "$DELTA_INTERVAL", 113 | "INSTRUMENTATION": "$INSTRUMENTATION", 114 | "LOGS": "$LOGS", 115 | "EXTENDED_LOGGING": "$EXTENDED_LOGGING", 116 | "MAILBOX_LOGGING": "$MAILBOX_LOGGING", 117 | "AWS_ACCESS_KEY_ID": "$AWS_ACCESS_KEY_ID", 118 | "AWS_SECRET_ACCESS_KEY": "$AWS_SECRET_ACCESS_KEY" 119 | }, 120 | "labels": { 121 | "HAPROXY_GROUP":"external", 122 | "HAPROXY_0_VHOST":"$ELB_HOST" 123 | }, 124 | "healthChecks": [ 125 | { 126 | "path": "/api/health", 127 | "portIndex": 0, 128 | "protocol": "HTTP", 129 | "gracePeriodSeconds": 300, 130 | "intervalSeconds": 60, 131 | "timeoutSeconds": 20, 132 | "maxConsecutiveFailures": 3, 133 | "ignoreHttp1xx": false 134 | } 135 | ] 136 | } 137 | EOF 138 | 139 | echo ">>> Adding lasp-server-$EVAL_TIMESTAMP to Marathon" 140 | curl -s -k -H 'Content-type: application/json' -X POST -d @lasp-server.json "$DCOS/service/marathon/v2/apps?force=true" > /dev/null 141 | sleep 10 142 | 143 | cat < lasp-client.json 144 | { 145 | "acceptedResourceRoles": [ 146 | "slave_public" 147 | ], 148 | "id": "lasp-client-$EVAL_TIMESTAMP", 149 | "dependencies": [], 150 | "cpus": $CLIENT_CPU, 151 | "mem": $CLIENT_MEMORY, 152 | "instances": $CLIENT_NUMBER, 153 | "container": { 154 | "type": "DOCKER", 155 | "docker": { 156 | "image": "$IMAGE", 157 | "network": "HOST", 158 | "forcePullImage": true, 159 | "parameters": [ 160 | { "key": "oom-kill-disable", "value": "true" } 161 | ] 162 | } 163 | }, 164 | "ports": [0, 0], 165 | "env": { 166 | "LASP_BRANCH": "$LASP_BRANCH", 167 | "AD_COUNTER_SIM_CLIENT": "true", 168 | "TAG": "client", 169 | "DCOS": "$DCOS", 170 | "PEER_SERVICE": "$PEER_SERVICE", 171 | "MODE": "$MODE", 172 | "BROADCAST": "$BROADCAST", 173 | "SIMULATION": "$SIMULATION", 174 | "EVAL_ID": "$EVAL_ID", 175 | "EVAL_TIMESTAMP": "$EVAL_TIMESTAMP", 176 | "CLIENT_NUMBER": "$CLIENT_NUMBER", 177 | "HEAVY_CLIENT": "$HEAVY_CLIENT", 178 | "REACTIVE_SERVER": "$REACTIVE_SERVER", 179 | "PARTITION_PROBABILITY": "$PARTITION_PROBABILITY", 180 | "STATE_INTERVAL": "$STATE_INTERVAL", 181 | "DELTA_INTERVAL": "$DELTA_INTERVAL", 182 | "INSTRUMENTATION": "$INSTRUMENTATION", 183 | "LOGS": "$LOGS", 184 | "EXTENDED_LOGGING": "$EXTENDED_LOGGING", 185 | "MAILBOX_LOGGING": "$MAILBOX_LOGGING", 186 | "AWS_ACCESS_KEY_ID": "$AWS_ACCESS_KEY_ID", 187 | "AWS_SECRET_ACCESS_KEY": "$AWS_SECRET_ACCESS_KEY" 188 | }, 189 | "healthChecks": [ 190 | { 191 | "path": "/api/health", 192 | "portIndex": 0, 193 | "protocol": "HTTP", 194 | "gracePeriodSeconds": 300, 195 | "intervalSeconds": 60, 196 | "timeoutSeconds": 20, 197 | "maxConsecutiveFailures": 3, 198 | "ignoreHttp1xx": false 199 | } 200 | ] 201 | } 202 | EOF 203 | 204 | echo ">>> Adding lasp-client-$EVAL_TIMESTAMP to Marathon" 205 | curl -s -k -H 'Content-type: application/json' -X POST -d @lasp-client.json "$DCOS/service/marathon/v2/apps?force=true" > /dev/null 206 | sleep 10 207 | 208 | echo $EVAL_TIMESTAMP > $TIMESTAMP_FILE 209 | -------------------------------------------------------------------------------- /bin/elb-host.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ELB_HOST=$(aws cloudformation describe-stacks --stack-name ${STACK_NAME} --query 'Stacks[0].Outputs[2].OutputValue' | sed -e s/\"//g) 4 | echo $ELB_HOST 5 | -------------------------------------------------------------------------------- /bin/env: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # If we're running in Kubernetes... 4 | if [ ! -z "$KUBERNETES_PORT" ]; then 5 | echo "Running in Kubernetes..." 6 | 7 | # Else, default to IP. 8 | if [ -z "$NODE_NAME" ]; then 9 | export NODE_NAME=${HOSTNAME}@${MY_POD_IP} 10 | fi 11 | 12 | export IP=${MY_POD_IP} 13 | fi 14 | 15 | # If we're running in Mesos... 16 | if [ ! -z "$MESOS_TASK_ID" ]; then 17 | # Choose publicly routable IP. 18 | if [ -z "$IP" ]; then 19 | export IP=$(ip route get 8.8.8.8 | head -1 | cut -d' ' -f8) 20 | fi 21 | 22 | # Choose the hostname for the epmd long name if the hostname exists 23 | # and if it resolves through the resolver; using a resolvable name 24 | # that's only resolvable with resolv.conf won't work for long names. 25 | if [ ! -z "$HOSTNAME" ]; then 26 | if /usr/bin/dig ${HOSTNAME} | grep -q 'NXDOMAIN' 27 | export NODE_NAME=lasp-${PORT1}@${HOSTNAME} 28 | then 29 | export NODE_NAME=lasp-${PORT1}@${IP} 30 | fi 31 | fi 32 | 33 | # Else, default to IP. 34 | if [ -z "$NODE_NAME" ]; then 35 | export NODE_NAME=lasp-${PORT1}@${IP} 36 | fi 37 | 38 | # The running port should be used as the name, given this is the 39 | # only identifier that is available via service discovery. 40 | export WEB_PORT=${PORT0} 41 | 42 | # Peer port 43 | export PEER_PORT=${PORT1} 44 | fi 45 | 46 | # If we're running in Docker compose... 47 | if [ ! -z "$DOCKER_COMPOSE" ]; then 48 | export IP=$(awk 'END{print $1}' /etc/hosts) 49 | export NODE_NAME=${HOSTNAME}@${IP} 50 | fi 51 | 52 | # Assume 127.0.0.1 as bind host. 53 | if [ -z "$IP" ]; then 54 | echo "IP address not set; defaulting to 127.0.0.1." 55 | export IP=127.0.0.1 56 | fi 57 | 58 | if [ -z "$NODE_NAME" ]; then 59 | export NODE_NAME=lasp@${IP} 60 | fi 61 | 62 | if [ -z "$COOKIE" ]; then 63 | export COOKIE=lasp 64 | fi 65 | 66 | export RELX_REPLACE_OS_VARS=true 67 | 68 | echo "MESOS_TASK_ID: ${MESOS_TASK_ID}" 69 | echo "PORT0: ${PORT0}" 70 | echo "PEER_PORT: ${PEER_PORT}" 71 | echo "WEB_PORT: ${WEB_PORT}" 72 | echo "NODE_NAME: ${NODE_NAME}" 73 | echo "COOKIE: ${COOKIE}" 74 | echo "IP: ${IP}" 75 | echo "HOSTNAME: ${HOSTNAME}" 76 | echo "APISERVER: ${APISERVER}" 77 | echo "MY_POD_IP: ${MY_POD_IP}" 78 | echo "AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}" 79 | echo "AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}" 80 | 81 | echo "Printing the environment:" 82 | env 83 | 84 | RELNAME="`dirname \"$0\"`"/lasp 85 | exec ${RELNAME} foreground "$@" 86 | -------------------------------------------------------------------------------- /bin/event-interval: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | print int((1000/440 * ($ENV{'N'} - 1))) + 1; 4 | -------------------------------------------------------------------------------- /bin/gce-start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | gcloud beta container clusters create lasp 4 | gcloud beta container clusters get-credentials lasp 5 | -------------------------------------------------------------------------------- /bin/gce-stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | gcloud beta container clusters delete lasp 4 | -------------------------------------------------------------------------------- /bin/helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function wait_for_completion { 4 | LAST_TIMESTAMP=$1 5 | DONE=0 6 | 7 | while [ ! "$DONE" == "" ] 8 | do 9 | sleep 10 10 | DONE=$(curl -s -H 'Content-type: application/json' -X GET $DCOS/service/marathon/v2/apps | python -m json.tool | grep -E "lasp-client-$LAST_TIMESTAMP|lasp-server-$LAST_TIMESTAMP") 11 | done 12 | } 13 | -------------------------------------------------------------------------------- /bin/ienv: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # If we're running in Mesos... 4 | if [ ! -z "$MESOS_TASK_ID" ]; then 5 | # Choose publicly routable IP. 6 | if [ -z "$IP" ]; then 7 | export IP=$(ip route get 8.8.8.8 | head -1 | cut -d' ' -f8) 8 | fi 9 | 10 | # Choose the hostname for the epmd long name if the hostname exists 11 | # and if it resolves through the resolver; using a resolvable name 12 | # that's only resolvable with resolv.conf won't work for long names. 13 | if [ ! -z "$HOSTNAME" ]; then 14 | if /usr/bin/dig ${HOSTNAME} | grep -q 'NXDOMAIN' 15 | export NODE_NAME=lasp-${PORT1}@${HOSTNAME} 16 | then 17 | export NODE_NAME=lasp-${PORT1}@${IP} 18 | fi 19 | fi 20 | 21 | # Else, default to IP. 22 | if [ -z "$NODE_NAME" ]; then 23 | export NODE_NAME=lasp-${PORT1}@${IP} 24 | fi 25 | 26 | # The running port should be used as the name, given this is the 27 | # only identifier that is available via service discovery. 28 | export WEB_PORT=${PORT0} 29 | 30 | # Peer port 31 | export PEER_PORT=${PORT1} 32 | fi 33 | 34 | # Assume 127.0.0.1 as bind host. 35 | if [ -z "$IP" ]; then 36 | echo "IP address not set; defaulting to 127.0.0.1." 37 | export IP=127.0.0.1 38 | fi 39 | 40 | if [ -z "$NODE_NAME" ]; then 41 | export NODE_NAME=lasp@${IP} 42 | fi 43 | 44 | if [ -z "$COOKIE" ]; then 45 | export COOKIE=lasp 46 | fi 47 | 48 | export RELX_REPLACE_OS_VARS=true 49 | 50 | echo "MESOS_TASK_ID: ${MESOS_TASK_ID}" 51 | echo "PORT0: ${PORT0}" 52 | echo "WEB_PORT: ${WEB_PORT}" 53 | echo "NODE_NAME: ${NODE_NAME}" 54 | echo "COOKIE: ${COOKIE}" 55 | echo "IP: ${IP}" 56 | echo "HOSTNAME: ${HOSTNAME}" 57 | 58 | RELNAME="`dirname \"$0\"`"/lasp 59 | exec ${RELNAME} console "$@" 60 | -------------------------------------------------------------------------------- /bin/kube-divergence-automation: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | STATE_INTERVALS=(2 8 32 128 2048 4096) 4 | 5 | for k in ${STATE_INTERVALS[@]}; do 6 | echo "Running simulation with interval ${k}" 7 | STATE_INTERVAL=${k} bin/kube-divergence-simulation 8 | done 9 | -------------------------------------------------------------------------------- /bin/kube-throughput-simulation: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CLIENTS=(1 2 4) 4 | NODES=3 5 | LASP_BRANCH=workflow-v2 6 | IMAGE=lasp-dev 7 | REPS=1 8 | GCE=true 9 | MACHINE="n1-standard-8" 10 | MAX_EVENTS=50000 11 | STATE_INTERVAL=2000 12 | BLOCKING_SYNC=false 13 | 14 | # Rebuild image if desired. 15 | if [ ! -z "$REBUILD_IMAGE" ]; then 16 | # Delete image 17 | IMAGE_IDS=$(docker images | grep lasplang/${IMAGE} | awk '{print $3}') 18 | echo "Images matching for deletion: ${IMAGE_IDS}" 19 | 20 | if [ ! -z "$IMAGE_IDS" ]; then 21 | docker rmi ${IMAGE_IDS} 22 | fi 23 | 24 | # Rebuild image fresh, to ensure no stale dependencies 25 | docker build -f Dockerfiles/$IMAGE -t lasplang/${IMAGE} --no-cache=t . 26 | 27 | # Push image to hub 28 | docker push lasplang/${IMAGE} 29 | fi 30 | 31 | # Perform cluster operations if necessary. 32 | if [ ! -z "$CLUSTER_START" ]; then 33 | # Bootstrap cluster 34 | gcloud beta container clusters create lasp \ 35 | --machine-type=${MACHINE} \ 36 | --num-nodes=${NODES} 37 | 38 | # Get container credential 39 | gcloud beta container clusters get-credentials lasp 40 | fi 41 | 42 | echo "Removing initial labeling." 43 | kubectl label nodes --all client_number- 44 | 45 | echo "Removing deployments, services, pods, and replicasets." 46 | kubectl delete deployments --all 47 | kubectl delete replicasets --all 48 | kubectl delete services --all 49 | kubectl delete pods --all 50 | 51 | echo "Removing /tmp logs." 52 | rm -rf /tmp/logs 53 | 54 | if [ ! -z "$DELETE_LOGS" ]; then 55 | echo "Removing older logs." 56 | rm -rf priv/evaluation/logs 57 | fi 58 | 59 | # Allocate machines accordingly. 60 | for i in ${CLIENTS[@]}; do 61 | # Find a machine we can allocate these to. 62 | AVAILABLE=$(kubectl get nodes -l '!client_number' | grep Ready | head -1 | awk '{print $1}') 63 | 64 | # Label the node. 65 | kubectl label node ${AVAILABLE} client_number=${i} 66 | 67 | echo "Labeled node ${AVAILABLE} for runs of ${i} clients." 68 | done 69 | 70 | # Deploy a single redis instance. 71 | echo "Copying code to /tmp" 72 | cp bin/sync-redis.erl /tmp 73 | cp bin/kube-throughput /tmp 74 | mkdir -p /tmp/_build/exp/lib/eredis/ebin 75 | cp -Rp _build/exp/lib/eredis/ebin/* /tmp/_build/exp/lib/eredis/ebin 76 | 77 | cd /tmp 78 | 79 | cat < redis.yaml 80 | apiVersion: v1 81 | kind: Service 82 | metadata: 83 | name: redis 84 | labels: 85 | run: redis 86 | spec: 87 | type: LoadBalancer 88 | ports: 89 | - port: 6379 90 | protocol: TCP 91 | name: tcp 92 | selector: 93 | run: redis 94 | --- 95 | apiVersion: extensions/v1beta1 96 | kind: Deployment 97 | metadata: 98 | name: redis 99 | spec: 100 | replicas: 1 101 | template: 102 | metadata: 103 | labels: 104 | run: redis 105 | spec: 106 | containers: 107 | - name: redis 108 | image: redis 109 | EOF 110 | 111 | echo "Creating redis deployment." 112 | kubectl create -f /tmp/redis.yaml 113 | echo 114 | 115 | echo "Sleeping for redis deployment..." 116 | sleep 10 117 | 118 | # Start the executions in parallel. 119 | for k in ${CLIENTS[@]}; do 120 | echo "Launching client simulation: ${k}" 121 | BLOCKING_SYNC=${BLOCKING_SYNC} \ 122 | STATE_INTERVAL=${STATE_INTERVAL} \ 123 | MAX_EVENTS=${MAX_EVENTS} \ 124 | REPS=${REPS} \ 125 | LASP_BRANCH=${LASP_BRANCH} \ 126 | IMAGE=${IMAGE} \ 127 | GCE=${GCE} \ 128 | THROUGHPUT_TYPE=boolean \ 129 | CLIENT_NUMBER=${k} \ 130 | ./kube-throughput & 131 | sleep 10 132 | done 133 | 134 | # Wait for all of the tests to finish; 135 | RUNNING=$(kubectl get pods | wc -l) 136 | 137 | # redis will always be running, so wait until there are no more lasp pods 138 | # and a title line -- HACK. 139 | while [ $RUNNING -ne 2 ]; do 140 | echo "Sleeping until pods are destroyed." 141 | echo "Running pods: " 142 | kubectl get pods 143 | sleep 2 144 | RUNNING=$(kubectl get pods | wc -l) 145 | done 146 | 147 | echo "All tasks are finished." 148 | 149 | # Download data from Redis at the end of the execution. 150 | if [ "$GCE" ]; then 151 | echo "Running in Google Container Engine." 152 | export REDIS_SERVICE_HOST=$(kubectl get services | grep redis | awk '{print $3}' | head -1) 153 | # export REDIS_SERVICE_HOST=$(gcloud compute forwarding-rules list | grep TCP | awk '{print $3}' | tail -1) 154 | export REDIS_SERVICE_PORT=6379 155 | echo "REDIS_SERVICE_HOST: ${REDIS_SERVICE_HOST}" 156 | echo "REDIS_SERVICE_PORT: ${REDIS_SERVICE_PORT}" 157 | else 158 | export REDIS_SERVICE_HOST=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " " | head -1 | cut -f 2-2 -d ":" | sed -e 's/\/\///g') 159 | export REDIS_SERVICE_PORT=$(kubectl get service redis -o jsonpath="{.spec.ports[*].nodePort}") 160 | fi 161 | 162 | echo "Downloading data from Redis." 163 | ./sync-redis.erl 164 | mkdir -p ~/Documents/lasp/priv/evaluation/logs 165 | cp -Rp /tmp/logs/* ~/Documents/lasp/priv/evaluation/logs 166 | 167 | # Terminate redis only if we explicitly say so, given sometimes we have 168 | # to aggregate the logs later if for some instance we are being port 169 | # filtered. 170 | if [ ! -z "$REDIS_STOP" ]; then 171 | echo "Deleting redis deployments and servies." 172 | kubectl delete -f /tmp/redis.yaml 173 | echo 174 | fi 175 | 176 | # Perform cluster operations if necessary. 177 | if [ ! -z "$CLUSTER_STOP" ]; then 178 | # Terminate the cluster 179 | yes | gcloud beta container clusters delete lasp 180 | fi 181 | -------------------------------------------------------------------------------- /bin/launch-instances-m3-2xlarge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | KEY_NAME=dcos 4 | STACK_NAME=dcos-m3-2xlarge-ha 5 | 6 | echo "Launching Oregon." 7 | aws cloudformation create-stack \ 8 | --stack-name ${STACK_NAME} \ 9 | --template-url https://s3-us-west-2.amazonaws.com/cf-templates-akuyolple9l-us-west-2/2016343unS-HA-m3.2xlargeqc3w6invj9v2yhfcuq4dndn29 \ 10 | --capabilities CAPABILITY_IAM \ 11 | --parameters ParameterKey=KeyName,ParameterValue=${KEY_NAME} \ 12 | ParameterKey=PublicSlaveInstanceCount,ParameterValue=50 \ 13 | ParameterKey=OAuthEnabled,ParameterValue=false \ 14 | ParameterKey=SlaveInstanceCount,ParameterValue=0 15 | 16 | echo "Waiting for stack creation." 17 | aws cloudformation wait stack-create-complete --stack-name ${STACK_NAME} 18 | 19 | DCOS_URL=$(aws cloudformation describe-stacks --stack-name ${STACK_NAME} --query 'Stacks[0].Outputs[0].OutputValue' | sed -e s/\"//g) 20 | 21 | echo "Configuring DCOS url." 22 | dcos config set core.dcos_url "http://${DCOS_URL}" 23 | 24 | echo "Installing marathon-lb." 25 | yes | dcos package install marathon-lb 26 | 27 | # Determine platform. 28 | platform='unknown' 29 | unamestr=`uname` 30 | if [[ "$unamestr" == 'Linux' ]]; then 31 | platform='linux' 32 | else 33 | platform='darwin' 34 | fi 35 | 36 | if [[ $platform == 'linux' ]]; then 37 | google-chrome ${DCOS_URL} 38 | else 39 | open "http://${DCOS_URL}" 40 | fi 41 | -------------------------------------------------------------------------------- /bin/launch-instances-m4-4xlarge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | KEY_NAME=dcos 4 | STACK_NAME=dcos-m4-4xlarge 5 | 6 | echo "Launching Oregon." 7 | aws cloudformation create-stack \ 8 | --stack-name ${STACK_NAME} \ 9 | --template-url https://s3-us-west-2.amazonaws.com/cf-templates-akuyolple9l-us-west-2/2016348aHI-HA-m4.4xlarge2drq2cmkzv8ucvbt2ljfxhia4i \ 10 | --capabilities CAPABILITY_IAM \ 11 | --parameters ParameterKey=KeyName,ParameterValue=${KEY_NAME} \ 12 | ParameterKey=PublicSlaveInstanceCount,ParameterValue=35 \ 13 | ParameterKey=OAuthEnabled,ParameterValue=false \ 14 | ParameterKey=SlaveInstanceCount,ParameterValue=0 15 | 16 | echo "Waiting for stack creation." 17 | aws cloudformation wait stack-create-complete --stack-name ${STACK_NAME} 18 | 19 | DCOS_URL=$(aws cloudformation describe-stacks --stack-name ${STACK_NAME} --query 'Stacks[0].Outputs[0].OutputValue' | sed -e s/\"//g) 20 | 21 | echo "Configuring DCOS url." 22 | dcos config set core.dcos_url "http://${DCOS_URL}" 23 | 24 | echo "Installing marathon-lb." 25 | yes | dcos package install marathon-lb 26 | 27 | # Determine platform. 28 | platform='unknown' 29 | unamestr=`uname` 30 | if [[ "$unamestr" == 'Linux' ]]; then 31 | platform='linux' 32 | else 33 | platform='darwin' 34 | fi 35 | 36 | if [[ $platform == 'linux' ]]; then 37 | google-chrome ${DCOS_URL} 38 | else 39 | open "http://${DCOS_URL}" 40 | fi 41 | -------------------------------------------------------------------------------- /bin/launch-instances.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Launching Oregon." 4 | aws cloudformation create-stack \ 5 | --stack-name dcos \ 6 | --template-body https://s3-us-west-2.amazonaws.com/downloads.dcos.io/dcos/stable/commit/e64024af95b62c632c90b9063ed06296fcf38ea5/cloudformation/multi-master.cloudformation.json \ 7 | --capabilities CAPABILITY_IAM \ 8 | --parameters ParameterKey=KeyName,ParameterValue=dcos \ 9 | ParameterKey=PublicSlaveInstanceCount,ParameterValue=40 \ 10 | ParameterKey=OAuthEnabled,ParameterValue=false \ 11 | ParameterKey=SlaveInstanceCount,ParameterValue=0 12 | 13 | echo "Waiting for stack creation." 14 | aws cloudformation wait stack-create-complete --stack-name dcos 15 | 16 | DCOS_URL=$(aws cloudformation describe-stacks --stack-name dcos --query 'Stacks[0].Outputs[0].OutputValue' | sed -e s/\"//g) 17 | 18 | echo "Configuring DCOS url." 19 | dcos config set core.dcos_url "http://${DCOS_URL}" 20 | 21 | echo "Installing marathon-lb." 22 | yes | dcos package install marathon-lb 23 | 24 | # Determine platform. 25 | platform='unknown' 26 | unamestr=`uname` 27 | if [[ "$unamestr" == 'Linux' ]]; then 28 | platform='linux' 29 | else 30 | platform='darwin' 31 | fi 32 | 33 | if [[ $platform == 'linux' ]]; then 34 | google-chrome ${DCOS_URL} 35 | else 36 | open "http://${DCOS_URL}" 37 | fi 38 | -------------------------------------------------------------------------------- /bin/open-ui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "http://`STACK_NAME=dcos ./bin/elb-host.sh`" | xargs open 4 | -------------------------------------------------------------------------------- /bin/start-dcos-runner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DCOS=$(dcos config show core.dcos_url) 4 | ELB_HOST=$(./bin/elb-host.sh) 5 | 6 | ENV_VARS=( 7 | STACK_NAME 8 | LASP_BRANCH 9 | AWS_ACCESS_KEY_ID 10 | AWS_SECRET_ACCESS_KEY 11 | CLIENT_NUMBER 12 | PARTITION_PROBABILITY 13 | ) 14 | 15 | for ENV_VAR in "${ENV_VARS[@]}" 16 | do 17 | if [ -z "${!ENV_VAR}" ]; then 18 | echo ">>> ${ENV_VAR} is not configured; please export it." 19 | exit 1 20 | fi 21 | done 22 | 23 | echo ">>> Configuring Runner" 24 | cd /tmp 25 | 26 | # Memory of VM. 27 | MEMORY=512.0 28 | 29 | # CPU of VM. 30 | CPU=0.5 31 | 32 | cat < dcos-runner.json 33 | { 34 | "acceptedResourceRoles": [ 35 | "slave_public" 36 | ], 37 | "id": "dcos-runner-$CLIENT_NUMBER-$PARTITION_PROBABILITY", 38 | "dependencies": [], 39 | "constraints": [], 40 | "cpus": $CPU, 41 | "mem": $MEMORY, 42 | "instances": 1, 43 | "container": { 44 | "type": "DOCKER", 45 | "docker": { 46 | "image": "vitorenesduarte/dcos-runner", 47 | "network": "HOST", 48 | "forcePullImage": true, 49 | "parameters": [ 50 | { "key": "oom-kill-disable", "value": "true" } 51 | ] 52 | } 53 | }, 54 | "ports": [0, 0], 55 | "env": { 56 | "LASP_BRANCH": "$LASP_BRANCH", 57 | "DCOS": "$DCOS", 58 | "ELB_HOST": "$ELB_HOST", 59 | "AWS_ACCESS_KEY_ID": "$AWS_ACCESS_KEY_ID", 60 | "AWS_SECRET_ACCESS_KEY": "$AWS_SECRET_ACCESS_KEY", 61 | "CLIENT_NUMBER": "$CLIENT_NUMBER", 62 | "PARTITION_PROBABILITY": "$PARTITION_PROBABILITY" 63 | }, 64 | "healthChecks": [] 65 | } 66 | EOF 67 | 68 | echo ">>> Adding dcos-runner-$CLIENT_NUMBER-$PARTITION_PROBABILITY to Marathon" 69 | curl -s -k -H 'Content-type: application/json' -X POST -d @dcos-runner.json "$DCOS/service/marathon/v2/apps?force=true" > /dev/null 70 | 71 | sleep 120 72 | echo ">>> Tailing server logs." 73 | dcos task log --follow lasp-server 74 | -------------------------------------------------------------------------------- /bin/sync-redis.erl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | 3 | %%! -pa _build/exp/lib/eredis/ebin/ 4 | 5 | main(_) -> 6 | RedisHost = os:getenv("REDIS_SERVICE_HOST", "127.0.0.1"), 7 | RedisPort = os:getenv("REDIS_SERVICE_PORT", "6379"), 8 | {ok, C} = eredis:start_link(RedisHost, list_to_integer(RedisPort)), 9 | {ok, Keys} = eredis:q(C, ["KEYS", "*"]), 10 | 11 | lists:foreach(fun(Filename) -> 12 | {ok, Content} = eredis:q(C, ["GET", Filename]), 13 | Path = "logs/" ++ binary_to_list(Filename), 14 | io:format("Adding to /tmp, file: ~p~n", [Path]), 15 | ok = filelib:ensure_dir(Path), 16 | ok = file:write_file(Path, Content) 17 | end, Keys), 18 | 19 | ok. 20 | -------------------------------------------------------------------------------- /bin/transmission.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source helpers.sh 4 | 5 | ENV_VARS=( 6 | LASP_BRANCH 7 | DCOS 8 | ELB_HOST 9 | AWS_ACCESS_KEY_ID 10 | AWS_SECRET_ACCESS_KEY 11 | CLIENT_NUMBER 12 | PARTITION_PROBABILITY 13 | ) 14 | 15 | for ENV_VAR in "${ENV_VARS[@]}" 16 | do 17 | if [ -z "${!ENV_VAR}" ]; then 18 | echo ">>> ${ENV_VAR} is not configured; please export it." 19 | exit 1 20 | fi 21 | done 22 | 23 | EVAL_NUMBER=1 24 | SIMULATION=ad_counter 25 | STATE_INTERVAL=5000 26 | DELTA_INTERVAL=5000 27 | INSTRUMENTATION=true 28 | LOGS="s3" 29 | EXTENDED_LOGGING=true 30 | MAILBOX_LOGGING=true 31 | 32 | declare -A EVALUATIONS 33 | 34 | # peer service | mode | broadcast (boolean) | heavy_clients (boolean) | reactive_server (boolean) 35 | EVALUATIONS["peer_to_peer_state_based_with_aae_test"]="partisan_hyparview_peer_service_manager state_based false false false" 36 | #EVALUATIONS["peer_to_peer_state_based_with_aae_and_tree_test"]="partisan_default_peer_service_manager state_based true false false" 37 | #EVALUATIONS["peer_to_peer_state_based_with_aae_and_tree_test"]="partisan_hyparview_peer_service_manager state_based true false false" 38 | #EVALUATIONS["peer_to_peer_delta_based_with_aae_test"]="partisan_hyparview_peer_service_manager delta_based false false false" 39 | #EVALUATIONS["client_server_state_based_with_aae_test"]="partisan_client_server_peer_service_manager state_based false false false" 40 | 41 | for i in $(seq 1 $EVAL_NUMBER) 42 | do 43 | echo "[$(date +%T)] Running evaluation $i of $EVAL_NUMBER" 44 | 45 | for EVAL_ID in "${!EVALUATIONS[@]}" 46 | do 47 | STR=${EVALUATIONS["$EVAL_ID"]} 48 | IFS=' ' read -a CONFIG <<< "$STR" 49 | PEER_SERVICE=${CONFIG[0]} 50 | MODE=${CONFIG[1]} 51 | BROADCAST=${CONFIG[2]} 52 | HEAVY_CLIENT=${CONFIG[3]} 53 | REACTIVE_SERVER=${CONFIG[4]} 54 | # unix timestamp + nanoseconds 55 | TIMESTAMP=$(date +%s)$(date +%N) 56 | REAL_EVAL_ID=$EVAL_ID"_"$CLIENT_NUMBER"_"$PARTITION_PROBABILITY 57 | 58 | PEER_SERVICE=$PEER_SERVICE MODE=$MODE BROADCAST=$BROADCAST SIMULATION=$SIMULATION EVAL_ID=$REAL_EVAL_ID EVAL_TIMESTAMP=$TIMESTAMP HEAVY_CLIENT=$HEAVY_CLIENT REACTIVE_SERVER=$REACTIVE_SERVER STATE_INTERVAL=$STATE_INTERVAL DELTA_INTERVAL=$DELTA_INTERVAL INSTRUMENTATION=$INSTRUMENTATION LOGS=$LOGS EXTENDED_LOGGING=$EXTENDED_LOGGING MAILBOX_LOGGING=$MAILBOX_LOGGING ./dcos-deploy.sh 59 | 60 | echo "[$(date +%T)] Running $EVAL_ID with $CLIENT_NUMBER clients; $PARTITION_PROBABILITY % partitions; with configuration $STR" 61 | 62 | wait_for_completion $TIMESTAMP 63 | # Marathon may reply that no app is running but the resources may still be unavailable 64 | # Wait 10 minutes 65 | # sleep 600 66 | done 67 | 68 | echo "[$(date +%T)] Evaluation $i of $EVAL_NUMBER completed!" 69 | done 70 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | environment: 3 | PATH: ${HOME}/extras/bin:${HOME}/extras/otp/18.1/bin:${PATH} 4 | dependencies: 5 | pre: 6 | - curl -O -L https://raw.githubusercontent.com/yrashk/kerl/master/kerl && chmod 755 kerl 7 | - if [ ! -d ~/extras/otp/18.1 ]; then ./kerl build 18.1 18.1; ./kerl install 18.1 ~/extras/otp/18.1; fi 8 | override: 9 | - make 10 | 11 | test: 12 | override: 13 | - make eunit 14 | - make ct 15 | - make lint 16 | - make dialyzer 17 | - make xref 18 | post: 19 | - mkdir -p $CIRCLE_TEST_REPORTS/ 20 | - mv TEST-*.xml $CIRCLE_TEST_REPORTS 21 | -------------------------------------------------------------------------------- /config/.vm.args.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/config/.vm.args.swp -------------------------------------------------------------------------------- /config/sys.config: -------------------------------------------------------------------------------- 1 | [{lasp, [{storage_backend, lasp_ets_storage_backend}]}, 2 | {plumtree, [{broadcast_exchange_timer, 60000}, 3 | {broadcast_mods, [lasp_plumtree_backend]}]}]. 4 | -------------------------------------------------------------------------------- /config/vm.args: -------------------------------------------------------------------------------- 1 | ## Name of the node 2 | -name ${NODE_NAME} 3 | 4 | ## Cookie for distributed erlang 5 | -setcookie ${COOKIE} 6 | 7 | ## Increase distribution port buffer size. 8 | +zdbbl 32768 9 | 10 | ## Enable multi_time_warp 11 | +C multi_time_warp 12 | 13 | ## Hidden nodes 14 | -hidden 15 | 16 | ## Explicit connections only. 17 | -connect_all false 18 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | redis: 4 | image: "redis:alpine" 5 | ports: 6 | - "6379:6379" 7 | lasp-client: 8 | environment: 9 | - TAG=client 10 | - REDIS_SERVICE_HOST=redis 11 | - REDIS_PORT=6379 12 | - LASP_BRANCH=master 13 | - DOCKER_COMPOSE=true 14 | build: . 15 | lasp-server: 16 | environment: 17 | - TAG=server 18 | - REDIS_SERVICE_HOST=redis 19 | - REDIS_PORT=6379 20 | - LASP_BRANCH=master 21 | - DOCKER_COMPOSE=true 22 | build: . 23 | -------------------------------------------------------------------------------- /experiments/activity.md: -------------------------------------------------------------------------------- 1 | # Activity 2 | 3 | Cluster up-time: 4 | 5 | - 10 m3.xlarge 6 | - from __2016-11-21 21:07:33__ to __2016-11-21 22:18:49__ (01h11) 7 | 8 | - 25 m3.xlarge 9 | - from __2016-11-19 12:06:37__ to __2016-11-19 13:20:44__ (01h14) 10 | - from __2016-11-20 14:00:31__ to __2016-11-20 17:28:47__ (03h28) 11 | - from __2016-11-21 13:36:05__ to __2016-11-21 15:20:19__ (01h44) 12 | - from __2016-11-21 15:41:45__ to __2016-11-21 17:16:11__ (01h37) 13 | 14 | - 40 m3.xlarge 15 | - from __2016-11-21 22:06:48__ to __2016-11-22 00:06:27__ (02h00) 16 | 17 | - 70 m3.xlarge 18 | - from __2016-12-14 08:35:49__ to __2016-12-14 11:51:07__ (03h16) 19 | 20 | - 75 m3.xlarge 21 | - from __2016-11-22 11:10:38__ to __2016-11-22 15:11:35__ (04h01) 22 | 23 | - 10 m3.2xlarge 24 | - from __2016-12-13 20:52:30__ to __2016-12-13 22:04:53__ (01h12) 25 | 26 | - 15 m3.2xlarge 27 | - from __2016-12-12 09:53:20__ to __2016-12-12 12:01:05__ (02h08) 28 | 29 | - 20 m3.2xlarge 30 | - from __2016-12-06 13:24:35__ to __2016-12-06 14:31:13__ (01h07) 31 | - from __2016-12-08 22:10:25__ to __2016-12-08 22:47:09__ (00h37) 32 | - from __2016-12-09 19:44:23__ to __2016-12-09 22:34:17__ (02h50) 33 | - from __2016-12-11 14:29:01__ to __2016-12-11 17:38:37__ (03h09) 34 | 35 | - 35 m3.2xlarge 36 | - from __2016-12-06 11:19:17__ to __2016-12-06 13:22:24__ (02h03) 37 | - from __2016-12-07 13:10:30__ to __2016-12-07 18:56:35__ (05h46) 38 | - from __2016-12-12 20:45:30__ to __2016-12-12 22:28:55__ (01h43) 39 | - from __2016-12-13 08:48:15__ to __2016-12-13 10:36:56__ (01h48) 40 | 41 | - 40 m3.2xlarge 42 | - from __2016-11-28 09:09:09__ to __2016-11-28 22:23:21__ (13h14) 43 | - from __2016-11-29 10:53:41__ to __2016-11-29 13:13:58__ (02h20) 44 | - from __2016-11-29 14:07:56__ to __2016-11-29 16:33:14__ (02h26) 45 | - from __2016-12-07 18:57:23__ to __2016-12-07 20:52:16__ (01h55) 46 | - from __2016-12-09 08:39:43__ to __2016-12-09 11:21:48__ (02h42) 47 | 48 | - 70 m3.2xlarge 49 | - from __2016-12-08 12:04:20__ to __2016-12-08 15:44:47__ (03h40) 50 | - from __2016-12-13 15:02:45__ to __2016-12-13 19:32:58__ (04h30) 51 | - from __2016-12-14 11:51:54__ to __2016-12-14 20:27:34__ (08h36) 52 | - from __2016-12-15 19:02:07__ to __2016-12-15 19:31:00__ (00h29) 53 | 54 | - 140 m3.2xlarge 55 | - from __2016-12-08 15:47:36__ to __2016-12-08 16:45:46__ (00h58) 56 | - from __2016-12-08 17:07:19__ to __2016-12-08 18:14:43__ (01h07) 57 | 58 | - 35 m4.4xlarge 59 | - from __2016-12-13 13:20:11__ to __2016-12-13 14:26:39__ (01h06) 60 | 61 | - 70 m4.4xlarge 62 | - from __2016-12-13 09:44:07__ to __2016-12-13 11:39:57__ (01h55) 63 | - from __2016-12-13 11:50:40__ to __2016-12-13 12:22:55__ (00h32) 64 | 65 | Total up-time: 66 | - 10 m3.xlarge: 01h11 67 | - 25 m3.xlarge: 08h03 68 | - 40 m3.xlarge: 02h00 69 | - 70 m3.xlarge: 03h16 70 | - 75 m3.xlarge: 04h01 71 | - 10 m3.2xlarge: 01h12 72 | - 15 m3.2xlarge: 02h08 73 | - 20 m3.2xlarge: 07h43 74 | - 35 m3.2xlarge: 11h20 75 | - 40 m3.2xlarge: 22h37 76 | - 70 m3.2xlarge: 17h15 77 | - 140 m3.2xlarge: 02h05 78 | - 35 m4.4xlarge: 01h06 79 | - 70 m4.4xlarge: 02h27 80 | -------------------------------------------------------------------------------- /experiments/experiments.md: -------------------------------------------------------------------------------- 1 | ## Starting the experiments 2 | 3 | This assumes: 4 | - AWS CLI ([how to configure it](./launch.md#configuring-aws-cli)) 5 | - DCOS CLI ([how to configure it](./manual-launch.md#configuring-dcos-cli-if-already-installed)) 6 | 7 | ```bash 8 | $ cd bin/ 9 | $ STACK_NAME=dcos \ 10 | LASP_BRANCH=dcos_again \ 11 | CLIENT_NUMBER=32 \ 12 | PARTITION_PROBABILITY=0 ./start-dcos-runner.sh 13 | ``` 14 | -------------------------------------------------------------------------------- /experiments/launch.md: -------------------------------------------------------------------------------- 1 | ## Configuring AWS CLI 2 | 3 | Add the following to your __.bashrc__ 4 | 5 | ```bash 6 | export AWS_ACCESS_KEY_ID=your_key 7 | export AWS_SECRET_ACCESS_KEY=your_secret 8 | ``` 9 | 10 | ```bash 11 | $ source .bashrc 12 | $ aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID 13 | $ aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY 14 | $ aws configure set default.region us-west-2 15 | ``` 16 | 17 | ## Launching the cluster 18 | 19 | ```bash 20 | $ cd bin/ 21 | $ ./launch-instances.sh 22 | ``` 23 | 24 | If you didn't have DCOS CLI installed, the script above did not configure it properly. 25 | See [how to do it](manual-launch.md#installing-dcos-cli-if-not-yet-installed). 26 | -------------------------------------------------------------------------------- /experiments/manual-launch.md: -------------------------------------------------------------------------------- 1 | ## Launching the cluster manually 2 | 3 | 1. Go to [this](https://downloads.dcos.io/dcos/stable/aws.html) link and select __US West (Oregon)__/__Single Master__ 4 | 5 | 2. In __Select Template__ just click __Next__ 6 | 7 | 3. In __Specify Details__: 8 | - __Stack name__: dcos 9 | - Pick one of your keys in __KeyName__ 10 | - __OAuthEnabled__: false 11 | - __PublicSlaveInstanceCount__: 25 12 | - __SlaveInstanceCount__: 0 13 | 14 | 4. In __Options__ just click __Next__ 15 | 16 | 5. In __Review__ click in __I acknowledge that AWS CloudFormation might create IAM resources__ and then in __Create__ 17 | 18 | Once the cluster is created, go to the __CloudFormation__ page in your AWS console, select the cluster and in the __Outputs__ tab you have: 19 | 20 | - __DnsAddress__: _$DCOS_ 21 | - __ExhibitorS3Bucket__ 22 | - __PublicSlaveDnsAddress__: _$ELB_HOST_ 23 | 24 | ## Installing DCOS CLI (if not yet installed) 25 | 26 | - Open _$DCOS_ in the browser 27 | - Click in __Install CLI__ (bottom-left corner) 28 | 29 | ## Configuring DCOS CLI (if already installed) 30 | 31 | ```bash 32 | $ dcos config set core.dcos_url http://$DCOS 33 | ``` 34 | 35 | ## Installing Marathon-lb 36 | 37 | ```bash 38 | $ dcos package install marathon-lb 39 | ``` 40 | 41 | Now, if Lasp is running in the cluster and you open _$ELB_HOST_ in your browser, you should see the __Lasp web UI__. 42 | 43 | ## Stopping the cluster 44 | 45 | You can stop the cluster by going to the __CloudFormation__ page in your AWS console. 46 | -------------------------------------------------------------------------------- /images/fast_spinning_3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/fast_spinning_3.gif -------------------------------------------------------------------------------- /images/lasp-logo-large-square.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/lasp-logo-large-square.jpg -------------------------------------------------------------------------------- /images/lasp-logo-large-square.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/lasp-logo-large-square.pxm -------------------------------------------------------------------------------- /images/lasp-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/lasp-logo-large.png -------------------------------------------------------------------------------- /images/lasp-logo-text-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/lasp-logo-text-large.png -------------------------------------------------------------------------------- /images/lasp-logo-text-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/lasp-logo-text-small.png -------------------------------------------------------------------------------- /images/lasp-logo-tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/lasp-logo-tiny.png -------------------------------------------------------------------------------- /images/netnow3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/netnow3.gif -------------------------------------------------------------------------------- /images/packagecloud-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/images/packagecloud-logo-dark.png -------------------------------------------------------------------------------- /include/sprinter.hrl: -------------------------------------------------------------------------------- 1 | %% State record. 2 | -record(state, {backend, 3 | is_connected, 4 | was_connected, 5 | attempted_nodes, 6 | graph, 7 | tree, 8 | eredis, 9 | servers, 10 | nodes}). 11 | -------------------------------------------------------------------------------- /pkg.vars.config: -------------------------------------------------------------------------------- 1 | %% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ts=4 sw=4 et 3 | 4 | %% 5 | %% Packaging 6 | %% 7 | {package_name, "lasp"}. 8 | {package_install_name, "lasp"}. 9 | {package_install_user, "lasp"}. 10 | {package_install_group, "lasp"}. 11 | {package_install_user_desc, "Lasp user"}. 12 | {package_commands, {list, [[{name, "lasp"}], [{name, "lasp-admin"}] ]}}. 13 | {package_shortdesc, "Lasp: A Language for Distributed, Eventually Consistent Computations"}. 14 | {package_desc, "Lasp: A Language for Distributed, Eventually Consistent Computations"}. 15 | {bin_or_sbin, "sbin"}. 16 | {package_patch_dir, "lasp-patches"}. 17 | {solaris_pkgname, "LASPlang"}. 18 | {license_type, "Apache 2"}. 19 | {copyright, "2015 Christopher Meiklejohn"}. 20 | {vendor_name, "Christopher Meiklejohn"}. 21 | {vendor_url, "http://lasp-lang.org"}. 22 | {vendor_contact_name, "Christopher Meiklejohn"}. 23 | {vendor_contact_email, "christopher.meiklejohn@gmail.com"}. 24 | {license_full_text, "This file is provided to you under the Apache License,\n" 25 | "Version 2.0 (the \"License\"); you may not use this file\n" 26 | "except in compliance with the License. You may obtain\n" 27 | "a copy of the License at\n" 28 | "\n" 29 | " http://www.apache.org/licenses/LICENSE-2.0\n" 30 | "\n" 31 | "Unless required by applicable law or agreed to in writing,\n" 32 | "software distributed under the License is distributed on an\n" 33 | "\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" 34 | "KIND, either express or implied. See the License for the\n" 35 | "specific language governing permissions and limitations\n" 36 | "under the License."}. 37 | -------------------------------------------------------------------------------- /priv/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/priv/favicon.ico -------------------------------------------------------------------------------- /priv/images/lasp-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/priv/images/lasp-logo-large.png -------------------------------------------------------------------------------- /priv/images/lasp-logo-tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/priv/images/lasp-logo-tiny.png -------------------------------------------------------------------------------- /priv/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Lasp 6 | 10 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 68 | 69 | 95 | 96 | 97 |
98 | 101 |
102 |
103 |
104 |
105 |

Topology

106 |
107 |

Dependency graph

108 |
109 |
110 |
111 | 114 |
115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /priv/ssh/evaluation: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-128-CBC,26BB4B5770E4D8C29A1B383799FDB6F9 4 | 5 | hbIpnUePiQ0uaEngvF3VyM6sO2IYIepDMiaKrjTo5Yg+lP2ln9LITRitCc1cvRdj 6 | 746vtV1Az8PWT9RFBIx7/DLZTZJ1sZvehT3J9M8JRdtOl1l/DFJ42w0ZWMY+k75p 7 | GV/S08nzGTMq3tnUzaS5/EABwddDHLMqkfHQEJwOIPBSbavam3Rx/YGclP3JPt8U 8 | IauUg7ohv8/jSrA6Yk6b+IX2YyhC/O4w9INawuAHZ3yxkklz4ptHcwCTFnNYs3WN 9 | vIIiCoQCX9lJFvqcbJJUjcqIw12sQIq4mGxu+dzJrtEUpzK3IcbrMpWFg19Le5Im 10 | ++37+l4YTtHPbo3RJB6UbLGWjPtxvFISG6lYT4xM92kHOkfvk1cZcj3oJXrVcFNI 11 | Ut2Rcjb0xTa6sGBz5VKNSgmB3sK91Or7aJHZdt1ppkm6N4iFOqSwzs4i+Az4MM9l 12 | m9BKSeDGISg52YwkV8PeZlQaEg4ZSCgvY4OnTAfAo5YbwDe7gHl2VixbmNi+V3ti 13 | idhQsqzi/z+mxqNv25WXgMtsAc0QG3Yo2hhW/SPxzH9oIM3KnDJKYAe4YMzqtvPt 14 | 0uLQfbvHwf1ug6R2CQEwiConzRx6AukTwdc9oviH6Bu1F3zoEEytHGZuzTnUj/NM 15 | IYey44R9sge7CshGw5094DPlUht62OpJZPfm5k7iq9FFkwrtvoSGR9DPAsZ+GVmI 16 | g6KwK/h3OkmazFU3oGO2FT2nwup1nPnv80RyU7PBs7To6KdXImueqw8iAx7EAFYL 17 | 3WsBkIWV+DGcdiwB2tc0Q4Y5vVmznpnv5t5BHy62vXlx08Fy01/uQKS4OUCyc/aH 18 | eKiONfAUOuhw8rYCg/mDNuZe70AxC9MTA46AJQBhqllHKAQtZneBhVFV/Zqft26o 19 | MGC3Ofcg5B+YU1kZ+6yy0iPBO0ar3SfuSlka9Q8vV2BIMdO+6+851fptRkDiun3v 20 | FVgiQkiBRW26hPl+o2IMsifRJlE6qCFLoJ0JHQcoLc98RKPOULjJuPa18PKBt3tq 21 | X+t33ZcO41/TK7oiCUvLRsjyY4Lm+RoVkLKhGc48IURNpQ8aq7S2Ot7/K2NGXHhW 22 | UXsizPmPU4UD7F5fkH6wHxx30HFuP++VnZRbKhA4SwiSeuoX57ULOiJaB9Ep9b2q 23 | I1kjUsMDAWILlzrMWnjZH5IIJsRojKUWFtCnXnfaBW71jOU2inV/VHimkYDRFw3D 24 | h1GYpOWGREAWkTo+yAVH/ujjCBLcVBLsz00FIsZu5sXMiHRylezSflIHa24qZSZ/ 25 | d9iIRedU9w8pXJIlPwK5rWhS93qTnFQN537iUu0Gargh/BaVbN2yuP/rP/yePHkH 26 | fB67AMBE2fpwchPDoaDNEa1sfqb+TWeZdegv+R0lIcsv+o2hptrMNKfo31x4jUsc 27 | UFZAtNLEaw38w/P4f0fSeFuNwa40jB7QXDUceMA4iKWV/zvizt0rcsB2xai8qEWM 28 | konByJkbvnPwB29vi0H7Ac5cXB1Vm4MN7QsspFc8OIIoOsoHpbY01ff2aHRXu+IC 29 | AUiUmafUNAdXKp91XCN4pCFWRE/3Z9R9FT9qvh6yDy12nZ5oJ+9qvjYougIeWeWz 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /priv/ssh/wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $1 $2 4 | -------------------------------------------------------------------------------- /rebar.lock: -------------------------------------------------------------------------------- 1 | {"1.1.0", 2 | [{<<"acceptor_pool">>,{pkg,<<"acceptor_pool">>,<<"1.0.0-rc.0">>},1}, 3 | {<<"gen_flow">>,{pkg,<<"gen_flow">>,<<"0.0.5">>},0}, 4 | {<<"gen_fsm_compat">>,{pkg,<<"gen_fsm_compat">>,<<"0.3.0">>},0}, 5 | {<<"goldrush">>,{pkg,<<"goldrush">>,<<"0.1.9">>},1}, 6 | {<<"lager">>,{pkg,<<"lager">>,<<"3.6.8">>},0}, 7 | {<<"lasp_support">>,{pkg,<<"lasp_support">>,<<"0.0.3">>},0}, 8 | {<<"partisan">>,{pkg,<<"partisan">>,<<"4.1.0">>},0}, 9 | {<<"plumtree">>,{pkg,<<"plumtree">>,<<"0.6.0">>},0}, 10 | {<<"quickrand">>,{pkg,<<"quickrand">>,<<"1.7.5">>},2}, 11 | {<<"time_compat">>,{pkg,<<"time_compat">>,<<"0.0.1">>},1}, 12 | {<<"types">>,{pkg,<<"types">>,<<"0.1.8">>},0}, 13 | {<<"uuid">>,{pkg,<<"uuid_erl">>,<<"1.7.5">>},1}]}. 14 | [ 15 | {pkg_hash,[ 16 | {<<"acceptor_pool">>, <<"679D741DF87FC13599B1AEF2DF8F78F1F880449A6BEFAB7C44FB6FAE0E92A2DE">>}, 17 | {<<"gen_flow">>, <<"2FF6ABE3ED1C5C9BC41F81BF09364A3F63F96E4D378D45A2A2DDC4FC06F3484A">>}, 18 | {<<"gen_fsm_compat">>, <<"5903549F67D595F58A7101154CBE0FDD46955FBFBE40813F1E53C23A970FF5F4">>}, 19 | {<<"goldrush">>, <<"F06E5D5F1277DA5C413E84D5A2924174182FB108DABB39D5EC548B27424CD106">>}, 20 | {<<"lager">>, <<"897EFC7679BB82383448646C96768CDC4E747464DD18B999C7AACA485686B0DA">>}, 21 | {<<"lasp_support">>, <<"C1B7E1A472037AE82C71D2D16A10B7D644A621B66AE5AFE834CECF170F2E9169">>}, 22 | {<<"partisan">>, <<"51D3C1D6487BBB8F94D4FD313D03D93F1C0426350A3ADF84CC3B3243B8EA204E">>}, 23 | {<<"plumtree">>, <<"B347D5FAA640419160CB9DBADF624123A6C0C66ACF7886F36F3F6AEAC99253FA">>}, 24 | {<<"quickrand">>, <<"E3086A153EB13A057FC19192D05E2D4C6BB2BDBB55746A699BEAE9847AC17CA8">>}, 25 | {<<"time_compat">>, <<"23FE0AD1FDF3B5B88821B2D04B4B5E865BF587AE66056D671FE0F53514ED8139">>}, 26 | {<<"types">>, <<"5782B67231E8C174FE2835395E71E669FE0121076779D2A09F1C0D58EE0E2F13">>}, 27 | {<<"uuid">>, <<"3862FF9A21C42566DFD0376B97512FA202922897129E09A05E2AFA0D9CAFD97A">>}]} 28 | ]. 29 | -------------------------------------------------------------------------------- /rel/before-install: -------------------------------------------------------------------------------- 1 | addgroup lasp 2 | adduser lasp --ingroup lasp --system 3 | -------------------------------------------------------------------------------- /rel/etc/default/lasp: -------------------------------------------------------------------------------- 1 | ulimit -n 65535 2 | -------------------------------------------------------------------------------- /rel/etc/lasp/lasp.config: -------------------------------------------------------------------------------- 1 | []. 2 | -------------------------------------------------------------------------------- /rel/init: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | ### BEGIN INIT INFO 3 | # Provides: lasp 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Declarative, distributed, eventually consistent, compuations. 9 | # Description: Declarative, distributed, eventually consistent, compuations. 10 | ### END INIT INFO 11 | 12 | NAME=lasp 13 | USER=lasp 14 | HOME=/opt/lasp 15 | DAEMON=/opt/lasp/bin/$NAME 16 | SCRIPTNAME=/etc/init.d/$NAME 17 | 18 | # Read configuration variable file if it is present 19 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 20 | 21 | # Load the VERBOSE setting and other rcS variables 22 | . /lib/init/vars.sh 23 | . /lib/lsb/init-functions 24 | 25 | # 26 | # Function that starts the daemon/service 27 | # 28 | do_start() 29 | { 30 | # Return 31 | # 0 if daemon has been started 32 | # 1 if daemon was already running 33 | # 2 if daemon could not be started 34 | 35 | # Startup with the appropriate user 36 | start-stop-daemon --start \ 37 | --name $NAME \ 38 | --user $USER \ 39 | --exec $DAEMON -- start \ 40 | || return 2 41 | } 42 | 43 | # 44 | # Function that stops the daemon/service 45 | # 46 | do_stop() 47 | { 48 | # Identify the erts directory 49 | ERTS_PATH=`$DAEMON ertspath` 50 | 51 | # Attempt a clean shutdown. 52 | $DAEMON stop 53 | 54 | # Return 55 | # 0 if daemon has been stopped 56 | # 1 if daemon was already stopped 57 | # 2 if daemon could not be stopped 58 | # other if a failure occurred 59 | # Make sure it's down by using a more direct approach 60 | start-stop-daemon --stop \ 61 | --quiet \ 62 | --retry=TERM/30/KILL/5 \ 63 | --user $USER \ 64 | return $? 65 | } 66 | 67 | # 68 | # Function that graceful reload the daemon/service 69 | # 70 | do_reload() { 71 | # Restart the VM without exiting the process 72 | $DAEMON restart && return $? || return 2 73 | } 74 | 75 | # Checks the status of a node 76 | do_status() { 77 | $DAEMON ping && echo $"$NAME is running" && return 0 78 | echo $"$NAME is stopped" && return 2 79 | } 80 | 81 | case "$1" in 82 | start) 83 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $NAME" 84 | $DAEMON ping >/dev/null 2>&1 && echo $"$NAME is already running" && exit 0 85 | do_start 86 | case "$?" in 87 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 88 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 89 | exit 1 90 | ;; 91 | esac 92 | ;; 93 | stop) 94 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $NAME" 95 | do_stop 96 | case "$?" in 97 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 98 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 99 | exit 1 100 | ;; 101 | esac 102 | ;; 103 | ping) 104 | # See if the VM is alive 105 | $DAEMON ping || exit $? 106 | ;; 107 | reload|force-reload) 108 | log_daemon_msg "Reloading $NAME" 109 | do_reload 110 | ES=$? 111 | log_end_msg $ES 112 | exit $ES 113 | ;; 114 | restart) 115 | log_daemon_msg "Restarting $NAME" 116 | do_stop 117 | case "$?" in 118 | 0|1) 119 | do_start 120 | case "$?" in 121 | 0) log_end_msg 0 ;; 122 | 1) log_end_msg 1 && exit 1 ;; # Old process is still running 123 | *) log_end_msg 1 && exit 1 ;; # Failed to start 124 | esac 125 | ;; 126 | *) 127 | # Failed to stop 128 | log_end_msg 1 && exit 1 129 | ;; 130 | esac 131 | ;; 132 | status) 133 | do_status && exit 0 || exit $? 134 | ;; 135 | *) 136 | echo "Usage: $SCRIPTNAME {start|stop|ping|restart|force-reload|status}" >&2 137 | exit 3 138 | ;; 139 | esac 140 | -------------------------------------------------------------------------------- /rel/var/lib/lasp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/rel/var/lib/lasp/.gitkeep -------------------------------------------------------------------------------- /rel/var/log/lasp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lasp-lang/lasp/1701c8af77e193738dfc4ef4a5a703d205da41a1/rel/var/log/lasp/.gitkeep -------------------------------------------------------------------------------- /samples/docker.sh: -------------------------------------------------------------------------------- 1 | # Pull the docker image that contains Lasp 2 | $ docker pull cmeiklejohn/lasp 3 | 4 | # Start up the docker image with host networking and pseudo-tty 5 | $ docker run -i -t --net=host cmeiklejohn/lasp 6 | -------------------------------------------------------------------------------- /samples/map.erl: -------------------------------------------------------------------------------- 1 | %% Create initial set. 2 | {ok, {Id1, _, _, _}} = lasp:declare(orset), 3 | 4 | %% Add elements to initial set and update. 5 | {ok, _} = lasp:update(Id1, {add_all, [1,2,3]}, a), 6 | 7 | %% Create a second set. 8 | {ok, {Id2, _, _, _}} = lasp:declare(orset), 9 | 10 | %% Apply map. 11 | ok = lasp:map(Id1, fun(X) -> X * 2 end, Id2), 12 | 13 | %% Query map. 14 | {ok, Value1} = lasp:query(Id2), sets:to_list(Value1). 15 | -------------------------------------------------------------------------------- /scripts/hex.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Setup hex user 4 | mkdir -p ~/.hex 5 | echo '{username,<<"'${HEX_USERNAME}'">>}.' > ~/.hex/hex.config 6 | echo '{key,<<"'${HEX_KEY}'">>}.' >> ~/.hex/hex.config 7 | 8 | ## Add the rebar3 hex plugin to global 9 | mkdir -p ~/.config/rebar3 10 | echo '{plugins, [rebar3_hex]}.' > ~/.config/rebar3/rebar.config 11 | 12 | ./rebar3 hex publish <"). 23 | 24 | -export([init/1, 25 | content_types_provided/2, 26 | to_json/2]). 27 | 28 | -include("lasp.hrl"). 29 | 30 | -include_lib("webmachine/include/webmachine.hrl"). 31 | 32 | init(_) -> 33 | {ok, undefined}. 34 | 35 | content_types_provided(Req, Ctx) -> 36 | {[{"application/json", to_json}], Req, Ctx}. 37 | 38 | to_json(ReqData, State) -> 39 | Status = case lasp_config:get(dag_enabled, ?DAG_ENABLED) of 40 | false -> #{present => false}; 41 | true -> case lasp_dependence_dag:to_dot() of 42 | {ok, Content} -> #{present => true, dot_content => Content}; 43 | _ -> #{present => false} 44 | end 45 | end, 46 | {jsx:encode(Status), ReqData, State}. 47 | -------------------------------------------------------------------------------- /simulations/lasp_gui_resource.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_gui_resource). 22 | 23 | -export([init/1, 24 | content_types_provided/2, 25 | to_resource/2]). 26 | 27 | -include_lib("lasp/include/lasp.hrl"). 28 | -include_lib("webmachine/include/webmachine.hrl"). 29 | 30 | -record(ctx, { 31 | base_url, 32 | base_path 33 | }). 34 | -type context() :: #ctx{}. 35 | 36 | %% mappings to the various content types supported for this resource 37 | -define(CONTENT_TYPES, [{"text/css", to_resource}, 38 | {"text/html", to_resource}, 39 | {"text/plain", to_resource}, 40 | {"application/csv", to_resource}, 41 | {"application/pdf", to_resource}, 42 | {"text/csv", to_resource}, 43 | {"text/javascript", to_resource}]). 44 | 45 | %% entry-point for the resource from webmachine 46 | -spec init(any()) -> {ok, any()}. 47 | init(Resource) -> {ok, Resource}. 48 | 49 | %% return the list of available content types for webmachine 50 | -spec content_types_provided(wrq:reqdata(), context()) -> 51 | {[{ContentType::string(), HandlerFunction::atom()}], 52 | wrq:reqdata(), context()}. 53 | content_types_provided(Req, Ctx=index) -> 54 | {[{"text/html", to_resource}], Req, Ctx}; 55 | content_types_provided(Req, Ctx) -> 56 | Index = file_path(Req), 57 | MimeType = webmachine_util:guess_mime(Index), 58 | {[{MimeType, to_resource}], Req, Ctx}. 59 | 60 | %% return file path 61 | -spec file_path(wrq:reqdata() | list()) -> string(). 62 | file_path(Path) when is_list(Path) -> 63 | filename:join([code:priv_dir(?APP)] ++ [Path]); 64 | file_path(Req) -> 65 | Path=wrq:path_tokens(Req), 66 | filename:join([code:priv_dir(?APP)] ++ Path). 67 | 68 | %% loads a resource file from disk and returns it 69 | -spec get_file(wrq:reqdata()) -> binary(). 70 | get_file(Req) -> 71 | Index = file_path(Req), 72 | {ok, Source}=file:read_file(Index), 73 | Source. 74 | 75 | %% read a file from disk and return it 76 | read_file(File) -> 77 | Index = file_path(File), 78 | {ok, Source}=file:read_file(Index), 79 | Source. 80 | 81 | %% respond to an index or file request 82 | -spec to_resource(wrq:reqdata(), context()) -> 83 | {binary(), wrq:reqdata(), context()}. 84 | to_resource(Req, Ctx=index) -> 85 | {read_file("index.html"), Req, Ctx}; 86 | to_resource(Req, Ctx) -> 87 | {get_file(Req), Req, Ctx}. 88 | -------------------------------------------------------------------------------- /simulations/lasp_health_check_resource.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_health_check_resource). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([init/1, to_html/2]). 25 | 26 | -include_lib("webmachine/include/webmachine.hrl"). 27 | 28 | -spec init(list()) -> {ok, term()}. 29 | init(_) -> 30 | {ok, undefined}. 31 | 32 | -spec to_html(wrq:reqdata(), term()) -> {iodata(), wrq:reqdata(), term()}. 33 | to_html(ReqData, State) -> 34 | {"OK", ReqData, State}. 35 | -------------------------------------------------------------------------------- /simulations/lasp_kubernetes_simulations.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_kubernetes_simulations). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | -export([stop/0]). 25 | 26 | stop() -> 27 | lists:foreach( 28 | fun(Deployment) -> 29 | lager:info("Deleting Kubernetes deployment: ~p", [Deployment]), 30 | delete_deployment(Deployment), 31 | lager:info("Deleting Kubernetes replicasets."), 32 | delete_replicasets(Deployment), 33 | lager:info("Deleting Kubernetes pods."), 34 | delete_pods(Deployment) 35 | end, 36 | deployments()). 37 | 38 | %% @private 39 | delete_deployment(Deployment) -> 40 | DecodeFun = fun(Body) -> jsx:decode(Body, [return_maps]) end, 41 | DeploymentURL = deployment_url(Deployment), 42 | 43 | case delete_request(DeploymentURL, DecodeFun) of 44 | {ok, _Response} -> 45 | ok; 46 | Error -> 47 | _ = lager:info("Invalid Kubernetes response: ~p", [Error]), 48 | {error, Error} 49 | end. 50 | 51 | %% @private 52 | deployment_url(Deployment) -> 53 | EvaluationTimestamp = lasp_config:get(evaluation_timestamp, 0), 54 | APIServer = os:getenv("APISERVER"), 55 | APIServer ++ "/apis/extensions/v1beta1/namespaces/default/deployments/" ++ Deployment ++ "-" ++ integer_to_list(EvaluationTimestamp). 56 | 57 | %% @private 58 | delete_replicaset(#{<<"metadata">> := Metadata}) -> 59 | DecodeFun = fun(Body) -> jsx:decode(Body, [return_maps]) end, 60 | #{<<"selfLink">> := SelfUrl} = Metadata, 61 | 62 | APIServer = os:getenv("APISERVER"), 63 | PodUrl = APIServer ++ binary_to_list(SelfUrl), 64 | 65 | case delete_request(PodUrl, DecodeFun) of 66 | {ok, _Response} -> 67 | ok; 68 | Error -> 69 | _ = lager:info("Invalid Kubernetes response: ~p", [Error]), 70 | {error, Error} 71 | end. 72 | 73 | %% @private 74 | delete_pod(#{<<"metadata">> := Metadata}) -> 75 | DecodeFun = fun(Body) -> jsx:decode(Body, [return_maps]) end, 76 | #{<<"selfLink">> := SelfUrl} = Metadata, 77 | 78 | APIServer = os:getenv("APISERVER"), 79 | PodUrl = APIServer ++ binary_to_list(SelfUrl), 80 | 81 | case delete_request(PodUrl, DecodeFun) of 82 | {ok, _Response} -> 83 | ok; 84 | Error -> 85 | _ = lager:info("Invalid Kubernetes response: ~p", [Error]), 86 | {error, Error} 87 | end. 88 | 89 | %% @private 90 | delete_replicasets(Run) -> 91 | DecodeFun = fun(Body) -> jsx:decode(Body, [return_maps]) end, 92 | 93 | EvaluationTimestamp = lasp_config:get(evaluation_timestamp, 0), 94 | 95 | APIServer = os:getenv("APISERVER"), 96 | PodsUrl = APIServer ++ "/apis/extensions/v1beta1/namespaces/default/replicasets?labelSelector=run%3D" ++ Run ++ ",evaluation-timestamp%3D" ++ integer_to_list(EvaluationTimestamp), 97 | 98 | case get_request(PodsUrl, DecodeFun) of 99 | {ok, #{<<"items">> := Items}} -> 100 | [delete_replicaset(Item) || Item <- Items], 101 | ok; 102 | Error -> 103 | _ = lager:info("Invalid Kubernetes response: ~p", [Error]), 104 | {error, Error} 105 | end. 106 | 107 | %% @private 108 | delete_pods(Run) -> 109 | DecodeFun = fun(Body) -> jsx:decode(Body, [return_maps]) end, 110 | 111 | EvaluationTimestamp = lasp_config:get(evaluation_timestamp, 0), 112 | 113 | APIServer = os:getenv("APISERVER"), 114 | PodsUrl = APIServer ++ "/api/v1/pods?labelSelector=run%3D" ++ Run ++ ",evaluation-timestamp%3D" ++ integer_to_list(EvaluationTimestamp), 115 | 116 | case get_request(PodsUrl, DecodeFun) of 117 | {ok, #{<<"items">> := Items}} -> 118 | [delete_pod(Item) || Item <- Items], 119 | ok; 120 | Error -> 121 | _ = lager:info("Invalid Kubernetes response: ~p", [Error]), 122 | {error, Error} 123 | end. 124 | 125 | %% @private 126 | deployments() -> 127 | ["lasp-server", "lasp-client"]. 128 | 129 | %% @private 130 | get_request(Url, DecodeFun) -> 131 | lager:info("Issuing GET request to: ~p", [Url]), 132 | 133 | Headers = headers(), 134 | case httpc:request(get, {Url, Headers}, [], [{body_format, binary}]) of 135 | {ok, {{_, 200, _}, _, Body}} -> 136 | {ok, DecodeFun(Body)}; 137 | Other -> 138 | _ = lager:info("Request failed; ~p", [Other]), 139 | {error, invalid} 140 | end. 141 | 142 | %% @private 143 | delete_request(Url, DecodeFun) -> 144 | lager:info("Issuing DELETE request to: ~p", [Url]), 145 | 146 | Headers = headers(), 147 | case httpc:request(delete, {Url, Headers}, [], [{body_format, binary}]) of 148 | {ok, {{_, 200, _}, _, Body}} -> 149 | {ok, DecodeFun(Body)}; 150 | Other -> 151 | _ = lager:info("Request failed; ~p", [Other]), 152 | {error, invalid} 153 | end. 154 | 155 | %% @private 156 | headers() -> 157 | Token = os:getenv("TOKEN"), 158 | [{"Authorization", "Bearer " ++ Token}]. 159 | -------------------------------------------------------------------------------- /simulations/lasp_kv_resource.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_kv_resource). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([init/1, 25 | allowed_methods/2, 26 | process_post/2, 27 | content_types_provided/2, 28 | resource_exists/2, 29 | to_erlang/2]). 30 | 31 | -include("lasp.hrl"). 32 | -include_lib("webmachine/include/webmachine.hrl"). 33 | 34 | -record(ctx, {id, type, object}). 35 | 36 | -spec init(list()) -> {ok, term()}. 37 | init(_) -> 38 | {ok, #ctx{}}. 39 | 40 | allowed_methods(ReqData, Ctx) -> 41 | {['GET', 'POST', 'HEAD'], ReqData, Ctx}. 42 | 43 | content_types_provided(ReqData, Ctx) -> 44 | {[{"application/erlang", to_erlang}], ReqData, Ctx}. 45 | 46 | process_post(ReqData, Ctx) -> 47 | Body = wrq:req_body(ReqData), 48 | 49 | Id = wrq:path_info(id, ReqData), 50 | Type = wrq:path_info(type, ReqData), 51 | 52 | case {Id, Type} of 53 | {undefined, _} -> 54 | {false, ReqData, Ctx}; 55 | {_, undefined} -> 56 | {false, ReqData, Ctx}; 57 | {_, _} -> 58 | AtomType = atomize(Type), 59 | BinaryId = binary(Id), 60 | Decoded = lasp_type:decode(AtomType, erlang, Body), 61 | 62 | case lasp:bind({BinaryId, AtomType}, Decoded) of 63 | {ok, Object} -> 64 | {true, ReqData, Ctx#ctx{id=BinaryId, type=AtomType, object=Object}}; 65 | Error -> 66 | lager:info("Received error response: ~p", [Error]), 67 | {false, ReqData, Ctx} 68 | end 69 | end. 70 | 71 | resource_exists(ReqData, Ctx) -> 72 | Id = wrq:path_info(id, ReqData), 73 | Type = wrq:path_info(type, ReqData), 74 | 75 | case {Id, Type} of 76 | {undefined, _} -> 77 | {false, ReqData, Ctx}; 78 | {_, undefined} -> 79 | {false, ReqData, Ctx}; 80 | {_, _} -> 81 | AtomType = atomize(Type), 82 | BinaryId = binary(Id), 83 | 84 | case lasp:read({BinaryId, AtomType}, undefined) of 85 | {ok, Object} -> 86 | {true, ReqData, Ctx#ctx{id=BinaryId, type=AtomType, object=Object}}; 87 | Error -> 88 | lager:info("Received error response: ~p", [Error]), 89 | {false, ReqData, Ctx} 90 | end 91 | end. 92 | 93 | to_erlang(ReqData, #ctx{type=Type, object={_Id, _Type, _Metadata, Value}}=Ctx) -> 94 | Encoded = lasp_type:encode(Type, erlang, Value), 95 | {Encoded, ReqData, Ctx}. 96 | 97 | %%%=================================================================== 98 | %%% Internal functions 99 | %%%=================================================================== 100 | 101 | %% @private 102 | atomize(Type) when is_list(Type) -> 103 | list_to_existing_atom(Type). 104 | 105 | %% @private 106 | binary(Id) when is_list(Id) -> 107 | term_to_binary(Id). 108 | -------------------------------------------------------------------------------- /simulations/lasp_logs_resource.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_logs_resource). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([init/1, 25 | content_types_provided/2, 26 | to_json/2]). 27 | 28 | -include("lasp.hrl"). 29 | -include_lib("webmachine/include/webmachine.hrl"). 30 | 31 | -spec init(list()) -> {ok, term()}. 32 | init(_) -> 33 | {ok, undefined}. 34 | 35 | %% return the list of available content types for webmachine 36 | content_types_provided(Req, Ctx) -> 37 | {[{"application/json", to_json}], Req, Ctx}. 38 | 39 | to_json(ReqData, State) -> 40 | Filenames = filelib:wildcard("*.csv", code:priv_dir(?APP) ++ "/logs"), 41 | Filenames1 = [list_to_binary(Filename) || Filename <- Filenames], 42 | Encoded = jsx:encode(#{logs => Filenames1}), 43 | {Encoded, ReqData, State}. 44 | -------------------------------------------------------------------------------- /simulations/lasp_plots_resource.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_plots_resource). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([init/1, 25 | content_types_provided/2, 26 | to_json/2]). 27 | 28 | -include("lasp.hrl"). 29 | -include_lib("webmachine/include/webmachine.hrl"). 30 | 31 | -spec init(list()) -> {ok, term()}. 32 | init(_) -> 33 | {ok, undefined}. 34 | 35 | %% return the list of available content types for webmachine 36 | content_types_provided(Req, Ctx) -> 37 | {[{"application/json", to_json}], Req, Ctx}. 38 | 39 | to_json(ReqData, State) -> 40 | Filenames = filelib:wildcard("*.pdf", code:priv_dir(?APP) ++ "/plots"), 41 | Filenames1 = [list_to_binary(Filename) || Filename <- Filenames], 42 | Encoded = jsx:encode(#{plots => Filenames1}), 43 | {Encoded, ReqData, State}. 44 | -------------------------------------------------------------------------------- /simulations/lasp_simulation.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_simulation). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -type state() :: any(). 25 | 26 | %% Initialize the Lasp application. 27 | %% 28 | %% This callback is designed to have a majority of the Lasp 29 | %% computational graph defined and return any state information needed 30 | %% to run the simulation. 31 | %% 32 | -callback init([any()]) -> {ok, state()}. 33 | 34 | %% Initialize a series of clients that will perform computations and 35 | %% receive messages from the simulator. 36 | %% 37 | -callback clients(state()) -> {ok, state()}. 38 | 39 | %% Simulate clients actions by sending a message to each of the clients 40 | %% randomly. 41 | %% 42 | -callback simulate(state()) -> {ok, state()}. 43 | 44 | %% Wait until all clients process all messages. 45 | %% 46 | %% Normally, this should be done by sending a message to the harness for 47 | %% each messages processed, so we don't have to rely on iteratively 48 | %% inspecting mailboxes. 49 | %% 50 | -callback wait(state()) -> {ok, state()}. 51 | 52 | %% Terminate all client processes. 53 | -callback terminate(state()) -> {ok, state()}. 54 | 55 | %% Perform any summarization needed. 56 | -callback summarize(state()) -> {ok, state()}. 57 | 58 | -export([run/2]). 59 | 60 | %% @doc Prototype new simulator harness. 61 | %% 62 | %% @clippy Hey, it looks like you're writing a State monad here! Would 63 | %% you like some help? 64 | %% 65 | run(Module, Args) -> 66 | Pid = self(), 67 | 68 | spawn_link(fun() -> 69 | _ = lager:info("Initializing simulation!"), 70 | {ok, State} = Module:init(Args), 71 | 72 | %% Unfortunately, we have to wait for the cluster to stabilize, else 73 | %% some of the clients running at other node will get not_found 74 | %% operations. 75 | _ = lager:info("Waiting for cluster to stabilize..."), 76 | timer:sleep(2000), 77 | 78 | %% Launch client processes. 79 | _ = lager:info("Launching clients!"), 80 | {ok, State1} = Module:clients(State), 81 | 82 | %% Initialize simulation. 83 | _ = lager:info("Running simulation!"), 84 | {ok, State2} = Module:simulate(State1), 85 | 86 | %% Wait until we receive num events. 87 | _ = lager:info("Waiting for event generation to complete!"), 88 | {ok, State3} = Module:wait(State2), 89 | 90 | %% Terminate all clients. 91 | _ = lager:info("Terminating clients!"), 92 | {ok, State4} = Module:terminate(State3), 93 | 94 | %% Finish and summarize. 95 | _ = lager:info("Summarizing results!"), 96 | {ok, Term} = Module:summarize(State4), 97 | 98 | _ = lager:info("Processes before termination: ~p", 99 | [length(processes())]), 100 | 101 | Pid ! {ok, Term} 102 | end), 103 | receive 104 | {ok, Term} -> 105 | _ = lager:info("Processes after termination: ~p", 106 | [length(processes())]), 107 | {ok, Term} 108 | end. 109 | -------------------------------------------------------------------------------- /simulations/lasp_status_resource.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_status_resource). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([init/1, 25 | content_types_provided/2, 26 | to_json/2]). 27 | 28 | -include_lib("webmachine/include/webmachine.hrl"). 29 | 30 | -spec init(list()) -> {ok, term()}. 31 | init(_) -> 32 | {ok, undefined}. 33 | 34 | %% return the list of available content types for webmachine 35 | content_types_provided(Req, Ctx) -> 36 | {[{"application/json", to_json}], Req, Ctx}. 37 | 38 | -ifdef(TEST). 39 | 40 | to_json(ReqData, State) -> 41 | NumNodes = rand:uniform(2), 42 | NodeList = lists:seq(0, NumNodes), 43 | Nodes = [#{id => Name, name => Name, group => 1} || Name <- NodeList], 44 | Links = lists:flatten(generate_links(NodeList)), 45 | Encoded = jsx:encode(#{nodes => Nodes, links => Links}), 46 | {Encoded, ReqData, State}. 47 | 48 | generate_links(NodeList) -> 49 | lists:map(fun(Source) -> 50 | lists:map(fun(Target) -> 51 | #{source => Source, target => Target} 52 | end, NodeList) end, NodeList). 53 | 54 | -else. 55 | 56 | to_json(ReqData, State) -> 57 | {ok, {Vertices, Edges}} = case lasp_config:get(broadcast, false) of 58 | true -> 59 | sprinter_backend:tree(); 60 | false -> 61 | sprinter_backend:graph() 62 | end, 63 | Nodes = [#{id => Name, name => Name, group => 1} || Name <- Vertices], 64 | Links = [#{source => V1, target => V2} || {V1, V2} <- Edges], 65 | Encoded = jsx:encode(#{nodes => Nodes, links => Links}), 66 | {Encoded, ReqData, State}. 67 | 68 | -endif. 69 | -------------------------------------------------------------------------------- /src/lasp.app.src: -------------------------------------------------------------------------------- 1 | {application,lasp, 2 | [{description,"Declarative, distributed, eventually consistent compuations."}, 3 | {vsn,"git"}, 4 | {links,[{"Github","https://github.com/lasp-lang/lasp"}]}, 5 | {licenses,["Apache 2"]}, 6 | {registered,[]}, 7 | {applications,[kernel,stdlib,types,gen_flow,lager,sasl, 8 | lasp_support,partisan, 9 | plumtree, gen_fsm_compat]}, 10 | {mod,{lasp_app,[]}}, 11 | {env,[{data_root,"data"}, 12 | {web_ip,"0.0.0.0"}, 13 | {web_port,8080}, 14 | {peer_service,lasp_partisan_peer_service}, 15 | {storage_backend,lasp_ets_storage_backend}]}]}. 16 | -------------------------------------------------------------------------------- /src/lasp_app.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2014 SyncFree Consortium. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_app). 22 | 23 | -behaviour(application). 24 | 25 | -include("lasp.hrl"). 26 | 27 | %% Application callbacks 28 | -export([start/2, stop/1]). 29 | 30 | %% =================================================================== 31 | %% Application callbacks 32 | %% =================================================================== 33 | 34 | %% @doc Start the lasp application. 35 | start(_StartType, _StartArgs) -> 36 | case lasp_sup:start_link() of 37 | {ok, Pid} -> 38 | {ok, Pid}; 39 | {error, Reason} -> 40 | {error, Reason} 41 | end. 42 | 43 | %% @doc Stop the lasp application. 44 | stop(_State) -> 45 | ok. 46 | -------------------------------------------------------------------------------- /src/lasp_config.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_config). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -include("lasp.hrl"). 25 | 26 | -export([dispatch/0, 27 | set/2, 28 | get/2, 29 | peer_service_manager/0, 30 | web_config/0]). 31 | 32 | get(Key, Default) -> 33 | lasp_mochiglobal:get(Key, Default). 34 | 35 | set(Key, Value) -> 36 | application:set_env(?APP, Key, Value), 37 | lasp_mochiglobal:put(Key, Value). 38 | 39 | dispatch() -> 40 | lists:flatten([ 41 | {["api", "kv", id, type], lasp_kv_resource, undefined}, 42 | {["api", "plots"], lasp_plots_resource, undefined}, 43 | {["api", "logs"], lasp_logs_resource, undefined}, 44 | {["api", "health"], lasp_health_check_resource, undefined}, 45 | {["api", "status"], lasp_status_resource, undefined}, 46 | {["api", "dag"], lasp_dag_resource, undefined}, 47 | {[], lasp_gui_resource, index}, 48 | {['*'], lasp_gui_resource, undefined} 49 | ]). 50 | 51 | web_config() -> 52 | {ok, App} = application:get_application(?MODULE), 53 | {ok, Ip} = application:get_env(App, web_ip), 54 | Port = lasp_config:get(web_port, 8080), 55 | Config = [ 56 | {ip, Ip}, 57 | {port, Port}, 58 | {log_dir, "priv/log"}, 59 | {dispatch, dispatch()} 60 | ], 61 | Node = lasp_support:mynode(), 62 | lager:info("Node ~p enabling web configuration: ~p", [Node, Config]), 63 | Config. 64 | 65 | %% @private 66 | peer_service_manager() -> 67 | partisan_config:get(partisan_peer_service_manager, 68 | partisan_pluggable_peer_service_manager). 69 | -------------------------------------------------------------------------------- /src/lasp_console.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2014 SyncFree Consortium. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_console). 22 | 23 | -export([join/1]). 24 | 25 | join([NodeStr]) -> 26 | Node = list_to_atom(NodeStr), 27 | join(NodeStr, fun lasp_peer_service:join/1, 28 | "Success: join request for ~p to ~p~n", [lasp_support:mynode(), Node]). 29 | 30 | join(NodeStr, JoinFn, SuccessFmt, SuccessArgs) -> 31 | try 32 | case JoinFn(NodeStr) of 33 | ok -> 34 | io:format(SuccessFmt, SuccessArgs), 35 | ok; 36 | {error, _} -> 37 | io:format("Join failed. Try again in a few moments.~n", []), 38 | error 39 | end 40 | catch 41 | Exception:Reason -> 42 | lager:error("Join failed ~p:~p", [Exception, Reason]), 43 | io:format("Join failed, see log for details~n"), 44 | error 45 | end. 46 | -------------------------------------------------------------------------------- /src/lasp_dt.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_dt). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -include("lasp.hrl"). 25 | 26 | %% Unified interface for allowing parameterized CRDTs. 27 | -callback new([term()]) -> term(). 28 | 29 | %% Callback for delta update. 30 | -callback update_delta(term(), actor(), crdt()) -> 31 | {ok, crdt()} | {error, atom()}. 32 | -------------------------------------------------------------------------------- /src/lasp_eqc.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_eqc). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | -ifdef(TEST). 25 | -ifdef(EQC). 26 | 27 | -include_lib("eqc/include/eqc.hrl"). 28 | -include_lib("eqc/include/eqc_statem.hrl"). 29 | -include_lib("eunit/include/eunit.hrl"). 30 | 31 | -compile(export_all). 32 | 33 | -define(TIMEOUT, 1200). 34 | 35 | -define(TEST_TIME, 90). 36 | 37 | -define(NUM_TESTS, 2). 38 | 39 | -define(NODES, [rita, sue, bob]). 40 | 41 | -define(QC_OUT(P), 42 | eqc:on_output(fun(Str, Args) -> 43 | io:format(user, Str, Args) 44 | end, P)). 45 | 46 | %% State record. 47 | -record(state, {status, variables, nodes}). 48 | 49 | %% Generators. 50 | 51 | type() -> 52 | elements([orset]). 53 | 54 | %% Initial state. 55 | 56 | initial_state() -> 57 | %% Stop the runner and re-initialize. 58 | lasp_support:stop_runner(), 59 | lasp_support:start_runner(), 60 | 61 | #state{status=init, nodes=[], variables=[]}. 62 | 63 | %% Launch multiple nodes. 64 | 65 | provision(Name) -> 66 | lasp_support:start_and_join_node(Name, [], ?MODULE). 67 | 68 | provision_args(_S) -> 69 | [elements(?NODES)]. 70 | 71 | provision_pre(#state{nodes=Nodes, status=init}, [Name]) -> 72 | Members = [N || {N, _} <- Nodes], 73 | not lists:member(Name, Members); 74 | provision_pre(#state{status=running}, [_Name]) -> 75 | false. 76 | 77 | provision_next(#state{nodes=Nodes0}=S, Member, [Name]) -> 78 | Nodes = Nodes0 ++ [{Name, Member}], 79 | Status = case length(Nodes) =:= length(?NODES) of 80 | true -> 81 | running; 82 | false -> 83 | init 84 | end, 85 | S#state{status=Status, nodes=Nodes}. 86 | 87 | %% Verify the node could be clustered. 88 | provision_post(#state{nodes=_Nodes}=_S, [_Name], Member) -> 89 | RunnerNode = lasp_support:runner_node(), 90 | {ok, Members} = rpc:call(RunnerNode, partisan_peer_service, members, []), 91 | lists:member(Member, Members). 92 | 93 | %% Declare variables. 94 | 95 | declare(Id, Type) -> 96 | {ok, {{Id, Type}, _, _, _}} = lasp:declare(Id, Type), 97 | Id. 98 | 99 | declare_args(_S) -> 100 | [elements([a, b, c]), type()]. 101 | 102 | declare_pre(#state{status=init}, [_Id, _Type]) -> 103 | false; 104 | declare_pre(#state{status=running, variables=Variables}, [Id, _Type]) -> 105 | not lists:member(Id, Variables). 106 | 107 | declare_next(#state{variables=Variables0}=S, _Res, [Id, _Type]) -> 108 | Variables = Variables0 ++ [Id], 109 | S#state{variables=Variables}. 110 | 111 | %% Properties. 112 | 113 | prop_sequential() -> 114 | ?SETUP(fun() -> 115 | setup(), 116 | fun teardown/0 117 | end, 118 | ?FORALL(Cmds, commands(?MODULE), 119 | begin 120 | {H, S, Res} = run_commands(?MODULE, Cmds), 121 | pretty_commands(?MODULE, Cmds, {H, S, Res}, 122 | aggregate(command_names(Cmds), Res == ok)) 123 | end)). 124 | 125 | setup() -> 126 | {ok, _Apps} = application:ensure_all_started(lager), 127 | ok. 128 | 129 | teardown() -> 130 | ok. 131 | 132 | sequential_test_() -> 133 | {timeout, ?TIMEOUT, 134 | fun() -> ?assert(eqc:quickcheck(?QC_OUT(eqc:testing_time(?TEST_TIME, prop_sequential())))) end}. 135 | 136 | -endif. 137 | -endif. 138 | -------------------------------------------------------------------------------- /src/lasp_logger.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_logger). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([extended/1, 25 | extended/2, 26 | mailbox/1, 27 | mailbox/2]). 28 | 29 | extended(Message) -> 30 | extended(Message, []). 31 | 32 | extended(Message, Args) -> 33 | case lasp_config:get(extended_logging, false) of 34 | true -> 35 | lager:info(Message, Args); 36 | _ -> 37 | ok 38 | end. 39 | 40 | mailbox(Message) -> 41 | mailbox(Message, []). 42 | 43 | mailbox(Message, Args) -> 44 | case lasp_config:get(mailbox_logging, false) of 45 | true -> 46 | lager:info(Message, Args); 47 | _ -> 48 | ok 49 | end. 50 | -------------------------------------------------------------------------------- /src/lasp_marathon_simulations.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_marathon_simulations). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | -export([stop/0, 25 | log_message_queue_size/1]). 26 | 27 | stop() -> 28 | DCOS = os:getenv("DCOS", "false"), 29 | EvalTimestamp = lasp_config:get(evaluation_timestamp, 0), 30 | RunningApps = [ 31 | "lasp-client-" ++ integer_to_list(EvalTimestamp), 32 | "lasp-server-" ++ integer_to_list(EvalTimestamp) 33 | ], 34 | 35 | lists:foreach( 36 | fun(AppName) -> 37 | lager:info("Deleting Marathon app: ~p", [AppName]), 38 | delete_marathon_app(DCOS, AppName) 39 | end, 40 | RunningApps). 41 | 42 | %% @private 43 | delete_marathon_app(DCOS, AppName) -> 44 | Headers = [], 45 | Url = DCOS ++ "/marathon/v2/apps/" ++ AppName, 46 | case httpc:request(delete, {Url, Headers}, [], [{body_format, binary}]) of 47 | {ok, {{_, 200, _}, _, _Body}} -> 48 | ok; 49 | Other -> 50 | lager:info("Delete app ~p request failed: ~p", [AppName, Other]) 51 | end. 52 | 53 | log_message_queue_size(Method) -> 54 | {message_queue_len, MessageQueueLen} = process_info(self(), message_queue_len), 55 | lasp_logger:mailbox("MAILBOX " ++ Method ++ " message processed; messages remaining: ~p", [MessageQueueLen]). 56 | -------------------------------------------------------------------------------- /src/lasp_membership.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2017 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_membership). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | %% API 25 | -export([start_link/0, 26 | start_link/1]). 27 | 28 | %% gen_server callbacks 29 | -export([init/1, 30 | handle_call/3, 31 | handle_cast/2, 32 | handle_info/2, 33 | terminate/2, 34 | code_change/3]). 35 | 36 | %% State record. 37 | -record(state, {actor, membership_fun}). 38 | 39 | -include("lasp.hrl"). 40 | 41 | %%%=================================================================== 42 | %%% API 43 | %%%=================================================================== 44 | 45 | %% @doc Same as start_link([]). 46 | -spec start_link() -> {ok, pid()} | ignore | {error, term()}. 47 | start_link() -> 48 | start_link([]). 49 | 50 | %% @doc Start and link to calling process. 51 | -spec start_link(list())-> {ok, pid()} | ignore | {error, term()}. 52 | start_link(Opts) -> 53 | gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). 54 | 55 | %%%=================================================================== 56 | %%% gen_server callbacks 57 | %%%=================================================================== 58 | 59 | %% @private 60 | -spec init([]) -> {ok, #state{}}. 61 | init([]) -> 62 | %% Distribution backend needs to assign actor identifier first. 63 | Actor = case lasp_config:get(actor, undefined) of 64 | undefined -> 65 | {stop, no_actor_identifier}; 66 | A -> 67 | A 68 | end, 69 | 70 | %% Configure a membership callback to the peer service. 71 | MembershipFun = fun(S) -> 72 | update_membership(S, Actor) 73 | end, 74 | partisan_peer_service:add_sup_callback(MembershipFun), 75 | 76 | {ok, #state{actor=Actor, membership_fun=MembershipFun}}. 77 | 78 | %% @private 79 | -spec handle_call(term(), {pid(), term()}, #state{}) -> 80 | {reply, term(), #state{}}. 81 | 82 | handle_call(Msg, _From, State) -> 83 | _ = lager:warning("Unhandled call: ~p", [Msg]), 84 | {noreply, State}. 85 | 86 | -spec handle_cast(term(), #state{}) -> {noreply, #state{}}. 87 | 88 | %% @private 89 | handle_cast(Msg, State) -> 90 | _ = lager:warning("Unhandled cast: ~p", [Msg]), 91 | {noreply, State}. 92 | 93 | %% @private 94 | handle_info(Msg, State) -> 95 | _ = lager:warning("Unhandled info: ~p", [Msg]), 96 | {noreply, State}. 97 | 98 | %% @private 99 | -spec terminate(term(), #state{}) -> term(). 100 | terminate(_Reason, _State) -> 101 | ok. 102 | 103 | %% @private 104 | -spec code_change(term() | {down, term()}, #state{}, term()) -> 105 | {ok, #state{}}. 106 | code_change(_OldVsn, State, _Extra) -> 107 | {ok, State}. 108 | 109 | %%%=================================================================== 110 | %%% Internal functions 111 | %%%=================================================================== 112 | 113 | %% @private 114 | update_membership(State, Actor) -> 115 | lager:info("Attempting to update membership; state: ~p", [State]), 116 | 117 | %% Declare variable if necessary, ensure variable is dynamic and not 118 | %% synchronized: use a LWW-register. 119 | {ok, _} = lasp:declare_dynamic(?MEMBERSHIP_ID, ?MEMBERSHIP_TYPE), 120 | lager:info("Declared dynamic membership: ~p", [?MEMBERSHIP_ID]), 121 | 122 | %% Decode the membership. 123 | Membership = partisan_peer_service:decode(State), 124 | lager:info("Decoded membership: ~p", [Membership]), 125 | 126 | %% Bind the new membership to the register. 127 | {ok, _} = lasp:update(?MEMBERSHIP_ID, {set, timestamp(), Membership}, Actor), 128 | lager:info("Updated membership: ~p", [?MEMBERSHIP_ID]), 129 | 130 | ok. 131 | 132 | %% @private 133 | timestamp() -> 134 | {Mega, Sec, _Micro} = erlang:timestamp(), 135 | Mega * 1000000 + Sec. 136 | -------------------------------------------------------------------------------- /src/lasp_mochiglobal.erl: -------------------------------------------------------------------------------- 1 | %% @author Bob Ippolito 2 | %% @copyright 2010 Mochi Media, Inc. 3 | %% 4 | %% Permission is hereby granted, free of charge, to any person obtaining a 5 | %% copy of this software and associated documentation files (the "Software"), 6 | %% to deal in the Software without restriction, including without limitation 7 | %% the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | %% and/or sell copies of the Software, and to permit persons to whom the 9 | %% Software is furnished to do so, subject to the following conditions: 10 | %% 11 | %% The above copyright notice and this permission notice shall be included in 12 | %% all copies or substantial portions of the Software. 13 | %% 14 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | %% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | %% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | %% DEALINGS IN THE SOFTWARE. 21 | 22 | 23 | %% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6) 24 | %% [1]. 25 | -module(lasp_mochiglobal). 26 | -author("Bob Ippolito "). 27 | -export([get/1, get/2, put/2, delete/1]). 28 | 29 | -spec get(atom()) -> any() | undefined. 30 | %% @equiv get(K, undefined) 31 | get(K) -> 32 | get(K, undefined). 33 | 34 | -spec get(atom(), T) -> any() | T. 35 | %% @doc Get the term for K or return Default. 36 | get(K, Default) -> 37 | get(K, Default, key_to_module(K)). 38 | 39 | get(_K, Default, Mod) -> 40 | try Mod:term() 41 | catch error:undef -> 42 | Default 43 | end. 44 | 45 | -spec put(atom(), any()) -> ok. 46 | %% @doc Store term V at K, replaces an existing term if present. 47 | put(K, V) -> 48 | put(K, V, key_to_module(K)). 49 | 50 | put(_K, V, Mod) -> 51 | Bin = compile(Mod, V), 52 | code:purge(Mod), 53 | {module, Mod} = code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin), 54 | ok. 55 | 56 | -spec delete(atom()) -> boolean(). 57 | %% @doc Delete term stored at K, no-op if non-existent. 58 | delete(K) -> 59 | delete(K, key_to_module(K)). 60 | 61 | delete(_K, Mod) -> 62 | code:purge(Mod), 63 | code:delete(Mod). 64 | 65 | -spec key_to_module(atom()) -> atom(). 66 | key_to_module(K) -> 67 | list_to_atom("lasp_mochiglobal:" ++ atom_to_list(K)). 68 | 69 | -spec compile(atom(), any()) -> binary(). 70 | compile(Module, T) -> 71 | {ok, Module, Bin} = compile:forms(forms(Module, T), 72 | [verbose, report_errors]), 73 | Bin. 74 | 75 | -spec forms(atom(), any()) -> [erl_syntax:syntaxTree()]. 76 | forms(Module, T) -> 77 | [erl_syntax:revert(X) || X <- term_to_abstract(Module, term, T)]. 78 | 79 | -spec term_to_abstract(atom(), atom(), any()) -> [erl_syntax:syntaxTree()]. 80 | term_to_abstract(Module, Getter, T) -> 81 | [%% -module(Module). 82 | erl_syntax:attribute( 83 | erl_syntax:atom(module), 84 | [erl_syntax:atom(Module)]), 85 | %% -export([Getter/0]). 86 | erl_syntax:attribute( 87 | erl_syntax:atom(export), 88 | [erl_syntax:list( 89 | [erl_syntax:arity_qualifier( 90 | erl_syntax:atom(Getter), 91 | erl_syntax:integer(0))])]), 92 | %% Getter() -> T. 93 | erl_syntax:function( 94 | erl_syntax:atom(Getter), 95 | [erl_syntax:clause([], none, [erl_syntax:abstract(T)])])]. 96 | 97 | %% 98 | %% Tests 99 | %% 100 | -ifdef(TEST). 101 | -include_lib("eunit/include/eunit.hrl"). 102 | get_put_delete_test() -> 103 | K = '$$test$$mochiglobal', 104 | delete(K), 105 | ?assertEqual( 106 | bar, 107 | get(K, bar)), 108 | try 109 | ?MODULE:put(K, baz), 110 | ?assertEqual( 111 | baz, 112 | get(K, bar)), 113 | ?MODULE:put(K, wibble), 114 | ?assertEqual( 115 | wibble, 116 | ?MODULE:get(K)) 117 | after 118 | delete(K) 119 | end, 120 | ?assertEqual( 121 | bar, 122 | get(K, bar)), 123 | ?assertEqual( 124 | undefined, 125 | ?MODULE:get(K)), 126 | ok. 127 | -endif. 128 | -------------------------------------------------------------------------------- /src/lasp_operations.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_operations). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -export([inverse/2]). 25 | 26 | inverse(pncounter, {increment, X}) -> 27 | {decrement, X}. 28 | -------------------------------------------------------------------------------- /src/lasp_partisan_peer_service.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_partisan_peer_service). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -include("lasp.hrl"). 25 | 26 | -behaviour(lasp_peer_service). 27 | 28 | -define(PEER_SERVICE, partisan_peer_service). 29 | 30 | -export([join/1, 31 | join/2, 32 | join/3, 33 | leave/0, 34 | members/0, 35 | manager/0, 36 | stop/0, 37 | stop/1]). 38 | 39 | %%%=================================================================== 40 | %%% External API 41 | %%%=================================================================== 42 | 43 | %% @doc Prepare node to join a cluster. 44 | join(Node) -> 45 | do(join, [Node, true]). 46 | 47 | %% @doc Convert nodename to atom. 48 | join(NodeStr, Auto) when is_list(NodeStr) -> 49 | do(join, [NodeStr, Auto]); 50 | join(Node, Auto) when is_atom(Node) -> 51 | do(join, [Node, Auto]); 52 | join(#{name := _Name, listen_addrs := _ListenAddrs} = Node, Auto) -> 53 | do(join, [Node, Auto]). 54 | 55 | %% @doc Initiate join. Nodes cannot join themselves. 56 | join(Node, Node, Auto) -> 57 | do(join, [Node, Node, Auto]). 58 | 59 | %% @doc Leave the cluster. 60 | leave() -> 61 | do(leave, []). 62 | 63 | %% @doc Leave the cluster. 64 | members() -> 65 | do(?PEER_SERVICE, members, []). 66 | 67 | %% @doc Leave the cluster. 68 | manager() -> 69 | do(?PEER_SERVICE, manager, []). 70 | 71 | %% @doc Stop node. 72 | stop() -> 73 | stop("received stop request"). 74 | 75 | %% @doc Stop node for a given reason. 76 | stop(Reason) -> 77 | do(stop, [Reason]). 78 | 79 | %%%=================================================================== 80 | %%% Internal Functions 81 | %%%=================================================================== 82 | 83 | %% @doc Execute call to the proper backend. 84 | do(join, Args) -> 85 | erlang:apply(?PEER_SERVICE, join, Args); 86 | do(Function, Args) -> 87 | erlang:apply(?PEER_SERVICE, Function, Args). 88 | 89 | %% @doc Execute call to the proper backend. 90 | do(Module, Function, Args) -> 91 | erlang:apply(Module, Function, Args). 92 | -------------------------------------------------------------------------------- /src/lasp_peer_service.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_peer_service). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -include("lasp.hrl"). 25 | 26 | -export([peer_service/0]). 27 | 28 | -export([join/1, 29 | join/2, 30 | join/3, 31 | leave/0, 32 | members/0, 33 | manager/0, 34 | stop/0, 35 | stop/1]). 36 | 37 | %%%=================================================================== 38 | %%% Callback Interface 39 | %%%=================================================================== 40 | 41 | %% Attempt to join node. 42 | -callback join(node()) -> ok | {error, atom()}. 43 | 44 | %% Attempt to join node with or without automatically claiming ring 45 | %% ownership. 46 | -callback join(node(), boolean()) -> ok | {error, atom()}. 47 | 48 | %% Attempt to join node with or without automatically claiming ring 49 | %% ownership. 50 | -callback join(node(), node(), boolean()) -> ok | {error, atom()}. 51 | 52 | %% Remove a node from the cluster. 53 | -callback leave() -> ok. 54 | 55 | %% Return members of the cluster. 56 | -callback members() -> {ok, [node()]}. 57 | 58 | %% Return manager. 59 | -callback manager() -> module(). 60 | 61 | %% Stop the peer service on a given node. 62 | -callback stop() -> ok. 63 | 64 | %% Stop the peer service on a given node for a particular reason. 65 | -callback stop(iolist()) -> ok. 66 | 67 | %%%=================================================================== 68 | %%% External API 69 | %%%=================================================================== 70 | 71 | %% @doc Prepare node to join a cluster. 72 | join(Node) -> 73 | do(join, [Node, true]). 74 | 75 | %% @doc Convert nodename to atom. 76 | join(NodeStr, Auto) when is_list(NodeStr) -> 77 | do(join, [NodeStr, Auto]); 78 | join(Node, Auto) when is_atom(Node) -> 79 | do(join, [Node, Auto]). 80 | 81 | %% @doc Initiate join. Nodes cannot join themselves. 82 | join(Node, Node, Auto) -> 83 | do(join, [Node, Node, Auto]). 84 | 85 | %% @doc Return cluster members. 86 | members() -> 87 | do(members, []). 88 | 89 | %% @doc Return manager. 90 | manager() -> 91 | do(manager, []). 92 | 93 | %% @doc Leave the cluster. 94 | leave() -> 95 | do(leave, []). 96 | 97 | %% @doc Stop node. 98 | stop() -> 99 | stop("received stop request"). 100 | 101 | %% @doc Stop node for a given reason. 102 | stop(Reason) -> 103 | do(stop, [Reason]). 104 | 105 | %%%=================================================================== 106 | %%% Internal Functions 107 | %%%=================================================================== 108 | 109 | %% @doc Execute call to the proper backend. 110 | do(Function, Args) -> 111 | Backend = peer_service(), 112 | erlang:apply(Backend, Function, Args). 113 | 114 | %% @doc Return the currently active peer service. 115 | peer_service() -> 116 | application:get_env(?APP, 117 | peer_service, 118 | lasp_partisan_peer_service). 119 | -------------------------------------------------------------------------------- /src/lasp_plumtree_memory_report.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_plumtree_memory_report). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | -behaviour(gen_server). 25 | 26 | %% API 27 | -export([start_link/0, 28 | start_link/1]). 29 | 30 | %% gen_server callbacks 31 | -export([init/1, 32 | handle_call/3, 33 | handle_cast/2, 34 | handle_info/2, 35 | terminate/2, 36 | code_change/3]). 37 | 38 | -include("lasp.hrl"). 39 | 40 | %% State record. 41 | -record(state, {}). 42 | 43 | %%%=================================================================== 44 | %%% API 45 | %%%=================================================================== 46 | 47 | %% @doc Same as start_link([]). 48 | -spec start_link() -> {ok, pid()} | ignore | {error, term()}. 49 | start_link() -> 50 | start_link([]). 51 | 52 | %% @doc Start and link to calling process. 53 | -spec start_link(list())-> {ok, pid()} | ignore | {error, term()}. 54 | start_link(Opts) -> 55 | gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). 56 | 57 | %%%=================================================================== 58 | %%% gen_server callbacks 59 | %%%=================================================================== 60 | 61 | %% @private 62 | -spec init([]) -> {ok, #state{}}. 63 | init([]) -> 64 | %% Seed the process at initialization. 65 | rand:seed(exsplus, {erlang:phash2([lasp_support:mynode()]), 66 | erlang:monotonic_time(), 67 | erlang:unique_integer()}), 68 | 69 | %% Schedule reports. 70 | schedule_plumtree_memory_report(), 71 | 72 | {ok, #state{}}. 73 | 74 | %% @private 75 | -spec handle_call(term(), {pid(), term()}, #state{}) -> 76 | {reply, term(), #state{}}. 77 | handle_call(Msg, _From, State) -> 78 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 79 | {reply, ok, State}. 80 | 81 | -spec handle_cast(term(), #state{}) -> {noreply, #state{}}. 82 | %% @private 83 | handle_cast(Msg, State) -> 84 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 85 | {noreply, State}. 86 | 87 | %% @private 88 | -spec handle_info(term(), #state{}) -> {noreply, #state{}}. 89 | handle_info(plumtree_memory_report, State) -> 90 | lasp_marathon_simulations:log_message_queue_size("plumtree_memory_report"), 91 | 92 | %% Log 93 | plumtree_memory_report(), 94 | 95 | %% Schedule report. 96 | schedule_plumtree_memory_report(), 97 | 98 | {noreply, State}; 99 | 100 | handle_info(Msg, State) -> 101 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 102 | {noreply, State}. 103 | 104 | %% @private 105 | -spec terminate(term(), #state{}) -> term(). 106 | terminate(_Reason, _State) -> 107 | ok. 108 | 109 | %% @private 110 | -spec code_change(term() | {down, term()}, #state{}, term()) -> 111 | {ok, #state{}}. 112 | code_change(_OldVsn, State, _Extra) -> 113 | {ok, State}. 114 | 115 | %%%=================================================================== 116 | %%% Internal functions 117 | %%%=================================================================== 118 | 119 | %% @private 120 | schedule_plumtree_memory_report() -> 121 | case lasp_config:get(memory_report, false) of 122 | true -> 123 | timer:send_after(?PLUMTREE_MEMORY_INTERVAL, plumtree_memory_report); 124 | false -> 125 | ok 126 | end. 127 | 128 | %% @private 129 | plumtree_memory_report() -> 130 | PlumtreeBroadcast = erlang:whereis(plumtree_broadcast), 131 | lager:info("Plumtree message queue: ~p", 132 | [process_info(PlumtreeBroadcast, message_queue_len)]). 133 | -------------------------------------------------------------------------------- /src/lasp_process_sup.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2014 SyncFree Consortium. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_process_sup). 22 | -author('Christopher Meiklejohn '). 23 | 24 | -behaviour(supervisor). 25 | 26 | %% API 27 | -export([start_link/0, 28 | start_child/1, 29 | start_child/2, 30 | terminate/0, 31 | terminate_child/2]). 32 | 33 | %% Supervisor callbacks 34 | -export([init/1]). 35 | 36 | %% =================================================================== 37 | %% API functions 38 | %% =================================================================== 39 | 40 | %% @doc API for starting the supervisor. 41 | start_link() -> 42 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 43 | 44 | %% @doc Terminate all children. 45 | terminate() -> 46 | Children = supervisor:which_children(?MODULE), 47 | [terminate_child(?MODULE, Child) 48 | || {_Id, Child, _Type, _Modules} <- Children]. 49 | 50 | %% @doc Start a child. 51 | start_child(Args) -> 52 | supervisor:start_child(?MODULE, [Args]). 53 | 54 | start_child(EventCount, Args) -> 55 | supervisor:start_child(?MODULE, [EventCount, Args]). 56 | 57 | %% @doc Stop a child immediately 58 | terminate_child(Supervisor, Pid) -> 59 | supervisor:terminate_child(Supervisor, Pid). 60 | 61 | %% =================================================================== 62 | %% Supervisor callbacks 63 | %% =================================================================== 64 | 65 | %% @doc supervisor callback. 66 | init([]) -> 67 | Spec = {gen_flow, 68 | {gen_flow, start_link, [lasp_process]}, 69 | transient, 5000, worker, [gen_flow]}, 70 | 71 | {ok, {{simple_one_for_one, 10, 10}, [Spec]}}. 72 | -------------------------------------------------------------------------------- /src/lasp_sql_lexer.xrl: -------------------------------------------------------------------------------- 1 | Definitions. 2 | 3 | D = [0-9] 4 | L = [A-Za-z] 5 | WS = ([\000-\s]|%.*) 6 | C = (<|<=|=|=>|>) 7 | 8 | Rules. 9 | 10 | select : {token,{select,TokenLine,list_to_atom(TokenChars)}}. 11 | from : {token,{from,TokenLine,list_to_atom(TokenChars)}}. 12 | where : {token,{where,TokenLine,list_to_atom(TokenChars)}}. 13 | or : {token,{union,TokenLine,list_to_atom(TokenChars)}}. 14 | and : {token,{intersection,TokenLine,list_to_atom(TokenChars)}}. 15 | {C} : {token,{comparator,TokenLine,list_to_atom(TokenChars)}}. 16 | '{L}+' : S = strip(TokenChars,TokenLen), 17 | {token,{string,TokenLine,S}}. 18 | {L}+ : {token,{var,TokenLine,list_to_atom(TokenChars)}}. 19 | {D}+ : {token,{integer,TokenLine,list_to_integer(TokenChars)}}. 20 | [(),] : {token,{list_to_atom(TokenChars),TokenLine}}. 21 | {WS}+ : skip_token. 22 | 23 | Erlang code. 24 | 25 | strip(TokenChars,TokenLen) -> 26 | lists:sublist(TokenChars, 2, TokenLen - 2). 27 | 28 | % Taken from http://blog.rusty.io/2011/02/08/leex-and-yecc/ and 29 | % modified. 30 | -------------------------------------------------------------------------------- /src/lasp_sql_parser.yrl: -------------------------------------------------------------------------------- 1 | Nonterminals 2 | statement select_clause from_clause where_clause predicates predicate elements element. 3 | 4 | Terminals ',' atom var integer string select from where union intersection comparator. 5 | 6 | Expect 1. 7 | 8 | Rootsymbol statement. 9 | 10 | statement -> select_clause from_clause where_clause : {query, '$1', '$2', '$3'}. 11 | 12 | select_clause -> select elements : {select, '$2'}. 13 | 14 | from_clause -> from element : {from, '$2'}. 15 | 16 | where_clause -> where predicates : {where, '$2'}. 17 | 18 | predicates -> predicate : '$1'. 19 | predicates -> predicate union predicate : {union, '$1', '$3'}. 20 | predicates -> predicates union predicate : {union, '$1', '$3'}. 21 | 22 | predicates -> predicate intersection predicate : {intersection, '$1', '$3'}. 23 | 24 | predicate -> var comparator element : {predicate, {var, unwrap('$1')}, unwrap('$2'), '$3'}. 25 | 26 | elements -> element : ['$1']. 27 | elements -> element ',' elements : ['$1'] ++ '$3'. 28 | 29 | element -> atom : '$1'. 30 | element -> var : unwrap('$1'). 31 | element -> integer : unwrap('$1'). 32 | element -> string : unwrap('$1'). 33 | 34 | Erlang code. 35 | 36 | unwrap({_,_,V}) -> V. 37 | -------------------------------------------------------------------------------- /src/lasp_synchronization_backend.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_synchronization_backend). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | -callback(extract_log_type_and_payload(term()) -> [{term(), term()}]). 25 | 26 | -export([send/3, 27 | log_transmission/2]). 28 | 29 | -export([broadcast_tree_mode/0, 30 | client_server_mode/0, 31 | peer_to_peer_mode/0, 32 | i_am_server/0, 33 | i_am_client/0, 34 | reactive_server/0, 35 | seed/0, 36 | membership/0, 37 | compute_exchange/1, 38 | without_me/1]). 39 | 40 | %% @private 41 | membership() -> 42 | lasp_peer_service:members(). 43 | 44 | %% @private 45 | seed() -> 46 | rand:seed(exsplus, {erlang:phash2([lasp_support:mynode()]), 47 | erlang:monotonic_time(), 48 | erlang:unique_integer()}). 49 | 50 | %% @private 51 | compute_exchange(Peers) -> 52 | PeerServiceManager = lasp_config:peer_service_manager(), 53 | 54 | Probability = lasp_config:get(partition_probability, 0), 55 | Percent = lasp_support:puniform(100), 56 | 57 | case Percent =< Probability of 58 | true -> 59 | case PeerServiceManager of 60 | partisan_client_server_peer_service_manager -> 61 | lager:info("Partitioning from server."), 62 | []; 63 | _ -> 64 | lager:info("Partitioning ~p% of the network.", 65 | [Percent]), 66 | 67 | %% Select percentage, minus one node which will be 68 | %% the server node. 69 | K = round((Percent / 100) * length(Peers)), 70 | lager:info("Partitioning ~p%: ~p nodes.", 71 | [Percent, K]), 72 | ServerNodes = case PeerServiceManager:active(server) of 73 | {ok, undefined} -> 74 | []; 75 | {ok, Server} -> 76 | [Server]; 77 | error -> 78 | [] 79 | end, 80 | lager:info("ServerNodes: ~p", [ServerNodes]), 81 | 82 | Random = select_random_sublist(Peers, K), 83 | RandomAndServer = lists:usort(ServerNodes ++ Random), 84 | lager:info("Partitioning ~p from ~p during sync.", 85 | [RandomAndServer, Peers -- RandomAndServer]), 86 | Peers -- RandomAndServer 87 | end; 88 | false -> 89 | Peers 90 | end. 91 | 92 | %% @private 93 | without_me(Members) -> 94 | Members -- [lasp_support:mynode()]. 95 | 96 | %% @private 97 | select_random_sublist(List, K) -> 98 | lists:sublist(shuffle(List), K). 99 | 100 | %% @reference http://stackoverflow.com/questions/8817171/shuffling-elements-in-a-list-randomly-re-arrange-list-elements/8820501#8820501 101 | shuffle(L) -> 102 | [X || {_, X} <- lists:sort([{lasp_support:puniform(65535), N} || N <- L])]. 103 | 104 | %% @private 105 | broadcast_tree_mode() -> 106 | lasp_config:get(broadcast, false). 107 | 108 | %% @private 109 | client_server_mode() -> 110 | lasp_config:peer_service_manager() == partisan_client_server_peer_service_manager. 111 | 112 | %% @private 113 | peer_to_peer_mode() -> 114 | lasp_config:peer_service_manager() == partisan_hyparview_peer_service_manager orelse 115 | lasp_config:peer_service_manager() == partisan_pluggable_peer_service_manager. 116 | 117 | %% @private 118 | i_am_server() -> 119 | partisan_config:get(tag, undefined) == server. 120 | 121 | %% @private 122 | i_am_client() -> 123 | partisan_config:get(tag, undefined) == client. 124 | 125 | %% @private 126 | reactive_server() -> 127 | lasp_config:get(reactive_server, false). 128 | 129 | %% @private 130 | send(Mod, Msg, Peer) -> 131 | log_transmission(Mod:extract_log_type_and_payload(Msg), 1), 132 | PeerServiceManager = lasp_config:peer_service_manager(), 133 | case PeerServiceManager:cast_message(Peer, Mod, Msg) of 134 | ok -> 135 | ok; 136 | _Error -> 137 | % lager:error("Failed send to ~p for reason ~p", [Peer, Error]), 138 | ok 139 | end. 140 | 141 | %% @private 142 | log_transmission(ToLog, PeerCount) -> 143 | try 144 | case lasp_config:get(instrumentation, false) of 145 | true -> 146 | lists:foreach( 147 | fun({Type, Payload}) -> 148 | ok = lasp_instrumentation:transmission(Type, Payload, PeerCount) 149 | end, 150 | ToLog 151 | ), 152 | ok; 153 | false -> 154 | ok 155 | end 156 | catch 157 | _:Error -> 158 | lager:error("Couldn't log transmission: ~p", [Error]), 159 | ok 160 | end. 161 | -------------------------------------------------------------------------------- /src/lasp_throughput_server.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_throughput_server). 22 | -author("Vitor Enes Duarte "). 23 | 24 | -behaviour(gen_server). 25 | 26 | %% API 27 | -export([start_link/0]). 28 | 29 | %% gen_server callbacks 30 | -export([init/1, 31 | handle_call/3, 32 | handle_cast/2, 33 | handle_info/2, 34 | terminate/2, 35 | code_change/3]). 36 | 37 | -include("lasp.hrl"). 38 | 39 | %% State record. 40 | -record(state, {}). 41 | 42 | %%%=================================================================== 43 | %%% API 44 | %%%=================================================================== 45 | 46 | %% @doc Start and link to calling process. 47 | -spec start_link() -> {ok, pid()} | ignore | {error, term()}. 48 | start_link() -> 49 | gen_server:start_link(?MODULE, [], []). 50 | 51 | %%%=================================================================== 52 | %%% gen_server callbacks 53 | %%%=================================================================== 54 | 55 | %% @private 56 | -spec init([term()]) -> {ok, #state{}}. 57 | init([]) -> 58 | lager:info("Throughput server initialized."), 59 | 60 | %% Delay for graph connectedness. 61 | wait_for_connectedness(), 62 | lasp_instrumentation:experiment_started(), 63 | 64 | %% Track whether simulation has ended or not. 65 | lasp_config:set(simulation_end, false), 66 | 67 | %% Schedule check simulation end 68 | schedule_check_simulation_end(), 69 | 70 | %% Mark that the convergence reached. 71 | lasp_workflow:task_completed(convergence, lasp_support:mynode()), 72 | 73 | {ok, #state{}}. 74 | 75 | %% @private 76 | -spec handle_call(term(), {pid(), term()}, #state{}) -> 77 | {reply, term(), #state{}}. 78 | handle_call(Msg, _From, State) -> 79 | lager:warning("Unhandled messages: ~p", [Msg]), 80 | {reply, ok, State}. 81 | 82 | %% @private 83 | -spec handle_cast(term(), #state{}) -> {noreply, #state{}}. 84 | handle_cast(Msg, State) -> 85 | lager:warning("Unhandled messages: ~p", [Msg]), 86 | {noreply, State}. 87 | 88 | handle_info(check_simulation_end, State) -> 89 | lasp_marathon_simulations:log_message_queue_size("check_simulation_end"), 90 | 91 | {ok, NodesWithAllEvents} = lasp_workflow:task_progress(events), 92 | {ok, NodesWithLogsPushed} = lasp_workflow:task_progress(logs), 93 | 94 | lager:info("Checking for simulation end: ~p nodes with all events and ~p nodes with logs pushed.", 95 | [NodesWithAllEvents, NodesWithLogsPushed]), 96 | 97 | case lasp_workflow:is_task_completed(logs) of 98 | true -> 99 | log_convergence(), 100 | lasp_instrumentation:stop(), 101 | lasp_support:push_logs(), 102 | lasp_config:set(simulation_end, true), 103 | stop_simulation(); 104 | false -> 105 | schedule_check_simulation_end() 106 | end, 107 | 108 | {noreply, State}; 109 | 110 | handle_info(Msg, State) -> 111 | lager:warning("Unhandled messages: ~p", [Msg]), 112 | {noreply, State}. 113 | 114 | %% @private 115 | -spec terminate(term(), #state{}) -> term(). 116 | terminate(_Reason, _State) -> 117 | ok. 118 | 119 | %% @private 120 | -spec code_change(term() | {down, term()}, #state{}, term()) -> {ok, #state{}}. 121 | code_change(_OldVsn, State, _Extra) -> 122 | {ok, State}. 123 | 124 | %%%=================================================================== 125 | %%% Internal functions 126 | %%%=================================================================== 127 | 128 | %% @private 129 | schedule_check_simulation_end() -> 130 | timer:send_after(?STATUS_INTERVAL, check_simulation_end). 131 | 132 | %% @private 133 | log_convergence() -> 134 | case lasp_config:get(instrumentation, false) of 135 | true -> 136 | lasp_instrumentation:convergence(); 137 | false -> 138 | ok 139 | end. 140 | 141 | %% @private 142 | stop_simulation() -> 143 | case sprinter:orchestrated() of 144 | false -> 145 | ok; 146 | _ -> 147 | case sprinter:orchestration() of 148 | {ok, kubernetes} -> 149 | lasp_kubernetes_simulations:stop(); 150 | {ok, mesos} -> 151 | lasp_marathon_simulations:stop() 152 | end 153 | end. 154 | 155 | %% @private 156 | wait_for_connectedness() -> 157 | case sprinter:orchestrated() of 158 | false -> 159 | ok; 160 | _ -> 161 | case sprinter_backend:was_connected() of 162 | {ok, true} -> 163 | ok; 164 | {ok, false} -> 165 | timer:sleep(100), 166 | wait_for_connectedness() 167 | end 168 | end. 169 | -------------------------------------------------------------------------------- /src/lasp_type.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_type). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -include("lasp.hrl"). 25 | 26 | -export([new/1, 27 | update/4, 28 | merge/3, 29 | threshold_met/3, 30 | is_inflation/3, 31 | is_bottom/2, 32 | is_strict_inflation/3, 33 | encode/3, 34 | decode/3, 35 | query/2, 36 | get_type/1, 37 | delta/3]). 38 | 39 | types() -> 40 | [ 41 | {awmap, {state_awmap, undefined}}, 42 | {awset, {state_awset, undefined}}, 43 | {awset_ps, {state_awset_ps, undefined}}, 44 | {boolean, {state_boolean, undefined}}, 45 | {gcounter, {state_gcounter, undefined}}, 46 | {gmap, {state_gmap, undefined}}, 47 | {gset, {state_gset, undefined}}, 48 | {ivar, {state_ivar, undefined}}, 49 | {lwwregister, {state_lwwregister, undefined}}, 50 | {orset, {state_orset, undefined}}, 51 | {pair, {state_pair, undefined}}, 52 | {pncounter, {state_pncounter, undefined}}, 53 | {twopset, {state_twopset, undefined}} 54 | ]. 55 | 56 | get_mode() -> 57 | lasp_config:get(mode, state_based). 58 | 59 | %% @doc Return the internal type. 60 | get_type([]) -> 61 | []; 62 | get_type([H | T]) -> 63 | [get_type(H) | get_type(T)]; 64 | get_type({T1, T2}) -> 65 | {get_type(T1), get_type(T2)}; 66 | get_type(T) -> 67 | get_type(T, get_mode()). 68 | 69 | get_type(T, Mode) -> 70 | case orddict:find(T, types()) of 71 | {ok, {StateType, PureOpType}} -> 72 | case Mode of 73 | delta_based -> 74 | StateType; 75 | state_based -> 76 | StateType; 77 | pure_op_based -> 78 | PureOpType 79 | end; 80 | error -> 81 | T 82 | end. 83 | 84 | remove_args({T, _Args}) -> 85 | T; 86 | remove_args(T) -> 87 | T. 88 | 89 | encode(Type, Encoding, Value) -> 90 | T = get_type(remove_args(Type)), 91 | T:encode(Encoding, Value). 92 | 93 | decode(Type, Encoding, Value) -> 94 | T = get_type(remove_args(Type)), 95 | T:decode(Encoding, Value). 96 | 97 | %% @doc Is bottom? 98 | is_bottom(Type, Value) -> 99 | T = get_type(remove_args(Type)), 100 | T:is_bottom(Value). 101 | 102 | %% @doc Is strict inflation? 103 | is_strict_inflation(Type, Previous, Current) -> 104 | T = get_type(remove_args(Type)), 105 | T:is_strict_inflation(Previous, Current). 106 | 107 | %% @doc Is inflation? 108 | is_inflation(Type, Previous, Current) -> 109 | T = get_type(remove_args(Type)), 110 | T:is_inflation(Previous, Current). 111 | 112 | %% @doc Determine if a threshold is met. 113 | threshold_met(Type, Value, {strict, Threshold}) -> 114 | T = get_type(remove_args(Type)), 115 | T:is_strict_inflation(Threshold, Value); 116 | threshold_met(Type, Value, Threshold) -> 117 | T = get_type(remove_args(Type)), 118 | T:is_inflation(Threshold, Value). 119 | 120 | %% @doc Initialize a new variable for a given type. 121 | new(Type) -> 122 | T = get_type(remove_args(Type)), 123 | case Type of 124 | {_T0, Args} -> 125 | T:new(get_type(Args)); 126 | _T0 -> 127 | T:new() 128 | end. 129 | 130 | %% @doc Use the proper type for performing an update. 131 | update(Type, Operation, Actor, Value) -> 132 | Mode = get_mode(), 133 | T = get_type(remove_args(Type), Mode), 134 | RealActor = get_actor(T, Actor), 135 | case Mode of 136 | delta_based -> 137 | T:delta_mutate(Operation, RealActor, Value); 138 | state_based -> 139 | T:mutate(Operation, RealActor, Value); 140 | pure_op_based -> 141 | ok %% @todo 142 | end. 143 | 144 | %% @private 145 | get_actor(state_awset_ps, {{StorageId, _TypeId}, Actor}) -> 146 | {StorageId, Actor}; 147 | get_actor(_Type, {_Id, Actor}) -> 148 | Actor; 149 | get_actor(_Type, Actor) -> 150 | Actor. 151 | 152 | %% @doc Call the correct merge function for a given type. 153 | merge(Type, Value0, Value) -> 154 | T = get_type(remove_args(Type)), 155 | T:merge(Value0, Value). 156 | 157 | %% @doc Return the value of a CRDT. 158 | query(Type, Value) -> 159 | T = get_type(remove_args(Type)), 160 | T:query(Value). 161 | 162 | %% @doc 163 | delta(Type, A, B) -> 164 | T = get_type(remove_args(Type)), 165 | T:delta(A, B). 166 | -------------------------------------------------------------------------------- /src/lasp_unique.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_unique). 22 | -author("Christopher Meiklejohn "). 23 | 24 | -behaviour(gen_server). 25 | 26 | %% API 27 | -export([start_link/0, 28 | start_link/1, 29 | unique/0]). 30 | 31 | %% gen_server callbacks 32 | -export([init/1, 33 | handle_call/3, 34 | handle_cast/2, 35 | handle_info/2, 36 | terminate/2, 37 | code_change/3]). 38 | 39 | -record(state, {}). 40 | 41 | %%%=================================================================== 42 | %%% API 43 | %%%=================================================================== 44 | 45 | %% @doc Same as start_link([]). 46 | -spec start_link() -> {ok, pid()} | ignore | {error, term()}. 47 | start_link() -> 48 | start_link([]). 49 | 50 | %% @doc Start and link to calling process. 51 | -spec start_link(list())-> {ok, pid()} | ignore | {error, term()}. 52 | start_link(Opts) -> 53 | gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). 54 | 55 | -spec unique() -> {ok, binary()}. 56 | unique() -> 57 | gen_server:call(?MODULE, unique, infinity). 58 | 59 | %%%=================================================================== 60 | %%% gen_server callbacks 61 | %%%=================================================================== 62 | 63 | %% @private 64 | -spec init([]) -> {ok, #state{}}. 65 | init([]) -> 66 | {ok, #state{}}. 67 | 68 | %% @private 69 | -spec handle_call(term(), {pid(), term()}, #state{}) -> 70 | {reply, term(), #state{}}. 71 | 72 | handle_call(unique, _From, State) -> 73 | Unique = mk_unique(), 74 | {reply, {ok, Unique}, State}; 75 | 76 | %% @private 77 | handle_call(Msg, _From, State) -> 78 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 79 | {reply, ok, State}. 80 | 81 | %% @private 82 | -spec handle_cast(term(), #state{}) -> {noreply, #state{}}. 83 | handle_cast(Msg, State) -> 84 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 85 | {noreply, State}. 86 | 87 | %% @private 88 | -spec handle_info(term(), #state{}) -> {noreply, #state{}}. 89 | handle_info(Msg, State) -> 90 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 91 | {noreply, State}. 92 | 93 | %% @private 94 | -spec terminate(term(), #state{}) -> term(). 95 | terminate(_Reason, _State) -> 96 | ok. 97 | 98 | %% @private 99 | -spec code_change(term() | {down, term()}, #state{}, term()) -> {ok, #state{}}. 100 | code_change(_OldVsn, State, _Extra) -> 101 | {ok, State}. 102 | 103 | %%%=================================================================== 104 | %%% Internal functions 105 | %%%=================================================================== 106 | 107 | %% @private 108 | mk_unique() -> 109 | Node = atom_to_list(lasp_support:mynode()), 110 | Unique = erlang:unique_integer([monotonic, positive]), 111 | TS = integer_to_list(Unique), 112 | Term = Node ++ TS, 113 | crypto:hash(sha, Term). 114 | -------------------------------------------------------------------------------- /src/lasp_workflow.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2017 Christopher S. Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(lasp_workflow). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | %% API 25 | -export([start_link/0, 26 | start_link/1, 27 | task_completed/2, 28 | is_task_completed/1, 29 | is_task_completed/2, 30 | task_progress/1]). 31 | 32 | %% gen_server callbacks 33 | -export([init/1, 34 | handle_call/3, 35 | handle_cast/2, 36 | handle_info/2, 37 | terminate/2, 38 | code_change/3]). 39 | 40 | %% State record. 41 | -record(state, {eredis}). 42 | 43 | %%%=================================================================== 44 | %%% API 45 | %%%=================================================================== 46 | 47 | %% @doc Same as start_link([]). 48 | -spec start_link() -> {ok, pid()} | ignore | {error, term()}. 49 | start_link() -> 50 | start_link([]). 51 | 52 | %% @doc Start and link to calling process. 53 | -spec start_link(list())-> {ok, pid()} | ignore | {error, term()}. 54 | start_link(Opts) -> 55 | gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). 56 | 57 | %% @doc Mark a task as completed. 58 | -spec task_completed(atom(), atom()) -> ok. 59 | task_completed(Task, Node) -> 60 | gen_server:call(?MODULE, {task_completed, Task, Node}, infinity). 61 | 62 | %% @doc Determine if a task is completed. 63 | -spec is_task_completed(atom()) -> ok. 64 | is_task_completed(Task) -> 65 | ClientNumber = lasp_config:get(client_number, 0), 66 | gen_server:call(?MODULE, {is_task_completed, Task, ClientNumber}, infinity). 67 | 68 | %% @doc Determine if a task is completed. 69 | -spec is_task_completed(atom(), non_neg_integer()) -> ok. 70 | is_task_completed(Task, NodeCount) -> 71 | gen_server:call(?MODULE, {is_task_completed, Task, NodeCount}, infinity). 72 | 73 | %% @doc Determine if a task is completed. 74 | -spec task_progress(atom()) -> ok. 75 | task_progress(Task) -> 76 | gen_server:call(?MODULE, {task_progress, Task}, infinity). 77 | 78 | %%%=================================================================== 79 | %%% gen_server callbacks 80 | %%%=================================================================== 81 | 82 | %% @private 83 | -spec init([]) -> {ok, #state{}}. 84 | init([]) -> 85 | RedisHost = os:getenv("REDIS_SERVICE_HOST", "127.0.0.1"), 86 | RedisPort = os:getenv("REDIS_SERVICE_PORT", "6379"), 87 | Result = eredis:start_link(RedisHost, list_to_integer(RedisPort)), 88 | case Result of 89 | {ok, C} -> 90 | {ok, #state{eredis=C}}; 91 | Error -> 92 | lager:error("Error connecting to redis for workflow management: ~p", 93 | [Error]), 94 | {stop, Error} 95 | end. 96 | 97 | %% @private 98 | -spec handle_call(term(), {pid(), term()}, #state{}) -> 99 | {reply, term(), #state{}}. 100 | 101 | %% @private 102 | handle_call({task_progress, Task}, _From, #state{eredis=Eredis}=State) -> 103 | {ok, Objects} = eredis:q(Eredis, ["KEYS", prefix(Task, "*")]), 104 | NumObjects = length(Objects), 105 | % lager:info("Task ~p progress: ~p", [Task, NumObjects]), 106 | {reply, {ok, NumObjects}, State}; 107 | handle_call({is_task_completed, Task, NumNodes}, _From, #state{eredis=Eredis}=State) -> 108 | {ok, Objects} = eredis:q(Eredis, ["KEYS", prefix(Task, "*")]), 109 | Result = case length(Objects) of 110 | NumNodes -> 111 | % lager:info("Task ~p completed on all nodes.", [Task]), 112 | true; 113 | _Other -> 114 | % lager:info("Task ~p incomplete: only on ~p/~p nodes.", 115 | % [Task, Other, NumNodes]), 116 | false 117 | end, 118 | {reply, Result, State}; 119 | handle_call({task_completed, Task, Node}, _From, #state{eredis=Eredis}=State) -> 120 | Path = prefix(Task, Node), 121 | % lager:info("Setting ~p to true.", [Path]), 122 | {ok, <<"OK">>} = eredis:q(Eredis, ["SET", Path, true]), 123 | {reply, ok, State}; 124 | 125 | handle_call(Msg, _From, State) -> 126 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 127 | {reply, ok, State}. 128 | 129 | -spec handle_cast(term(), #state{}) -> {noreply, #state{}}. 130 | 131 | %% @private 132 | handle_cast(Msg, State) -> 133 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 134 | {noreply, State}. 135 | 136 | %% @private 137 | handle_info(Msg, State) -> 138 | _ = lager:warning("Unhandled messages: ~p", [Msg]), 139 | {noreply, State}. 140 | 141 | %% @private 142 | -spec terminate(term(), #state{}) -> term(). 143 | terminate(_Reason, _State) -> 144 | ok. 145 | 146 | %% @private 147 | -spec code_change(term() | {down, term()}, #state{}, term()) -> 148 | {ok, #state{}}. 149 | code_change(_OldVsn, State, _Extra) -> 150 | {ok, State}. 151 | 152 | %%%=================================================================== 153 | %%% Internal functions 154 | %%%=================================================================== 155 | 156 | %% @private 157 | prefix(Task, Node) when is_atom(Task) -> 158 | prefix(atom_to_list(Task), Node); 159 | prefix(Task, Node) when is_atom(Node) -> 160 | prefix(Task, atom_to_list(Node)); 161 | prefix(Task, Node) -> 162 | EvalId = lasp_config:get(evaluation_identifier, undefined), 163 | EvalTimestamp = lasp_config:get(evaluation_timestamp, 0), 164 | "workflow" ++ "/" ++ atom_to_list(EvalId) ++ "/" ++ integer_to_list(EvalTimestamp) ++ "/" ++ Task ++ "/" ++ Node. 165 | -------------------------------------------------------------------------------- /src/state_orset_ext.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | -module(state_orset_ext). 22 | -author("Christopher S. Meiklejohn "). 23 | 24 | -export([intersect/2, 25 | map/2, 26 | union/2, 27 | product/2, 28 | filter/2]). 29 | 30 | union(LValue, RValue) -> 31 | state_orset:merge(LValue, RValue). 32 | 33 | product({state_orset, LValue}, {state_orset, RValue}) -> 34 | FolderFun = fun({X, XCausality}, {state_orset, Acc}) -> 35 | {state_orset, Acc ++ [{{X, Y}, causal_product(XCausality, YCausality)} || {Y, YCausality} <- RValue]} 36 | end, 37 | lists:foldl(FolderFun, new(), LValue). 38 | 39 | intersect({state_orset, LValue}, RValue) -> 40 | lists:foldl(intersect_folder(RValue), new(), LValue). 41 | 42 | %% @private 43 | intersect_folder({state_orset, RValue}) -> 44 | fun({X, XCausality}, {state_orset, Acc}) -> 45 | Values = case lists:keyfind(X, 1, RValue) of 46 | {_Y, YCausality} -> 47 | [{X, causal_union(XCausality, YCausality)}]; 48 | false -> 49 | [] 50 | end, 51 | {state_orset, Acc ++ Values} 52 | end. 53 | 54 | map(Function, {state_orset, V}) -> 55 | FolderFun = fun({X, Causality}, {state_orset, Acc}) -> 56 | {state_orset, Acc ++ [{Function(X), Causality}]} 57 | end, 58 | lists:foldl(FolderFun, new(), V). 59 | 60 | filter(Function, {state_orset, V}) -> 61 | FolderFun = fun({X, Causality}, {state_orset, Acc}) -> 62 | case Function(X) of 63 | true -> 64 | {state_orset, Acc ++ [{X, Causality}]}; 65 | false -> 66 | {state_orset, Acc} 67 | end 68 | end, 69 | lists:foldl(FolderFun, new(), V). 70 | 71 | %% @private 72 | new() -> 73 | state_orset:new(). 74 | 75 | %% @private 76 | causal_product(Xs, Ys) -> 77 | lists:foldl(fun({X, XActive}, XAcc) -> 78 | lists:foldl(fun({Y, YActive}, YAcc) -> 79 | [{[X, Y], XActive andalso YActive}] ++ YAcc 80 | end, [], Ys) ++ XAcc 81 | end, [], Xs). 82 | 83 | %% @private 84 | causal_union(Xs, Ys) -> 85 | Xs ++ Ys. 86 | -------------------------------------------------------------------------------- /test/lasp_advertisement_counter_overcounting_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_advertisement_counter_overcounting_SUITE). 23 | -author("Vitor Enes Duarte "). 24 | 25 | %% common_test callbacks 26 | -export([%% suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | %% =================================================================== 43 | %% common_test callbacks 44 | %% =================================================================== 45 | 46 | init_per_suite(_Config) -> 47 | _Config. 48 | 49 | end_per_suite(_Config) -> 50 | _Config. 51 | 52 | init_per_testcase(Case, _Config) -> 53 | ct:pal("Beginning test case ~p", [Case]), 54 | 55 | _Config. 56 | 57 | end_per_testcase(Case, _Config) -> 58 | ct:pal("Ending test case ~p", [Case]), 59 | 60 | _Config. 61 | 62 | all() -> 63 | [ 64 | client_server_overcounting_test, 65 | peer_to_peer_overcounting_test, 66 | code_peer_to_peer_overcounting_test 67 | ]. 68 | 69 | %% =================================================================== 70 | %% tests 71 | %% =================================================================== 72 | 73 | -define(MIN_POW, 2). 74 | -define(MAX_POW, 3). 75 | 76 | default_test(_Config) -> 77 | ok. 78 | 79 | client_server_overcounting_test(Config) -> 80 | lists:foreach( 81 | fun(ClientNumber) -> 82 | lasp_config:set(client_number, ClientNumber), 83 | EvaluationIdentifier = list_to_atom("client_server_overcounting_" ++ integer_to_list(ClientNumber)), 84 | 85 | lasp_simulation_support:run(client_server_overcounting_test, 86 | Config, 87 | [{mode, delta_based}, 88 | {simulation, ad_counter_overcounting}, 89 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 90 | {set, orset}, 91 | {broadcast, false}, 92 | {heavy_client, false}, 93 | {evaluation_identifier, EvaluationIdentifier}] 94 | ) 95 | end, 96 | clients() 97 | ), 98 | ok. 99 | 100 | peer_to_peer_overcounting_test(Config) -> 101 | lists:foreach( 102 | fun(ClientNumber) -> 103 | lasp_config:set(client_number, ClientNumber), 104 | EvaluationIdentifier = list_to_atom("peer_to_peer_overcounting_" ++ integer_to_list(ClientNumber)), 105 | 106 | lasp_simulation_support:run(peer_to_peer_overcounting_test, 107 | Config, 108 | [{mode, delta_based}, 109 | {simulation, ad_counter_overcounting}, 110 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 111 | {set, orset}, 112 | {broadcast, false}, 113 | {heavy_client, false}, 114 | {evaluation_identifier, EvaluationIdentifier}] 115 | ) 116 | end, 117 | clients() 118 | ), 119 | ok. 120 | 121 | code_peer_to_peer_overcounting_test(Config) -> 122 | lists:foreach( 123 | fun(ClientNumber) -> 124 | lasp_config:set(client_number, ClientNumber), 125 | EvaluationIdentifier = list_to_atom("code_peer_to_peer_overcounting_" ++ integer_to_list(ClientNumber)), 126 | 127 | lasp_simulation_support:run(code_peer_to_peer_overcounting_test, 128 | Config, 129 | [{mode, delta_based}, 130 | {simulation, ad_counter_overcounting}, 131 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 132 | {set, orset}, 133 | {broadcast, false}, 134 | {heavy_client, true}, 135 | {evaluation_identifier, EvaluationIdentifier}] 136 | ) 137 | end, 138 | clients() 139 | ), 140 | ok. 141 | 142 | %% =================================================================== 143 | %% Internal functions 144 | %% =================================================================== 145 | 146 | clients() -> 147 | lists:map( 148 | fun(Power) -> 149 | round(math:pow(2, Power)) 150 | end, 151 | lists:seq(?MIN_POW, ?MAX_POW) 152 | ). 153 | 154 | -------------------------------------------------------------------------------- /test/lasp_advertisement_counter_partition_overcounting_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_advertisement_counter_partition_overcounting_SUITE). 23 | -author("Christopher S. Meiklejohn "). 24 | 25 | %% common_test callbacks 26 | -export([suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | %% =================================================================== 43 | %% common_test callbacks 44 | %% =================================================================== 45 | 46 | suite() -> 47 | [{timetrap, infinity}]. 48 | 49 | init_per_suite(_Config) -> 50 | _Config. 51 | 52 | end_per_suite(_Config) -> 53 | _Config. 54 | 55 | init_per_testcase(Case, _Config) -> 56 | ct:pal("Beginning test case ~p", [Case]), 57 | _Config. 58 | 59 | end_per_testcase(Case, _Config) -> 60 | ct:pal("Ending test case ~p", [Case]), 61 | 62 | _Config. 63 | 64 | all() -> 65 | [ 66 | client_server_partition_overcounting_test, 67 | peer_to_peer_partition_overcounting_test, 68 | code_peer_to_peer_partition_overcounting_test 69 | ]. 70 | 71 | -define(CLIENTS, 4). 72 | 73 | %% =================================================================== 74 | %% tests 75 | %% =================================================================== 76 | 77 | default_test(_Config) -> 78 | ok. 79 | 80 | client_server_partition_overcounting_test(Config) -> 81 | lists:foreach( 82 | fun(PartitionProbability) -> 83 | lasp_config:set(client_number, ?CLIENTS), 84 | lasp_config:set(partition_probability, PartitionProbability), 85 | EvaluationIdentifier = list_to_atom("client_server_partition_overcounting_" ++ integer_to_list(PartitionProbability)), 86 | 87 | lasp_simulation_support:run(client_server_partition_overcounting_test, 88 | Config, 89 | [{mode, delta_based}, 90 | {simulation, ad_counter}, 91 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 92 | {set, orset}, 93 | {broadcast, false}, 94 | {heavy_client, false}, 95 | {partition_probability, PartitionProbability}, 96 | {evaluation_identifier, EvaluationIdentifier}] 97 | ) 98 | end, 99 | partitions() 100 | ), 101 | ok. 102 | 103 | peer_to_peer_partition_overcounting_test(Config) -> 104 | lists:foreach( 105 | fun(PartitionProbability) -> 106 | lasp_config:set(client_number, ?CLIENTS), 107 | lasp_config:set(partition_probability, PartitionProbability), 108 | EvaluationIdentifier = list_to_atom("peer_to_peer_partition_overcounting_" ++ integer_to_list(PartitionProbability)), 109 | 110 | lasp_simulation_support:run(peer_to_peer_partition_overcounting_test, 111 | Config, 112 | [{mode, delta_based}, 113 | {simulation, ad_counter}, 114 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 115 | {set, orset}, 116 | {broadcast, false}, 117 | {heavy_client, false}, 118 | {partition_probability, PartitionProbability}, 119 | {evaluation_identifier, EvaluationIdentifier}] 120 | ) 121 | end, 122 | partitions() 123 | ), 124 | ok. 125 | 126 | code_peer_to_peer_partition_overcounting_test(Config) -> 127 | lists:foreach( 128 | fun(PartitionProbability) -> 129 | lasp_config:set(client_number, ?CLIENTS), 130 | lasp_config:set(partition_probability, PartitionProbability), 131 | EvaluationIdentifier = list_to_atom("code_peer_to_peer_partition_overcounting_" ++ integer_to_list(PartitionProbability)), 132 | 133 | lasp_simulation_support:run(code_peer_to_peer_partition_overcounting_test, 134 | Config, 135 | [{mode, delta_based}, 136 | {simulation, ad_counter}, 137 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 138 | {set, orset}, 139 | {broadcast, false}, 140 | {heavy_client, true}, 141 | {partition_probability, PartitionProbability}, 142 | {evaluation_identifier, EvaluationIdentifier}] 143 | ) 144 | end, 145 | partitions() 146 | ), 147 | ok. 148 | 149 | %% =================================================================== 150 | %% Internal functions 151 | %% =================================================================== 152 | 153 | %% @private 154 | partitions() -> 155 | [0, 10, 20, 30, 40, 50, 60, 70]. 156 | -------------------------------------------------------------------------------- /test/lasp_client_server_advertisement_counter_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_client_server_advertisement_counter_SUITE). 23 | -author("Christopher Meiklejohn "). 24 | 25 | %% common_test callbacks 26 | -export([%% suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | %% =================================================================== 43 | %% common_test callbacks 44 | %% =================================================================== 45 | 46 | init_per_suite(_Config) -> 47 | _Config. 48 | 49 | end_per_suite(_Config) -> 50 | _Config. 51 | 52 | init_per_testcase(Case, _Config) -> 53 | ct:pal("Beginning test case ~p", [Case]), 54 | 55 | _Config. 56 | 57 | end_per_testcase(Case, _Config) -> 58 | ct:pal("Ending test case ~p", [Case]), 59 | 60 | _Config. 61 | 62 | all() -> 63 | [ 64 | client_server_state_based_test, 65 | client_server_delta_based_test, 66 | reactive_client_server_state_based_test, 67 | reactive_client_server_delta_based_test 68 | %%client_server_state_based_ps_test, 69 | %%client_server_delta_based_ps_test 70 | ]. 71 | 72 | %% =================================================================== 73 | %% tests 74 | %% =================================================================== 75 | 76 | default_test(_Config) -> 77 | ok. 78 | 79 | %% =================================================================== 80 | %% client/server with local replica 81 | %% =================================================================== 82 | 83 | client_server_state_based_test(Config) -> 84 | lasp_simulation_support:run(client_server_ad_counter_state_based_test, 85 | Config, 86 | [{mode, state_based}, 87 | {simulation, ad_counter}, 88 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 89 | {set, orset}, 90 | {broadcast, false}, 91 | {evaluation_identifier, client_server_state_based}]), 92 | ok. 93 | 94 | client_server_delta_based_test(Config) -> 95 | lasp_simulation_support:run(client_server_ad_counter_delta_based_test, 96 | Config, 97 | [{mode, delta_based}, 98 | {simulation, ad_counter}, 99 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 100 | {set, orset}, 101 | {broadcast, false}, 102 | {evaluation_identifier, client_server_delta_based}]), 103 | ok. 104 | 105 | reactive_client_server_state_based_test(Config) -> 106 | lasp_simulation_support:run(reactive_client_server_ad_counter_state_based_test, 107 | Config, 108 | [{mode, state_based}, 109 | {simulation, ad_counter}, 110 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 111 | {set, orset}, 112 | {broadcast, false}, 113 | {reactive_server, true}, 114 | {evaluation_identifier, reactive_client_server_state_based}]), 115 | ok. 116 | 117 | reactive_client_server_delta_based_test(Config) -> 118 | lasp_simulation_support:run(reactive_client_server_ad_counter_delta_based_test, 119 | Config, 120 | [{mode, delta_based}, 121 | {simulation, ad_counter}, 122 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 123 | {set, orset}, 124 | {broadcast, false}, 125 | {reactive_server, true}, 126 | {evaluation_identifier, reactive_client_server_delta_based}]), 127 | ok. 128 | 129 | client_server_state_based_ps_test(Config) -> 130 | lasp_simulation_support:run(client_server_ad_counter_state_based_ps_test, 131 | Config, 132 | [{mode, state_based}, 133 | {simulation, ad_counter}, 134 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 135 | {set, awset_ps}, 136 | {broadcast, false}, 137 | {evaluation_identifier, client_server_state_based_ps}]), 138 | ok. 139 | 140 | client_server_delta_based_ps_test(Config) -> 141 | lasp_simulation_support:run(client_server_ad_counter_delta_based_ps_test, 142 | Config, 143 | [{mode, delta_based}, 144 | {simulation, ad_counter}, 145 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 146 | {set, awset_ps}, 147 | {broadcast, false}, 148 | {evaluation_identifier, client_server_delta_based_ps}]), 149 | ok. 150 | 151 | %% =================================================================== 152 | %% Internal functions 153 | %% =================================================================== 154 | -------------------------------------------------------------------------------- /test/lasp_client_server_divergence_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2017 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_client_server_divergence_SUITE). 23 | -author("Christopher S. Meiklejohn "). 24 | 25 | %% common_test callbacks 26 | -export([suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | -define(RUNS, [1, 2, 4]). 43 | 44 | %% =================================================================== 45 | %% common_test callbacks 46 | %% =================================================================== 47 | 48 | suite() -> 49 | [{timetrap, {hours, 1}}]. 50 | 51 | init_per_suite(_Config) -> 52 | _Config. 53 | 54 | end_per_suite(_Config) -> 55 | _Config. 56 | 57 | init_per_testcase(Case, _Config) -> 58 | ct:pal("Beginning test case ~p", [Case]), 59 | 60 | _Config. 61 | 62 | end_per_testcase(Case, _Config) -> 63 | ct:pal("Ending test case ~p", [Case]), 64 | 65 | _Config. 66 | 67 | all() -> 68 | [ 69 | client_server_state_based_gcounter 70 | ]. 71 | 72 | %% =================================================================== 73 | %% tests 74 | %% =================================================================== 75 | 76 | default_test(_Config) -> 77 | ok. 78 | 79 | %% =================================================================== 80 | %% peer-to-peer 81 | %% =================================================================== 82 | 83 | client_server_state_based_gcounter(Config) -> 84 | lists:foreach(fun(N) -> 85 | lasp_simulation_support:run(client_server_state_based_gcounter, 86 | Config, 87 | [{mode, state_based}, 88 | {client_number, N}, 89 | {simulation, divergence}, 90 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 91 | {set, orset}, 92 | {throughput_type, gcounter}, 93 | {divergence_type, gcounter}, 94 | {broadcast, false}, 95 | {blocking_sync, true}, 96 | {evaluation_identifier, client_server_state_based_gcounter}]) 97 | end, ?RUNS), 98 | ok. 99 | -------------------------------------------------------------------------------- /test/lasp_client_server_game_tournament_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_client_server_game_tournament_SUITE). 23 | -author("Christopher Meiklejohn "). 24 | 25 | %% common_test callbacks 26 | -export([%% suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | %% =================================================================== 43 | %% common_test callbacks 44 | %% =================================================================== 45 | 46 | init_per_suite(_Config) -> 47 | _Config. 48 | 49 | end_per_suite(_Config) -> 50 | _Config. 51 | 52 | init_per_testcase(Case, _Config) -> 53 | ct:pal("Beginning test case ~p", [Case]), 54 | 55 | _Config. 56 | 57 | end_per_testcase(Case, _Config) -> 58 | ct:pal("Ending test case ~p", [Case]), 59 | 60 | _Config. 61 | 62 | all() -> 63 | [ 64 | client_server_state_based_test, 65 | client_server_delta_based_test, 66 | reactive_client_server_state_based_test, 67 | reactive_client_server_delta_based_test 68 | %%client_server_state_based_ps_test, 69 | %%client_server_delta_based_ps_test 70 | ]. 71 | 72 | %% =================================================================== 73 | %% tests 74 | %% =================================================================== 75 | 76 | default_test(_Config) -> 77 | ok. 78 | 79 | %% =================================================================== 80 | %% client/server with local replica 81 | %% =================================================================== 82 | 83 | client_server_state_based_test(Config) -> 84 | lasp_simulation_support:run(client_server_game_tournament_state_based_test, 85 | Config, 86 | [{mode, state_based}, 87 | {simulation, game_tournament}, 88 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 89 | {set, orset}, 90 | {broadcast, false}, 91 | {evaluation_identifier, client_server_state_based}]), 92 | ok. 93 | 94 | client_server_delta_based_test(Config) -> 95 | lasp_simulation_support:run(client_server_game_tournament_delta_based_test, 96 | Config, 97 | [{mode, delta_based}, 98 | {simulation, game_tournament}, 99 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 100 | {set, orset}, 101 | {broadcast, false}, 102 | {evaluation_identifier, client_server_delta_based}]), 103 | ok. 104 | 105 | reactive_client_server_state_based_test(Config) -> 106 | lasp_simulation_support:run(reactive_client_server_game_tournament_state_based_test, 107 | Config, 108 | [{mode, state_based}, 109 | {simulation, game_tournament}, 110 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 111 | {set, orset}, 112 | {broadcast, false}, 113 | {reactive_server, true}, 114 | {evaluation_identifier, reactive_client_server_state_based}]), 115 | ok. 116 | 117 | reactive_client_server_delta_based_test(Config) -> 118 | lasp_simulation_support:run(reactive_client_server_game_tournament_delta_based_test, 119 | Config, 120 | [{mode, delta_based}, 121 | {simulation, game_tournament}, 122 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 123 | {set, orset}, 124 | {broadcast, false}, 125 | {reactive_server, true}, 126 | {evaluation_identifier, reactive_client_server_delta_based}]), 127 | ok. 128 | 129 | client_server_state_based_ps_test(Config) -> 130 | lasp_simulation_support:run(client_server_game_tournament_state_based_ps_test, 131 | Config, 132 | [{mode, state_based}, 133 | {simulation, game_tournament}, 134 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 135 | {set, awset_ps}, 136 | {broadcast, false}, 137 | {evaluation_identifier, client_server_state_based_ps}]), 138 | ok. 139 | 140 | client_server_delta_based_ps_test(Config) -> 141 | lasp_simulation_support:run(client_server_game_tournament_delta_based_ps_test, 142 | Config, 143 | [{mode, delta_based}, 144 | {simulation, game_tournament}, 145 | {partisan_peer_service_manager, partisan_client_server_peer_service_manager}, 146 | {set, awset_ps}, 147 | {broadcast, false}, 148 | {evaluation_identifier, client_server_delta_based_ps}]), 149 | ok. 150 | 151 | %% =================================================================== 152 | %% Internal functions 153 | %% =================================================================== 154 | -------------------------------------------------------------------------------- /test/lasp_peer_to_peer_game_tournament_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2016 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_peer_to_peer_game_tournament_SUITE). 23 | -author("Christopher Meiklejohn "). 24 | 25 | %% common_test callbacks 26 | -export([%% suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | %% =================================================================== 43 | %% common_test callbacks 44 | %% =================================================================== 45 | 46 | init_per_suite(_Config) -> 47 | _Config. 48 | 49 | end_per_suite(_Config) -> 50 | _Config. 51 | 52 | init_per_testcase(Case, _Config) -> 53 | ct:pal("Beginning test case ~p", [Case]), 54 | 55 | _Config. 56 | 57 | end_per_testcase(Case, _Config) -> 58 | ct:pal("Ending test case ~p", [Case]), 59 | 60 | _Config. 61 | 62 | all() -> 63 | [ 64 | peer_to_peer_state_based_test, 65 | peer_to_peer_state_based_tree_test, 66 | peer_to_peer_delta_based_test%%, 67 | %%peer_to_peer_state_based_ps_test, 68 | %%peer_to_peer_state_based_ps_tree_test, 69 | %%peer_to_peer_delta_based_ps_test 70 | ]. 71 | 72 | %% =================================================================== 73 | %% tests 74 | %% =================================================================== 75 | 76 | default_test(_Config) -> 77 | ok. 78 | 79 | %% =================================================================== 80 | %% peer-to-peer 81 | %% =================================================================== 82 | 83 | peer_to_peer_state_based_test(Config) -> 84 | lasp_simulation_support:run(peer_to_peer_game_tournament_state_based_test, 85 | Config, 86 | [{mode, state_based}, 87 | {simulation, game_tournament}, 88 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 89 | {set, orset}, 90 | {broadcast, false}, 91 | {evaluation_identifier, peer_to_peer_state_based}]), 92 | ok. 93 | 94 | peer_to_peer_state_based_tree_test(Config) -> 95 | lasp_simulation_support:run(peer_to_peer_game_tournament_state_based_tree_test, 96 | Config, 97 | [{mode, state_based}, 98 | {simulation, game_tournament}, 99 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 100 | {set, orset}, 101 | {broadcast, true}, 102 | {evaluation_identifier, peer_to_peer_state_based_tree}]), 103 | ok. 104 | 105 | peer_to_peer_delta_based_test(Config) -> 106 | lasp_simulation_support:run(peer_to_peer_game_tournament_delta_based_test, 107 | Config, 108 | [{mode, delta_based}, 109 | {simulation, game_tournament}, 110 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 111 | {set, orset}, 112 | {broadcast, false}, 113 | {evaluation_identifier, peer_to_peer_delta_based}]), 114 | ok. 115 | 116 | peer_to_peer_state_based_ps_test(Config) -> 117 | lasp_simulation_support:run(peer_to_peer_game_tournament_state_based_ps_test, 118 | Config, 119 | [{mode, state_based}, 120 | {simulation, game_tournament}, 121 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 122 | {set, awset_ps}, 123 | {broadcast, false}, 124 | {evaluation_identifier, peer_to_peer_state_based_ps}]), 125 | ok. 126 | 127 | peer_to_peer_state_based_ps_tree_test(Config) -> 128 | lasp_simulation_support:run(peer_to_peer_game_tournament_state_based_ps_tree_test, 129 | Config, 130 | [{mode, state_based}, 131 | {simulation, game_tournament}, 132 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 133 | {set, awset_ps}, 134 | {broadcast, true}, 135 | {evaluation_identifier, peer_to_peer_state_based_ps_tree}]), 136 | ok. 137 | 138 | peer_to_peer_delta_based_ps_test(Config) -> 139 | lasp_simulation_support:run(peer_to_peer_game_tournament_delta_based_ps_test, 140 | Config, 141 | [{mode, delta_based}, 142 | {simulation, game_tournament}, 143 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 144 | {set, awset_ps}, 145 | {broadcast, false}, 146 | {evaluation_identifier, peer_to_peer_delta_based_ps}]), 147 | ok. 148 | -------------------------------------------------------------------------------- /test/lasp_peer_to_peer_throughput_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2017 Christopher Meiklejohn. All Rights Reserved. 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | %% 21 | 22 | -module(lasp_peer_to_peer_throughput_SUITE). 23 | -author("Christopher S. Meiklejohn "). 24 | 25 | %% common_test callbacks 26 | -export([%% suite/0, 27 | init_per_suite/1, 28 | end_per_suite/1, 29 | init_per_testcase/2, 30 | end_per_testcase/2, 31 | all/0]). 32 | 33 | %% tests 34 | -compile([export_all]). 35 | 36 | -include("lasp.hrl"). 37 | 38 | -include_lib("common_test/include/ct.hrl"). 39 | -include_lib("eunit/include/eunit.hrl"). 40 | -include_lib("kernel/include/inet.hrl"). 41 | 42 | %% =================================================================== 43 | %% common_test callbacks 44 | %% =================================================================== 45 | 46 | init_per_suite(_Config) -> 47 | _Config. 48 | 49 | end_per_suite(_Config) -> 50 | _Config. 51 | 52 | init_per_testcase(Case, _Config) -> 53 | ct:pal("Beginning test case ~p", [Case]), 54 | 55 | _Config. 56 | 57 | end_per_testcase(Case, _Config) -> 58 | ct:pal("Ending test case ~p", [Case]), 59 | 60 | _Config. 61 | 62 | all() -> 63 | [ 64 | peer_to_peer_state_based 65 | ]. 66 | 67 | %% =================================================================== 68 | %% tests 69 | %% =================================================================== 70 | 71 | default_test(_Config) -> 72 | ok. 73 | 74 | %% =================================================================== 75 | %% peer-to-peer 76 | %% =================================================================== 77 | 78 | peer_to_peer_state_based(Config) -> 79 | lasp_simulation_support:run(peer_to_peer_throughput_state_based, 80 | Config, 81 | [{mode, state_based}, 82 | {simulation, throughput}, 83 | {partisan_peer_service_manager, partisan_hyparview_peer_service_manager}, 84 | {set, orset}, 85 | {broadcast, false}, 86 | {evaluation_identifier, peer_to_peer_throughput_state_based}]), 87 | ok. 88 | -------------------------------------------------------------------------------- /tools.mk: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------- 2 | # 3 | # Copyright (c) 2014 Basho Technologies, Inc. 4 | # 5 | # This file is provided to you under the Apache License, 6 | # Version 2.0 (the "License"); you may not use this file 7 | # except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | # ------------------------------------------------------------------- 20 | 21 | # ------------------------------------------------------------------- 22 | # NOTE: This file is is from https://github.com/basho/tools.mk. 23 | # It should not be edited in a project. It should simply be updated 24 | # wholesale when a new version of tools.mk is released. 25 | # ------------------------------------------------------------------- 26 | 27 | REBAR ?= rebar3 28 | REVISION ?= $(shell git rev-parse --short HEAD) 29 | PROJECT ?= $(shell basename `find src -name "*.app.src"` .app.src) 30 | DEP_DIR ?= "deps" 31 | EBIN_DIR ?= "ebin" 32 | 33 | .PHONY: compile-no-deps test docs xref dialyzer-run dialyzer-quick dialyzer \ 34 | cleanplt upload-docs 35 | 36 | compile-no-deps: 37 | ${REBAR} compile 38 | 39 | docs: 40 | ${REBAR} doc 41 | 42 | xref: compile 43 | ${REBAR} xref 44 | 45 | dialyzer: compile 46 | ${REBAR} dialyzer 47 | --------------------------------------------------------------------------------