diff --git a/.circleci/config.yml b/.circleci/config.yml index 43e93c1b81..59d7613582 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,7 +4,6 @@ parameters: run_default_flow: default: true type: boolean - run_benchmark_flow_label: default: false type: boolean @@ -67,7 +66,7 @@ commands: if [[ $(uname -s) == Darwin ]]; then rm -f /usr/local/bin/python3; fi ./deps/readies/bin/getpy3 - run: - name: Setup automation (2) + name: Setup automation (part 2) shell: /bin/bash -l -eo pipefail command: | export HOMEBREW_NO_AUTO_UPDATE=1 @@ -81,7 +80,7 @@ commands: parameters: redis_version: type: string - default: "6" + default: "7" getredis_params: type: string default: "" @@ -149,7 +148,7 @@ commands: parameters: redis_version: type: string - default: "6" + default: "7" build_params: type: string default: "" @@ -229,6 +228,12 @@ commands: make build OSNICK=<> VERSION="$CIRCLE_TAG" BRANCH="$CIRCLE_BRANCH" TEST=1 OFFICIAL=<> SHOW=1 VERBOSE=1 - save-tests-logs - early-return-for-forked-pull-requests + - run: + name: Upload artifacts to S3 + command: | + if [[ -n $CIRCLE_BRANCH ]]; then + make upload-artifacts OSNICK=<> SHOW=1 VERBOSE=1 + fi - run: name: Publish container shell: /bin/bash -l -eo pipefail @@ -289,12 +294,21 @@ commands: benchmark_glob: type: string default: "*.yml" + benchmark_regex: + type: string + default: ".*" triggering_env: type: string default: "circleci" allowed_envs: type: string default: "oss-standalone" + benchmark_runner_group_member_id: + type: string + default: "1" + benchmark_runner_group_total: + type: string + default: "1" steps: - run: name: Run CI benchmarks on aws @@ -308,6 +322,9 @@ commands: export EC2_PRIVATE_PEM=$PERFORMANCE_EC2_PRIVATE_PEM export PROFILE=<< parameters.profile_env >> export BENCHMARK_GLOB=<< parameters.benchmark_glob >> + export BENCHMARK_REGEX="<< parameters.benchmark_regex >>" + export BENCHMARK_RUNNER_GROUP_M_ID=<< parameters.benchmark_runner_group_member_id >> + export BENCHMARK_RUNNER_GROUP_TOTAL=<< parameters.benchmark_runner_group_total >> export PERF_CALLGRAPH_MODE="dwarf" redisbench-admin run-remote \ --module_path << parameters.module_path >> \ @@ -346,7 +363,7 @@ jobs: parameters: redis_version: type: string - default: "6" + default: "7" build_params: type: string default: "" @@ -414,7 +431,7 @@ jobs: - run: name: Flow tests shell: /bin/bash -l -eo pipefail - command: make flow-tests CLEAR_LOGS=0 SAN=<> + command: make flow-tests CLEAR_LOGS=0 SAN=<> PARALLEL=8 no_output_timeout: 45m - run: name: TCK tests @@ -477,9 +494,9 @@ jobs: platform: <> official: "0" - build-macos: + build-macos-x64: macos: - xcode: 12.5.1 + xcode: 13.4.1 resource_class: macos.x86.medium.gen2 parameters: upload: @@ -497,6 +514,32 @@ jobs: fi - persist-artifacts + build-macos-m1: + macos: + xcode: 14.2.0 + resource_class: macos.m1.large.gen1 + parameters: + upload: + type: string + default: "yes" + steps: + - early-returns + - build-steps + - test-steps + - run: + name: Persist artifacts? + command: | + if [[ "<>" != "yes" ]]; then + circleci step halt + fi + - run: + name: Upload artifacts to S3 + command: | + if [[ -n $CIRCLE_BRANCH && "<>" == "yes" ]]; then + make upload-artifacts SHOW=1 VERBOSE=1 + fi + - persist-artifacts + upload-artifacts: parameters: staging-lab: @@ -534,23 +577,46 @@ jobs: name: Run QA Automation command: MODULE_VERSION=$CIRCLE_TAG VERBOSE=1 TEST=release ./tests/qa/run - nightly-automation: + benchmark-group-1-of-6: docker: - image: redisfab/rmbuilder:6.2.7-x64-bullseye + resource_class: large steps: - early-returns - - early-return-for-forked-pull-requests - - checkout - - setup-automation + - checkout-all + - install-prerequisites: + benchmarks: "yes" + - attach_workspace: + at: ~/workspace - run: - name: Run QA Automation - command: MODULE_VERSION=$CIRCLE_BRANCH VERBOSE=1 TEST=nightly QUICK=1 ./tests/qa/run + name: Build artifact + shell: /bin/bash -l -eo pipefail + command: make NPROC=16 + - benchmark-steps: + module_path: "/root/project/bin/linux-x64-release/src/$PACKAGE_NAME.so" + benchmark_runner_group_member_id: "1" + benchmark_runner_group_total: "6" + benchmark-group-2-of-6: + docker: + - image: redisfab/rmbuilder:6.2.7-x64-bullseye + resource_class: large + steps: + - early-returns + - checkout-all + - install-prerequisites: + benchmarks: "yes" + - attach_workspace: + at: ~/workspace - run: - name: Run 10-minute fuzz test + name: Build artifact shell: /bin/bash -l -eo pipefail - command: make fuzz-tests TIMEOUT=600 + command: make NPROC=16 + - benchmark-steps: + module_path: "/root/project/bin/linux-x64-release/src/$PACKAGE_NAME.so" + benchmark_runner_group_member_id: "2" + benchmark_runner_group_total: "6" - benchmark: + benchmark-group-3-of-6: docker: - image: redisfab/rmbuilder:6.2.7-x64-bullseye resource_class: large @@ -567,6 +633,68 @@ jobs: command: make NPROC=16 - benchmark-steps: module_path: "/root/project/bin/linux-x64-release/src/$PACKAGE_NAME.so" + benchmark_runner_group_member_id: "3" + benchmark_runner_group_total: "6" + + benchmark-group-4-of-6: + docker: + - image: redisfab/rmbuilder:6.2.7-x64-bullseye + resource_class: large + steps: + - early-returns + - checkout-all + - install-prerequisites: + benchmarks: "yes" + - attach_workspace: + at: ~/workspace + - run: + name: Build artifact + shell: /bin/bash -l -eo pipefail + command: make NPROC=16 + - benchmark-steps: + module_path: "/root/project/bin/linux-x64-release/src/$PACKAGE_NAME.so" + benchmark_runner_group_member_id: "4" + benchmark_runner_group_total: "6" + + benchmark-group-5-of-6: + docker: + - image: redisfab/rmbuilder:6.2.7-x64-bullseye + resource_class: large + steps: + - early-returns + - checkout-all + - install-prerequisites: + benchmarks: "yes" + - attach_workspace: + at: ~/workspace + - run: + name: Build artifact + shell: /bin/bash -l -eo pipefail + command: make NPROC=16 + - benchmark-steps: + module_path: "/root/project/bin/linux-x64-release/src/$PACKAGE_NAME.so" + benchmark_runner_group_member_id: "5" + benchmark_runner_group_total: "6" + + benchmark-group-6-of-6: + docker: + - image: redisfab/rmbuilder:6.2.7-x64-bullseye + resource_class: large + steps: + - early-returns + - checkout-all + - install-prerequisites: + benchmarks: "yes" + - attach_workspace: + at: ~/workspace + - run: + name: Build artifact + shell: /bin/bash -l -eo pipefail + command: make NPROC=16 + - benchmark-steps: + module_path: "/root/project/bin/linux-x64-release/src/$PACKAGE_NAME.so" + benchmark_runner_group_member_id: "6" + benchmark_runner_group_total: "6" benchmark-profiler: docker: @@ -683,14 +811,17 @@ workflows: context: common matrix: parameters: - platform: [jammy, focal, bionic, amzn2, xenial, centos7, rocky8, bullseye] + platform: [bullseye, jammy, focal, bionic, centos7, rocky8, amzn2] - build-arm-platforms: <<: *on-integ-and-version-tags context: common matrix: parameters: platform: [jammy, focal, bionic] - - build-macos: + - build-macos-x64: + <<: *on-integ-and-version-tags + context: common + - build-macos-m1: context: common <<: *on-integ-and-version-tags - coverage: @@ -709,7 +840,8 @@ workflows: requires: - build-platforms - build-arm-platforms - - build-macos + - build-macos-x64 + - build-macos-m1 - upload-artifacts: name: upload-release-artifacts context: common @@ -717,48 +849,53 @@ workflows: requires: - build-platforms - build-arm-platforms - - build-macos + - build-macos-x64 + - build-macos-m1 - release-automation: <<: *on-version-tags context: common requires: - upload-release-artifacts - - benchmark: + - benchmark-group-1-of-6: + context: common <<: *on-integ-and-version-tags + - benchmark-group-2-of-6: context: common + <<: *on-integ-and-version-tags + - benchmark-group-3-of-6: + context: common + <<: *on-integ-and-version-tags + - benchmark-group-4-of-6: + context: common + <<: *on-integ-and-version-tags + - benchmark-group-5-of-6: + context: common + <<: *on-integ-and-version-tags + - benchmark-group-6-of-6: + context: common + <<: *on-integ-and-version-tags benchmark-flow-label: when: << pipeline.parameters.run_benchmark_flow_label >> jobs: - - benchmark: + - benchmark-group-1-of-6: context: common <<: *always - - nightly: - triggers: - - schedule: - cron: "07 20 * * *" - <<: *on-integ-branch-cron - jobs: - - build-linux-debian: - name: build-with-redis-<> - matrix: - parameters: - redis_version: ["6.0", "6.2", "7", "unstable"] - - valgrind-test: - name: nightly-valgrind - - fuzzer: - name: nightly-fuzzer - - nightly-perf-once-a-week: - triggers: - - schedule: - # “At 07:00 on Mondays.” - cron: "00 07 * * 1" - filters: - branches: - only: master - jobs: - - benchmark: + - benchmark-group-2-of-6: + context: common + <<: *always + - benchmark-group-3-of-6: context: common + <<: *always + - benchmark-group-4-of-6: + context: common + <<: *always + - benchmark-group-5-of-6: + context: common + <<: *always + - benchmark-group-6-of-6: + context: common + <<: *always + + diff --git a/.github/wordlist.txt b/.github/wordlist.txt index addba7bb5c..fa3ed19454 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -1,7 +1,6 @@ CodeQL Jedis js -Kolevska's Lexicographically metamodel QL @@ -87,4 +86,5 @@ cli Quickstart queryable RSALv -SSPLv \ No newline at end of file +SSPLv +th diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index e4697e0be7..52b4811e24 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -14,6 +14,9 @@ jobs: - uses: actions/checkout@v3 with: submodules: true + - run: | + git config --global --add safe.directory '*' + git submodule update --init --recursive - name: Setup run: | ./sbin/setup diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ef8943c272..1237beb589 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,13 +43,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true + - run: | + git config --global --add safe.directory '*' + git submodule update --init --recursive # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -78,4 +81,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore index e4937116c0..ca0277725e 100644 --- a/.gitignore +++ b/.gitignore @@ -49,8 +49,6 @@ deps/GraphBLAS/Config/GraphBLAS.h.tmp # Additional suffixes *.pyc -*.cmake -*.make *.xml *.iml *.d diff --git a/LICENSE.txt b/LICENSE.txt index 129ce99f54..853eb3f3f9 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,2 +1,5 @@ -Except as otherwise specified in the source code headers for specific files, the source code in this repository is made available to you under your choice of -(i) Redis Source Available License 2.0 (RSALv2) or (ii) the Server Side Public License v1 (SSPLv1) \ No newline at end of file +Except as otherwise specified in the source code headers for specific files, the source code in this repository is made available to you under your choice of + (i) Redis Source Available License 2.0 (RSALv2); + (ii) the Server Side Public License v1 (SSPLv1); or + (iii) the GNU Affero General Public License version 3 (AGPLv3). +Please review the license folder for the full license terms and conditions. diff --git a/Makefile b/Makefile index c4c5e7e6e1..7b40f546ad 100644 --- a/Makefile +++ b/Makefile @@ -235,9 +235,11 @@ $(RAX): graphblas: $(GRAPHBLAS) +GRAPHBLAS_MAKE_FLAGS.xenial-x64=CC=gcc-5 CXX=gxx-5 + $(GRAPHBLAS): @echo Building $@ ... - $(SHOW)$(MAKE) --no-print-directory -C $(ROOT)/build/GraphBLAS DEBUG=$(DEPS_DEBUG) + $(SHOW)$(MAKE) --no-print-directory -C $(ROOT)/build/GraphBLAS DEBUG=$(DEPS_DEBUG) $(GRAPHBLAS_MAKE_FLAGS.$(OSNICK)-$(ARCH)) libcypher-parser: $(LIBCYPHER_PARSER) @@ -412,6 +414,6 @@ SANBOX_ARGS += -v /w:/w endif sanbox: - @docker run -it -v $(PWD):/build -w /build --cap-add=SYS_PTRACE --security-opt seccomp=unconfined $(SANBOX_ARGS) redisfab/clang:13-x64-bullseye bash + @docker run -it -v $(PWD):/build -w /build --cap-add=SYS_PTRACE --security-opt seccomp=unconfined $(SANBOX_ARGS) redisfab/clang:16-$(ARCH)-bullseye bash .PHONY: box sanbox diff --git a/README.md b/README.md index 76232a17b0..9373ee6450 100644 --- a/README.md +++ b/README.md @@ -1,301 +1,14 @@ -[![Release](https://img.shields.io/github/release/RedisGraph/RedisGraph.svg?sort=semver)](https://github.com/RedisGraph/RedisGraph/releases/latest) -[![CircleCI](https://circleci.com/gh/RedisGraph/RedisGraph/tree/master.svg?style=svg)](https://circleci.com/gh/RedisGraph/RedisGraph/tree/master) -[![Dockerhub](https://img.shields.io/docker/pulls/redis/redis-stack-server?label=redis-stack-server)](https://img.shields.io/docker/pulls/redis/redis-stack-server) -[![Codecov](https://codecov.io/gh/RedisGraph/RedisGraph/branch/master/graph/badge.svg)](https://codecov.io/gh/RedisGraph/RedisGraph) -[![Bounty](https://img.shields.io/bountysource/team/redislabsmodules/activity)](https://app.bountysource.com/teams/redislabsmodules/issues) - # RedisGraph ## A graph database module for Redis -[![Forum](https://img.shields.io/badge/Forum-RedisGraph-blue)](https://forum.redislabs.com/c/modules/redisgraph) -[![Discord](https://img.shields.io/discord/697882427875393627?style=flat-square)](https://discord.gg/gWBRT6P) - -RedisGraph is the first queryable [Property Graph](https://github.com/opencypher/openCypher/blob/master/docs/property-graph-model.adoc) database to use [sparse matrices](https://en.wikipedia.org/wiki/Sparse_matrix) to represent the [adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix) in graphs and [linear algebra](http://faculty.cse.tamu.edu/davis/GraphBLAS.html) to query the graph. - -Primary features: -* Adopting the [Property Graph Model](https://github.com/opencypher/openCypher/blob/master/docs/property-graph-model.adoc) - * Nodes (vertices) and Relationships (edges) that may have attributes - * Nodes can have multiple labels - * Relationships have a relationship type -* Graphs represented as sparse adjacency matrices -* [OpenCypher](http://www.opencypher.org/) with proprietary extensions as a query language - * Queries are translated into linear algebra expressions - -To see RedisGraph in action, visit [Demos](https://github.com/RedisGraph/RedisGraph/tree/master/demo). -To read the docs, visit [redis.io](https://redis.io/docs/stack/graph/). - -## Quickstart - -1. [Trying RedisGraph](#trying-redisgraph) -2. [Docker](#docker) -3. [Build](#building) -4. [Start](#loading-redisgraph-into-redis) -5. [Use from any client](#using-redisgraph) - -## Trying RedisGraph - -To try RedisGraph, either use the RedisGraph Docker image, or [create a free Redis Cloud Essentials account](https://redislabs.com/try-free/) to get a RedisGraph instance in the cloud. - -## Docker - -To quickly tryout RedisGraph, launch an instance using docker: - -```sh -docker run -p 6379:6379 -it --rm redis/redis-stack-server:latest -``` - -### Give it a try - -Once loaded you can interact with RedisGraph using redis-cli. - -Here we'll quickly create a small graph representing a subset of motorcycle riders and teams taking part in the MotoGP league, -once created we'll start querying our data. - -### With `redis-cli` - -The format of results through `redis-cli` is described in [the RedisGraph documentation](https://redis.io/docs/stack/graph/design/result_structure/). - -```sh -$ redis-cli -127.0.0.1:6379> GRAPH.QUERY MotoGP "CREATE (:Rider {name:'Valentino Rossi'})-[:rides]->(:Team {name:'Yamaha'}), (:Rider {name:'Dani Pedrosa'})-[:rides]->(:Team {name:'Honda'}), (:Rider {name:'Andrea Dovizioso'})-[:rides]->(:Team {name:'Ducati'})" -1) 1) Labels added: 2 - 2) Nodes created: 6 - 3) Properties set: 6 - 4) Relationships created: 3 - 5) "Query internal execution time: 0.399000 milliseconds" -``` - -Now that our MotoGP graph is created, we can start asking questions, for example: -Who's riding for team Yamaha? - -```sh -127.0.0.1:6379> GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, t.name" -1) 1) "r.name" - 2) "t.name" -2) 1) 1) "Valentino Rossi" - 2) "Yamaha" -3) 1) "Query internal execution time: 0.625399 milliseconds" -``` - -How many riders represent team Ducati? - -```sh -127.0.0.1:6379> GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team {name:'Ducati'}) RETURN count(r)" -1) 1) "count(r)" -2) 1) 1) (integer) 1 -3) 1) "Query internal execution time: 0.624435 milliseconds" -``` - -## Building - -### Compiling - -Requirements: - -* The RedisGraph repository: `git clone --recurse-submodules -j8 https://github.com/RedisGraph/RedisGraph.git` - -* On Ubuntu Linux, run: `apt-get install build-essential cmake m4 automake peg libtool autoconf python3` - -* On OS X, verify that `homebrew` is installed and run: `brew install cmake m4 automake peg libtool autoconf`. - * The version of Clang that ships with the OS X toolchain does not support OpenMP, which is a requirement for RedisGraph. One way to resolve this is to run `brew install gcc g++` and follow the on-screen instructions to update the symbolic links. Note that this is a system-wide change - setting the environment variables for `CC` and `CXX` will work if that is not an option. - -To build, run `make` in the project's directory. - -Congratulations! You can find the compiled binary at `src/redisgraph.so`. - -### Running tests - -First, install required Python packages by running ```pip install -r requirements.txt``` from the ```tests``` directory. - -If you've got ```redis-server``` in PATH, just invoke ```make test```. - -Otherwise, invoke ```REDIS_SERVER= make test```. - -For more verbose output, run ```make test V=1```. - -### Building in a docker - -The RedisGraph build system runs within docker. For detailed instructions on building, please [see here](docs/docker-examples/README.md). - -## Loading RedisGraph into Redis - -RedisGraph is hosted by [Redis](https://redis.io), so you'll first have to load it as a Module to a Redis server: running [Redis v5.0.7 or above](https://redis.io/download). - -We recommend having Redis load RedisGraph during startup by adding the following to your redis.conf file: - -``` -loadmodule /path/to/module/src/redisgraph.so -``` - -In the line above, replace `/path/to/module/src/redisgraph.so` with the actual path to RedisGraph's library. -If Redis is running as a service, you must ensure that the `redis` user (default) has the necessary file/folder permissions -to access `redisgraph.so`. - -Alternatively, you can have Redis load RedisGraph using the following command line argument syntax: - -```sh -~/$ redis-server --loadmodule /path/to/module/src/redisgraph.so -``` - -Lastly, you can also use the [`MODULE LOAD`](http://redis.io/commands/module-load) command. Note, however, that `MODULE LOAD` is a dangerous command and may be blocked/deprecated in the future due to security considerations. - -Once you've successfully loaded RedisGraph your Redis log should have lines similar to: - -``` -... -30707:M 20 Jun 02:08:12.314 * Module 'graph' loaded from /src/redisgraph.so -... -``` - -If the server fails to launch with output similar to: - -``` -# Module /usr/lib/redis/modules/redisgraph.so failed to load: libgomp.so.1: cannot open shared object file: No such file or directory -# Can't load module from /usr/lib/redis/modules/redisgraph.so: server aborting -``` - -The system is missing the run-time dependency OpenMP. This can be installed on Ubuntu with `apt-get install libgomp1`, on RHEL/CentOS with `yum install libgomp`, and on OSX with `brew install libomp`. - -## Using RedisGraph - -You can call RedisGraph's commands from any Redis client. - -### With `redis-cli` - -```sh -$ redis-cli -127.0.0.1:6379> GRAPH.QUERY social "CREATE (:person {name: 'roi', age: 33, gender: 'male', status: 'married'})" -``` - -### With any other client - -You can interact with RedisGraph using your client's ability to send raw Redis commands. - -Depending on your client of choice, the exact method for doing that may vary. - -#### Python example - -This code snippet shows how to use RedisGraph with raw Redis commands from Python via -[redis-py](https://github.com/andymccurdy/redis-py): - -```python -import redis - -r = redis.StrictRedis() -reply = r.execute_command('GRAPH.QUERY', 'social', "CREATE (:person {name:'roi', age:33, gender:'male', status:'married'})") -``` - -### Client libraries - -Some languages have client libraries that provide support for RedisGraph's commands: - -| Project | Language | License | Author | Stars | Package | Comment | -| --------------------------------------------------------- | ---------- | ------- | ------------------------------------------- | ----------------------------------------------------------------- | ------- | ---------- | -| [jedis][jedis-url] | Java | MIT | [Redis][redis-url] | ![Stars][jedis-stars] | [Maven][jedis-package]|| -| [redis-py][redis-py-url] | Python | MIT | [Redis][redis-url] | ![Stars][redis-py-stars] | [pypi][redis-py-package]|| -| [node-redis][node-redis-url] | Node.JS | MIT | [Redis][redis-url] | ![Stars][node-redis-stars] | [npm][node-redis-package]|| -| [nredisstack][nredisstack-url] | .NET | MIT | [Redis][redis-url] | ![Stars][nredisstack-stars] | [nuget][nredisstack-package]|| -| [redisgraph-rb][redisgraph-rb-url] | Ruby | BSD | [Redis][redisgraph-rb-author] | [![redisgraph-rb-stars]][redisgraph-rb-url] | [GitHub][redisgraph-rb-url] || -| [redisgraph-go][redisgraph-go-url] | Go | BSD | [Redis][redisgraph-go-author] | [![redisgraph-go-stars]][redisgraph-go-url] | [GitHub][redisgraph-go-url]|| -| [rueidis][rueidis-url] | Go | Apache 2.0 | [Rueian][rueidis-author] | [![rueidis-stars]][rueidis-url] | [GitHub][rueidis-url] || -| [ioredisgraph][ioredisgraph-url] | JavaScript | ISC | [Jonah][ioredisgraph-author] | [![ioredisgraph-stars]][ioredisgraph-url] | [GitHub][ioredisgraph-url] || -| [@hydre/rgraph][rgraph-url] | JavaScript | MIT | [Sceat][rgraph-author] | [![rgraph-stars]][rgraph-url] | [GitHub][rgraph-url] || -| [php-redis-graph][php-redis-graph-url] | PHP | MIT | [KJDev][php-redis-graph-author] | [![php-redis-graph-stars]][php-redis-graph-url] | [GitHub][php-redis-graph-url] || -| [redisgraph_php][redisgraph_php-url] | PHP | MIT | [jpbourbon][redisgraph_php-author] | [![redisgraph_php-stars]][redisgraph_php-url] | [GitHub][redisgraph_php-url] || -| [redisgraph-ex][redisgraph-ex-url] | Elixir | MIT | [crflynn][redisgraph-ex-author] | [![redisgraph-ex-stars]][redisgraph-ex-url] | [GitHub][redisgraph-ex-url] || -| [redisgraph-rs][redisgraph-rs-url] | Rust | MIT | [malte-v][redisgraph-rs-author] | [![redisgraph-rs-stars]][redisgraph-rs-url] | [GitHub][redisgraph-rs-url] || -| [redis_graph][redis_graph-url] | Rust | BSD | [tompro][redis_graph-author] | [![redis_graph-stars]][redis_graph-url] | [GitHub][redis_graph-url] || -| [rustis][rustis-url] | Rust | MIT | [Dahomey Technologies][rustis-author] | [![rustis-stars]][rustis-url] | [Crate](https://crates.io/crates/rustis) | [Documentation](https://docs.rs/rustis/latest/rustis/commands/trait.GraphCommands.html) | -| [NRedisGraph][NRedisGraph-url] | C# | BSD | [tombatron][NRedisGraph-author] | [![NRedisGraph-stars]][NRedisGraph-url] | [GitHub][NRedisGraph-url] || -| [RedisGraph.jl][RedisGraph.jl-url] | Julia | MIT | [xyxel][RedisGraph.jl-author] | [![RedisGraph.jl-stars]][RedisGraph.jl-url] | [GitHub][RedisGraph.jl-url] || - -[redis-url]: https://redis.com - -[redis-py-url]: https://github.com/redis/redis-py -[redis-py-stars]: https://img.shields.io/github/stars/redis/redis-py.svg?style=social&label=Star&maxAge=2592000 -[redis-py-package]: https://pypi.python.org/pypi/redis - -[jedis-url]: https://github.com/redis/jedis -[jedis-stars]: https://img.shields.io/github/stars/redis/jedis.svg?style=social&label=Star&maxAge=2592000 -[Jedis-package]: https://search.maven.org/artifact/redis.clients/jedis - -[nredisstack-url]: https://github.com/redis/nredisstack -[nredisstack-stars]: https://img.shields.io/github/stars/redis/nredisstack.svg?style=social&label=Star&maxAge=2592000 -[nredisstack-package]: https://www.nuget.org/packages/nredisstack/ - -[node-redis-url]: https://github.com/redis/node-redis -[node-redis-stars]: https://img.shields.io/github/stars/redis/node-redis.svg?style=social&label=Star&maxAge=2592000 -[node-redis-package]: https://www.npmjs.com/package/redis - - -[redisgraph-rb-author]: https://redislabs.com -[redisgraph-rb-url]: https://github.com/RedisGraph/redisgraph-rb -[redisgraph-rb-stars]: https://img.shields.io/github/stars/RedisGraph/redisgraph-rb.svg?style=social&label=Star&maxAge=2592000 - -[redisgraph-go-author]: https://redislabs.com -[redisgraph-go-url]: https://github.com/RedisGraph/redisgraph-go -[redisgraph-go-stars]: https://img.shields.io/github/stars/RedisGraph/redisgraph-go.svg?style=social&label=Star&maxAge=2592000 - -[rueidis-url]: https://github.com/rueian/rueidis -[rueidis-author]: https://github.com/rueian -[rueidis-stars]: https://img.shields.io/github/stars/rueian/rueidis.svg?style=social&label=Star&maxAge=2592000 - - -[rgraph-author]: https://github.com/Sceat -[rgraph-url]: https://github.com/HydreIO/rgraph -[rgraph-stars]: https://img.shields.io/github/stars/HydreIO/rgraph.svg?style=social&label=Star&maxAge=2592000 - -[ioredisgraph-author]: https://github.com/Jonahss -[ioredisgraph-url]: https://github.com/Jonahss/ioredisgraph -[ioredisgraph-stars]: https://img.shields.io/github/stars/Jonahss/ioredisgraph.svg?style=social&label=Star&maxAge=2592000 - -[php-redis-graph-author]: https://github.com/kjdev -[php-redis-graph-url]: https://github.com/kjdev/php-redis-graph -[php-redis-graph-stars]: https://img.shields.io/github/stars/kjdev/php-redis-graph.svg?style=social&label=Star&maxAge=2592000 - -[redisgraph_php-author]: https://github.com/jpbourbon -[redisgraph_php-url]: https://github.com/jpbourbon/redisgraph_php -[redisgraph_php-stars]: https://img.shields.io/github/stars/jpbourbon/redisgraph_php.svg?style=social&label=Star&maxAge=2592000 - -[redislabs-redisgraph-php-author]: https://github.com/mkorkmaz -[redislabs-redisgraph-php-url]: https://github.com/mkorkmaz/redislabs-redisgraph-php -[redislabs-redisgraph-php-stars]: https://img.shields.io/github/stars/mkorkmaz/redislabs-redisgraph-php.svg?style=social&label=Star&maxAge=2592000 - -[redisgraph-ex-author]: https://github.com/crflynn -[redisgraph-ex-url]: https://github.com/crflynn/redisgraph-ex -[redisgraph-ex-stars]: https://img.shields.io/github/stars/crflynn/redisgraph-ex.svg?style=social&label=Star&maxAge=2592000 - -[redisgraph-rs-author]: https://github.com/malte-v -[redisgraph-rs-url]: https://github.com/malte-v/redisgraph-rs -[redisgraph-rs-stars]: https://img.shields.io/github/stars/malte-v/redisgraph-rs.svg?style=social&label=Star&maxAge=2592000 - -[redis_graph-author]: https://github.com/tompro -[redis_graph-url]: https://github.com/tompro/redis_graph -[redis_graph-stars]: https://img.shields.io/github/stars/tompro/redis_graph.svg?style=social&label=Star&maxAge=2592000 - -[NRedisGraph-author]: https://github.com/tombatron -[NRedisGraph-url]: https://github.com/tombatron/NRedisGraph -[NRedisGraph-stars]: https://img.shields.io/github/stars/tombatron/NRedisGraph.svg?style=social&label=Star&maxAge=2592000 - -[RedisGraphDotNet.Client-author]: https://github.com/Sgawrys -[RedisGraphDotNet.Client-url]: https://github.com/Sgawrys/RedisGraphDotNet.Client -[RedisGraphDotNet.Client-stars]: https://img.shields.io/github/stars/Sgawrys/RedisGraphDotNet.Client.svg?style=social&label=Star&maxAge=2592000 - -[RedisGraph.jl-author]: https://github.com/xyxel -[RedisGraph.jl-url]: https://github.com/xyxel/RedisGraph.jl -[RedisGraph.jl-stars]: https://img.shields.io/github/stars/xyxel/RedisGraph.jl.svg?style=social&label=Star&maxAge=2592000 - -[rustis-url]: https://github.com/dahomey-technologies/rustis -[rustis-author]: https://github.com/dahomey-technologies -[rustis-stars]: https://img.shields.io/github/stars/dahomey-technologies/rustis.svg?style=social&label=Star&maxAge=2592000 - -## Documentation -Read the docs at [redisgraph.io](http://redisgraph.io). +--- +### RedisGraph is no longer maintained. -## Mailing List / Forum +### We are grateful to the RedisGraph community for their interest and support. -Got questions? Feel free to ask at the [RedisGraph forum](https://forum.redislabs.com/c/modules/redisgraph). +### You can read more about the end of life of RedisGraph [here](https://redis.com/blog/redisgraph-eol/). +--- ## License -Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or the Server Side Public License v1 (SSPLv1). See [LICENSE](LICENSE.txt). +RedisGraph is licensed under your choice of: (i) Redis Source Available License 2.0 (RSALv2); (ii) the Server Side Public License v1 (SSPLv1); or (iii) the GNU Affero General Public License version 3 (AGPLv3). Please review the license folder for the full license terms and conditions. diff --git a/build/GraphBLAS/Makefile b/build/GraphBLAS/Makefile index e9f96d6cba..a0b5f21b60 100644 --- a/build/GraphBLAS/Makefile +++ b/build/GraphBLAS/Makefile @@ -34,7 +34,7 @@ TARGET=$(BINDIR)/libgraphblas.a include $(MK)/defs define CMAKE_DEFS += - BUILD_GRB_STATIC_LIBRARY=1 + NSTATIC=off BUILD_TESTING=off CMAKE_POSITION_INDEPENDENT_CODE=on endef diff --git a/build/docker/Makefile b/build/docker/Makefile index bb6da59364..2ca7b2bbd6 100644 --- a/build/docker/Makefile +++ b/build/docker/Makefile @@ -14,4 +14,8 @@ PREVIEW_BRANCH=2.10 ART_DIR=$(ROOT)/bin/artifacts +XENIAL_MODERN_OMP ?= 0 + +DOCKER_VARS += XENIAL_MODERN_OMP + include $(MK)/module.docker.rules diff --git a/build/docker/dockerfile.tmpl b/build/docker/dockerfile.tmpl index 7a8c577a20..61b96315c0 100644 --- a/build/docker/dockerfile.tmpl +++ b/build/docker/dockerfile.tmpl @@ -55,9 +55,22 @@ RUN chown -R redis:redis /var/opt/redislabs COPY --from=builder /build/bin/artifacts/ /var/opt/redislabs/artifacts/ {% endif %} +{% if OSNICK == "xenial" and ARCH == "x64" and XENIAL_MODERN_OMP == "1" %} +RUN apt-get install -qy ca-certificates wget +RUN wget -P /tmp https://redismodules.s3.amazonaws.com/platform/xenial-x64/gcc-9-base_9.4.0-1ubuntu1~16.04_amd64.deb +RUN wget -P /tmp https://redismodules.s3.amazonaws.com/platform/xenial-x64/libgomp1_9.4.0-1ubuntu1~16.04_amd64.deb +RUN md5sum --quiet -c <&1 > /dev/null; then apt-get -qq update; apt-get -q install -y libgomp1; fi RUN if command -v yum 2>&1 > /dev/null; then yum install -y libgomp; fi RUN if command -v apk 2>&1 > /dev/null; then apk add libgomp; fi +{% endif %} EXPOSE 6379 CMD ["redis-server", "--loadmodule", "{{MODULES_DIR}}/redisgraph.so"] diff --git a/deps/GraphBLAS/.github/pull_request_template.md b/deps/GraphBLAS/.github/pull_request_template.md new file mode 100644 index 0000000000..696ba2ef34 --- /dev/null +++ b/deps/GraphBLAS/.github/pull_request_template.md @@ -0,0 +1,10 @@ +# Pull request template for SuiteSparse + + * Please describe your pull request: + + * No pull request can be accepted unless you first sign the + Contributor License Agreement [ CONTRIBUTOR-LICENSE.txt ]. Print a copy of + the txt file (as a PDF), sign and date it, and email it to me at + DrTimothyAldenDavis@gmail.com. Pull requests will only be included into + SuiteSparse after I receive your email with the signed PDF. + diff --git a/deps/GraphBLAS/CMakeLists.txt b/deps/GraphBLAS/CMakeLists.txt index a730ced3dd..5c0efeaa4f 100644 --- a/deps/GraphBLAS/CMakeLists.txt +++ b/deps/GraphBLAS/CMakeLists.txt @@ -13,11 +13,10 @@ cmake_minimum_required ( VERSION 3.19 ) -# version of SuiteSparse:GraphBLAS -set ( GraphBLAS_DATE "Oct 14, 2022" ) -set ( GraphBLAS_VERSION_MAJOR 7 ) -set ( GraphBLAS_VERSION_MINOR 3 ) -set ( GraphBLAS_VERSION_SUB 0 ) +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/cmake_modules ) + +include ( GraphBLAS_version ) # GraphBLAS C API Specification version, at graphblas.org set ( GraphBLAS_API_DATE "Nov 15, 2021" ) @@ -37,15 +36,15 @@ message ( STATUS "GraphBLAS C API: v" # SuiteSparse policies #------------------------------------------------------------------------------- -set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules - ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/cmake_modules - ${CMAKE_SOURCE_DIR}/../SuiteSparse/SuiteSparse_config/cmake_modules - ) - # CUDA is under development for now, and not deployed in production: +# option ( ENABLE_CUDA "Enable CUDA acceleration" off ) set ( ENABLE_CUDA false ) # set ( ENABLE_CUDA true ) + +# GraphBLAS takes a long time to build, so do not build the static library +# by default +set ( NSTATIC_DEFAULT_ON true ) + include ( SuiteSparsePolicy ) #------------------------------------------------------------------------------- @@ -69,7 +68,14 @@ endif ( ) # find OpenMP, CUDA, RMM, and cpu_features #------------------------------------------------------------------------------- -find_package ( OpenMP ) +option ( NOPENMP "ON: do not use OpenMP. OFF (default): use OpenMP" off ) +if ( NOPENMP ) + # OpenMP has been disabled. + + set ( OPENMP_FOUND false ) +else ( ) + find_package ( OpenMP ) +endif ( ) if ( SUITESPARSE_CUDA ) # with CUDA and RMM @@ -129,11 +135,11 @@ endif ( ) #------------------------------------------------------------------------------- # select "true" to build both dynamic and static libraries: -# set ( BUILD_GRB_STATIC_LIBRARY true ) -# set ( BUILD_GRB_STATIC_LIBRARY false ) -# or use cmake with -DBUILD_GRB_STATIC_LIBRARY=1 +# set ( NOT NSTATIC true ) +# set ( NOT NSTATIC false ) +# or use cmake with -DNSTATIC=1 -if ( BUILD_GRB_STATIC_LIBRARY ) +if ( NOT NSTATIC ) message ( STATUS "Building all GraphBLAS libraries (static and dynamic)" ) else ( ) message ( STATUS "Building dynamic GraphBLAS library" ) @@ -148,11 +154,21 @@ endif ( ) # Configure Include/GraphBLAS.h and documentation with version number #------------------------------------------------------------------------------- -configure_file ( "Config/GraphBLAS.h.in" "${PROJECT_SOURCE_DIR}/Include/GraphBLAS.h" ) -configure_file ( "Config/GraphBLAS_version.tex.in" "${PROJECT_SOURCE_DIR}/Doc/GraphBLAS_version.tex" ) +configure_file ( "Config/GraphBLAS.h.in" + "${PROJECT_SOURCE_DIR}/Include/GraphBLAS.h" + NEWLINE_STYLE LF ) +configure_file ( "Config/GraphBLAS_version.tex.in" + "${PROJECT_SOURCE_DIR}/Doc/GraphBLAS_version.tex" + NEWLINE_STYLE LF ) configure_file ( "Config/GraphBLAS_API_version.tex.in" - "${PROJECT_SOURCE_DIR}/Doc/GraphBLAS_API_version.tex" ) -configure_file ( "Config/README.md.in" "${PROJECT_SOURCE_DIR}/README.md" ) + "${PROJECT_SOURCE_DIR}/Doc/GraphBLAS_API_version.tex" + NEWLINE_STYLE LF ) +configure_file ( "Config/README.md.in" + "${PROJECT_SOURCE_DIR}/README.md" + NEWLINE_STYLE LF ) +configure_file ( "Config/alternative_Makefile.in" + "${PROJECT_SOURCE_DIR}/alternative/Makefile" + NEWLINE_STYLE LF ) #------------------------------------------------------------------------------- # include directories for both graphblas and graphblasdemo libraries @@ -160,9 +176,11 @@ configure_file ( "Config/README.md.in" "${PROJECT_SOURCE_DIR}/README.md" ) if ( CMAKE_CUDA_DEV ) # for CUDA development only; not for production use - include_directories ( Source/Template Source Include Source/Generated1 lz4 zstd zstd/zstd_subset Demo/Include rmm_wrap ) + include_directories ( Source/Template Source Include Source/Generated1 + lz4 zstd zstd/zstd_subset Demo/Include rmm_wrap ) else ( ) - include_directories ( Source/Template Source Include Source/Generated1 lz4 zstd zstd/zstd_subset Source/Generated2 Demo/Include rmm_wrap ) + include_directories ( Source/Template Source Include Source/Generated1 + lz4 zstd zstd/zstd_subset Source/Generated2 Demo/Include rmm_wrap ) endif ( ) #------------------------------------------------------------------------------- @@ -216,7 +234,7 @@ elseif ( "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" ) if ( CMAKE_C_COMPILER_VERSION VERSION_LESS 3.3 ) message ( FATAL_ERROR "clang version must be at least 3.3" ) endif ( ) -elseif ( "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" ) +elseif ( MSVC ) # options for MicroSoft Visual Studio set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2 -wd\"4244\" -wd\"4146\" -wd\"4018\" -wd\"4996\" -wd\"4047\" -wd\"4554\"" ) elseif ( "${CMAKE_C_COMPILER_ID}" STREQUAL "PGI" ) @@ -266,11 +284,12 @@ endif ( ) add_library ( graphblas SHARED ${GRAPHBLAS_SOURCES} ) -SET_TARGET_PROPERTIES ( graphblas PROPERTIES +set_target_properties ( graphblas PROPERTIES VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} SOVERSION ${GraphBLAS_VERSION_MAJOR} C_STANDARD_REQUIRED 11 - PUBLIC_HEADER "Include/GraphBLAS.h" ) + PUBLIC_HEADER "Include/GraphBLAS.h" + WINDOWS_EXPORT_ALL_SYMBOLS ON ) set_property ( TARGET graphblas PROPERTY C_STANDARD 11 ) if ( SUITESPARSE_CUDA ) @@ -278,20 +297,30 @@ if ( SUITESPARSE_CUDA ) add_dependencies ( graphblas rmm_wrap ) endif ( ) +if ( WIN32 ) + # Compiling the graphblas dll on Windows: export the dll symbols + target_compile_definitions ( graphblas PRIVATE GB_DLL_EXPORT ) +endif ( ) + #------------------------------------------------------------------------------- # static graphblas library properties #------------------------------------------------------------------------------- -if ( BUILD_GRB_STATIC_LIBRARY ) +if ( NOT NSTATIC ) add_library ( graphblas_static STATIC ${GRAPHBLAS_SOURCES} ) - SET_TARGET_PROPERTIES ( graphblas_static PROPERTIES + set_target_properties ( graphblas_static PROPERTIES VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} OUTPUT_NAME graphblas SOVERSION ${GraphBLAS_VERSION_MAJOR} - C_STANDARD_REQUIRED 11 - PUBLIC_HEADER "Include/GraphBLAS.h" ) + C_STANDARD_REQUIRED 11 ) + + if ( MSVC ) + set_target_properties ( graphblas_static PROPERTIES + OUTPUT_NAME graphblas_static ) + endif ( ) + set_property ( TARGET graphblas_static PROPERTY C_STANDARD 11 ) if ( SUITESPARSE_CUDA ) @@ -313,7 +342,7 @@ if ( NOT GBNCPUFEAT ) if ( HAVE_DLFCN_H ) message ( STATUS "cpu_feautures has dlfcn.h" ) target_compile_definitions ( graphblas PRIVATE HAVE_DLFCN_H ) - if ( BUILD_GRB_STATIC_LIBRARY ) + if ( NOT NSTATIC ) target_compile_definitions ( graphblas_static PRIVATE HAVE_DLFCN_H ) endif ( ) else ( ) @@ -323,7 +352,7 @@ if ( NOT GBNCPUFEAT ) if ( HAVE_STRONG_GETAUXVAL ) message ( STATUS "cpu_feautures has getauxval from sys/auxv.h" ) target_compile_definitions ( graphblas PRIVATE HAVE_STRONG_GETAUXVAL ) - if ( BUILD_GRB_STATIC_LIBRARY ) + if ( NOT NSTATIC ) target_compile_definitions ( graphblas_static PRIVATE HAVE_STRONG_GETAUXVAL ) endif ( ) else ( ) @@ -336,15 +365,21 @@ endif ( ) # select the math library (not required for Microsoft Visual Studio) #------------------------------------------------------------------------------- -if ( "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" ) - set ( M_LIB "" ) -else ( ) - set ( M_LIB "m" ) +# libm: +if ( NOT WIN32 ) + target_link_libraries ( graphblas PUBLIC m ) + if ( NOT NSTATIC ) + target_link_libraries ( graphblas_static PUBLIC m ) + endif ( ) endif ( ) -target_link_libraries ( graphblas PUBLIC ${M_LIB} ) -if ( BUILD_GRB_STATIC_LIBRARY ) - target_link_libraries ( graphblas_static PUBLIC ${M_LIB} ) +# atomic +include ( SuiteSparseAtomic ) +if ( LIBATOMIC_REQUIRED ) + target_link_libraries ( graphblas PUBLIC atomic ) + if ( NOT NSTATIC ) + target_link_libraries ( graphblas_static PUBLIC atomic ) + endif ( ) endif ( ) #------------------------------------------------------------------------------- @@ -355,17 +390,28 @@ if ( OPENMP_FOUND ) message ( STATUS "CMAKE OpenMP libraries: " ${OpenMP_C_LIBRARIES} ) message ( STATUS "CMAKE OpenMP include: " ${OpenMP_C_INCLUDE_DIRS} ) target_link_libraries ( graphblas PUBLIC ${OpenMP_C_LIBRARIES} ) - if ( BUILD_GRB_STATIC_LIBRARY ) + if ( NOT NSTATIC ) target_link_libraries ( graphblas_static PUBLIC ${OpenMP_C_LIBRARIES} ) endif ( ) message ( STATUS "CMAKE OpenMP C flags: " ${OpenMP_C_FLAGS} ) set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} " ) include_directories ( ${OpenMP_C_INCLUDE_DIRS} ) +else ( ) + message ( WARNING + "WARNING: OpenMP was not found (or was disabled with NOPENMP). See the " + "GrapBLAS user guide on the consequences of compiling GraphBLAS without " + "OpenMP. GraphBLAS will work but may not be thread-safe, since it relies " + "on '#pragma omp flush' to ensure the work performed by one user thread is " + "available to another, in GrB_wait. If OpenMP is not in use, the " + "thread-safety of GrB_wait becomes the responsibilty of the user " + "application (perhaps through a pthreads construct). Compiling GraphBLAS " + "without OpenMP is not recommended for installation in a package manager " + "(Linux, conda-forge, spack, brew, vcpkg, etc). " ) endif ( ) if ( SUITESPARSE_CUDA ) target_link_libraries ( graphblas PUBLIC ${GB_CUDA} ${GB_RMM} ) - if ( BUILD_GRB_STATIC_LIBRARY ) + if ( NOT NSTATIC ) target_link_libraries ( graphblas_static PUBLIC ${GB_CUDA} ${GB_RMM} ) endif ( ) endif ( ) @@ -380,6 +426,7 @@ message ( STATUS "CMAKE C flags: " ${CMAKE_C_FLAGS} ) # Demo library and programs #------------------------------------------------------------------------------- +option ( DEMO "ON: Build the demo programs. OFF (default): do not build the demo programs." off ) if ( DEMO ) #--------------------------------------------------------------------------- @@ -391,20 +438,22 @@ if ( DEMO ) file ( GLOB DEMO_SOURCES "Demo/Source/*.c" ) add_library ( graphblasdemo SHARED ${DEMO_SOURCES} ) - SET_TARGET_PROPERTIES ( graphblasdemo PROPERTIES + set_target_properties ( graphblasdemo PROPERTIES VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} SOVERSION ${GraphBLAS_VERSION_MAJOR} C_STANDARD_REQUIRED 11 ) set_property ( TARGET graphblasdemo PROPERTY C_STANDARD 11 ) - target_link_libraries ( graphblasdemo PUBLIC ${M_LIB} graphblas ${GB_CUDA} ${GB_RMM} ) + target_link_libraries ( graphblasdemo PUBLIC graphblas + ${GB_CUDA} ${GB_RMM} ) - if ( BUILD_GRB_STATIC_LIBRARY ) + if ( NOT NSTATIC ) add_library ( graphblasdemo_static STATIC ${DEMO_SOURCES} ) - SET_TARGET_PROPERTIES ( graphblasdemo_static PROPERTIES + set_target_properties ( graphblasdemo_static PROPERTIES VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} C_STANDARD_REQUIRED 11 ) set_property ( TARGET graphblasdemo_static PROPERTY C_STANDARD 11 ) - target_link_libraries ( graphblasdemo_static PUBLIC graphblas_static ${GB_CUDA} ${GB_RMM} ) + target_link_libraries ( graphblasdemo_static PUBLIC + graphblas_static ${GB_CUDA} ${GB_RMM} ) endif ( ) #--------------------------------------------------------------------------- @@ -412,6 +461,7 @@ if ( DEMO ) #--------------------------------------------------------------------------- add_executable ( openmp_demo "Demo/Program/openmp_demo.c" ) + add_executable ( openmp2_demo "Demo/Program/openmp2_demo.c" ) add_executable ( complex_demo "Demo/Program/complex_demo.c" ) add_executable ( kron_demo "Demo/Program/kron_demo.c" ) add_executable ( simple_demo "Demo/Program/simple_demo.c" ) @@ -422,6 +472,7 @@ if ( DEMO ) # Libraries required for Demo programs target_link_libraries ( openmp_demo PUBLIC graphblas graphblasdemo ${GB_CUDA} ${GB_RMM} ) + target_link_libraries ( openmp2_demo PUBLIC graphblas graphblasdemo ${GB_CUDA} ${GB_RMM} ) target_link_libraries ( complex_demo PUBLIC graphblas graphblasdemo ${GB_CUDA} ${GB_RMM} ) target_link_libraries ( kron_demo PUBLIC graphblas graphblasdemo ${GB_CUDA} ${GB_RMM} ) target_link_libraries ( simple_demo PUBLIC graphblasdemo ${GB_CUDA} ${GB_RMM} ) @@ -440,34 +491,17 @@ endif ( ) # installation location #------------------------------------------------------------------------------- -# use "cmake -DSUITESPARSE_LOCAL=1" to install only in ../lib and -# ../include. - -if ( NOT SUITESPARSE_LOCAL ) - # install in /usr/local/lib and /usr/local/include. - # requires "sudo make install" - message ( STATUS "Installation will be system-wide (requires 'sudo make install')" ) - install ( TARGETS graphblas - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) - if ( BUILD_GRB_STATIC_LIBRARY ) - install ( TARGETS graphblas_static - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - endif ( ) -endif ( ) - -if ( INSIDE_SUITESPARSE ) - # also install in SuiteSparse/lib and SuiteSparse/include; - # does not require "sudo make install", just "make install" - message ( STATUS "Installation in ../../lib and ../../include," ) - message ( STATUS " with 'make local ; make install'. No 'sudo' required." ) - install ( TARGETS graphblas - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) - if ( BUILD_GRB_STATIC_LIBRARY ) - install ( TARGETS graphblas_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) - endif ( ) +install ( TARGETS graphblas + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +install ( FILES ${CMAKE_SOURCE_DIR}/cmake_modules/FindGraphBLAS.cmake + DESTINATION ${SUITESPARSE_LIBDIR}/cmake/SuiteSparse + COMPONENT Development ) +if ( NOT NSTATIC ) + install ( TARGETS graphblas_static + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) endif ( ) #------------------------------------------------------------------------------- diff --git a/deps/GraphBLAS/CUDA/CMakeLists.txt b/deps/GraphBLAS/CUDA/CMakeLists.txt index b8b4c36d10..204e2b5f27 100644 --- a/deps/GraphBLAS/CUDA/CMakeLists.txt +++ b/deps/GraphBLAS/CUDA/CMakeLists.txt @@ -5,7 +5,10 @@ cmake_minimum_required ( VERSION 3.19 ) # specific parameters. The output of this build is an executable that can be used to # run the gtests. -project(GRAPHBLAS_CUDA VERSION 0.1 LANGUAGES CXX CUDA) +project ( GRAPHBLAS_CUDA + VERSION "${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB}" + LANGUAGES CXX CUDA ) +cmake_policy ( SET CMP0135 NEW ) # URL download timestamp policy set(CMAKE_CUDA_FLAGS "-cudart=static -lineinfo ") set(CMAKE_CXX_STANDARD 17) @@ -22,13 +25,20 @@ add_library(graphblascuda SHARED ${GRAPHBLAS_CUDA_SOURCES} ) +set_target_properties ( graphblascuda PROPERTIES + VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} + SOVERSION ${GraphBLAS_VERSION_MAJOR} + C_STANDARD_REQUIRED 11 ) + set(RMM_WRAP_INCLUDES "../rmm_wrap") message(STATUS "RMM_WRAP_INCLUDES: ${RMM_WRAP_INCLUDES}") set(GRAPHBLAS_CUDA_INCLUDES ${RMM_WRAP_INCLUDES} ../Source + ../Source/Shared ../Source/Template + ../Source/SharedTemplate ../Include ../CUDA) @@ -54,7 +64,7 @@ target_include_directories(graphblascuda PUBLIC ${GRAPHBLAS_CUDA_INCLUDES}) set_target_properties(graphblascuda PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(graphblascuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) -set_target_properties(graphblascuda PROPERTIES CUDA_ARCHITECTURES "75") +set_target_properties(graphblascuda PROPERTIES CUDA_ARCHITECTURES "52;75;80" ) target_link_libraries(graphblascuda CUDA::nvrtc CUDA::cudart_static CUDA::nvToolsExt ) @@ -62,40 +72,15 @@ target_link_libraries(graphblascuda CUDA::nvrtc CUDA::cudart_static CUDA::nvTool # installation location #------------------------------------------------------------------------------- -# use "cmake -DSUITESPARSE_LOCAL=1" to install only in ../lib and -# ../include. - -if ( NOT SUITESPARSE_LOCAL ) - # install in /usr/local/lib and /usr/local/include. - # requires "sudo make install" - message ( STATUS "Installation will be system-wide (requires 'sudo make install')" ) - install ( TARGETS graphblascuda - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) -# if ( BUILD_GRB_STATIC_LIBRARY ) -# install ( TARGETS graphblas_static -# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -# endif ( ) -endif ( ) - -if ( INSIDE_SUITESPARSE ) - # also install in SuiteSparse/lib and SuiteSparse/include; - # does not require "sudo make install", just "make install" - message ( STATUS "Installation in ../../lib and ../../include," ) - message ( STATUS " with 'make local ; make install'. No 'sudo' required." ) - install ( TARGETS graphblascuda - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) -# if ( BUILD_GRB_STATIC_LIBRARY ) -# install ( TARGETS graphblas_static -# ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) -# endif ( ) -endif ( ) - -# install ( TARGETS graphblascuda -# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} -# PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} -# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) +install ( TARGETS graphblascuda + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +# if ( BUILD_GRB_STATIC_LIBRARY ) +# install ( TARGETS graphblas_static +# ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) +# endif ( ) #------------------------------------------------------------------------------- @@ -189,7 +174,7 @@ add_executable(graphblascuda_test ${CUDA_TEST_CPP_FILES} ${CMAKE_CURRENT_SOURCE_ set_target_properties(graphblascuda_test PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(graphblascuda_test PROPERTIES CUDA_SEPARABLE_COMPILATION ON) -set_target_properties(graphblascuda_test PROPERTIES CUDA_ARCHITECTURES "75") +set_target_properties(graphblascuda_test PROPERTIES CUDA_ARCHITECTURES "52;75;80" ) include(GoogleTest) diff --git a/deps/GraphBLAS/CUDA/GB_cuda_kernel.h b/deps/GraphBLAS/CUDA/GB_cuda_kernel.h index 2f3dc67988..696e1019e1 100644 --- a/deps/GraphBLAS/CUDA/GB_cuda_kernel.h +++ b/deps/GraphBLAS/CUDA/GB_cuda_kernel.h @@ -124,7 +124,7 @@ GB_ADD (c, c, x_op_y) ; /* c += x_op_y */ \ } - #define GB_DOT_TERMINAL( c ) GB_IF_TERMINAL_BREAK (c) + #define GB_DOT_TERMINAL( c ) GB_IF_TERMINAL_BREAK ( c, z ) #if GB_IS_PLUS_PAIR_REAL_SEMIRING @@ -184,8 +184,6 @@ #define GB_XSTR(x) GB_STR(x) #define GB_STR(x) #x -#undef GB_PUBLIC -#define GB_PUBLIC extern #undef GxB_MAX_NAME_LEN #define GxB_MAX_NAME_LEN 128 diff --git a/deps/GraphBLAS/CUDA/TODO.txt b/deps/GraphBLAS/CUDA/TODO.txt index c10b3ce946..54605d99fb 100644 --- a/deps/GraphBLAS/CUDA/TODO.txt +++ b/deps/GraphBLAS/CUDA/TODO.txt @@ -11,6 +11,3 @@ complex types/ops, CPU & GPU reduce: do any monoid (but Tim needs to do the GB*reduce_23482304823094.h) -CPU: #define GB_STATIC_INLINE static inline -CUDA: #define GB_STATIC_INLINE static __device__ __inline__ - diff --git a/deps/GraphBLAS/CUDA/test/graphblascuda_test b/deps/GraphBLAS/CUDA/test/graphblascuda_test deleted file mode 120000 index d1da298faa..0000000000 --- a/deps/GraphBLAS/CUDA/test/graphblascuda_test +++ /dev/null @@ -1 +0,0 @@ -../../build/CUDA/graphblascuda_test \ No newline at end of file diff --git a/deps/GraphBLAS/Config/GraphBLAS.h.in b/deps/GraphBLAS/Config/GraphBLAS.h.in index 3d094a017a..4883845227 100644 --- a/deps/GraphBLAS/Config/GraphBLAS.h.in +++ b/deps/GraphBLAS/Config/GraphBLAS.h.in @@ -83,19 +83,28 @@ // compiler variations //============================================================================== -// Exporting/importing symbols for Microsoft Visual Studio - +// GB_GLOBAL: for declaring global variables visible to the user application. +// These are not used for functions, just global variables like the predefined +// operators (GrB_PLUS_FP32), types, monoids, semirings, and descriptors. #if ( _MSC_VER && !(__INTEL_COMPILER || __INTEL_CLANG_COMPILER) ) -#ifdef GB_LIBRARY -// compiling SuiteSparse:GraphBLAS itself, exporting symbols to user apps -#define GB_PUBLIC extern __declspec ( dllexport ) -#else -// compiling the user application, importing symbols from SuiteSparse:GraphBLAS -#define GB_PUBLIC extern __declspec ( dllimport ) -#endif + #if defined ( GB_DLL_EXPORT ) + // Compiling SuiteSparse:GraphBLAS as a Windows DLL, exporting symbols + // to user apps. + #define GB_GLOBAL extern __declspec ( dllexport ) + #elif defined ( GB_STATIC ) + // Compiling the user application on Windows, importing symbols from + // a static GraphBLAS library on Windows. The user application must do: + // #define GB_STATIC + // #include "GraphBLAS.h" + #define GB_GLOBAL extern + #else + // Compiling the user application on Windows, importing symbols from + // the SuiteSparse:GraphBLAS DLL. This is the default. + #define GB_GLOBAL extern __declspec ( dllimport ) + #endif #else -// for other compilers -#define GB_PUBLIC extern + // for other compilers + #define GB_GLOBAL extern #endif // GraphBLAS requires an ANSI C11 compiler for its polymorphic functions (using @@ -360,13 +369,11 @@ typedef enum } GrB_Mode ; -GB_PUBLIC GrB_Info GrB_init // start up GraphBLAS ( GrB_Mode mode // blocking or non-blocking mode, no GPU ) ; -GB_PUBLIC GrB_Info GxB_init // start up GraphBLAS and also define malloc, etc ( GrB_Mode mode, // blocking or non-blocking mode, @@ -378,7 +385,6 @@ GrB_Info GxB_init // start up GraphBLAS and also define malloc, etc void (* user_free_function ) (void *) ) ; -GB_PUBLIC GrB_Info GrB_finalize (void) ; // finish GraphBLAS //============================================================================== @@ -386,7 +392,6 @@ GrB_Info GrB_finalize (void) ; // finish GraphBLAS //============================================================================== // GrB_getVersion provides a runtime access of the C API Version. -GB_PUBLIC GrB_Info GrB_getVersion // runtime access to C API version number ( unsigned int *version, // returns GRB_VERSION @@ -420,16 +425,6 @@ GrB_Info GrB_getVersion // runtime access to C API version number // // GrB_INP1: the same as GrB_INP0 but for the second input // -// GxB_NTHREADS: the maximum number of threads to use in the current method. -// If <= GxB_DEFAULT (which is zero), then the number of threads is -// determined automatically. This is the default value. -// -// GxB_CHUNK: an integer parameter that determines the number of threads to use -// for a small problem. If w is the work to be performed, and chunk is -// the value of this parameter, then the # of threads is limited to floor -// (w/chunk). The default chunk is currently 64K, but this may change in -// the future. If chunk is set to <= GxB_DEFAULT (that is, zero), the -// default is used. // // GxB_AxB_METHOD: this is a hint to SuiteSparse:GraphBLAS on which algorithm // it should use to compute C=A*B, in GrB_mxm, GrB_mxv, and GrB_vxm. @@ -494,12 +489,9 @@ typedef enum GrB_INP0 = 2, // descriptor for the first input of a method GrB_INP1 = 3, // descriptor for the second input of a method - GxB_DESCRIPTOR_NTHREADS = GxB_NTHREADS, // max number of threads to use. - // If <= GxB_DEFAULT, then GraphBLAS selects the number - // of threads automatically. - - GxB_DESCRIPTOR_CHUNK = GxB_CHUNK, // chunk size for small problems. - // If <= GxB_DEFAULT, then the default is used. + // setting NTHREADS and CHUNK in the descriptor is deprecated + GxB_DESCRIPTOR_NTHREADS = GxB_NTHREADS, // DEPRECATED + GxB_DESCRIPTOR_CHUNK = GxB_CHUNK, // DEPRECATED // GPU control (DRAFT: in progress, do not use) GxB_DESCRIPTOR_GPU_CONTROL = GxB_GPU_CONTROL, @@ -547,13 +539,11 @@ GrB_Desc_Value ; typedef struct GB_Descriptor_opaque *GrB_Descriptor ; -GB_PUBLIC GrB_Info GrB_Descriptor_new // create a new descriptor ( GrB_Descriptor *descriptor // handle of descriptor to create ) ; -GB_PUBLIC GrB_Info GrB_Descriptor_set // set a parameter in a descriptor ( GrB_Descriptor desc, // descriptor to modify @@ -561,7 +551,6 @@ GrB_Info GrB_Descriptor_set // set a parameter in a descriptor GrB_Desc_Value val // value to change it to ) ; -GB_PUBLIC GrB_Info GxB_Descriptor_get // get a parameter from a descriptor ( GrB_Desc_Value *val, // value of the parameter @@ -569,7 +558,6 @@ GrB_Info GxB_Descriptor_get // get a parameter from a descriptor GrB_Desc_Field field // parameter to query ) ; -GB_PUBLIC GrB_Info GxB_Desc_set // set a parameter in a descriptor ( GrB_Descriptor desc, // descriptor to modify @@ -577,7 +565,20 @@ GrB_Info GxB_Desc_set // set a parameter in a descriptor ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Desc_set_INT32 // set a parameter in a descriptor +( + GrB_Descriptor desc, // descriptor to modify + GrB_Desc_Field field, // parameter to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Desc_set_FP64 // set a parameter in a descriptor +( + GrB_Descriptor desc, // descriptor to modify + GrB_Desc_Field field, // parameter to change + double value // value to change it to +) ; + GrB_Info GxB_Desc_get // get a parameter from a descriptor ( GrB_Descriptor desc, // descriptor to query; NULL means defaults @@ -585,7 +586,20 @@ GrB_Info GxB_Desc_get // get a parameter from a descriptor ... // value of the parameter ) ; -GB_PUBLIC +GrB_Info GxB_Desc_get_INT32 // get a parameter from a descriptor +( + GrB_Descriptor desc, // descriptor to query; NULL is ok + GrB_Desc_Field field, // parameter to query + int32_t *value // return value of the descriptor +) ; + +GrB_Info GxB_Desc_get_FP64 // get a parameter from a descriptor +( + GrB_Descriptor desc, // descriptor to query; NULL is ok + GrB_Desc_Field field, // parameter to query + double *value // return value of the descriptor +) ; + GrB_Info GrB_Descriptor_free // free a descriptor ( GrB_Descriptor *descriptor // handle of descriptor to free @@ -593,8 +607,8 @@ GrB_Info GrB_Descriptor_free // free a descriptor // Predefined descriptors and their values: -GB_PUBLIC -GrB_Descriptor // OUTP MASK MASK INP0 INP1 +GB_GLOBAL GrB_Descriptor + // OUTP MASK MASK INP0 INP1 // structural complement // =========== ============== ========== ======== ======== @@ -656,7 +670,7 @@ GrB_DESC_RSCT0T1 ; // GrB_REPLACE GrB_STRUCTURE GrB_COMP GrB_TRAN GrB_TRAN typedef struct GB_Type_opaque *GrB_Type ; // GraphBLAS predefined types and their counterparts in pure C: -GB_PUBLIC GrB_Type +GB_GLOBAL GrB_Type GrB_BOOL , // in C: bool GrB_INT8 , // in C: int8_t GrB_INT16 , // in C: int16_t @@ -678,37 +692,54 @@ GB_PUBLIC GrB_Type #define GB_CAT(w,x,y,z) w ## x ## y ## z #define GB_CONCAT(w,x,y,z) GB_CAT (w, x, y, z) -#if GxB_STDC_VERSION >= 201112L -#define GB_CASES(p,prefix,func) \ - const bool p : GB_CONCAT ( prefix, _, func, _BOOL ), \ - bool p : GB_CONCAT ( prefix, _, func, _BOOL ), \ - const int8_t p : GB_CONCAT ( prefix, _, func, _INT8 ), \ - int8_t p : GB_CONCAT ( prefix, _, func, _INT8 ), \ - const int16_t p : GB_CONCAT ( prefix, _, func, _INT16 ), \ - int16_t p : GB_CONCAT ( prefix, _, func, _INT16 ), \ - const int32_t p : GB_CONCAT ( prefix, _, func, _INT32 ), \ - int32_t p : GB_CONCAT ( prefix, _, func, _INT32 ), \ - const int64_t p : GB_CONCAT ( prefix, _, func, _INT64 ), \ - int64_t p : GB_CONCAT ( prefix, _, func, _INT64 ), \ - const uint8_t p : GB_CONCAT ( prefix, _, func, _UINT8 ), \ - uint8_t p : GB_CONCAT ( prefix, _, func, _UINT8 ), \ - const uint16_t p : GB_CONCAT ( prefix, _, func, _UINT16 ), \ - uint16_t p : GB_CONCAT ( prefix, _, func, _UINT16 ), \ - const uint32_t p : GB_CONCAT ( prefix, _, func, _UINT32 ), \ - uint32_t p : GB_CONCAT ( prefix, _, func, _UINT32 ), \ - const uint64_t p : GB_CONCAT ( prefix, _, func, _UINT64 ), \ - uint64_t p : GB_CONCAT ( prefix, _, func, _UINT64 ), \ - const float p : GB_CONCAT ( prefix, _, func, _FP32 ), \ - float p : GB_CONCAT ( prefix, _, func, _FP32 ), \ - const double p : GB_CONCAT ( prefix, _, func, _FP64 ), \ - double p : GB_CONCAT ( prefix, _, func, _FP64 ), \ - const GxB_FC32_t p : GB_CONCAT ( GxB , _, func, _FC32 ), \ - GxB_FC32_t p : GB_CONCAT ( GxB , _, func, _FC32 ), \ - const GxB_FC64_t p : GB_CONCAT ( GxB , _, func, _FC64 ), \ - GxB_FC64_t p : GB_CONCAT ( GxB , _, func, _FC64 ), \ +// methods for C scalars of various types +#define GB_CASES(prefix,func) \ + bool : GB_CONCAT ( prefix, _, func, _BOOL ), \ + int8_t : GB_CONCAT ( prefix, _, func, _INT8 ), \ + int16_t : GB_CONCAT ( prefix, _, func, _INT16 ), \ + int32_t : GB_CONCAT ( prefix, _, func, _INT32 ), \ + int64_t : GB_CONCAT ( prefix, _, func, _INT64 ), \ + uint8_t : GB_CONCAT ( prefix, _, func, _UINT8 ), \ + uint16_t : GB_CONCAT ( prefix, _, func, _UINT16 ), \ + uint32_t : GB_CONCAT ( prefix, _, func, _UINT32 ), \ + uint64_t : GB_CONCAT ( prefix, _, func, _UINT64 ), \ + float : GB_CONCAT ( prefix, _, func, _FP32 ), \ + double : GB_CONCAT ( prefix, _, func, _FP64 ), \ + GxB_FC32_t : GB_CONCAT ( GxB , _, func, _FC32 ), \ + GxB_FC64_t : GB_CONCAT ( GxB , _, func, _FC64 ), \ + const void * : GB_CONCAT ( prefix, _, func, _UDT ), \ + void * : GB_CONCAT ( prefix, _, func, _UDT ) + +// methods for C arrays of various types +#define GB_PCASES(prefix,func) \ + const bool * : GB_CONCAT ( prefix, _, func, _BOOL ), \ + bool * : GB_CONCAT ( prefix, _, func, _BOOL ), \ + const int8_t * : GB_CONCAT ( prefix, _, func, _INT8 ), \ + int8_t * : GB_CONCAT ( prefix, _, func, _INT8 ), \ + const int16_t * : GB_CONCAT ( prefix, _, func, _INT16 ), \ + int16_t * : GB_CONCAT ( prefix, _, func, _INT16 ), \ + const int32_t * : GB_CONCAT ( prefix, _, func, _INT32 ), \ + int32_t * : GB_CONCAT ( prefix, _, func, _INT32 ), \ + const int64_t * : GB_CONCAT ( prefix, _, func, _INT64 ), \ + int64_t * : GB_CONCAT ( prefix, _, func, _INT64 ), \ + const uint8_t * : GB_CONCAT ( prefix, _, func, _UINT8 ), \ + uint8_t * : GB_CONCAT ( prefix, _, func, _UINT8 ), \ + const uint16_t * : GB_CONCAT ( prefix, _, func, _UINT16 ), \ + uint16_t * : GB_CONCAT ( prefix, _, func, _UINT16 ), \ + const uint32_t * : GB_CONCAT ( prefix, _, func, _UINT32 ), \ + uint32_t * : GB_CONCAT ( prefix, _, func, _UINT32 ), \ + const uint64_t * : GB_CONCAT ( prefix, _, func, _UINT64 ), \ + uint64_t * : GB_CONCAT ( prefix, _, func, _UINT64 ), \ + const float * : GB_CONCAT ( prefix, _, func, _FP32 ), \ + float * : GB_CONCAT ( prefix, _, func, _FP32 ), \ + const double * : GB_CONCAT ( prefix, _, func, _FP64 ), \ + double * : GB_CONCAT ( prefix, _, func, _FP64 ), \ + const GxB_FC32_t * : GB_CONCAT ( GxB , _, func, _FC32 ), \ + GxB_FC32_t * : GB_CONCAT ( GxB , _, func, _FC32 ), \ + const GxB_FC64_t * : GB_CONCAT ( GxB , _, func, _FC64 ), \ + GxB_FC64_t * : GB_CONCAT ( GxB , _, func, _FC64 ), \ const void * : GB_CONCAT ( prefix, _, func, _UDT ), \ void * : GB_CONCAT ( prefix, _, func, _UDT ) -#endif //------------------------------------------------------------------------------ // GrB_Type_new: create a new type @@ -722,7 +753,6 @@ GB_PUBLIC GrB_Type #undef GrB_Type_new #undef GrM_Type_new -GB_PUBLIC GrB_Info GRB (Type_new) // create a new GraphBLAS type ( GrB_Type *type, // handle of user type to create @@ -763,7 +793,6 @@ GrB_Info GRB (Type_new) // create a new GraphBLAS type #define GxB_MAX_NAME_LEN 128 -GB_PUBLIC GrB_Info GxB_Type_new // create a new named GraphBLAS type ( GrB_Type *type, // handle of user type to create @@ -773,7 +802,6 @@ GrB_Info GxB_Type_new // create a new named GraphBLAS type ) ; // GB_Type_new is historical: use GxB_Type_new instead -GB_PUBLIC GrB_Info GB_Type_new // not user-callable ( GrB_Type *type, // handle of user type to create @@ -781,7 +809,6 @@ GrB_Info GB_Type_new // not user-callable const char *type_name // name of the type, as "sizeof (ctype)" ) ; -GB_PUBLIC GrB_Info GxB_Type_name // return the name of a GraphBLAS type ( char *type_name, // name of the type (char array of size at least @@ -789,21 +816,18 @@ GrB_Info GxB_Type_name // return the name of a GraphBLAS type const GrB_Type type ) ; -GB_PUBLIC GrB_Info GxB_Type_size // determine the size of the type ( size_t *size, // the sizeof the type const GrB_Type type // type to determine the sizeof ) ; -GB_PUBLIC GrB_Info GxB_Type_from_name // return the built-in GrB_Type from a name ( GrB_Type *type, // built-in type, or NULL if user-defined const char *type_name // array of size at least GxB_MAX_NAME_LEN ) ; -GB_PUBLIC GrB_Info GrB_Type_free // free a user-defined type ( GrB_Type *type // handle of user-defined type to free @@ -827,7 +851,7 @@ typedef struct GB_UnaryOp_opaque *GrB_UnaryOp ; // built-in unary operators, z = f(x) //------------------------------------------------------------------------------ -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp // For these functions z=f(x), z and x have the same type. // The suffix in the name is the type of x and z. // z = x z = -x z = 1/x z = ! (x != 0) @@ -871,7 +895,7 @@ GB_PUBLIC GrB_UnaryOp GrB_LNOT ; // GxB_ABS is now in the v1.3 spec, the following names are historical: -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp // z = abs(x) GxB_ABS_BOOL, @@ -893,7 +917,7 @@ GB_PUBLIC GrB_UnaryOp // The following floating-point unary operators and their ANSI C11 equivalents, // are only defined for floating-point (real and complex) types. -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp //-------------------------------------------------------------------------- // z = f(x) where z and x have the same type (all 4 floating-point types) @@ -1009,7 +1033,6 @@ typedef void (*GxB_unary_function) (void *, const void *) ; // detection of the operator name. #undef GrB_UnaryOp_new #undef GrM_UnaryOp_new -GB_PUBLIC GrB_Info GRB (UnaryOp_new) // create a new user-defined unary operator ( GrB_UnaryOp *unaryop, // handle for the new unary operator @@ -1023,7 +1046,6 @@ GrB_Info GRB (UnaryOp_new) // create a new user-defined unary operator GxM_UnaryOp_new(op,f,z,x, GB_STR(f), NULL) // GxB_UnaryOp_new creates a named user-defined unary op. -GB_PUBLIC GrB_Info GxB_UnaryOp_new // create a new user-defined unary operator ( GrB_UnaryOp *unaryop, // handle for the new unary operator @@ -1035,7 +1057,6 @@ GrB_Info GxB_UnaryOp_new // create a new user-defined unary operator ) ; // GB_UnaryOp_new is historical: use GxB_UnaryOp_new instead -GB_PUBLIC GrB_Info GB_UnaryOp_new // not user-callable ( GrB_UnaryOp *unaryop, // handle for the new unary operator @@ -1046,13 +1067,11 @@ GrB_Info GB_UnaryOp_new // not user-callable ) ; // GxB_UnaryOp_ztype is historical. Use GxB_UnaryOp_ztype_name instead. -GB_PUBLIC GrB_Info GxB_UnaryOp_ztype // return the type of z ( GrB_Type *ztype, // return type of output z GrB_UnaryOp unaryop // unary operator ) ; -GB_PUBLIC GrB_Info GxB_UnaryOp_ztype_name // return the type_name of z ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1060,20 +1079,17 @@ GrB_Info GxB_UnaryOp_ztype_name // return the type_name of z ) ; // GxB_UnaryOp_xtype is historical. Use GxB_UnaryOp_xtype_name instead. -GB_PUBLIC GrB_Info GxB_UnaryOp_xtype // return the type of x ( GrB_Type *xtype, // return type of input x GrB_UnaryOp unaryop // unary operator ) ; -GB_PUBLIC GrB_Info GxB_UnaryOp_xtype_name // return the type_name of x ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_UnaryOp unaryop // unary operator ) ; -GB_PUBLIC GrB_Info GrB_UnaryOp_free // free a user-created unary operator ( GrB_UnaryOp *unaryop // handle of unary operator to free @@ -1096,7 +1112,7 @@ typedef struct GB_BinaryOp_opaque *GrB_BinaryOp ; // built-in binary operators, z = f(x,y), where x,y,z all have the same type //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // operators for all 13 types (including complex): @@ -1273,7 +1289,7 @@ GB_PUBLIC GrB_BinaryOp // The GxB_BSHIFT_* operators compute the arithmetic shift, and produce the // same results as the bitshift.m function, for all possible inputs. -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // z = bitshift(x,y) GxB_BSHIFT_INT8, @@ -1289,7 +1305,7 @@ GB_PUBLIC GrB_BinaryOp // z=f(x,y) where z is BOOL and the type of x,y is given by the suffix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // Six comparators z=f(x,y) return their result as boolean, but // where x and y have the same type. The suffix in their names refers to @@ -1331,7 +1347,7 @@ GB_PUBLIC GrB_BinaryOp // z=f(x,y) where z is complex and the type of x,y is given by the suffix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // z = cmplx (x,y) GxB_CMPLX_FP32, @@ -1371,7 +1387,7 @@ GB_PUBLIC GrB_BinaryOp // are identical. If C(i,j) += t is computed where t = A(i,k)*B(k,j), then // t = k in both cases. Likewise, FIRSTJ1 and SECONDI1 are identical. -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp GxB_FIRSTI_INT32, GxB_FIRSTI_INT64, // z = first_i(A(i,j),y) == i GxB_FIRSTI1_INT32, GxB_FIRSTI1_INT64, // z = first_i1(A(i,j),y) == i+1 @@ -1382,7 +1398,7 @@ GB_PUBLIC GrB_BinaryOp GxB_SECONDJ_INT32, GxB_SECONDJ_INT64, // z = second_j(x,B(i,j)) == j GxB_SECONDJ1_INT32, GxB_SECONDJ1_INT64 ; // z = second_j1(x,B(i,j)) == j+1 -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp GxB_POSITIONI_INT32, GxB_POSITIONI_INT64, // z=position_i(A(i,j)) == i GxB_POSITIONI1_INT32, GxB_POSITIONI1_INT64, // z=position_i1(A(i,j)) == i+1 @@ -1399,7 +1415,7 @@ GB_PUBLIC GrB_UnaryOp // GxB_IGNORE_DUP is a special case. It is not an operator, but an indication // that any duplicates are to be ignored. -GB_PUBLIC GrB_BinaryOp GxB_IGNORE_DUP ; +GB_GLOBAL GrB_BinaryOp GxB_IGNORE_DUP ; //============================================================================== // About boolean and bitwise binary operators @@ -1488,7 +1504,6 @@ typedef void (*GxB_binary_function) (void *, const void *, const void *) ; // detection of the operator name. #undef GrB_BinaryOp_new #undef GrM_BinaryOp_new -GB_PUBLIC GrB_Info GRB (BinaryOp_new) ( GrB_BinaryOp *binaryop, // handle for the new binary operator @@ -1503,7 +1518,6 @@ GrB_Info GRB (BinaryOp_new) GxM_BinaryOp_new(op,f,z,x,y, GB_STR(f), NULL) // GxB_BinaryOp_new creates a named user-defined binary op. -GB_PUBLIC GrB_Info GxB_BinaryOp_new ( GrB_BinaryOp *op, // handle for the new binary operator @@ -1516,7 +1530,6 @@ GrB_Info GxB_BinaryOp_new ) ; // GB_BinaryOp_new is historical: use GxB_BinaryOp_new instead -GB_PUBLIC GrB_Info GB_BinaryOp_new // not user-callable ( GrB_BinaryOp *binaryop, // handle for the new binary operator @@ -1528,13 +1541,11 @@ GrB_Info GB_BinaryOp_new // not user-callable ) ; // NOTE: GxB_BinaryOp_ztype is historical. Use GxB_BinaryOp_ztype_name instead. -GB_PUBLIC GrB_Info GxB_BinaryOp_ztype // return the type of z ( GrB_Type *ztype, // return type of output z GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_ztype_name // return the type_name of z ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1542,13 +1553,11 @@ GrB_Info GxB_BinaryOp_ztype_name // return the type_name of z ) ; // NOTE: GxB_BinaryOp_xtype is historical. Use GxB_BinaryOp_xtype_name instead. -GB_PUBLIC GrB_Info GxB_BinaryOp_xtype // return the type of x ( GrB_Type *xtype, // return type of input x GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_xtype_name // return the type_name of x ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1556,20 +1565,17 @@ GrB_Info GxB_BinaryOp_xtype_name // return the type_name of x ) ; // NOTE: GxB_BinaryOp_ytype is historical. Use GxB_BinaryOp_ytype_name instead. -GB_PUBLIC GrB_Info GxB_BinaryOp_ytype // return the type of y ( GrB_Type *ytype, // return type of input y GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_ytype_name // return the type_name of y ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GrB_BinaryOp_free // free a user-created binary operator ( GrB_BinaryOp *binaryop // handle of binary operator to free @@ -1620,7 +1626,7 @@ typedef struct GB_SelectOp_opaque *GxB_SelectOp ; // GxB_select (C, Mask, accum, op, A, Thunk, desc) always returns a matrix C of // the same size as A (or A' if GrB_TRAN is in the descriptor). -GB_PUBLIC GxB_SelectOp +GB_GLOBAL GxB_SelectOp GxB_TRIL, // C=tril(A,thunk): returns true if ((j-i) <= thunk) GxB_TRIU, // C=triu(A,thunk): returns true if ((j-i) >= thunk) @@ -1675,7 +1681,6 @@ typedef bool (*GxB_select_function) // return true if A(i,j) is kept #undef GxB_SelectOp_new #undef GxM_SelectOp_new -GB_PUBLIC GrB_Info GXB (SelectOp_new) // create a new user-defined select operator ( GxB_SelectOp *selectop, // handle for the new select operator @@ -1689,7 +1694,6 @@ GrB_Info GXB (SelectOp_new) // create a new user-defined select operator // GB_SelectOp_new should not be called directly, but only through the // GxB_SelectOp_new macro (but use GrB_IndexUnaryOp_new instead). -GB_PUBLIC GrB_Info GB_SelectOp_new // not user-callable ( GxB_SelectOp *selectop, // handle for the new select operator @@ -1700,7 +1704,6 @@ GrB_Info GB_SelectOp_new // not user-callable ) ; // GxB_SelectOp_xtype is historical. Use a GrB_IndexUnaryOp instead. -GB_PUBLIC GrB_Info GxB_SelectOp_xtype // return the type of x ( GrB_Type *xtype, // return type of input x @@ -1708,14 +1711,12 @@ GrB_Info GxB_SelectOp_xtype // return the type of x ) ; // GxB_SelectOp_ttype is historical. Use a GrB_IndexUnaryOp instead. -GB_PUBLIC GrB_Info GxB_SelectOp_ttype // return the type of thunk ( GrB_Type *ttype, // return type of input thunk GxB_SelectOp selectop // select operator ) ; -GB_PUBLIC GrB_Info GxB_SelectOp_free // free a user-created select operator ( GxB_SelectOp *selectop // handle of select operator to free @@ -1745,7 +1746,6 @@ typedef void (*GxB_index_unary_function) #undef GrB_IndexUnaryOp_new #undef GrM_IndexUnaryOp_new -GB_PUBLIC GrB_Info GRB (IndexUnaryOp_new) // create a new user-defined IndexUnary op ( GrB_IndexUnaryOp *op, // handle for the new IndexUnary operator @@ -1760,7 +1760,6 @@ GrB_Info GRB (IndexUnaryOp_new) // create a new user-defined IndexUnary op #define GrM_IndexUnaryOp_new(op,f,z,x,y) \ GxM_IndexUnaryOp_new(op,f,z,x,y, GB_STR(f), NULL) -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_new // create a named user-created IndexUnaryOp ( GrB_IndexUnaryOp *op, // handle for the new IndexUnary operator @@ -1772,7 +1771,6 @@ GrB_Info GxB_IndexUnaryOp_new // create a named user-created IndexUnaryOp const char *idxop_defn // definition of the user function ) ; -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_ztype_name // return the type_name of z ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1782,21 +1780,18 @@ GrB_Info GxB_IndexUnaryOp_ztype_name // return the type_name of z // For TRIL, TRIU, DIAG, OFFDIAG, COLLE, COLGT, ROWLE, and ROWGT, // the xtype_name is an empty string (""), since these functions do not depend // on the type of the matrix input. -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_xtype_name // return the type_name of x ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_IndexUnaryOp op // select operator ) ; -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_ytype_name // return the type_name of the scalary y ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_IndexUnaryOp op // select operator ) ; -GB_PUBLIC GrB_Info GrB_IndexUnaryOp_free // free a user-created IndexUnaryOp ( GrB_IndexUnaryOp *op // handle of IndexUnary to free @@ -1810,7 +1805,7 @@ GrB_Info GrB_IndexUnaryOp_free // free a user-created IndexUnaryOp // of type int64_t. The scalar y has the type corresponding to the suffix // of the name of the operator. -GB_PUBLIC GrB_IndexUnaryOp +GB_GLOBAL GrB_IndexUnaryOp //-------------------------------------------------------------------------- // Result has the integer type INT32 or INT64, the same as the suffix @@ -1915,7 +1910,6 @@ GB_PUBLIC GrB_IndexUnaryOp typedef struct GB_Monoid_opaque *GrB_Monoid ; -GB_PUBLIC GrB_Info GrB_Monoid_new_BOOL // create a new boolean monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1923,7 +1917,6 @@ GrB_Info GrB_Monoid_new_BOOL // create a new boolean monoid bool identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT8 // create a new int8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1931,7 +1924,6 @@ GrB_Info GrB_Monoid_new_INT8 // create a new int8 monoid int8_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT8 // create a new uint8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1939,7 +1931,6 @@ GrB_Info GrB_Monoid_new_UINT8 // create a new uint8 monoid uint8_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT16 // create a new int16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1947,7 +1938,6 @@ GrB_Info GrB_Monoid_new_INT16 // create a new int16 monoid int16_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT16 // create a new uint16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1955,7 +1945,6 @@ GrB_Info GrB_Monoid_new_UINT16 // create a new uint16 monoid uint16_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT32 // create a new int32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1963,7 +1952,6 @@ GrB_Info GrB_Monoid_new_INT32 // create a new int32 monoid int32_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT32 // create a new uint32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1971,7 +1959,6 @@ GrB_Info GrB_Monoid_new_UINT32 // create a new uint32 monoid uint32_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT64 // create a new int64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1979,7 +1966,6 @@ GrB_Info GrB_Monoid_new_INT64 // create a new int64 monoid int64_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT64 // create a new uint64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1987,7 +1973,6 @@ GrB_Info GrB_Monoid_new_UINT64 // create a new uint64 monoid uint64_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_FP32 // create a new float monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1995,7 +1980,6 @@ GrB_Info GrB_Monoid_new_FP32 // create a new float monoid float identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_FP64 // create a new double monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2003,7 +1987,6 @@ GrB_Info GrB_Monoid_new_FP64 // create a new double monoid double identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_new_FC32 // create a new float complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2011,7 +1994,6 @@ GrB_Info GxB_Monoid_new_FC32 // create a new float complex monoid GxB_FC32_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_new_FC64 // create a new double complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2019,7 +2001,6 @@ GrB_Info GxB_Monoid_new_FC64 // create a new double complex monoid GxB_FC64_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UDT // create a monoid with a user-defined type ( GrB_Monoid *monoid, // handle of monoid to create @@ -2031,7 +2012,6 @@ GrB_Info GrB_Monoid_new_UDT // create a monoid with a user-defined type /* -GB_PUBLIC GrB_Info GrB_Monoid_new // create a monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2046,7 +2026,7 @@ GrB_Info GrB_Monoid_new // create a monoid _Generic \ ( \ (identity), \ - GB_CASES (, GrB, Monoid_new) \ + GB_CASES (GrB, Monoid_new) \ ) \ (monoid, op, identity) #endif @@ -2056,7 +2036,6 @@ GrB_Info GrB_Monoid_new // create a monoid // no terminal value (and in this case, it is identical to GrB_Monoid_new). // The terminal value, if not NULL, must have the same type as the identity. -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_BOOL // create a new boolean monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2065,7 +2044,6 @@ GrB_Info GxB_Monoid_terminal_new_BOOL // create a new boolean monoid bool terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT8 // create a new int8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2074,7 +2052,6 @@ GrB_Info GxB_Monoid_terminal_new_INT8 // create a new int8 monoid int8_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT8 // create a new uint8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2083,7 +2060,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT8 // create a new uint8 monoid uint8_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT16 // create a new int16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2092,7 +2068,6 @@ GrB_Info GxB_Monoid_terminal_new_INT16 // create a new int16 monoid int16_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT16 // create a new uint16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2101,7 +2076,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT16 // create a new uint16 monoid uint16_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT32 // create a new int32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2110,7 +2084,6 @@ GrB_Info GxB_Monoid_terminal_new_INT32 // create a new int32 monoid int32_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT32 // create a new uint32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2119,7 +2092,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT32 // create a new uint32 monoid uint32_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT64 // create a new int64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2128,7 +2100,6 @@ GrB_Info GxB_Monoid_terminal_new_INT64 // create a new int64 monoid int64_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT64 // create a new uint64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2137,7 +2108,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT64 // create a new uint64 monoid uint64_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FP32 // create a new float monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2146,7 +2116,6 @@ GrB_Info GxB_Monoid_terminal_new_FP32 // create a new float monoid float terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FP64 // create a new double monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2155,7 +2124,6 @@ GrB_Info GxB_Monoid_terminal_new_FP64 // create a new double monoid double terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FC32 // create a new float complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2164,7 +2132,6 @@ GrB_Info GxB_Monoid_terminal_new_FC32 // create a new float complex monoid GxB_FC32_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FC64 // create a new double complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2173,7 +2140,6 @@ GrB_Info GxB_Monoid_terminal_new_FC64 // create a new double complex monoid GxB_FC64_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UDT // create a monoid with a user type ( GrB_Monoid *monoid, // handle of monoid to create @@ -2186,7 +2152,6 @@ GrB_Info GxB_Monoid_terminal_new_UDT // create a monoid with a user type /* -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new // create a monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2202,26 +2167,23 @@ GrB_Info GxB_Monoid_terminal_new // create a monoid _Generic \ ( \ (identity), \ - GB_CASES (, GxB, Monoid_terminal_new) \ + GB_CASES (GxB, Monoid_terminal_new) \ ) \ (monoid, op, identity, terminal) #endif -GB_PUBLIC GrB_Info GxB_Monoid_operator // return the monoid operator ( GrB_BinaryOp *op, // returns the binary op of the monoid GrB_Monoid monoid // monoid to query ) ; -GB_PUBLIC GrB_Info GxB_Monoid_identity // return the monoid identity ( void *identity, // returns the identity of the monoid GrB_Monoid monoid // monoid to query ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal // return the monoid terminal ( bool *has_terminal, // true if the monoid has a terminal value @@ -2230,7 +2192,6 @@ GrB_Info GxB_Monoid_terminal // return the monoid terminal GrB_Monoid monoid // monoid to query ) ; -GB_PUBLIC GrB_Info GrB_Monoid_free // free a user-created monoid ( GrB_Monoid *monoid // handle of monoid to free @@ -2242,7 +2203,6 @@ GrB_Info GrB_Monoid_free // free a user-created monoid typedef struct GB_Semiring_opaque *GrB_Semiring ; -GB_PUBLIC GrB_Info GrB_Semiring_new // create a semiring ( GrB_Semiring *semiring, // handle of semiring to create @@ -2250,21 +2210,18 @@ GrB_Info GrB_Semiring_new // create a semiring GrB_BinaryOp multiply // multiply operator of the semiring ) ; -GB_PUBLIC GrB_Info GxB_Semiring_add // return the add monoid of a semiring ( GrB_Monoid *add, // returns add monoid of the semiring GrB_Semiring semiring // semiring to query ) ; -GB_PUBLIC GrB_Info GxB_Semiring_multiply // return multiply operator of a semiring ( GrB_BinaryOp *multiply, // returns multiply operator of the semiring GrB_Semiring semiring // semiring to query ) ; -GB_PUBLIC GrB_Info GrB_Semiring_free // free a user-created semiring ( GrB_Semiring *semiring // handle of semiring to free @@ -2283,27 +2240,23 @@ typedef struct GB_Scalar_opaque *GrB_Scalar ; // use this instead // These methods create, free, copy, and clear a GrB_Scalar. The nvals, // and type methods return basic information about a GrB_Scalar. -GB_PUBLIC GrB_Info GrB_Scalar_new // create a new GrB_Scalar with no entry ( GrB_Scalar *s, // handle of GrB_Scalar to create GrB_Type type // type of GrB_Scalar to create ) ; -GB_PUBLIC GrB_Info GrB_Scalar_dup // make an exact copy of a GrB_Scalar ( GrB_Scalar *s, // handle of output GrB_Scalar to create const GrB_Scalar t // input GrB_Scalar to copy ) ; -GB_PUBLIC GrB_Info GrB_Scalar_clear // clear a GrB_Scalar of its entry ( // type remains unchanged. GrB_Scalar s // GrB_Scalar to clear ) ; -GB_PUBLIC GrB_Info GrB_Scalar_nvals // get the number of entries in a GrB_Scalar ( GrB_Index *nvals, // GrB_Scalar has nvals entries (0 or 1) @@ -2311,13 +2264,11 @@ GrB_Info GrB_Scalar_nvals // get the number of entries in a GrB_Scalar ) ; // NOTE: GxB_Scalar_type is historical. Use GxB_Scalar_type_name instead. -GB_PUBLIC GrB_Info GxB_Scalar_type // get the type of a GrB_Scalar ( GrB_Type *type, // returns the type of the GrB_Scalar const GrB_Scalar s // GrB_Scalar to query ) ; -GB_PUBLIC GrB_Info GxB_Scalar_type_name // return the name of the type of a scalar ( char *type_name, // name of the type (char array of size at least @@ -2325,25 +2276,23 @@ GrB_Info GxB_Scalar_type_name // return the name of the type of a scalar const GrB_Scalar s // GrB_Scalar to query ) ; -GB_PUBLIC GrB_Info GxB_Scalar_memoryUsage // return # of bytes used for a scalar ( size_t *size, // # of bytes used by the scalar s const GrB_Scalar s // GrB_Scalar to query ) ; -GB_PUBLIC GrB_Info GrB_Scalar_free // free a GrB_Scalar ( GrB_Scalar *s // handle of GrB_Scalar to free ) ; // historical names identical to GrB_Scalar_methods above: -GB_PUBLIC GrB_Info GxB_Scalar_new (GrB_Scalar *s, GrB_Type type) ; -GB_PUBLIC GrB_Info GxB_Scalar_dup (GrB_Scalar *s, const GrB_Scalar t) ; -GB_PUBLIC GrB_Info GxB_Scalar_clear (GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_nvals (GrB_Index *nvals, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_free (GrB_Scalar *s) ; +GrB_Info GxB_Scalar_new (GrB_Scalar *s, GrB_Type type) ; +GrB_Info GxB_Scalar_dup (GrB_Scalar *s, const GrB_Scalar t) ; +GrB_Info GxB_Scalar_clear (GrB_Scalar s) ; +GrB_Info GxB_Scalar_nvals (GrB_Index *nvals, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_free (GrB_Scalar *s) ; //------------------------------------------------------------------------------ // GrB_Scalar_setElement @@ -2352,98 +2301,84 @@ GB_PUBLIC GrB_Info GxB_Scalar_free (GrB_Scalar *s) ; // Set a single GrB_Scalar s, from a user scalar x: s = x, typecasting from the // type of x to the type of w as needed. -GB_PUBLIC GrB_Info GrB_Scalar_setElement_BOOL // s = x ( GrB_Scalar s, // GrB_Scalar to modify bool x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT8 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int8_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT8 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint8_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT16 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int16_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT16 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint16_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int32_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint32_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int64_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint64_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_FP32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify float x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_FP64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify double x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FC32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify GxB_FC32_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FC64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify GxB_FC64_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UDT // s = x ( GrB_Scalar s, // GrB_Scalar to modify @@ -2451,25 +2386,24 @@ GrB_Info GrB_Scalar_setElement_UDT // s = x ) ; // historical names identical to GrB_Scalar_methods above: -GB_PUBLIC GrB_Info GxB_Scalar_setElement_BOOL (GrB_Scalar s, bool x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT8 (GrB_Scalar s, int8_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT16 (GrB_Scalar s, int16_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT32 (GrB_Scalar s, int32_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT64 (GrB_Scalar s, int64_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT8 (GrB_Scalar s, uint8_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT16 (GrB_Scalar s, uint16_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT32 (GrB_Scalar s, uint32_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT64 (GrB_Scalar s, uint64_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FP32 (GrB_Scalar s, float x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FP64 (GrB_Scalar s, double x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UDT (GrB_Scalar s, void *x) ; +GrB_Info GxB_Scalar_setElement_BOOL (GrB_Scalar s, bool x) ; +GrB_Info GxB_Scalar_setElement_INT8 (GrB_Scalar s, int8_t x) ; +GrB_Info GxB_Scalar_setElement_INT16 (GrB_Scalar s, int16_t x) ; +GrB_Info GxB_Scalar_setElement_INT32 (GrB_Scalar s, int32_t x) ; +GrB_Info GxB_Scalar_setElement_INT64 (GrB_Scalar s, int64_t x) ; +GrB_Info GxB_Scalar_setElement_UINT8 (GrB_Scalar s, uint8_t x) ; +GrB_Info GxB_Scalar_setElement_UINT16 (GrB_Scalar s, uint16_t x) ; +GrB_Info GxB_Scalar_setElement_UINT32 (GrB_Scalar s, uint32_t x) ; +GrB_Info GxB_Scalar_setElement_UINT64 (GrB_Scalar s, uint64_t x) ; +GrB_Info GxB_Scalar_setElement_FP32 (GrB_Scalar s, float x) ; +GrB_Info GxB_Scalar_setElement_FP64 (GrB_Scalar s, double x) ; +GrB_Info GxB_Scalar_setElement_UDT (GrB_Scalar s, void *x) ; // Type-generic version: x can be any supported C type or void * for a // user-defined type. /* -GB_PUBLIC GrB_Info GrB_Scalar_setElement // s = x ( GrB_Scalar s, // GrB_Scalar to modify @@ -2483,7 +2417,7 @@ GrB_Info GrB_Scalar_setElement // s = x _Generic \ ( \ (x), \ - GB_CASES (, GrB, Scalar_setElement) \ + GB_CASES (GrB, Scalar_setElement) \ ) \ (s, x) @@ -2497,98 +2431,84 @@ GrB_Info GrB_Scalar_setElement // s = x // Extract a single entry from a GrB_Scalar, x = s, typecasting from the type // of s to the type of x as needed. -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_BOOL // x = s ( bool *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT8 // x = s ( int8_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT8 // x = s ( uint8_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT16 // x = s ( int16_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT16 // x = s ( uint16_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT32 // x = s ( int32_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT32 // x = s ( uint32_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT64 // x = s ( int64_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT64 // x = s ( uint64_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_FP32 // x = s ( float *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_FP64 // x = s ( double *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FC32 // x = s ( GxB_FC32_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FC64 // x = s ( GxB_FC64_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UDT // x = s ( void *x, // user scalar extracted @@ -2596,25 +2516,24 @@ GrB_Info GrB_Scalar_extractElement_UDT // x = s ) ; // historical names identical to GrB_Scalar_methods above: -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_BOOL (bool *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT8 (int8_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT16 (int16_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT32 (int32_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT64 (int64_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT8 (uint8_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT16 (uint16_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT32 (uint32_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT64 (uint64_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FP32 (float *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FP64 (double *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UDT (void *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_BOOL (bool *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT8 (int8_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT16 (int16_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT32 (int32_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT64 (int64_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT8 (uint8_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT16 (uint16_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT32 (uint32_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT64 (uint64_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_FP32 (float *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_FP64 (double *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UDT (void *x, const GrB_Scalar s) ; // Type-generic version: x can be a pointer to any supported C type or void * // for a user-defined type. /* -GB_PUBLIC GrB_Info GrB_Scalar_extractElement // x = s ( *x, // user scalar extracted @@ -2628,7 +2547,7 @@ GrB_Info GrB_Scalar_extractElement // x = s _Generic \ ( \ (x), \ - GB_CASES (*, GrB, Scalar_extractElement) \ + GB_PCASES (GrB, Scalar_extractElement) \ ) \ (x, s) @@ -2644,7 +2563,6 @@ typedef struct GB_Vector_opaque *GrB_Vector ; // These methods create, free, copy, and clear a vector. The size, nvals, // and type methods return basic information about a vector. -GB_PUBLIC GrB_Info GrB_Vector_new // create a new vector with no entries ( GrB_Vector *v, // handle of vector to create @@ -2653,27 +2571,23 @@ GrB_Info GrB_Vector_new // create a new vector with no entries // (n must be <= GrB_INDEX_MAX+1) ) ; -GB_PUBLIC GrB_Info GrB_Vector_dup // make an exact copy of a vector ( GrB_Vector *w, // handle of output vector to create const GrB_Vector u // input vector to copy ) ; -GB_PUBLIC GrB_Info GrB_Vector_clear // clear a vector of all entries; ( // type and dimension remain unchanged. GrB_Vector v // vector to clear ) ; -GB_PUBLIC GrB_Info GrB_Vector_size // get the dimension of a vector ( GrB_Index *n, // vector dimension is n-by-1 const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GrB_Vector_nvals // get the number of entries in a vector ( GrB_Index *nvals, // vector has nvals entries @@ -2681,13 +2595,11 @@ GrB_Info GrB_Vector_nvals // get the number of entries in a vector ) ; // NOTE: GxB_Vector_type is historical. Use GxB_Vector_type_name instead. -GB_PUBLIC GrB_Info GxB_Vector_type // get the type of a vector ( GrB_Type *type, // returns the type of the vector const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GxB_Vector_type_name // return the name of the type of a vector ( char *type_name, // name of the type (char array of size at least @@ -2695,21 +2607,18 @@ GrB_Info GxB_Vector_type_name // return the name of the type of a vector const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GxB_Vector_memoryUsage // return # of bytes used for a vector ( size_t *size, // # of bytes used by the vector v const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GxB_Vector_iso // return iso status of a vector ( bool *iso, // true if the vector is iso-valued const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GrB_Vector_free // free a vector ( GrB_Vector *v // handle of vector to free @@ -2722,7 +2631,6 @@ GrB_Info GrB_Vector_free // free a vector // GrB_Vector_build: w = sparse (I,1,X), but using any // associative operator to assemble duplicate entries. -GB_PUBLIC GrB_Info GrB_Vector_build_BOOL // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2732,7 +2640,6 @@ GrB_Info GrB_Vector_build_BOOL // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT8 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2742,7 +2649,6 @@ GrB_Info GrB_Vector_build_INT8 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT8 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2752,7 +2658,6 @@ GrB_Info GrB_Vector_build_UINT8 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT16 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2762,7 +2667,6 @@ GrB_Info GrB_Vector_build_INT16 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT16 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2772,7 +2676,6 @@ GrB_Info GrB_Vector_build_UINT16 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2782,7 +2685,6 @@ GrB_Info GrB_Vector_build_INT32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2792,7 +2694,6 @@ GrB_Info GrB_Vector_build_UINT32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2802,7 +2703,6 @@ GrB_Info GrB_Vector_build_INT64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2812,7 +2712,6 @@ GrB_Info GrB_Vector_build_UINT64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_FP32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2822,7 +2721,6 @@ GrB_Info GrB_Vector_build_FP32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_FP64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2832,7 +2730,6 @@ GrB_Info GrB_Vector_build_FP64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Vector_build_FC32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2842,7 +2739,6 @@ GrB_Info GxB_Vector_build_FC32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Vector_build_FC64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2852,7 +2748,6 @@ GrB_Info GxB_Vector_build_FC64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UDT // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2862,7 +2757,6 @@ GrB_Info GrB_Vector_build_UDT // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Vector_build_Scalar // build a vector from (i,scalar) tuples ( GrB_Vector w, // vector to build @@ -2876,7 +2770,6 @@ GrB_Info GxB_Vector_build_Scalar // build a vector from (i,scalar) tuples /* -GB_PUBLIC GrB_Info GrB_Vector_build // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2893,7 +2786,7 @@ GrB_Info GrB_Vector_build // build a vector from (I,X) tuples _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Vector_build) \ + GB_PCASES (GrB, Vector_build) \ ) \ (w, I, ((const void *) (X)), nvals, dup) #endif @@ -2905,7 +2798,6 @@ GrB_Info GrB_Vector_build // build a vector from (I,X) tuples // Set a single scalar in a vector, w(i) = x, typecasting from the type of x to // the type of w as needed. -GB_PUBLIC GrB_Info GrB_Vector_setElement_BOOL // w(i) = x ( GrB_Vector w, // vector to modify @@ -2913,7 +2805,6 @@ GrB_Info GrB_Vector_setElement_BOOL // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT8 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2921,7 +2812,6 @@ GrB_Info GrB_Vector_setElement_INT8 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT8 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2929,7 +2819,6 @@ GrB_Info GrB_Vector_setElement_UINT8 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT16 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2937,7 +2826,6 @@ GrB_Info GrB_Vector_setElement_INT16 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT16 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2945,7 +2833,6 @@ GrB_Info GrB_Vector_setElement_UINT16 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2953,7 +2840,6 @@ GrB_Info GrB_Vector_setElement_INT32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2961,7 +2847,6 @@ GrB_Info GrB_Vector_setElement_UINT32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2969,7 +2854,6 @@ GrB_Info GrB_Vector_setElement_INT64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2977,7 +2861,6 @@ GrB_Info GrB_Vector_setElement_UINT64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_FP32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2985,7 +2868,6 @@ GrB_Info GrB_Vector_setElement_FP32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_FP64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2993,7 +2875,6 @@ GrB_Info GrB_Vector_setElement_FP64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_setElement_FC32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -3001,7 +2882,6 @@ GrB_Info GxB_Vector_setElement_FC32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_setElement_FC64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -3009,7 +2889,6 @@ GrB_Info GxB_Vector_setElement_FC64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UDT // w(i) = x ( GrB_Vector w, // vector to modify @@ -3017,7 +2896,6 @@ GrB_Info GrB_Vector_setElement_UDT // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_Scalar // w(i) = x ( GrB_Vector w, // vector to modify @@ -3030,7 +2908,6 @@ GrB_Info GrB_Vector_setElement_Scalar // w(i) = x /* -GB_PUBLIC GrB_Info GrB_Vector_setElement // w(i) = x ( GrB_Vector w, // vector to modify @@ -3045,7 +2922,7 @@ GrB_Info GrB_Vector_setElement // w(i) = x _Generic \ ( \ (x), \ - GB_CASES (, GrB, Vector_setElement), \ + GB_CASES (GrB, Vector_setElement), \ default: GrB_Vector_setElement_Scalar \ ) \ (w, x, i) @@ -3058,7 +2935,6 @@ GrB_Info GrB_Vector_setElement // w(i) = x // Extract a single entry from a vector, x = v(i), typecasting from the type of // v to the type of x as needed. -GB_PUBLIC GrB_Info GrB_Vector_extractElement_BOOL // x = v(i) ( bool *x, // scalar extracted @@ -3066,7 +2942,6 @@ GrB_Info GrB_Vector_extractElement_BOOL // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT8 // x = v(i) ( int8_t *x, // scalar extracted @@ -3074,7 +2949,6 @@ GrB_Info GrB_Vector_extractElement_INT8 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT8 // x = v(i) ( uint8_t *x, // scalar extracted @@ -3082,7 +2956,6 @@ GrB_Info GrB_Vector_extractElement_UINT8 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT16 // x = v(i) ( int16_t *x, // scalar extracted @@ -3090,7 +2963,6 @@ GrB_Info GrB_Vector_extractElement_INT16 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT16 // x = v(i) ( uint16_t *x, // scalar extracted @@ -3098,7 +2970,6 @@ GrB_Info GrB_Vector_extractElement_UINT16 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT32 // x = v(i) ( int32_t *x, // scalar extracted @@ -3106,7 +2977,6 @@ GrB_Info GrB_Vector_extractElement_INT32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT32 // x = v(i) ( uint32_t *x, // scalar extracted @@ -3114,7 +2984,6 @@ GrB_Info GrB_Vector_extractElement_UINT32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT64 // x = v(i) ( int64_t *x, // scalar extracted @@ -3122,7 +2991,6 @@ GrB_Info GrB_Vector_extractElement_INT64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT64 // x = v(i) ( uint64_t *x, // scalar extracted @@ -3130,7 +2998,6 @@ GrB_Info GrB_Vector_extractElement_UINT64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_FP32 // x = v(i) ( float *x, // scalar extracted @@ -3138,7 +3005,6 @@ GrB_Info GrB_Vector_extractElement_FP32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_FP64 // x = v(i) ( double *x, // scalar extracted @@ -3146,7 +3012,6 @@ GrB_Info GrB_Vector_extractElement_FP64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractElement_FC32 // x = v(i) ( GxB_FC32_t *x, // scalar extracted @@ -3154,7 +3019,6 @@ GrB_Info GxB_Vector_extractElement_FC32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractElement_FC64 // x = v(i) ( GxB_FC64_t *x, // scalar extracted @@ -3162,7 +3026,6 @@ GrB_Info GxB_Vector_extractElement_FC64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UDT // x = v(i) ( void *x, // scalar extracted @@ -3170,7 +3033,6 @@ GrB_Info GrB_Vector_extractElement_UDT // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_Scalar // x = v(i) ( GrB_Scalar x, // scalar extracted @@ -3183,7 +3045,6 @@ GrB_Info GrB_Vector_extractElement_Scalar // x = v(i) /* -GB_PUBLIC GrB_Info GrB_Vector_extractElement // x = v(i) ( *x, // scalar extracted @@ -3198,7 +3059,7 @@ GrB_Info GrB_Vector_extractElement // x = v(i) _Generic \ ( \ (x), \ - GB_CASES (*, GrB, Vector_extractElement), \ + GB_PCASES (GrB, Vector_extractElement), \ default: GrB_Vector_extractElement_Scalar \ ) \ (x, v, i) @@ -3208,7 +3069,6 @@ GrB_Info GrB_Vector_extractElement // x = v(i) // of the vector v, as a stored element. It does not return the value. It // returns GrB_SUCCESS if the element is present, or GrB_NO_VALUE otherwise. -GB_PUBLIC GrB_Info GxB_Vector_isStoredElement // determine if v(i) is a stored element ( const GrB_Vector v, // vector to check @@ -3221,7 +3081,6 @@ GrB_Info GxB_Vector_isStoredElement // determine if v(i) is a stored element // GrB_Vector_removeElement (v,i) removes the element v(i) from the vector v. -GB_PUBLIC GrB_Info GrB_Vector_removeElement ( GrB_Vector v, // vector to remove an element from @@ -3237,7 +3096,6 @@ GrB_Info GrB_Vector_removeElement // example, to extract just the row indices, pass I as non-NULL, and X as NULL. // This is like [I,~,~] = find (v). -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_BOOL // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3246,7 +3104,6 @@ GrB_Info GrB_Vector_extractTuples_BOOL // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT8 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3255,7 +3112,6 @@ GrB_Info GrB_Vector_extractTuples_INT8 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT8 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3264,7 +3120,6 @@ GrB_Info GrB_Vector_extractTuples_UINT8 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT16 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3273,7 +3128,6 @@ GrB_Info GrB_Vector_extractTuples_INT16 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT16 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3282,7 +3136,6 @@ GrB_Info GrB_Vector_extractTuples_UINT16 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3291,7 +3144,6 @@ GrB_Info GrB_Vector_extractTuples_INT32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3300,7 +3152,6 @@ GrB_Info GrB_Vector_extractTuples_UINT32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3309,7 +3160,6 @@ GrB_Info GrB_Vector_extractTuples_INT64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3318,7 +3168,6 @@ GrB_Info GrB_Vector_extractTuples_UINT64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_FP32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3327,7 +3176,6 @@ GrB_Info GrB_Vector_extractTuples_FP32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_FP64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3336,7 +3184,6 @@ GrB_Info GrB_Vector_extractTuples_FP64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractTuples_FC32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3345,7 +3192,6 @@ GrB_Info GxB_Vector_extractTuples_FC32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractTuples_FC64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3354,7 +3200,6 @@ GrB_Info GxB_Vector_extractTuples_FC64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UDT // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3368,7 +3213,6 @@ GrB_Info GrB_Vector_extractTuples_UDT // [I,~,X] = find (v) /* -GB_PUBLIC GrB_Info GrB_Vector_extractTuples // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3384,7 +3228,7 @@ GrB_Info GrB_Vector_extractTuples // [I,~,X] = find (v) _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Vector_extractTuples) \ + GB_PCASES (GrB, Vector_extractTuples) \ ) \ (I, X, nvals, v) #endif @@ -3398,7 +3242,6 @@ typedef struct GB_Matrix_opaque *GrB_Matrix ; // These methods create, free, copy, and clear a matrix. The nrows, ncols, // nvals, and type methods return basic information about a matrix. -GB_PUBLIC GrB_Info GrB_Matrix_new // create a new matrix with no entries ( GrB_Matrix *A, // handle of matrix to create @@ -3407,34 +3250,29 @@ GrB_Info GrB_Matrix_new // create a new matrix with no entries GrB_Index ncols // (nrows and ncols must be <= GrB_INDEX_MAX+1) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_dup // make an exact copy of a matrix ( GrB_Matrix *C, // handle of output matrix to create const GrB_Matrix A // input matrix to copy ) ; -GB_PUBLIC GrB_Info GrB_Matrix_clear // clear a matrix of all entries; ( // type and dimensions remain unchanged GrB_Matrix A // matrix to clear ) ; -GB_PUBLIC GrB_Info GrB_Matrix_nrows // get the number of rows of a matrix ( GrB_Index *nrows, // matrix has nrows rows const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GrB_Matrix_ncols // get the number of columns of a matrix ( GrB_Index *ncols, // matrix has ncols columns const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GrB_Matrix_nvals // get the number of entries in a matrix ( GrB_Index *nvals, // matrix has nvals entries @@ -3442,13 +3280,11 @@ GrB_Info GrB_Matrix_nvals // get the number of entries in a matrix ) ; // NOTE: GxB_Matrix_type is historical. Use GxB_Matrix_type_name instead. -GB_PUBLIC GrB_Info GxB_Matrix_type // get the type of a matrix ( GrB_Type *type, // returns the type of the matrix const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GxB_Matrix_type_name // return the name of the type of a matrix ( char *type_name, // name of the type (char array of size at least @@ -3456,21 +3292,18 @@ GrB_Info GxB_Matrix_type_name // return the name of the type of a matrix const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GxB_Matrix_memoryUsage // return # of bytes used for a matrix ( size_t *size, // # of bytes used by the matrix A const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GxB_Matrix_iso // return iso status of a matrix ( bool *iso, // true if the matrix is iso-valued const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GrB_Matrix_free // free a matrix ( GrB_Matrix *A // handle of matrix to free @@ -3483,7 +3316,6 @@ GrB_Info GrB_Matrix_free // free a matrix // GrB_Matrix_build: C = sparse (I,J,X), but using any // associative operator to assemble duplicate entries. -GB_PUBLIC GrB_Info GrB_Matrix_build_BOOL // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3494,7 +3326,6 @@ GrB_Info GrB_Matrix_build_BOOL // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT8 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3505,7 +3336,6 @@ GrB_Info GrB_Matrix_build_INT8 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT8 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3516,7 +3346,6 @@ GrB_Info GrB_Matrix_build_UINT8 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT16 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3527,7 +3356,6 @@ GrB_Info GrB_Matrix_build_INT16 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT16 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3538,7 +3366,6 @@ GrB_Info GrB_Matrix_build_UINT16 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3549,7 +3376,6 @@ GrB_Info GrB_Matrix_build_INT32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3560,7 +3386,6 @@ GrB_Info GrB_Matrix_build_UINT32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3571,7 +3396,6 @@ GrB_Info GrB_Matrix_build_INT64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3582,7 +3406,6 @@ GrB_Info GrB_Matrix_build_UINT64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_FP32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3593,7 +3416,6 @@ GrB_Info GrB_Matrix_build_FP32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_FP64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3604,7 +3426,6 @@ GrB_Info GrB_Matrix_build_FP64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Matrix_build_FC32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3615,7 +3436,6 @@ GrB_Info GxB_Matrix_build_FC32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Matrix_build_FC64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3626,7 +3446,6 @@ GrB_Info GxB_Matrix_build_FC64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UDT // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3637,7 +3456,6 @@ GrB_Info GrB_Matrix_build_UDT // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Matrix_build_Scalar // build a matrix from (I,J,scalar) tuples ( GrB_Matrix C, // matrix to build @@ -3652,7 +3470,6 @@ GrB_Info GxB_Matrix_build_Scalar // build a matrix from (I,J,scalar) tuples /* -GB_PUBLIC GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3670,7 +3487,7 @@ GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Matrix_build) \ + GB_PCASES (GrB, Matrix_build) \ ) \ (C, I, J, ((const void *) (X)), nvals, dup) #endif @@ -3682,7 +3499,6 @@ GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples // Set a single entry in a matrix, C(i,j) = x, typecasting // from the type of x to the type of C, as needed. -GB_PUBLIC GrB_Info GrB_Matrix_setElement_BOOL // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3691,7 +3507,6 @@ GrB_Info GrB_Matrix_setElement_BOOL // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT8 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3700,7 +3515,6 @@ GrB_Info GrB_Matrix_setElement_INT8 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT8 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3709,7 +3523,6 @@ GrB_Info GrB_Matrix_setElement_UINT8 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT16 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3718,7 +3531,6 @@ GrB_Info GrB_Matrix_setElement_INT16 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT16 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3727,7 +3539,6 @@ GrB_Info GrB_Matrix_setElement_UINT16 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3736,7 +3547,6 @@ GrB_Info GrB_Matrix_setElement_INT32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3745,7 +3555,6 @@ GrB_Info GrB_Matrix_setElement_UINT32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3754,7 +3563,6 @@ GrB_Info GrB_Matrix_setElement_INT64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3763,7 +3571,6 @@ GrB_Info GrB_Matrix_setElement_UINT64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_FP32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3772,7 +3579,6 @@ GrB_Info GrB_Matrix_setElement_FP32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_FP64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3781,7 +3587,6 @@ GrB_Info GrB_Matrix_setElement_FP64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_setElement_FC32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3790,7 +3595,6 @@ GrB_Info GxB_Matrix_setElement_FC32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_setElement_FC64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3799,7 +3603,6 @@ GrB_Info GxB_Matrix_setElement_FC64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UDT // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3808,7 +3611,6 @@ GrB_Info GrB_Matrix_setElement_UDT // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_Scalar // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3822,7 +3624,6 @@ GrB_Info GrB_Matrix_setElement_Scalar // C (i,j) = x /* -GB_PUBLIC GrB_Info GrB_Matrix_setElement // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3838,7 +3639,7 @@ GrB_Info GrB_Matrix_setElement // C (i,j) = x _Generic \ ( \ (x), \ - GB_CASES (, GrB, Matrix_setElement), \ + GB_CASES (GrB, Matrix_setElement), \ default: GrB_Matrix_setElement_Scalar \ ) \ (C, x, i, j) @@ -3851,7 +3652,6 @@ GrB_Info GrB_Matrix_setElement // C (i,j) = x // Extract a single entry from a matrix, x = A(i,j), typecasting from the type // of A to the type of x, as needed. -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_BOOL // x = A(i,j) ( bool *x, // extracted scalar @@ -3860,7 +3660,6 @@ GrB_Info GrB_Matrix_extractElement_BOOL // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT8 // x = A(i,j) ( int8_t *x, // extracted scalar @@ -3869,7 +3668,6 @@ GrB_Info GrB_Matrix_extractElement_INT8 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT8 // x = A(i,j) ( uint8_t *x, // extracted scalar @@ -3878,7 +3676,6 @@ GrB_Info GrB_Matrix_extractElement_UINT8 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT16 // x = A(i,j) ( int16_t *x, // extracted scalar @@ -3887,7 +3684,6 @@ GrB_Info GrB_Matrix_extractElement_INT16 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT16 // x = A(i,j) ( uint16_t *x, // extracted scalar @@ -3896,7 +3692,6 @@ GrB_Info GrB_Matrix_extractElement_UINT16 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT32 // x = A(i,j) ( int32_t *x, // extracted scalar @@ -3905,7 +3700,6 @@ GrB_Info GrB_Matrix_extractElement_INT32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT32 // x = A(i,j) ( uint32_t *x, // extracted scalar @@ -3914,7 +3708,6 @@ GrB_Info GrB_Matrix_extractElement_UINT32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT64 // x = A(i,j) ( int64_t *x, // extracted scalar @@ -3923,7 +3716,6 @@ GrB_Info GrB_Matrix_extractElement_INT64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT64 // x = A(i,j) ( uint64_t *x, // extracted scalar @@ -3932,7 +3724,6 @@ GrB_Info GrB_Matrix_extractElement_UINT64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_FP32 // x = A(i,j) ( float *x, // extracted scalar @@ -3941,7 +3732,6 @@ GrB_Info GrB_Matrix_extractElement_FP32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_FP64 // x = A(i,j) ( double *x, // extracted scalar @@ -3950,7 +3740,6 @@ GrB_Info GrB_Matrix_extractElement_FP64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractElement_FC32 // x = A(i,j) ( GxB_FC32_t *x, // extracted scalar @@ -3959,7 +3748,6 @@ GrB_Info GxB_Matrix_extractElement_FC32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractElement_FC64 // x = A(i,j) ( GxB_FC64_t *x, // extracted scalar @@ -3968,7 +3756,6 @@ GrB_Info GxB_Matrix_extractElement_FC64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UDT // x = A(i,j) ( void *x, // extracted scalar @@ -3977,7 +3764,6 @@ GrB_Info GrB_Matrix_extractElement_UDT // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_Scalar // x = A(i,j) ( GrB_Scalar x, // extracted scalar @@ -3991,7 +3777,6 @@ GrB_Info GrB_Matrix_extractElement_Scalar // x = A(i,j) /* -GB_PUBLIC GrB_Info GrB_Matrix_extractElement // x = A(i,j) ( *x, // extracted scalar @@ -4007,7 +3792,7 @@ GrB_Info GrB_Matrix_extractElement // x = A(i,j) _Generic \ ( \ (x), \ - GB_CASES (*, GrB, Matrix_extractElement), \ + GB_PCASES (GrB, Matrix_extractElement), \ default: GrB_Matrix_extractElement_Scalar \ ) \ (x, A, i, j) @@ -4017,7 +3802,6 @@ GrB_Info GrB_Matrix_extractElement // x = A(i,j) // of the matrix A, as a stored element. It does not return the value. It // returns GrB_SUCCESS if the element is present, or GrB_NO_VALUE otherwise. -GB_PUBLIC GrB_Info GxB_Matrix_isStoredElement // determine if A(i,j) is a stored element ( const GrB_Matrix A, // matrix to check @@ -4031,7 +3815,6 @@ GrB_Info GxB_Matrix_isStoredElement // determine if A(i,j) is a stored element // GrB_Matrix_removeElement (A,i,j) removes the entry A(i,j) from the matrix A. -GB_PUBLIC GrB_Info GrB_Matrix_removeElement ( GrB_Matrix C, // matrix to remove entry from @@ -4048,7 +3831,6 @@ GrB_Info GrB_Matrix_removeElement // For example, to extract just the row and col indices, pass I and J as // non-NULL, and X as NULL. This is like [I,J,~] = find (A). -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_BOOL // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4058,7 +3840,6 @@ GrB_Info GrB_Matrix_extractTuples_BOOL // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT8 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4068,7 +3849,6 @@ GrB_Info GrB_Matrix_extractTuples_INT8 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT8 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4078,7 +3858,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT8 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT16 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4088,7 +3867,6 @@ GrB_Info GrB_Matrix_extractTuples_INT16 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT16 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4098,7 +3876,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT16 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4108,7 +3885,6 @@ GrB_Info GrB_Matrix_extractTuples_INT32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4118,7 +3894,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4128,7 +3903,6 @@ GrB_Info GrB_Matrix_extractTuples_INT64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4138,7 +3912,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_FP32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4148,7 +3921,6 @@ GrB_Info GrB_Matrix_extractTuples_FP32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_FP64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4158,7 +3930,6 @@ GrB_Info GrB_Matrix_extractTuples_FP64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractTuples_FC32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4168,7 +3939,6 @@ GrB_Info GxB_Matrix_extractTuples_FC32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractTuples_FC64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4178,7 +3948,6 @@ GrB_Info GxB_Matrix_extractTuples_FC64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UDT // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4193,7 +3962,6 @@ GrB_Info GrB_Matrix_extractTuples_UDT // [I,J,X] = find (A) /* -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4210,7 +3978,7 @@ GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Matrix_extractTuples) \ + GB_PCASES (GrB, Matrix_extractTuples) \ ) \ (I, J, X, nvals, A) #endif @@ -4246,7 +4014,6 @@ GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) // or by column, bitmap switch, hyper switch, and sparsity control) are // unchanged. -GB_PUBLIC GrB_Info GxB_Matrix_concat // concatenate a 2D array of matrices ( GrB_Matrix C, // input/output matrix for results @@ -4266,7 +4033,6 @@ GrB_Info GxB_Matrix_concat // concatenate a 2D array of matrices // number of columns of A. The type of each tile is the same as the type of A; // no typecasting is done. -GB_PUBLIC GrB_Info GxB_Matrix_split // split a matrix into 2D array of matrices ( GrB_Matrix *Tiles, // 2D row-major array of size m-by-n @@ -4291,7 +4057,6 @@ GrB_Info GxB_Matrix_split // split a matrix into 2D array of matrices // diagonal of C, with C(i-k,i) = v(i). C is constructed with the same type // as v. -GB_PUBLIC GrB_Info GrB_Matrix_diag // build a diagonal matrix from a vector ( GrB_Matrix *C, // output matrix @@ -4306,13 +4071,12 @@ GrB_Info GrB_Matrix_diag // build a diagonal matrix from a vector // C by GxB_Matrix_Option_set (format by row or by column, bitmap switch, hyper // switch, and sparsity control) are unchanged. -GB_PUBLIC GrB_Info GxB_Matrix_diag // construct a diagonal matrix from a vector ( GrB_Matrix C, // output matrix const GrB_Vector v, // input vector int64_t k, - const GrB_Descriptor desc // to specify # of threads + const GrB_Descriptor desc ) ; // GxB_Vector_diag extracts a vector v from an input matrix A, which may be @@ -4331,7 +4095,6 @@ GrB_Info GxB_Matrix_diag // construct a diagonal matrix from a vector // typecasted into the type of v. Any settings made to v by // GxB_Vector_Option_set (bitmap switch and sparsity control) are unchanged. -GB_PUBLIC GrB_Info GxB_Vector_diag // extract a diagonal from a matrix, as a vector ( GrB_Vector v, // output vector @@ -4390,6 +4153,7 @@ typedef enum // for global options or matrix options GxB_API_URL = 19, // URL for the API (char *) GxB_COMPILER_VERSION = 23, // compiler version (3 int's) GxB_COMPILER_NAME = 24, // compiler name (char *) + GxB_LIBRARY_OPENMP = 25, // library compiled with OpenMP //------------------------------------------------------------ // for GxB_Global_Option_get/set only: @@ -4439,14 +4203,14 @@ typedef enum } GxB_Format_Value ; -// The default format is by row. These constants are defined as GB_PUBLIC +// The default format is by row. These constants are defined as GB_GLOBAL // const, so that if SuiteSparse:GraphBLAS is recompiled with a different // default format, and the application is relinked but not recompiled, it will // acquire the new default values. -GB_PUBLIC const GxB_Format_Value GxB_FORMAT_DEFAULT ; +GB_GLOBAL const GxB_Format_Value GxB_FORMAT_DEFAULT ; // the default hyper_switch parameter -GB_PUBLIC const double GxB_HYPER_DEFAULT ; +GB_GLOBAL const double GxB_HYPER_DEFAULT ; // GxB_SPARSITY_CONTROL can be any sum or bitwise OR of these 4 values: #define GxB_HYPERSPARSE 1 // store matrix in hypersparse form @@ -4519,9 +4283,8 @@ GB_PUBLIC const double GxB_HYPER_DEFAULT ; // a matrix always stays hypersparse, or always stays non-hypersparse, // respectively. -GB_PUBLIC const double GxB_ALWAYS_HYPER, GxB_NEVER_HYPER ; +GB_GLOBAL const double GxB_ALWAYS_HYPER, GxB_NEVER_HYPER ; -GB_PUBLIC GrB_Info GxB_Matrix_Option_set // set an option in a matrix ( GrB_Matrix A, // matrix to modify @@ -4529,7 +4292,20 @@ GrB_Info GxB_Matrix_Option_set // set an option in a matrix ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Matrix_Option_set_INT32 // set an option in a matrix +( + GrB_Matrix A, // matrix to modify + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Matrix_Option_set_FP64 // set an option in a matrix +( + GrB_Matrix A, // matrix to modify + GxB_Option_Field field, // option to change + double value // value to change it to +) ; + GrB_Info GxB_Matrix_Option_get // gets the current option of a matrix ( GrB_Matrix A, // matrix to query @@ -4537,7 +4313,20 @@ GrB_Info GxB_Matrix_Option_get // gets the current option of a matrix ... // return value of the matrix option ) ; -GB_PUBLIC +GrB_Info GxB_Matrix_Option_get_INT32 // gets the current option of a matrix +( + GrB_Matrix A, // matrix to query + GxB_Option_Field field, // option to query + int32_t *value // return value of the matrix option +) ; + +GrB_Info GxB_Matrix_Option_get_FP64 // gets the current option of a matrix +( + GrB_Matrix A, // matrix to query + GxB_Option_Field field, // option to query + double *value // return value of the matrix option +) ; + GrB_Info GxB_Vector_Option_set // set an option in a vector ( GrB_Vector A, // vector to modify @@ -4545,7 +4334,20 @@ GrB_Info GxB_Vector_Option_set // set an option in a vector ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Vector_Option_set_INT32 // set an option in a vector +( + GrB_Vector v, // vector to modify + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Vector_Option_set_FP64 // set an option in a vector +( + GrB_Vector v, // vector to modify + GxB_Option_Field field, // option to change + double value // value to change it to +) ; + GrB_Info GxB_Vector_Option_get // gets the current option of a vector ( GrB_Vector A, // vector to query @@ -4553,6 +4355,20 @@ GrB_Info GxB_Vector_Option_get // gets the current option of a vector ... // return value of the vector option ) ; +GrB_Info GxB_Vector_Option_get_INT32 // gets the current option of a vector +( + GrB_Vector v, // vector to query + GxB_Option_Field field, // option to query + int32_t *value // return value of the vector option +) ; + +GrB_Info GxB_Vector_Option_get_FP64 // gets the current option of a vector +( + GrB_Vector v, // vector to query + GxB_Option_Field field, // option to query + double *value // return value of the vector option +) ; + // GxB_Global_Option_set controls the global defaults used when a new matrix is // created. GrB_init defines the following initial settings: // @@ -4568,20 +4384,78 @@ GrB_Info GxB_Vector_Option_get // gets the current option of a vector // global settings via GxB_Global_Option_set has no effect on matrices already // created. -GB_PUBLIC GrB_Info GxB_Global_Option_set // set a global default option ( GxB_Option_Field field, // option to change ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Global_Option_set_INT32 // set a global default option +( + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_FP64 // set a global default option +( + GxB_Option_Field field, // option to change + double value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_FP64_ARRAY // set a global default option +( + GxB_Option_Field field, // option to change + double *value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_INT64_ARRAY // set a global default option +( + GxB_Option_Field field, // option to change + int64_t *value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_FUNCTION // set a global default option +( + GxB_Option_Field field, // option to change + void *value // value to change it to +) ; + GrB_Info GxB_Global_Option_get // gets the current global default option ( GxB_Option_Field field, // option to query ... // return value of the global option ) ; +GrB_Info GxB_Global_Option_get_INT32 // gets the current global option +( + GxB_Option_Field field, // option to query + int32_t *value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_FP64 // gets the current global option +( + GxB_Option_Field field, // option to query + double *value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_INT64 // gets the current global option +( + GxB_Option_Field field, // option to query + int64_t *value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_CHAR // gets the current global option +( + GxB_Option_Field field, // option to query + char **value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_FUNCTION // gets the current global option +( + GxB_Option_Field field, // option to query + void **value // return value of the global option +) ; + //------------------------------------------------------------------------------ // GxB_set and GxB_get //------------------------------------------------------------------------------ @@ -4594,8 +4468,7 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set and GxB_get are generic methods that and set or query the options in // a GrB_Matrix, a GrB_Descriptor, or in the global options. They can be used -// with the following syntax. Note that GxB_NTHREADS can be used for both the -// global nthreads_max, and for the # of threads in the descriptor. +// with the following syntax. // To set/get the global options: // @@ -4699,12 +4572,6 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set (GrB_Descriptor d, GxB_AxB_METHOD, GxB_AxB_DOT) ; // GxB_get (GrB_Descriptor d, GrB_AxB_METHOD, GrB_Desc_Value *v) ; // -// GxB_set (GrB_Descriptor d, GxB_NTHREADS, nthreads) ; -// GxB_get (GrB_Descriptor d, GxB_NTHREADS, int *nthreads) ; -// -// GxB_set (GrB_Descriptor d, GxB_CHUNK, double chunk) ; -// GxB_get (GrB_Descriptor d, GxB_CHUNK, double *chunk) ; -// // GxB_set (GrB_Descriptor d, GxB_SORT, int sort) ; // GxB_get (GrB_Descriptor d, GxB_SORT, int *sort) ; // @@ -4731,16 +4598,11 @@ GrB_Info GxB_Global_Option_get // gets the current global default option _Generic \ ( \ (arg1), \ - const int : GxB_Global_Option_get , \ - int : GxB_Global_Option_get , \ - const GxB_Option_Field : GxB_Global_Option_get , \ - GxB_Option_Field : GxB_Global_Option_get , \ - const GrB_Vector : GxB_Vector_Option_get , \ - GrB_Vector : GxB_Vector_Option_get , \ - const GrB_Matrix : GxB_Matrix_Option_get , \ - GrB_Matrix : GxB_Matrix_Option_get , \ - const GrB_Descriptor : GxB_Desc_get , \ - GrB_Descriptor : GxB_Desc_get \ + int : GxB_Global_Option_get , \ + GxB_Option_Field : GxB_Global_Option_get , \ + GrB_Vector : GxB_Vector_Option_get , \ + GrB_Matrix : GxB_Matrix_Option_get , \ + GrB_Descriptor : GxB_Desc_get \ ) \ (arg1, __VA_ARGS__) #endif @@ -4787,17 +4649,17 @@ GrB_WaitMode ; // Finish all pending work in a specific object. -GB_PUBLIC GrB_Info GrB_Type_wait (GrB_Type type , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_UnaryOp_wait (GrB_UnaryOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_BinaryOp_wait (GrB_BinaryOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GxB_SelectOp_wait (GxB_SelectOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_IndexUnaryOp_wait (GrB_IndexUnaryOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Monoid_wait (GrB_Monoid monoid , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Semiring_wait (GrB_Semiring semiring, GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Descriptor_wait (GrB_Descriptor desc , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Scalar_wait (GrB_Scalar s , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Vector_wait (GrB_Vector v , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Matrix_wait (GrB_Matrix A , GrB_WaitMode waitmode) ; +GrB_Info GrB_Type_wait (GrB_Type type , GrB_WaitMode waitmode); +GrB_Info GrB_UnaryOp_wait (GrB_UnaryOp op , GrB_WaitMode waitmode); +GrB_Info GrB_BinaryOp_wait (GrB_BinaryOp op , GrB_WaitMode waitmode); +GrB_Info GxB_SelectOp_wait (GxB_SelectOp op , GrB_WaitMode waitmode); +GrB_Info GrB_IndexUnaryOp_wait (GrB_IndexUnaryOp op , GrB_WaitMode waitmode); +GrB_Info GrB_Monoid_wait (GrB_Monoid monoid , GrB_WaitMode waitmode); +GrB_Info GrB_Semiring_wait (GrB_Semiring semiring, GrB_WaitMode waitmode); +GrB_Info GrB_Descriptor_wait (GrB_Descriptor desc , GrB_WaitMode waitmode); +GrB_Info GrB_Scalar_wait (GrB_Scalar s , GrB_WaitMode waitmode); +GrB_Info GrB_Vector_wait (GrB_Vector v , GrB_WaitMode waitmode); +GrB_Info GrB_Matrix_wait (GrB_Matrix A , GrB_WaitMode waitmode); // GrB_wait (object,waitmode) polymorphic function: #if GxB_STDC_VERSION >= 201112L @@ -4821,7 +4683,7 @@ GB_PUBLIC GrB_Info GrB_Matrix_wait (GrB_Matrix A , GrB_WaitMode #endif // NOTE: GxB_Scalar_wait is historical; use GrB_Scalar_wait instead -GB_PUBLIC GrB_Info GxB_Scalar_wait (GrB_Scalar *s) ; +GrB_Info GxB_Scalar_wait (GrB_Scalar *s) ; //============================================================================== // GrB_error: error handling @@ -4832,19 +4694,19 @@ GB_PUBLIC GrB_Info GxB_Scalar_wait (GrB_Scalar *s) ; // null-terminated string. The string returned by GrB_error is owned by // the GraphBLAS library and must not be free'd. -GB_PUBLIC GrB_Info GrB_Type_error (const char **error, const GrB_Type type) ; -GB_PUBLIC GrB_Info GrB_UnaryOp_error (const char **error, const GrB_UnaryOp op) ; -GB_PUBLIC GrB_Info GrB_BinaryOp_error (const char **error, const GrB_BinaryOp op) ; -GB_PUBLIC GrB_Info GxB_SelectOp_error (const char **error, const GxB_SelectOp op) ; -GB_PUBLIC GrB_Info GrB_IndexUnaryOp_error (const char **error, const GrB_IndexUnaryOp op) ; -GB_PUBLIC GrB_Info GrB_Monoid_error (const char **error, const GrB_Monoid monoid) ; -GB_PUBLIC GrB_Info GrB_Semiring_error (const char **error, const GrB_Semiring semiring) ; -GB_PUBLIC GrB_Info GrB_Scalar_error (const char **error, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GrB_Vector_error (const char **error, const GrB_Vector v) ; -GB_PUBLIC GrB_Info GrB_Matrix_error (const char **error, const GrB_Matrix A) ; -GB_PUBLIC GrB_Info GrB_Descriptor_error (const char **error, const GrB_Descriptor d) ; +GrB_Info GrB_Type_error (const char **error, const GrB_Type type) ; +GrB_Info GrB_UnaryOp_error (const char **error, const GrB_UnaryOp op) ; +GrB_Info GrB_BinaryOp_error (const char **error, const GrB_BinaryOp op) ; +GrB_Info GxB_SelectOp_error (const char **error, const GxB_SelectOp op) ; +GrB_Info GrB_IndexUnaryOp_error (const char **error, const GrB_IndexUnaryOp op) ; +GrB_Info GrB_Monoid_error (const char **error, const GrB_Monoid monoid) ; +GrB_Info GrB_Semiring_error (const char **error, const GrB_Semiring semiring) ; +GrB_Info GrB_Scalar_error (const char **error, const GrB_Scalar s) ; +GrB_Info GrB_Vector_error (const char **error, const GrB_Vector v) ; +GrB_Info GrB_Matrix_error (const char **error, const GrB_Matrix A) ; +GrB_Info GrB_Descriptor_error (const char **error, const GrB_Descriptor d) ; // GxB_Scalar_error is historical: use GrB_Scalar_error instead -GB_PUBLIC GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar s) ; // GrB_error (error,object) polymorphic function: #if GxB_STDC_VERSION >= 201112L @@ -4852,27 +4714,16 @@ GB_PUBLIC GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar _Generic \ ( \ (object), \ - const GrB_Type : GrB_Type_error , \ GrB_Type : GrB_Type_error , \ - const GrB_UnaryOp : GrB_UnaryOp_error , \ GrB_UnaryOp : GrB_UnaryOp_error , \ - const GrB_BinaryOp : GrB_BinaryOp_error , \ GrB_BinaryOp : GrB_BinaryOp_error , \ - const GxB_SelectOp : GxB_SelectOp_error , \ GxB_SelectOp : GxB_SelectOp_error , \ - const GrB_IndexUnaryOp : GrB_IndexUnaryOp_error , \ GrB_IndexUnaryOp : GrB_IndexUnaryOp_error , \ - const GrB_Monoid : GrB_Monoid_error , \ GrB_Monoid : GrB_Monoid_error , \ - const GrB_Semiring : GrB_Semiring_error , \ GrB_Semiring : GrB_Semiring_error , \ - const GrB_Scalar : GrB_Scalar_error , \ GrB_Scalar : GrB_Scalar_error , \ - const GrB_Vector : GrB_Vector_error , \ GrB_Vector : GrB_Vector_error , \ - const GrB_Matrix : GrB_Matrix_error , \ GrB_Matrix : GrB_Matrix_error , \ - const GrB_Descriptor : GrB_Descriptor_error , \ GrB_Descriptor : GrB_Descriptor_error \ ) \ (error, object) @@ -4882,7 +4733,6 @@ GB_PUBLIC GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar // GrB_mxm, vxm, mxv: matrix multiplication over a semiring //============================================================================== -GB_PUBLIC GrB_Info GrB_mxm // C = accum (C, A*B) ( GrB_Matrix C, // input/output matrix for results @@ -4894,7 +4744,6 @@ GrB_Info GrB_mxm // C = accum (C, A*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_vxm // w' = accum (w, u'*A) ( GrB_Vector w, // input/output vector for results @@ -4906,7 +4755,6 @@ GrB_Info GrB_vxm // w' = accum (w, u'*A) const GrB_Descriptor desc // descriptor for w, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_mxv // w = accum (w, A*u) ( GrB_Vector w, // input/output vector for results @@ -4926,7 +4774,6 @@ GrB_Info GrB_mxv // w = accum (w, A*u) // product, and where pairs of elements in two matrices (or vectors) are // pairwise "multiplied" with C(i,j) = mult (A(i,j),B(i,j)). -GB_PUBLIC GrB_Info GrB_Vector_eWiseMult_Semiring // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results @@ -4938,7 +4785,6 @@ GrB_Info GrB_Vector_eWiseMult_Semiring // w = accum (w, u.*v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseMult_Monoid // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results @@ -4950,7 +4796,6 @@ GrB_Info GrB_Vector_eWiseMult_Monoid // w = accum (w, u.*v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseMult_BinaryOp // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results @@ -4962,7 +4807,6 @@ GrB_Info GrB_Vector_eWiseMult_BinaryOp // w = accum (w, u.*v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseMult_Semiring // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results @@ -4974,7 +4818,6 @@ GrB_Info GrB_Matrix_eWiseMult_Semiring // C = accum (C, A.*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseMult_Monoid // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results @@ -4986,7 +4829,6 @@ GrB_Info GrB_Matrix_eWiseMult_Monoid // C = accum (C, A.*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results @@ -5010,22 +4852,16 @@ GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Matrix_eWiseMult_Semiring , \ GrB_Semiring : GrB_Matrix_eWiseMult_Semiring , \ - const GrB_Monoid : GrB_Matrix_eWiseMult_Monoid , \ GrB_Monoid : GrB_Matrix_eWiseMult_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_eWiseMult_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_eWiseMult_BinaryOp \ ), \ GrB_Vector : \ _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Vector_eWiseMult_Semiring , \ GrB_Semiring : GrB_Vector_eWiseMult_Semiring , \ - const GrB_Monoid : GrB_Vector_eWiseMult_Monoid , \ GrB_Monoid : GrB_Vector_eWiseMult_Monoid , \ - const GrB_BinaryOp : GrB_Vector_eWiseMult_BinaryOp , \ GrB_BinaryOp : GrB_Vector_eWiseMult_BinaryOp \ ) \ ) \ @@ -5039,7 +4875,6 @@ GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) // GrB_eWiseAdd computes C = accum (C, A+B), where pairs of elements in // two matrices (or two vectors) are pairwise "added". -GB_PUBLIC GrB_Info GrB_Vector_eWiseAdd_Semiring // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5051,7 +4886,6 @@ GrB_Info GrB_Vector_eWiseAdd_Semiring // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseAdd_Monoid // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5063,7 +4897,6 @@ GrB_Info GrB_Vector_eWiseAdd_Monoid // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseAdd_BinaryOp // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5075,7 +4908,6 @@ GrB_Info GrB_Vector_eWiseAdd_BinaryOp // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseAdd_Semiring // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5087,7 +4919,6 @@ GrB_Info GrB_Matrix_eWiseAdd_Semiring // C = accum (C, A+B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseAdd_Monoid // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5099,7 +4930,6 @@ GrB_Info GrB_Matrix_eWiseAdd_Monoid // C = accum (C, A+B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5120,22 +4950,16 @@ GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Matrix_eWiseAdd_Semiring , \ GrB_Semiring : GrB_Matrix_eWiseAdd_Semiring , \ - const GrB_Monoid : GrB_Matrix_eWiseAdd_Monoid , \ GrB_Monoid : GrB_Matrix_eWiseAdd_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_eWiseAdd_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_eWiseAdd_BinaryOp \ ), \ GrB_Vector : \ _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Vector_eWiseAdd_Semiring , \ GrB_Semiring : GrB_Vector_eWiseAdd_Semiring , \ - const GrB_Monoid : GrB_Vector_eWiseAdd_Monoid , \ GrB_Monoid : GrB_Vector_eWiseAdd_Monoid , \ - const GrB_BinaryOp : GrB_Vector_eWiseAdd_BinaryOp , \ GrB_BinaryOp : GrB_Vector_eWiseAdd_BinaryOp \ ) \ ) \ @@ -5168,7 +4992,6 @@ GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) // else if B(i,j) is present but not A(i,j) // C(i,j) = alpha + B(i,j) -GB_PUBLIC GrB_Info GxB_Vector_eWiseUnion // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5182,7 +5005,6 @@ GrB_Info GxB_Vector_eWiseUnion // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_eWiseUnion // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5201,9 +5023,7 @@ GrB_Info GxB_Matrix_eWiseUnion // C = accum (C, A+B) _Generic \ ( \ (C), \ - const GrB_Matrix : GxB_Matrix_eWiseUnion , \ GrB_Matrix : GxB_Matrix_eWiseUnion , \ - const GrB_Vector : GxB_Vector_eWiseUnion , \ GrB_Vector : GxB_Vector_eWiseUnion \ ) \ (C, Mask, accum, op, A, alpha, B, beta, desc) @@ -5219,7 +5039,7 @@ GrB_Info GxB_Matrix_eWiseUnion // C = accum (C, A+B) // To extract all rows of a matrix or vector, as in A (:,J), use I=GrB_ALL as // the input argument. For all columns of a matrix, use J=GrB_ALL. -GB_PUBLIC const uint64_t *GrB_ALL ; +GB_GLOBAL const uint64_t *GrB_ALL ; // To extract a range of rows and columns, I and J can be a list of 2 or 3 // indices that defines a range (begin:end) or a strided range (begin:inc:end). @@ -5253,7 +5073,6 @@ GB_PUBLIC const uint64_t *GrB_ALL ; // I [GxB_INC ] = 2 ; // the magnitude of the increment // I [GxB_END ] = 1 ; // the end of the sequence -GB_PUBLIC GrB_Info GrB_Vector_extract // w = accum (w, u(I)) ( GrB_Vector w, // input/output vector for results @@ -5265,7 +5084,6 @@ GrB_Info GrB_Vector_extract // w = accum (w, u(I)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extract // C = accum (C, A(I,J)) ( GrB_Matrix C, // input/output matrix for results @@ -5279,7 +5097,6 @@ GrB_Info GrB_Matrix_extract // C = accum (C, A(I,J)) const GrB_Descriptor desc // descriptor for C, Mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) ( GrB_Vector w, // input/output matrix for results @@ -5311,9 +5128,7 @@ GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) _Generic \ ( \ (arg4), \ - const GrB_Vector : GrB_Vector_extract , \ GrB_Vector : GrB_Vector_extract , \ - const GrB_Matrix : GrB_Col_extract , \ GrB_Matrix : GrB_Col_extract \ ), \ GrB_Matrix : GrB_Matrix_extract \ @@ -5368,7 +5183,6 @@ GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) // GxB_Col_subassign C(I,j) += u m same size as column vector u. // u is |I|-by-1, j is a scalar. -GB_PUBLIC GrB_Info GxB_Vector_subassign // w(I) = accum (w(I),u) ( GrB_Vector w, // input/output matrix for results @@ -5380,7 +5194,6 @@ GrB_Info GxB_Vector_subassign // w(I) = accum (w(I),u) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign // C(I,J) = accum (C(I,J),A) ( GrB_Matrix C, // input/output matrix for results @@ -5394,7 +5207,6 @@ GrB_Info GxB_Matrix_subassign // C(I,J) = accum (C(I,J),A) const GrB_Descriptor desc // descriptor for C(I,J), Mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Col_subassign // C(I,j) = accum (C(I,j),u) ( GrB_Matrix C, // input/output matrix for results @@ -5407,7 +5219,6 @@ GrB_Info GxB_Col_subassign // C(I,j) = accum (C(I,j),u) const GrB_Descriptor desc // descriptor for C(I,j) and mask ) ; -GB_PUBLIC GrB_Info GxB_Row_subassign // C(i,J) = accum (C(i,J),u') ( GrB_Matrix C, // input/output matrix for results @@ -5428,7 +5239,6 @@ GrB_Info GxB_Row_subassign // C(i,J) = accum (C(i,J),u') // scalar x is implicitly expanded into a vector u of size ni-by-1, with each // entry in u equal to x, and then w(I) = accum(w(I),u) is done. -GB_PUBLIC GrB_Info GxB_Vector_subassign_BOOL // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5440,7 +5250,6 @@ GrB_Info GxB_Vector_subassign_BOOL // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5452,7 +5261,6 @@ GrB_Info GxB_Vector_subassign_INT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5464,7 +5272,6 @@ GrB_Info GxB_Vector_subassign_UINT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5476,7 +5283,6 @@ GrB_Info GxB_Vector_subassign_INT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5488,7 +5294,6 @@ GrB_Info GxB_Vector_subassign_UINT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5500,7 +5305,6 @@ GrB_Info GxB_Vector_subassign_INT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5512,7 +5316,6 @@ GrB_Info GxB_Vector_subassign_UINT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5524,7 +5327,6 @@ GrB_Info GxB_Vector_subassign_INT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5536,7 +5338,6 @@ GrB_Info GxB_Vector_subassign_UINT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FP32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5548,7 +5349,6 @@ GrB_Info GxB_Vector_subassign_FP32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FP64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5560,7 +5360,6 @@ GrB_Info GxB_Vector_subassign_FP64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FC32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5572,7 +5371,6 @@ GrB_Info GxB_Vector_subassign_FC32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FC64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5584,7 +5382,6 @@ GrB_Info GxB_Vector_subassign_FC64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UDT // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5596,7 +5393,6 @@ GrB_Info GxB_Vector_subassign_UDT // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_Scalar // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5616,7 +5412,6 @@ GrB_Info GxB_Vector_subassign_Scalar // w(I) = accum (w(I),x) // scalar x is implicitly expanded into a matrix A of size ni-by-nj, with each // entry in A equal to x, and then C(I,J) = accum(C(I,J),A) is done. -GB_PUBLIC GrB_Info GxB_Matrix_subassign_BOOL // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5630,7 +5425,6 @@ GrB_Info GxB_Matrix_subassign_BOOL // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5644,7 +5438,6 @@ GrB_Info GxB_Matrix_subassign_INT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5658,7 +5451,6 @@ GrB_Info GxB_Matrix_subassign_UINT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5672,7 +5464,6 @@ GrB_Info GxB_Matrix_subassign_INT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5686,7 +5477,6 @@ GrB_Info GxB_Matrix_subassign_UINT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5700,7 +5490,6 @@ GrB_Info GxB_Matrix_subassign_INT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5714,7 +5503,6 @@ GrB_Info GxB_Matrix_subassign_UINT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5728,7 +5516,6 @@ GrB_Info GxB_Matrix_subassign_INT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5742,7 +5529,6 @@ GrB_Info GxB_Matrix_subassign_UINT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FP32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5756,7 +5542,6 @@ GrB_Info GxB_Matrix_subassign_FP32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FP64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5770,7 +5555,6 @@ GrB_Info GxB_Matrix_subassign_FP64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FC32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5784,7 +5568,6 @@ GrB_Info GxB_Matrix_subassign_FC32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FC64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5798,7 +5581,6 @@ GrB_Info GxB_Matrix_subassign_FC64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5812,7 +5594,6 @@ GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5849,26 +5630,16 @@ GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),x) _Generic \ ( \ (arg4), \ - GB_CASES (, GxB, Vector_subassign) , \ - const GrB_Scalar : GxB_Vector_subassign_Scalar, \ - GrB_Scalar : GxB_Vector_subassign_Scalar, \ + GB_CASES (GxB, Vector_subassign) , \ + GrB_Scalar : GxB_Vector_subassign_Scalar, \ default: GxB_Vector_subassign \ ), \ default: \ _Generic \ ( \ (arg4), \ - GB_CASES (, GxB, Matrix_subassign) , \ - const GrB_Scalar : GxB_Matrix_subassign_Scalar, \ - GrB_Scalar : GxB_Matrix_subassign_Scalar, \ - const GrB_Vector : \ - _Generic \ - ( \ - (arg5), \ - const GrB_Index *: GxB_Col_subassign , \ - GrB_Index *: GxB_Col_subassign , \ - default: GxB_Row_subassign \ - ), \ + GB_CASES (GxB, Matrix_subassign) , \ + GrB_Scalar : GxB_Matrix_subassign_Scalar, \ GrB_Vector : \ _Generic \ ( \ @@ -5890,7 +5661,6 @@ GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),x) // Assign entries in a matrix or vector; C(I,J) = A. // Each of these can be used with their generic name, GrB_assign. -GB_PUBLIC GrB_Info GrB_Vector_assign // w(I) = accum (w(I),u) ( GrB_Vector w, // input/output matrix for results @@ -5902,7 +5672,6 @@ GrB_Info GrB_Vector_assign // w(I) = accum (w(I),u) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign // C(I,J) = accum (C(I,J),A) ( GrB_Matrix C, // input/output matrix for results @@ -5916,7 +5685,6 @@ GrB_Info GrB_Matrix_assign // C(I,J) = accum (C(I,J),A) const GrB_Descriptor desc // descriptor for C, Mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Col_assign // C(I,j) = accum (C(I,j),u) ( GrB_Matrix C, // input/output matrix for results @@ -5929,7 +5697,6 @@ GrB_Info GrB_Col_assign // C(I,j) = accum (C(I,j),u) const GrB_Descriptor desc // descriptor for C(:,j) and mask ) ; -GB_PUBLIC GrB_Info GrB_Row_assign // C(i,J) = accum (C(i,J),u') ( GrB_Matrix C, // input/output matrix for results @@ -5950,7 +5717,6 @@ GrB_Info GrB_Row_assign // C(i,J) = accum (C(i,J),u') // scalar x is implicitly expanded into a vector u of size ni-by-1, with each // entry in u equal to x, and then w(I) = accum(w(I),u) is done. -GB_PUBLIC GrB_Info GrB_Vector_assign_BOOL // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5962,7 +5728,6 @@ GrB_Info GrB_Vector_assign_BOOL // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5974,7 +5739,6 @@ GrB_Info GrB_Vector_assign_INT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5986,7 +5750,6 @@ GrB_Info GrB_Vector_assign_UINT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5998,7 +5761,6 @@ GrB_Info GrB_Vector_assign_INT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6010,7 +5772,6 @@ GrB_Info GrB_Vector_assign_UINT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6022,7 +5783,6 @@ GrB_Info GrB_Vector_assign_INT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6034,7 +5794,6 @@ GrB_Info GrB_Vector_assign_UINT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6046,7 +5805,6 @@ GrB_Info GrB_Vector_assign_INT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6058,7 +5816,6 @@ GrB_Info GrB_Vector_assign_UINT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_FP32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6070,7 +5827,6 @@ GrB_Info GrB_Vector_assign_FP32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_FP64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6082,7 +5838,6 @@ GrB_Info GrB_Vector_assign_FP64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_assign_FC32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6094,7 +5849,6 @@ GrB_Info GxB_Vector_assign_FC32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_assign_FC64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6106,7 +5860,6 @@ GrB_Info GxB_Vector_assign_FC64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UDT // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6118,7 +5871,6 @@ GrB_Info GrB_Vector_assign_UDT // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_Scalar // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6138,7 +5890,6 @@ GrB_Info GrB_Vector_assign_Scalar // w(I) = accum (w(I),x) // scalar x is implicitly expanded into a matrix A of size ni-by-nj, with each // entry in A equal to x, and then C(I,J) = accum(C(I,J),A) is done. -GB_PUBLIC GrB_Info GrB_Matrix_assign_BOOL // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6152,7 +5903,6 @@ GrB_Info GrB_Matrix_assign_BOOL // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6166,7 +5916,6 @@ GrB_Info GrB_Matrix_assign_INT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6180,7 +5929,6 @@ GrB_Info GrB_Matrix_assign_UINT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6194,7 +5942,6 @@ GrB_Info GrB_Matrix_assign_INT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6208,7 +5955,6 @@ GrB_Info GrB_Matrix_assign_UINT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6222,7 +5968,6 @@ GrB_Info GrB_Matrix_assign_INT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6236,7 +5981,6 @@ GrB_Info GrB_Matrix_assign_UINT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6250,7 +5994,6 @@ GrB_Info GrB_Matrix_assign_INT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6264,7 +6007,6 @@ GrB_Info GrB_Matrix_assign_UINT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_FP32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6278,7 +6020,6 @@ GrB_Info GrB_Matrix_assign_FP32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_FP64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6292,7 +6033,6 @@ GrB_Info GrB_Matrix_assign_FP64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_assign_FC32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6306,7 +6046,6 @@ GrB_Info GxB_Matrix_assign_FC32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_assign_FC64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6320,7 +6059,6 @@ GrB_Info GxB_Matrix_assign_FC64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6334,7 +6072,6 @@ GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6371,26 +6108,16 @@ GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),x) _Generic \ ( \ (arg4), \ - GB_CASES (, GrB, Vector_assign) , \ - const GrB_Scalar : GrB_Vector_assign_Scalar , \ - GrB_Scalar : GrB_Vector_assign_Scalar , \ + GB_CASES (GrB, Vector_assign) , \ + GrB_Scalar : GrB_Vector_assign_Scalar , \ default: GrB_Vector_assign \ ), \ default: \ _Generic \ ( \ (arg4), \ - GB_CASES (, GrB, Matrix_assign) , \ - const GrB_Scalar : GrB_Matrix_assign_Scalar , \ - GrB_Scalar : GrB_Matrix_assign_Scalar , \ - const GrB_Vector : \ - _Generic \ - ( \ - (arg5), \ - const GrB_Index *: GrB_Col_assign , \ - GrB_Index *: GrB_Col_assign , \ - default: GrB_Row_assign \ - ), \ + GB_CASES (GrB, Matrix_assign) , \ + GrB_Scalar : GrB_Matrix_assign_Scalar , \ GrB_Vector : \ _Generic \ ( \ @@ -6412,7 +6139,6 @@ GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),x) // Apply a unary, index_unary, or binary operator to entries in a matrix or // vector, C = accum (C, op (A)). -GB_PUBLIC GrB_Info GrB_Vector_apply // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6423,7 +6149,6 @@ GrB_Info GrB_Vector_apply // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') ( GrB_Matrix C, // input/output matrix for results @@ -6441,7 +6166,6 @@ GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') // Apply a binary operator to the entries in a vector, binding the first // input to a scalar x, w = accum (w, op (x,u)). -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_Scalar // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6454,7 +6178,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_Scalar // w = accum (w, op(x,u)) ) ; // historical: identical to GxB_Vector_apply_BinaryOp1st -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp1st // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6466,7 +6189,6 @@ GrB_Info GxB_Vector_apply_BinaryOp1st // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_BOOL // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6478,7 +6200,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_BOOL // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT8 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6490,7 +6211,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT8 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT16 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6502,7 +6222,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT16 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6514,7 +6233,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6526,7 +6244,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT8 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6538,7 +6255,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT8 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT16 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6550,7 +6266,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT16 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6562,7 +6277,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6574,7 +6288,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_FP32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6586,7 +6299,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_FP32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_FP64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6598,7 +6310,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_FP64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp1st_FC32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6610,7 +6321,6 @@ GrB_Info GxB_Vector_apply_BinaryOp1st_FC32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp1st_FC64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6622,7 +6332,6 @@ GrB_Info GxB_Vector_apply_BinaryOp1st_FC64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UDT // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6641,7 +6350,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UDT // w = accum (w, op(x,u)) // Apply a binary operator to the entries in a vector, binding the second // input to a scalar y, w = accum (w, op (u,y)). -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_Scalar // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6654,7 +6362,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_Scalar // w = accum (w, op(u,y)) ) ; // historical: identical to GrB_Vector_apply_BinaryOp2nd_Scalar -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp2nd // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6666,7 +6373,6 @@ GrB_Info GxB_Vector_apply_BinaryOp2nd // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_BOOL // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6678,7 +6384,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_BOOL // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT8 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6690,7 +6395,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT8 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT16 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6702,7 +6406,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT16 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6714,7 +6417,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6726,7 +6428,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT8 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6738,7 +6439,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT8 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT16 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6750,7 +6450,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT16 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6762,7 +6461,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6774,7 +6472,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_FP32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6786,7 +6483,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_FP32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_FP64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6798,7 +6494,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_FP64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp2nd_FC32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6810,7 +6505,6 @@ GrB_Info GxB_Vector_apply_BinaryOp2nd_FC32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp2nd_FC64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6822,7 +6516,6 @@ GrB_Info GxB_Vector_apply_BinaryOp2nd_FC64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UDT // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6840,7 +6533,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UDT // w = accum (w, op(u,y)) // Apply a GrB_IndexUnaryOp to the entries in a vector -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_Scalar // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6852,7 +6544,6 @@ GrB_Info GrB_Vector_apply_IndexOp_Scalar // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_BOOL // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6864,7 +6555,6 @@ GrB_Info GrB_Vector_apply_IndexOp_BOOL // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6876,7 +6566,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6888,7 +6577,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6900,7 +6588,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6912,7 +6599,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6924,7 +6610,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6936,7 +6621,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6948,7 +6632,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6960,7 +6643,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_FP32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6972,7 +6654,6 @@ GrB_Info GrB_Vector_apply_IndexOp_FP32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_FP64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6984,7 +6665,6 @@ GrB_Info GrB_Vector_apply_IndexOp_FP64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_IndexOp_FC32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6996,7 +6676,6 @@ GrB_Info GxB_Vector_apply_IndexOp_FC32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_IndexOp_FC64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7008,7 +6687,6 @@ GrB_Info GxB_Vector_apply_IndexOp_FC64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UDT // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7027,7 +6705,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UDT // w = accum (w, op(u)) // Apply a binary operator to the entries in a matrix, binding the first input // to a scalar x, C = accum (C, op (x,A)), or op(x,A'). -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_Scalar // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7040,7 +6717,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_Scalar // C=accum(C,op(x,A)) ) ; // historical: identical to GrB_Matrix_apply_BinaryOp1st_Scalar -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp1st // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7052,7 +6728,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp1st // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_BOOL // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7064,7 +6739,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_BOOL // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT8 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7076,7 +6750,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT8 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT16 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7088,7 +6761,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT16 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7100,7 +6772,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7112,7 +6783,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT8 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7124,7 +6794,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT8 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT16 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7136,7 +6805,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT16 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7148,7 +6816,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7160,7 +6827,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_FP32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7172,7 +6838,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_FP32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_FP64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7184,7 +6849,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_FP64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp1st_FC32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7196,7 +6860,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp1st_FC32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp1st_FC64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7208,7 +6871,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp1st_FC64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UDT // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7227,7 +6889,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UDT // C=accum(C,op(x,A)) // Apply a binary operator to the entries in a matrix, binding the second input // to a scalar y, C = accum (C, op (A,y)), or op(A',y). -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_Scalar // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7240,7 +6901,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_Scalar // C=accum(C,op(A,y)) ) ; // historical: identical to GrB_Matrix_apply_BinaryOp2nd_Scalar -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp2nd // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7252,7 +6912,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp2nd // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_BOOL // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7264,7 +6923,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_BOOL // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT8 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7276,7 +6934,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT8 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT16 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7288,7 +6945,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT16 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7300,7 +6956,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7312,7 +6967,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT8 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7324,7 +6978,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT8 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT16 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7336,7 +6989,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT16 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7348,7 +7000,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7360,7 +7011,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7372,7 +7022,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7384,7 +7033,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7396,7 +7044,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7408,7 +7055,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UDT // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7426,7 +7072,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UDT // C=accum(C,op(A,y)) // Apply a GrB_IndexUnaryOp to the entries in a matrix. -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_Scalar // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7438,7 +7083,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_Scalar // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_BOOL // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7450,7 +7094,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_BOOL // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7462,7 +7105,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7474,7 +7116,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7486,7 +7127,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7498,7 +7138,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7510,7 +7149,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7522,7 +7160,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7534,7 +7171,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7546,7 +7182,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_FP32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7558,7 +7193,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_FP32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_FP64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7570,7 +7204,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_FP64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_IndexOp_FC32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7582,7 +7215,6 @@ GrB_Info GxB_Matrix_apply_IndexOp_FC32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_IndexOp_FC64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7594,7 +7226,6 @@ GrB_Info GxB_Matrix_apply_IndexOp_FC64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7632,14 +7263,13 @@ GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) _Generic \ ( \ (x), \ - const GrB_Scalar: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp1st_Scalar), \ - GrB_Scalar: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp1st_Scalar), \ - GB_CASES (, GrB, GB_CONCAT ( kind, _apply_BinaryOp1st,, )) , \ + GrB_Scalar: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp1st_Scalar), \ + GB_CASES (GrB, GB_CONCAT ( kind, _apply_BinaryOp1st,, )) , \ default: \ _Generic \ ( \ (y), \ - GB_CASES (, GrB, GB_CONCAT ( kind , _apply_BinaryOp2nd,, )), \ + GB_CASES (GrB, GB_CONCAT ( kind , _apply_BinaryOp2nd,, )), \ default: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp2nd_Scalar) \ ) \ ) @@ -7648,7 +7278,7 @@ GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) _Generic \ ( \ (y), \ - GB_CASES (, GrB, GB_CONCAT ( kind, _apply_IndexOp,, )), \ + GB_CASES (GrB, GB_CONCAT ( kind, _apply_IndexOp,, )), \ default: GB_CONCAT ( GrB, _, kind, _apply_IndexOp_Scalar) \ ) @@ -7684,7 +7314,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) // vector select using an IndexUnaryOp //------------------------------------------- -GB_PUBLIC GrB_Info GrB_Vector_select_Scalar // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7696,7 +7325,6 @@ GrB_Info GrB_Vector_select_Scalar // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_BOOL // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7708,7 +7336,6 @@ GrB_Info GrB_Vector_select_BOOL // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7720,7 +7347,6 @@ GrB_Info GrB_Vector_select_INT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7732,7 +7358,6 @@ GrB_Info GrB_Vector_select_INT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7744,7 +7369,6 @@ GrB_Info GrB_Vector_select_INT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7756,7 +7380,6 @@ GrB_Info GrB_Vector_select_INT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7768,7 +7391,6 @@ GrB_Info GrB_Vector_select_UINT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7780,7 +7402,6 @@ GrB_Info GrB_Vector_select_UINT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7792,7 +7413,6 @@ GrB_Info GrB_Vector_select_UINT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7804,7 +7424,6 @@ GrB_Info GrB_Vector_select_UINT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_FP32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7816,7 +7435,6 @@ GrB_Info GrB_Vector_select_FP32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_FP64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7828,7 +7446,6 @@ GrB_Info GrB_Vector_select_FP64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_select_FC32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7840,7 +7457,6 @@ GrB_Info GxB_Vector_select_FC32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_select_FC64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7852,7 +7468,6 @@ GrB_Info GxB_Vector_select_FC64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UDT // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7868,7 +7483,6 @@ GrB_Info GrB_Vector_select_UDT // w = accum (w, op(u)) // matrix select using an IndexUnaryOp //------------------------------------------- -GB_PUBLIC GrB_Info GrB_Matrix_select_Scalar // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7880,7 +7494,6 @@ GrB_Info GrB_Matrix_select_Scalar // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_BOOL // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7892,7 +7505,6 @@ GrB_Info GrB_Matrix_select_BOOL // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7904,7 +7516,6 @@ GrB_Info GrB_Matrix_select_INT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7916,7 +7527,6 @@ GrB_Info GrB_Matrix_select_INT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7928,7 +7538,6 @@ GrB_Info GrB_Matrix_select_INT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7940,7 +7549,6 @@ GrB_Info GrB_Matrix_select_INT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7952,7 +7560,6 @@ GrB_Info GrB_Matrix_select_UINT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7964,7 +7571,6 @@ GrB_Info GrB_Matrix_select_UINT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7976,7 +7582,6 @@ GrB_Info GrB_Matrix_select_UINT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7988,7 +7593,6 @@ GrB_Info GrB_Matrix_select_UINT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_FP32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8000,7 +7604,6 @@ GrB_Info GrB_Matrix_select_FP32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_FP64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8012,7 +7615,6 @@ GrB_Info GrB_Matrix_select_FP64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_select_FC32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8024,7 +7626,6 @@ GrB_Info GxB_Matrix_select_FC32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_select_FC64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8036,7 +7637,6 @@ GrB_Info GxB_Matrix_select_FC64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UDT // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8063,14 +7663,14 @@ GrB_Info GrB_Matrix_select_UDT // C=accum(C,op(A)) _Generic \ ( \ (y), \ - GB_CASES (, GrB, Vector_select), \ + GB_CASES (GrB, Vector_select), \ default: GrB_Vector_select_Scalar \ ), \ GrB_Matrix : \ _Generic \ ( \ (y), \ - GB_CASES (, GrB, Matrix_select), \ + GB_CASES (GrB, Matrix_select), \ default: GrB_Matrix_select_Scalar \ ) \ ) \ @@ -8083,7 +7683,6 @@ GrB_Info GrB_Matrix_select_UDT // C=accum(C,op(A)) // GrB_select and with the GrB_IndexUnaryOp operators should be used instead. -GB_PUBLIC GrB_Info GxB_Vector_select // w = accum (w, op(u,k)) ( GrB_Vector w, // input/output vector for results @@ -8095,7 +7694,6 @@ GrB_Info GxB_Vector_select // w = accum (w, op(u,k)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_select // C = accum (C, op(A,k)) or op(A',k) ( GrB_Matrix C, // input/output matrix for results @@ -8138,7 +7736,6 @@ GrB_Info GxB_Matrix_select // C = accum (C, op(A,k)) or op(A',k) // LOR, LAND, LXOR, EQ BOOL // BOR, BAND, BXOR, BXNOR UINT* -GB_PUBLIC GrB_Info GrB_Matrix_reduce_Monoid // w = accum (w,reduce(A)) ( GrB_Vector w, // input/output vector for results @@ -8149,7 +7746,6 @@ GrB_Info GrB_Matrix_reduce_Monoid // w = accum (w,reduce(A)) const GrB_Descriptor desc // descriptor for w, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_BinaryOp // w = accum (w,reduce(A)) ( GrB_Vector w, // input/output vector for results @@ -8166,7 +7762,6 @@ GrB_Info GrB_Matrix_reduce_BinaryOp // w = accum (w,reduce(A)) // Reduce entries in a vector to a scalar, c = accum (c, reduce_to_scalar(u)) -GB_PUBLIC GrB_Info GrB_Vector_reduce_BOOL // c = accum (c, reduce_to_scalar (u)) ( bool *c, // result scalar @@ -8176,7 +7771,6 @@ GrB_Info GrB_Vector_reduce_BOOL // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT8 // c = accum (c, reduce_to_scalar (u)) ( int8_t *c, // result scalar @@ -8186,7 +7780,6 @@ GrB_Info GrB_Vector_reduce_INT8 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT8 // c = accum (c, reduce_to_scalar (u)) ( uint8_t *c, // result scalar @@ -8196,7 +7789,6 @@ GrB_Info GrB_Vector_reduce_UINT8 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT16 // c = accum (c, reduce_to_scalar (u)) ( int16_t *c, // result scalar @@ -8206,7 +7798,6 @@ GrB_Info GrB_Vector_reduce_INT16 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT16 // c = accum (c, reduce_to_scalar (u)) ( uint16_t *c, // result scalar @@ -8216,7 +7807,6 @@ GrB_Info GrB_Vector_reduce_UINT16 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT32 // c = accum (c, reduce_to_scalar (u)) ( int32_t *c, // result scalar @@ -8226,7 +7816,6 @@ GrB_Info GrB_Vector_reduce_INT32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT32 // c = accum (c, reduce_to_scalar (u)) ( uint32_t *c, // result scalar @@ -8236,7 +7825,6 @@ GrB_Info GrB_Vector_reduce_UINT32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT64 // c = accum (c, reduce_to_scalar (u)) ( int64_t *c, // result scalar @@ -8246,7 +7834,6 @@ GrB_Info GrB_Vector_reduce_INT64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT64 // c = accum (c, reduce_to_scalar (u)) ( uint64_t *c, // result scalar @@ -8256,7 +7843,6 @@ GrB_Info GrB_Vector_reduce_UINT64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_FP32 // c = accum (c, reduce_to_scalar (u)) ( float *c, // result scalar @@ -8266,7 +7852,6 @@ GrB_Info GrB_Vector_reduce_FP32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_FP64 // c = accum (c, reduce_to_scalar (u)) ( double *c, // result scalar @@ -8276,7 +7861,6 @@ GrB_Info GrB_Vector_reduce_FP64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_reduce_FC32 // c = accum (c, reduce_to_scalar (u)) ( GxB_FC32_t *c, // result scalar @@ -8286,7 +7870,6 @@ GrB_Info GxB_Vector_reduce_FC32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_reduce_FC64 // c = accum (c, reduce_to_scalar (u)) ( GxB_FC64_t *c, // result scalar @@ -8296,7 +7879,6 @@ GrB_Info GxB_Vector_reduce_FC64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UDT // c = accum (c, reduce_to_scalar (u)) ( void *c, // result scalar @@ -8306,7 +7888,6 @@ GrB_Info GrB_Vector_reduce_UDT // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(u)) ( GrB_Scalar c, // result scalar @@ -8316,7 +7897,6 @@ GrB_Info GrB_Vector_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_BinaryOp_Scalar ( GrB_Scalar c, // result scalar @@ -8332,7 +7912,6 @@ GrB_Info GrB_Vector_reduce_BinaryOp_Scalar // Reduce entries in a matrix to a scalar, c = accum (c, reduce_to_scalar(A)) -GB_PUBLIC GrB_Info GrB_Matrix_reduce_BOOL // c = accum (c, reduce_to_scalar (A)) ( bool *c, // result scalar @@ -8342,7 +7921,6 @@ GrB_Info GrB_Matrix_reduce_BOOL // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT8 // c = accum (c, reduce_to_scalar (A)) ( int8_t *c, // result scalar @@ -8352,7 +7930,6 @@ GrB_Info GrB_Matrix_reduce_INT8 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT8 // c = accum (c, reduce_to_scalar (A)) ( uint8_t *c, // result scalar @@ -8362,7 +7939,6 @@ GrB_Info GrB_Matrix_reduce_UINT8 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT16 // c = accum (c, reduce_to_scalar (A)) ( int16_t *c, // result scalar @@ -8372,7 +7948,6 @@ GrB_Info GrB_Matrix_reduce_INT16 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT16 // c = accum (c, reduce_to_scalar (A)) ( uint16_t *c, // result scalar @@ -8382,7 +7957,6 @@ GrB_Info GrB_Matrix_reduce_UINT16 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT32 // c = accum (c, reduce_to_scalar (A)) ( int32_t *c, // result scalar @@ -8392,7 +7966,6 @@ GrB_Info GrB_Matrix_reduce_INT32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT32 // c = accum (c, reduce_to_scalar (A)) ( uint32_t *c, // result scalar @@ -8402,7 +7975,6 @@ GrB_Info GrB_Matrix_reduce_UINT32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT64 // c = accum (c, reduce_to_scalar (A)) ( int64_t *c, // result scalar @@ -8412,7 +7984,6 @@ GrB_Info GrB_Matrix_reduce_INT64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT64 // c = accum (c, reduce_to_scalar (A)) ( uint64_t *c, // result scalar @@ -8422,7 +7993,6 @@ GrB_Info GrB_Matrix_reduce_UINT64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_FP32 // c = accum (c, reduce_to_scalar (A)) ( float *c, // result scalar @@ -8432,7 +8002,6 @@ GrB_Info GrB_Matrix_reduce_FP32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_FP64 // c = accum (c, reduce_to_scalar (A)) ( double *c, // result scalar @@ -8442,7 +8011,6 @@ GrB_Info GrB_Matrix_reduce_FP64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_reduce_FC32 // c = accum (c, reduce_to_scalar (A)) ( GxB_FC32_t *c, // result scalar @@ -8452,7 +8020,6 @@ GrB_Info GxB_Matrix_reduce_FC32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_reduce_FC64 // c = accum (c, reduce_to_scalar (A)) ( GxB_FC64_t *c, // result scalar @@ -8462,7 +8029,6 @@ GrB_Info GxB_Matrix_reduce_FC64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UDT // c = accum (c, reduce_to_scalar (A)) ( void *c, // result scalar @@ -8472,7 +8038,6 @@ GrB_Info GrB_Matrix_reduce_UDT // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(A)) ( GrB_Scalar c, // result scalar @@ -8482,7 +8047,6 @@ GrB_Info GrB_Matrix_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar ( GrB_Scalar S, // result scalar @@ -8516,14 +8080,12 @@ GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar _Generic \ ( \ (c), \ - GB_CASES (*, GrB, GB_CONCAT ( kind, _reduce,, )), \ + GB_PCASES (GrB, GB_CONCAT ( kind, _reduce,, )), \ default: \ _Generic \ ( \ (op), \ - const GrB_BinaryOp : \ - GB_CONCAT (GrB,_,kind,_reduce_BinaryOp_Scalar),\ - GrB_BinaryOp : \ + GrB_BinaryOp : \ GB_CONCAT (GrB,_,kind,_reduce_BinaryOp_Scalar),\ default: GB_CONCAT (GrB,_,kind,_reduce_Monoid_Scalar) \ ) \ @@ -8533,13 +8095,9 @@ GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar _Generic \ ( \ (arg4), \ - const GrB_Vector : GB_REDUCE_TO_SCALAR (Vector, arg1, arg3), \ GrB_Vector : GB_REDUCE_TO_SCALAR (Vector, arg1, arg3), \ - const GrB_Matrix : GB_REDUCE_TO_SCALAR (Matrix, arg1, arg3), \ GrB_Matrix : GB_REDUCE_TO_SCALAR (Matrix, arg1, arg3), \ - const GrB_Monoid : GrB_Matrix_reduce_Monoid , \ GrB_Monoid : GrB_Matrix_reduce_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp \ ) \ (arg1, arg2, arg3, arg4, __VA_ARGS__) @@ -8549,7 +8107,6 @@ GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar // GrB_transpose: matrix transpose //============================================================================== -GB_PUBLIC GrB_Info GrB_transpose // C = accum (C, A') ( GrB_Matrix C, // input/output matrix for results @@ -8564,7 +8121,6 @@ GrB_Info GrB_transpose // C = accum (C, A') //============================================================================== // GxB_kron is historical; use GrB_kronecker instead -GB_PUBLIC GrB_Info GxB_kron // C = accum(C,kron(A,B)) (historical) ( GrB_Matrix C, // input/output matrix for results @@ -8576,7 +8132,6 @@ GrB_Info GxB_kron // C = accum(C,kron(A,B)) (historical) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_kronecker_BinaryOp // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results @@ -8588,7 +8143,6 @@ GrB_Info GrB_Matrix_kronecker_BinaryOp // C = accum (C, kron(A,B)) const GrB_Descriptor desc // descriptor for C, M, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_kronecker_Monoid // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results @@ -8600,7 +8154,6 @@ GrB_Info GrB_Matrix_kronecker_Monoid // C = accum (C, kron(A,B)) const GrB_Descriptor desc // descriptor for C, M, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results @@ -8617,11 +8170,8 @@ GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Matrix_kronecker_Semiring , \ GrB_Semiring : GrB_Matrix_kronecker_Semiring , \ - const GrB_Monoid : GrB_Matrix_kronecker_Monoid , \ GrB_Monoid : GrB_Matrix_kronecker_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_kronecker_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_kronecker_BinaryOp \ ) \ (C, Mask, accum, op, A, B, desc) @@ -8632,7 +8182,7 @@ GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) // GrB_Monoid: built-in monoids //============================================================================== -GB_PUBLIC GrB_Monoid +GB_GLOBAL GrB_Monoid //-------------------------------------------------------------------------- // 10 MIN monoids: (not for complex types) @@ -8909,7 +8459,7 @@ GB_PUBLIC GrB_Monoid // identical, as are FIRSTJ1 and SECONDI1. These semirings still appear as // predefined, for convenience. -GB_PUBLIC GrB_Semiring +GB_GLOBAL GrB_Semiring //------------------------------------------------------------------------------ // 1000 non-Boolean semirings where all types are the same, given by suffix _T @@ -9402,7 +8952,7 @@ GB_PUBLIC GrB_Semiring // GxB_* semirings corresponding to the equivalent GrB_* semiring are // historical. -GB_PUBLIC GrB_Semiring +GB_GLOBAL GrB_Semiring //-------------------------------------------------------------------------- // 20 semirings with PLUS monoids @@ -9576,7 +9126,6 @@ GB_PUBLIC GrB_Semiring // If the dimensions decrease, entries that fall outside the resized matrix or // vector are deleted. -GB_PUBLIC GrB_Info GrB_Matrix_resize // change the size of a matrix ( GrB_Matrix C, // matrix to modify @@ -9584,7 +9133,6 @@ GrB_Info GrB_Matrix_resize // change the size of a matrix GrB_Index ncols_new // new number of columns in matrix ) ; -GB_PUBLIC GrB_Info GrB_Vector_resize // change the size of a vector ( GrB_Vector w, // vector to modify @@ -9592,7 +9140,6 @@ GrB_Info GrB_Vector_resize // change the size of a vector ) ; // GxB_*_resize are identical to the GrB_*resize methods above -GB_PUBLIC GrB_Info GxB_Matrix_resize // change the size of a matrix (historical) ( GrB_Matrix C, // matrix to modify @@ -9600,7 +9147,6 @@ GrB_Info GxB_Matrix_resize // change the size of a matrix (historical) GrB_Index ncols_new // new number of columns in matrix ) ; -GB_PUBLIC GrB_Info GxB_Vector_resize // change the size of a vector (historical) ( GrB_Vector w, // vector to modify @@ -9689,7 +9235,6 @@ typedef enum } GxB_Print_Level ; -GB_PUBLIC GrB_Info GxB_Type_fprint // print and check a GrB_Type ( GrB_Type type, // object to print and check @@ -9698,7 +9243,6 @@ GrB_Info GxB_Type_fprint // print and check a GrB_Type FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_UnaryOp_fprint // print and check a GrB_UnaryOp ( GrB_UnaryOp unaryop, // object to print and check @@ -9707,7 +9251,6 @@ GrB_Info GxB_UnaryOp_fprint // print and check a GrB_UnaryOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_fprint // print and check a GrB_BinaryOp ( GrB_BinaryOp binaryop, // object to print and check @@ -9716,7 +9259,6 @@ GrB_Info GxB_BinaryOp_fprint // print and check a GrB_BinaryOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_fprint // print and check a GrB_IndexUnaryOp ( GrB_IndexUnaryOp op, // object to print and check @@ -9725,7 +9267,6 @@ GrB_Info GxB_IndexUnaryOp_fprint // print and check a GrB_IndexUnaryOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_SelectOp_fprint // print and check a GxB_SelectOp ( GxB_SelectOp selectop, // object to print and check @@ -9734,7 +9275,6 @@ GrB_Info GxB_SelectOp_fprint // print and check a GxB_SelectOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Monoid_fprint // print and check a GrB_Monoid ( GrB_Monoid monoid, // object to print and check @@ -9743,7 +9283,6 @@ GrB_Info GxB_Monoid_fprint // print and check a GrB_Monoid FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Semiring_fprint // print and check a GrB_Semiring ( GrB_Semiring semiring, // object to print and check @@ -9752,7 +9291,6 @@ GrB_Info GxB_Semiring_fprint // print and check a GrB_Semiring FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Descriptor_fprint // print and check a GrB_Descriptor ( GrB_Descriptor descriptor, // object to print and check @@ -9761,7 +9299,6 @@ GrB_Info GxB_Descriptor_fprint // print and check a GrB_Descriptor FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Matrix_fprint // print and check a GrB_Matrix ( GrB_Matrix A, // object to print and check @@ -9770,7 +9307,6 @@ GrB_Info GxB_Matrix_fprint // print and check a GrB_Matrix FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Vector_fprint // print and check a GrB_Vector ( GrB_Vector v, // object to print and check @@ -9779,7 +9315,6 @@ GrB_Info GxB_Vector_fprint // print and check a GrB_Vector FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Scalar_fprint // print and check a GrB_Scalar ( GrB_Scalar s, // object to print and check @@ -9793,27 +9328,16 @@ GrB_Info GxB_Scalar_fprint // print and check a GrB_Scalar _Generic \ ( \ (object), \ - const GrB_Type : GxB_Type_fprint , \ GrB_Type : GxB_Type_fprint , \ - const GrB_UnaryOp : GxB_UnaryOp_fprint , \ GrB_UnaryOp : GxB_UnaryOp_fprint , \ - const GrB_BinaryOp : GxB_BinaryOp_fprint , \ GrB_BinaryOp : GxB_BinaryOp_fprint , \ - const GrB_IndexUnaryOp : GxB_IndexUnaryOp_fprint , \ GrB_IndexUnaryOp : GxB_IndexUnaryOp_fprint , \ - const GxB_SelectOp : GxB_SelectOp_fprint , \ GxB_SelectOp : GxB_SelectOp_fprint , \ - const GrB_Monoid : GxB_Monoid_fprint , \ GrB_Monoid : GxB_Monoid_fprint , \ - const GrB_Semiring : GxB_Semiring_fprint , \ GrB_Semiring : GxB_Semiring_fprint , \ - const GrB_Scalar : GxB_Scalar_fprint , \ GrB_Scalar : GxB_Scalar_fprint , \ - const GrB_Vector : GxB_Vector_fprint , \ GrB_Vector : GxB_Vector_fprint , \ - const GrB_Matrix : GxB_Matrix_fprint , \ GrB_Matrix : GxB_Matrix_fprint , \ - const GrB_Descriptor : GxB_Descriptor_fprint , \ GrB_Descriptor : GxB_Descriptor_fprint \ ) \ (object, GB_STR(object), pr, f) @@ -9917,7 +9441,6 @@ GrB_Info GxB_Scalar_fprint // print and check a GrB_Scalar // GxB_Matrix_pack_CSR: pack a CSR matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_CSR // historical: use GxB_Matrix_pack_CSR ( GrB_Matrix *A, // handle of matrix to create @@ -9936,7 +9459,6 @@ GrB_Info GxB_Matrix_import_CSR // historical: use GxB_Matrix_pack_CSR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_CSR // pack a CSR matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -9972,7 +9494,6 @@ GrB_Info GxB_Matrix_pack_CSR // pack a CSR matrix // GxB_Matrix_pack_CSC: pack a CSC matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_CSC // historical: use GxB_Matrix_pack_CSC ( GrB_Matrix *A, // handle of matrix to create @@ -9991,7 +9512,6 @@ GrB_Info GxB_Matrix_import_CSC // historical: use GxB_Matrix_pack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_CSC // pack a CSC matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10027,7 +9547,6 @@ GrB_Info GxB_Matrix_pack_CSC // pack a CSC matrix // GxB_Matrix_pack_HyperCSR: pack a hypersparse CSR matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_HyperCSR // historical: use GxB_Matrix_pack_HyperCSR ( GrB_Matrix *A, // handle of matrix to create @@ -10049,7 +9568,6 @@ GrB_Info GxB_Matrix_import_HyperCSR // historical: use GxB_Matrix_pack_HyperCSR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_HyperCSR // pack a hypersparse CSR matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10095,7 +9613,6 @@ GrB_Info GxB_Matrix_pack_HyperCSR // pack a hypersparse CSR matrix // GxB_Matrix_pack_HyperCSC: pack a hypersparse CSC matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_HyperCSC // historical: use GxB_Matrix_pack_HyperCSC ( GrB_Matrix *A, // handle of matrix to create @@ -10117,7 +9634,6 @@ GrB_Info GxB_Matrix_import_HyperCSC // historical: use GxB_Matrix_pack_HyperCSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_HyperCSC // pack a hypersparse CSC matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10164,7 +9680,6 @@ GrB_Info GxB_Matrix_pack_HyperCSC // pack a hypersparse CSC matrix // GxB_Matrix_pack_BitmapR: pack a bitmap matrix, held by row //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_BitmapR // historical: use GxB_Matrix_pack_BitmapR ( GrB_Matrix *A, // handle of matrix to create @@ -10181,7 +9696,6 @@ GrB_Info GxB_Matrix_import_BitmapR // historical: use GxB_Matrix_pack_BitmapR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_BitmapR // pack a bitmap matrix, held by row ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10209,7 +9723,6 @@ GrB_Info GxB_Matrix_pack_BitmapR // pack a bitmap matrix, held by row // GxB_Matrix_pack_BitmapC: pack a bitmap matrix, held by column //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_BitmapC // historical: use GxB_Matrix_pack_BitmapC ( GrB_Matrix *A, // handle of matrix to create @@ -10226,7 +9739,6 @@ GrB_Info GxB_Matrix_import_BitmapC // historical: use GxB_Matrix_pack_BitmapC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_BitmapC // pack a bitmap matrix, held by column ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10254,7 +9766,6 @@ GrB_Info GxB_Matrix_pack_BitmapC // pack a bitmap matrix, held by column // GxB_Matrix_pack_FullR: pack a full matrix, held by row //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_FullR // historical: use GxB_Matrix_pack_FullR ( GrB_Matrix *A, // handle of matrix to create @@ -10268,7 +9779,6 @@ GrB_Info GxB_Matrix_import_FullR // historical: use GxB_Matrix_pack_FullR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_FullR // pack a full matrix, held by row ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10290,7 +9800,6 @@ GrB_Info GxB_Matrix_pack_FullR // pack a full matrix, held by row // GxB_Matrix_pack_FullC: pack a full matrix, held by column //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_FullC // historical: use GxB_Matrix_pack_FullC ( GrB_Matrix *A, // handle of matrix to create @@ -10304,7 +9813,6 @@ GrB_Info GxB_Matrix_import_FullC // historical: use GxB_Matrix_pack_FullC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_FullC // pack a full matrix, held by column ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10326,7 +9834,6 @@ GrB_Info GxB_Matrix_pack_FullC // pack a full matrix, held by column // GxB_Vector_pack_CSC: import/pack a vector in CSC format //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Vector_import_CSC // historical: use GxB_Vector_pack_CSC ( GrB_Vector *v, // handle of vector to create @@ -10343,7 +9850,6 @@ GrB_Info GxB_Vector_import_CSC // historical: use GxB_Vector_pack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_pack_CSC // pack a vector in CSC format ( GrB_Vector v, // vector to create (type and length unchanged) @@ -10366,7 +9872,6 @@ GrB_Info GxB_Vector_pack_CSC // pack a vector in CSC format // GxB_Vector_pack_Bitmap: pack a vector in bitmap format //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Vector_import_Bitmap // historical: GxB_Vector_pack_Bitmap ( GrB_Vector *v, // handle of vector to create @@ -10382,7 +9887,6 @@ GrB_Info GxB_Vector_import_Bitmap // historical: GxB_Vector_pack_Bitmap const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_pack_Bitmap // pack a bitmap vector ( GrB_Vector v, // vector to create (type and length unchanged) @@ -10403,7 +9907,6 @@ GrB_Info GxB_Vector_pack_Bitmap // pack a bitmap vector // GxB_Vector_pack_Full: pack a vector in full format //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Vector_import_Full // historical: use GxB_Vector_pack_Full ( GrB_Vector *v, // handle of vector to create @@ -10416,7 +9919,6 @@ GrB_Info GxB_Vector_import_Full // historical: use GxB_Vector_pack_Full const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_pack_Full // pack a full vector ( GrB_Vector v, // vector to create (type and length unchanged) @@ -10467,7 +9969,6 @@ GrB_Info GxB_Vector_pack_Full // pack a full vector // If the export/unpack is not successful, the export/unpack functions do not // modify matrix or vector and the user arrays are returned as NULL. -GB_PUBLIC GrB_Info GxB_Matrix_export_CSR // historical: use GxB_Matrix_unpack_CSR ( GrB_Matrix *A, // handle of matrix to export and free @@ -10485,7 +9986,6 @@ GrB_Info GxB_Matrix_export_CSR // historical: use GxB_Matrix_unpack_CSR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_CSR // unpack a CSR matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10500,7 +10000,6 @@ GrB_Info GxB_Matrix_unpack_CSR // unpack a CSR matrix const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_CSC // historical: use GxB_Matrix_unpack_CSC ( GrB_Matrix *A, // handle of matrix to export and free @@ -10518,7 +10017,6 @@ GrB_Info GxB_Matrix_export_CSC // historical: use GxB_Matrix_unpack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_CSC // unpack a CSC matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10533,8 +10031,7 @@ GrB_Info GxB_Matrix_unpack_CSC // unpack a CSC matrix const GrB_Descriptor desc ) ; -GB_PUBLIC -GrB_Info GxB_Matrix_export_HyperCSR // historical: use GxB_Matrix_unpack_HyperCSR +GrB_Info GxB_Matrix_export_HyperCSR //historical: use GxB_Matrix_unpack_HyperCSR ( GrB_Matrix *A, // handle of matrix to export and free GrB_Type *type, // type of matrix exported @@ -10554,7 +10051,6 @@ GrB_Info GxB_Matrix_export_HyperCSR // historical: use GxB_Matrix_unpack_HyperCS const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_HyperCSR // unpack a hypersparse CSR matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10572,8 +10068,7 @@ GrB_Info GxB_Matrix_unpack_HyperCSR // unpack a hypersparse CSR matrix const GrB_Descriptor desc ) ; -GB_PUBLIC -GrB_Info GxB_Matrix_export_HyperCSC // historical: use GxB_Matrix_unpack_HyperCSC +GrB_Info GxB_Matrix_export_HyperCSC //historical: use GxB_Matrix_unpack_HyperCSC ( GrB_Matrix *A, // handle of matrix to export and free GrB_Type *type, // type of matrix exported @@ -10593,7 +10088,6 @@ GrB_Info GxB_Matrix_export_HyperCSC // historical: use GxB_Matrix_unpack_HyperCS const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_HyperCSC // unpack a hypersparse CSC matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10611,7 +10105,6 @@ GrB_Info GxB_Matrix_unpack_HyperCSC // unpack a hypersparse CSC matrix const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_BitmapR // historical: use GxB_Matrix_unpack_BitmapR ( GrB_Matrix *A, // handle of matrix to export and free @@ -10627,7 +10120,6 @@ GrB_Info GxB_Matrix_export_BitmapR // historical: use GxB_Matrix_unpack_BitmapR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_BitmapR // unpack a bitmap matrix, by row ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10640,7 +10132,6 @@ GrB_Info GxB_Matrix_unpack_BitmapR // unpack a bitmap matrix, by row const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_BitmapC // historical: use GxB_Matrix_unpack_BitmapC ( GrB_Matrix *A, // handle of matrix to export and free @@ -10656,7 +10147,6 @@ GrB_Info GxB_Matrix_export_BitmapC // historical: use GxB_Matrix_unpack_BitmapC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_BitmapC // unpack a bitmap matrix, by col ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10669,7 +10159,6 @@ GrB_Info GxB_Matrix_unpack_BitmapC // unpack a bitmap matrix, by col const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FullR // historical: use GxB_Matrix_unpack_FullR ( GrB_Matrix *A, // handle of matrix to export and free @@ -10682,7 +10171,6 @@ GrB_Info GxB_Matrix_export_FullR // historical: use GxB_Matrix_unpack_FullR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_FullR // unpack a full matrix, by row ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10692,7 +10180,6 @@ GrB_Info GxB_Matrix_unpack_FullR // unpack a full matrix, by row const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FullC // historical: use GxB_Matrix_unpack_FullC ( GrB_Matrix *A, // handle of matrix to export and free @@ -10705,7 +10192,6 @@ GrB_Info GxB_Matrix_export_FullC // historical: use GxB_Matrix_unpack_FullC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_FullC // unpack a full matrix, by column ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10715,7 +10201,6 @@ GrB_Info GxB_Matrix_unpack_FullC // unpack a full matrix, by column const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_export_CSC // historical: use GxB_Vector_unpack_CSC ( GrB_Vector *v, // handle of vector to export and free @@ -10731,7 +10216,6 @@ GrB_Info GxB_Vector_export_CSC // historical: use GxB_Vector_unpack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_unpack_CSC // unpack a CSC vector ( GrB_Vector v, // vector to unpack (type and length unchanged) @@ -10745,7 +10229,6 @@ GrB_Info GxB_Vector_unpack_CSC // unpack a CSC vector const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_export_Bitmap // historical: use GxB_Vector_unpack_Bitmap ( GrB_Vector *v, // handle of vector to export and free @@ -10760,7 +10243,6 @@ GrB_Info GxB_Vector_export_Bitmap // historical: use GxB_Vector_unpack_Bitmap const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_unpack_Bitmap // unpack a bitmap vector ( GrB_Vector v, // vector to unpack (type and length unchanged) @@ -10773,7 +10255,6 @@ GrB_Info GxB_Vector_unpack_Bitmap // unpack a bitmap vector const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_export_Full // historical: use GxB_Vector_unpack_Full ( GrB_Vector *v, // handle of vector to export and free @@ -10785,7 +10266,6 @@ GrB_Info GxB_Vector_export_Full // historical: use GxB_Vector_unpack_Full const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_unpack_Full // unpack a full vector ( GrB_Vector v, // vector to unpack (type and length unchanged) @@ -10842,7 +10322,6 @@ GrB_Info GxB_Vector_unpack_Full // unpack a full vector // matrix A, and then GrB_Matrix_wait (A) is called, a new hyper_hash matrix is // constructed for A. -GB_PUBLIC GrB_Info GxB_unpack_HyperHash // move A->Y into Y ( GrB_Matrix A, // matrix to modify @@ -10879,7 +10358,6 @@ GrB_Info GxB_unpack_HyperHash // move A->Y into Y // modified after they were exported/unpacked by // GxB_Matrix_(export/unpack)_Hyper(CSR/CSC). -GB_PUBLIC GrB_Info GxB_pack_HyperHash // move Y into A->Y ( GrB_Matrix A, // matrix to modify @@ -10915,7 +10393,6 @@ typedef enum } GrB_Format ; -GB_PUBLIC GrB_Info GrB_Matrix_import_BOOL // import a GrB_BOOL matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10931,7 +10408,6 @@ GrB_Info GrB_Matrix_import_BOOL // import a GrB_BOOL matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT8 // import a GrB_INT8 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10947,7 +10423,6 @@ GrB_Info GrB_Matrix_import_INT8 // import a GrB_INT8 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT16 // import a GrB_INT16 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10963,7 +10438,6 @@ GrB_Info GrB_Matrix_import_INT16 // import a GrB_INT16 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT32 // import a GrB_INT32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10979,7 +10453,6 @@ GrB_Info GrB_Matrix_import_INT32 // import a GrB_INT32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT64 // import a GrB_INT64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10995,7 +10468,6 @@ GrB_Info GrB_Matrix_import_INT64 // import a GrB_INT64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT8 // import a GrB_UINT8 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11011,7 +10483,6 @@ GrB_Info GrB_Matrix_import_UINT8 // import a GrB_UINT8 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT16 // import a GrB_UINT16 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11027,7 +10498,6 @@ GrB_Info GrB_Matrix_import_UINT16 // import a GrB_UINT16 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT32 // import a GrB_UINT32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11043,7 +10513,6 @@ GrB_Info GrB_Matrix_import_UINT32 // import a GrB_UINT32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT64 // import a GrB_UINT64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11059,7 +10528,6 @@ GrB_Info GrB_Matrix_import_UINT64 // import a GrB_UINT64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_FP32 // import a GrB_FP32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11075,7 +10543,6 @@ GrB_Info GrB_Matrix_import_FP32 // import a GrB_FP32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_FP64 // import a GrB_FP64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11091,7 +10558,6 @@ GrB_Info GrB_Matrix_import_FP64 // import a GrB_FP64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GxB_Matrix_import_FC32 // import a GxB_FC32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11107,7 +10573,6 @@ GrB_Info GxB_Matrix_import_FC32 // import a GxB_FC32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GxB_Matrix_import_FC64 // import a GxB_FC64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11123,7 +10588,6 @@ GrB_Info GxB_Matrix_import_FC64 // import a GxB_FC64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UDT // import a matrix with a user-defined type ( GrB_Matrix *A, // handle of matrix to create @@ -11144,7 +10608,7 @@ GrB_Info GrB_Matrix_import_UDT // import a matrix with a user-defined type _Generic \ ( \ (Ax), \ - GB_CASES (*, GrB, Matrix_import) \ + GB_PCASES (GrB, Matrix_import) \ ) \ (A, type, nrows, ncols, Ap, Ai, Ax, Ap_len, Ai_len, Ax_len, fmt) #endif @@ -11154,7 +10618,6 @@ GrB_Info GrB_Matrix_import_UDT // import a matrix with a user-defined type // On output, these 3 values are modified to be the # of entries copied // into those 3 arrays. -GB_PUBLIC GrB_Info GrB_Matrix_export_BOOL // export a GrB_BOOL matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11167,7 +10630,6 @@ GrB_Info GrB_Matrix_export_BOOL // export a GrB_BOOL matrix GrB_Matrix A // matrix to export (must be of type GrB_BOOL) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT8 // export a GrB_INT8 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11180,7 +10642,6 @@ GrB_Info GrB_Matrix_export_INT8 // export a GrB_INT8 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT8) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT16 // export a GrB_INT16 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11193,7 +10654,6 @@ GrB_Info GrB_Matrix_export_INT16 // export a GrB_INT16 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT16) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT32 // export a GrB_INT32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11206,7 +10666,6 @@ GrB_Info GrB_Matrix_export_INT32 // export a GrB_INT32 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT32) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT64 // export a GrB_INT64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11219,7 +10678,6 @@ GrB_Info GrB_Matrix_export_INT64 // export a GrB_INT64 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT64) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT8 // export a GrB_UINT8 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11232,7 +10690,6 @@ GrB_Info GrB_Matrix_export_UINT8 // export a GrB_UINT8 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT8) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT16 // export a GrB_UINT16 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11245,7 +10702,6 @@ GrB_Info GrB_Matrix_export_UINT16 // export a GrB_UINT16 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT16) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT32 // export a GrB_UINT32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11258,7 +10714,6 @@ GrB_Info GrB_Matrix_export_UINT32 // export a GrB_UINT32 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT32) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT64 // export a GrB_UINT64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11271,7 +10726,6 @@ GrB_Info GrB_Matrix_export_UINT64 // export a GrB_UINT64 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT64) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_FP32 // export a GrB_FP32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11284,7 +10738,6 @@ GrB_Info GrB_Matrix_export_FP32 // export a GrB_FP32 matrix GrB_Matrix A // matrix to export (must be of type GrB_FP32) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_FP64 // export a GrB_FP64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11297,7 +10750,6 @@ GrB_Info GrB_Matrix_export_FP64 // export a GrB_FP64 matrix GrB_Matrix A // matrix to export (must be of type GrB_FP64) ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FC32 // export a GrB_FC32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11310,7 +10762,6 @@ GrB_Info GxB_Matrix_export_FC32 // export a GrB_FC32 matrix GrB_Matrix A // matrix to export (must be of type GrB_FC32) ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FC64 // export a GrB_FC64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11323,7 +10774,6 @@ GrB_Info GxB_Matrix_export_FC64 // export a GrB_FC64 matrix GrB_Matrix A // matrix to export (must be of type GrB_FC64) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UDT // export a matrix with a user-defined type ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11341,12 +10791,11 @@ GrB_Info GrB_Matrix_export_UDT // export a matrix with a user-defined type _Generic \ ( \ (Ax), \ - GB_CASES (*, GrB, Matrix_export) \ + GB_PCASES (GrB, Matrix_export) \ ) \ (Ap, Ai, Ax, Ap_len, Ai_len, Ax_len, fmt, A) #endif -GB_PUBLIC GrB_Info GrB_Matrix_exportSize // determine sizes of user arrays for export ( GrB_Index *Ap_len, // # of entries required for Ap (not # of bytes) @@ -11356,7 +10805,6 @@ GrB_Info GrB_Matrix_exportSize // determine sizes of user arrays for export GrB_Matrix A // matrix to export ) ; -GB_PUBLIC GrB_Info GrB_Matrix_exportHint // suggest the best export format ( GrB_Format *format, // export format @@ -11498,7 +10946,6 @@ GrB_Info GrB_Matrix_exportHint // suggest the best export format // positive but unrecognized, the default is used (GxB_COMPRESSION_ZSTD, // level 1). -GB_PUBLIC GrB_Info GxB_Matrix_serialize // serialize a GrB_Matrix to a blob ( // output: @@ -11507,10 +10954,8 @@ GrB_Info GxB_Matrix_serialize // serialize a GrB_Matrix to a blob // input: GrB_Matrix A, // matrix to serialize const GrB_Descriptor desc // descriptor to select compression method - // and to control # of threads used ) ; -GB_PUBLIC GrB_Info GrB_Matrix_serialize // serialize a GrB_Matrix to a blob ( // output: @@ -11522,7 +10967,6 @@ GrB_Info GrB_Matrix_serialize // serialize a GrB_Matrix to a blob GrB_Matrix A // matrix to serialize ) ; -GB_PUBLIC GrB_Info GxB_Vector_serialize // serialize a GrB_Vector to a blob ( // output: @@ -11531,10 +10975,8 @@ GrB_Info GxB_Vector_serialize // serialize a GrB_Vector to a blob // input: GrB_Vector u, // vector to serialize const GrB_Descriptor desc // descriptor to select compression method - // and to control # of threads used ) ; -GB_PUBLIC GrB_Info GrB_Matrix_serializeSize // estimate the size of a blob ( // output: @@ -11545,10 +10987,8 @@ GrB_Info GrB_Matrix_serializeSize // estimate the size of a blob ) ; // The GrB* and GxB* deserialize methods are nearly identical. The GxB* -// deserialize methods simply add the descriptor, which allows for optional -// control of the # of threads used to deserialize the blob. +// deserialize methods simply add the descriptor. -GB_PUBLIC GrB_Info GxB_Matrix_deserialize // deserialize blob into a GrB_Matrix ( // output: @@ -11560,10 +11000,9 @@ GrB_Info GxB_Matrix_deserialize // deserialize blob into a GrB_Matrix // type of C. const void *blob, // the blob GrB_Index blob_size, // size of the blob - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_deserialize // deserialize blob into a GrB_Matrix ( // output: @@ -11577,7 +11016,6 @@ GrB_Info GrB_Matrix_deserialize // deserialize blob into a GrB_Matrix GrB_Index blob_size // size of the blob ) ; -GB_PUBLIC GrB_Info GxB_Vector_deserialize // deserialize blob into a GrB_Vector ( // output: @@ -11589,7 +11027,7 @@ GrB_Info GxB_Vector_deserialize // deserialize blob into a GrB_Vector // type of w. const void *blob, // the blob GrB_Index blob_size, // size of the blob - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; // GxB_deserialize_type_name extracts the type_name of the GrB_Type of the @@ -11600,7 +11038,6 @@ GrB_Info GxB_Vector_deserialize // deserialize blob into a GrB_Vector // holds a matrix of a built-in type, the name is returned as "bool" for // GrB_BOOL, "uint8_t" for GrB_UINT8, "float complex" for GxB_FC32, etc. // See GxB_Type_name to convert this name into a GrB_Type. -GB_PUBLIC GrB_Info GxB_deserialize_type_name // return the type name of a blob ( // output: @@ -11615,7 +11052,6 @@ GrB_Info GxB_deserialize_type_name // return the type name of a blob // GxB_Vector_sort and GxB_Matrix_sort: sort a matrix or vector //============================================================================== -GB_PUBLIC GrB_Info GxB_Vector_sort ( // output: @@ -11627,7 +11063,6 @@ GrB_Info GxB_Vector_sort const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_sort ( // output: @@ -11675,7 +11110,6 @@ GrB_Info GxB_Matrix_sort // The format of the input matrix (by row or by column) is unchanged; this // format need not match the by_col input parameter. -GB_PUBLIC GrB_Info GxB_Matrix_reshape // reshape a GrB_Matrix in place ( // input/output: @@ -11684,7 +11118,7 @@ GrB_Info GxB_Matrix_reshape // reshape a GrB_Matrix in place bool by_col, // true if reshape by column, false if by row GrB_Index nrows_new, // new number of rows of C GrB_Index ncols_new, // new number of columns of C - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; // GxB_Matrix_reshapeDup reshapes a matrix into another matrix. @@ -11695,7 +11129,6 @@ GrB_Info GxB_Matrix_reshape // reshape a GrB_Matrix in place // determines the format of the output matrix C, which need not match the // by_col input parameter. -GB_PUBLIC GrB_Info GxB_Matrix_reshapeDup // reshape a GrB_Matrix into another GrB_Matrix ( // output: @@ -11705,7 +11138,7 @@ GrB_Info GxB_Matrix_reshapeDup // reshape a GrB_Matrix into another GrB_Matrix bool by_col, // true if reshape by column, false if by row GrB_Index nrows_new, // number of rows of C GrB_Index ncols_new, // number of columns of C - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; //============================================================================== @@ -11826,10 +11259,10 @@ struct GB_Iterator_opaque typedef struct GB_Iterator_opaque *GxB_Iterator ; // GxB_Iterator_new: create a new iterator, not attached to any matrix/vector -GB_PUBLIC GrB_Info GxB_Iterator_new (GxB_Iterator *iterator) ; +GrB_Info GxB_Iterator_new (GxB_Iterator *iterator) ; // GxB_Iterator_free: free an iterator -GB_PUBLIC GrB_Info GxB_Iterator_free (GxB_Iterator *iterator) ; +GrB_Info GxB_Iterator_free (GxB_Iterator *iterator) ; //============================================================================== // GB_Iterator_*: implements user-callable GxB_*Iterator_* methods @@ -11842,7 +11275,7 @@ GB_PUBLIC GrB_Info GxB_Iterator_free (GxB_Iterator *iterator) ; // GB_Iterator_attach: attach a row/col/entry iterator to a matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Iterator_attach +GrB_Info GB_Iterator_attach ( GxB_Iterator iterator, // iterator to attach to the matrix A GrB_Matrix A, // matrix to attach @@ -11854,7 +11287,7 @@ GB_PUBLIC GrB_Info GB_Iterator_attach // GB_Iterator_rc_seek: seek a row/col iterator to a particular vector //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Iterator_rc_seek +GrB_Info GB_Iterator_rc_seek ( GxB_Iterator iterator, GrB_Index j, @@ -11865,7 +11298,7 @@ GB_PUBLIC GrB_Info GB_Iterator_rc_seek // GB_Iterator_rc_bitmap_next: move a row/col iterator to next entry in bitmap //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Iterator_rc_bitmap_next (GxB_Iterator iterator) ; +GrB_Info GB_Iterator_rc_bitmap_next (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ // GB_Iterator_rc_knext: move a row/col iterator to the next vector @@ -12016,7 +11449,6 @@ GB_PUBLIC GrB_Info GB_Iterator_rc_bitmap_next (GxB_Iterator iterator) ; // If successful, the row iterator is attached to the matrix, but not to any // specific row. Use GxB_rowIterator_*seek* to move the iterator to a row. -GB_PUBLIC GrB_Info GxB_rowIterator_attach ( GxB_Iterator iterator, @@ -12046,7 +11478,6 @@ GrB_Info GxB_rowIterator_attach // kount == m. If A is hypersparse, kount is the # of vectors held in the data // structure for the matrix, some of which may be empty, and kount <= m. -GB_PUBLIC GrB_Index GxB_rowIterator_kount (GxB_Iterator iterator) ; #define GxB_rowIterator_kount(iterator) \ @@ -12081,7 +11512,6 @@ GrB_Index GxB_rowIterator_kount (GxB_Iterator iterator) ; // the first entry in A(row,:), and GxB_Iterator_get* can // return its value. -GB_PUBLIC GrB_Info GxB_rowIterator_seekRow (GxB_Iterator iterator, GrB_Index row) ; #define GxB_rowIterator_seekRow(iterator, row) \ @@ -12101,7 +11531,6 @@ GrB_Info GxB_rowIterator_seekRow (GxB_Iterator iterator, GrB_Index row) ; // More precisely, k is in the range 0 to kount-1, where kount is the value // returned by GxB_rowIterator_kount. -GB_PUBLIC GrB_Info GxB_rowIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; #define GxB_rowIterator_kseek(iterator, k) \ @@ -12125,7 +11554,6 @@ GrB_Info GxB_rowIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; // The method is always successful, and the return conditions are identical to // the return conditions of GxB_rowIterator_seekRow. -GB_PUBLIC GrB_Info GxB_rowIterator_nextRow (GxB_Iterator iterator) ; #define GxB_rowIterator_nextRow(iterator) \ @@ -12148,7 +11576,6 @@ GrB_Info GxB_rowIterator_nextRow (GxB_Iterator iterator) ; // GrB_SUCCESS: If the row iterator has been moved to the next entry in // A(row,:). -GB_PUBLIC GrB_Info GxB_rowIterator_nextCol (GxB_Iterator iterator) ; #define GxB_rowIterator_nextCol(iterator) \ @@ -12169,7 +11596,6 @@ GrB_Info GxB_rowIterator_nextCol (GxB_Iterator iterator) ; // GxB_rowIterator_*seek* has not been called, but this does not mean the // iterator is positioned at row zero. -GB_PUBLIC GrB_Index GxB_rowIterator_getRowIndex (GxB_Iterator iterator) ; #define GxB_rowIterator_getRowIndex(iterator) \ @@ -12187,7 +11613,6 @@ GrB_Index GxB_rowIterator_getRowIndex (GxB_Iterator iterator) ; // GxB_rowIterator_*seek* or GxB_rowIterator_*next*, must have returned // GrB_SUCCESS. Results are undefined if this condition is not met. -GB_PUBLIC GrB_Index GxB_rowIterator_getColIndex (GxB_Iterator iterator) ; #define GxB_rowIterator_getColIndex(iterator) \ @@ -12211,7 +11636,6 @@ GrB_Index GxB_rowIterator_getColIndex (GxB_Iterator iterator) ; #undef GxB_colIterator_getRowIndex // GxB_colIterator_attach: attach a column iterator to a matrix -GB_PUBLIC GrB_Info GxB_colIterator_attach ( GxB_Iterator iterator, @@ -12224,7 +11648,6 @@ GrB_Info GxB_colIterator_attach ) // GxB_colIterator_kount: return # of nonempty columns of the matrix -GB_PUBLIC GrB_Index GxB_colIterator_kount (GxB_Iterator iterator) ; #define GxB_colIterator_kount(iterator) \ ( \ @@ -12232,7 +11655,6 @@ GrB_Index GxB_colIterator_kount (GxB_Iterator iterator) ; ) // GxB_colIterator_seekCol: move a column iterator to A(:,col) -GB_PUBLIC GrB_Info GxB_colIterator_seekCol (GxB_Iterator iterator, GrB_Index col) ; #define GxB_colIterator_seekCol(iterator, col) \ ( \ @@ -12240,7 +11662,6 @@ GrB_Info GxB_colIterator_seekCol (GxB_Iterator iterator, GrB_Index col) ; ) // GxB_colIterator_kseek: move a column iterator to kth non-empty column of A -GB_PUBLIC GrB_Info GxB_colIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; #define GxB_colIterator_kseek(iterator, k) \ ( \ @@ -12248,7 +11669,6 @@ GrB_Info GxB_colIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; ) // GxB_colIterator_nextCol: move a column iterator to first entry of next column -GB_PUBLIC GrB_Info GxB_colIterator_nextCol (GxB_Iterator iterator) ; #define GxB_colIterator_nextCol(iterator) \ ( \ @@ -12256,7 +11676,6 @@ GrB_Info GxB_colIterator_nextCol (GxB_Iterator iterator) ; ) // GxB_colIterator_nextRow: move a column iterator to next entry in column -GB_PUBLIC GrB_Info GxB_colIterator_nextRow (GxB_Iterator iterator) ; #define GxB_colIterator_nextRow(iterator) \ ( \ @@ -12264,7 +11683,6 @@ GrB_Info GxB_colIterator_nextRow (GxB_Iterator iterator) ; ) // GxB_colIterator_getColIndex: return the column index of current entry -GB_PUBLIC GrB_Index GxB_colIterator_getColIndex (GxB_Iterator iterator) ; #define GxB_colIterator_getColIndex(iterator) \ ( \ @@ -12272,7 +11690,6 @@ GrB_Index GxB_colIterator_getColIndex (GxB_Iterator iterator) ; ) // GxB_colIterator_getRowIndex: return the row index of current entry -GB_PUBLIC GrB_Index GxB_colIterator_getRowIndex (GxB_Iterator iterator) ; #define GxB_colIterator_getRowIndex(iterator) \ ( \ @@ -12328,7 +11745,6 @@ GrB_Index GxB_colIterator_getRowIndex (GxB_Iterator iterator) ; // specific entry. Use GxB_Matrix_Iterator_*seek* to move the iterator to a // particular entry. -GB_PUBLIC GrB_Info GxB_Matrix_Iterator_attach ( GxB_Iterator iterator, @@ -12349,7 +11765,6 @@ GrB_Info GxB_Matrix_Iterator_attach // to nvals(A). For an m-by-n bitmap matrix, pmax=m*n, or pmax=0 if the // matrix has no entries. -GB_PUBLIC GrB_Index GxB_Matrix_Iterator_getpmax (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ @@ -12367,7 +11782,6 @@ GrB_Index GxB_Matrix_Iterator_getpmax (GxB_Iterator iterator) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // matrix, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GxB_Matrix_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; //------------------------------------------------------------------------------ @@ -12383,7 +11797,6 @@ GrB_Info GxB_Matrix_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // matrix, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GxB_Matrix_Iterator_next (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ @@ -12396,7 +11809,6 @@ GrB_Info GxB_Matrix_Iterator_next (GxB_Iterator iterator) ; // GxB_Matrix_Iterator_next. Results are undefined if these conditions are not // met. -GB_PUBLIC GrB_Index GxB_Matrix_Iterator_getp (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ @@ -12409,7 +11821,6 @@ GrB_Index GxB_Matrix_Iterator_getp (GxB_Iterator iterator) ; // GxB_Matrix_Iterator_next, with a return value of GrB_SUCCESS. Results are // undefined if these conditions are not met. -GB_PUBLIC void GxB_Matrix_Iterator_getIndex ( GxB_Iterator iterator, @@ -12471,7 +11882,7 @@ single thread iteration of a whole vector, one entry at at time // specific entry. Use GxB_Vector_Iterator_seek to move the iterator to a // particular entry. -GB_PUBLIC GrB_Info GxB_Vector_Iterator_attach +GrB_Info GxB_Vector_Iterator_attach ( GxB_Iterator iterator, GrB_Vector v, @@ -12490,7 +11901,6 @@ GB_PUBLIC GrB_Info GxB_Vector_Iterator_attach // pmax >= nvals(v). For sparse and full vectors, pmax is equal to nvals(v). // For a size-m bitmap vector, pmax=m, or pmax=0 if the vector has no entries. -GB_PUBLIC GrB_Index GxB_Vector_Iterator_getpmax (GxB_Iterator iterator) ; #define GxB_Vector_Iterator_getpmax(iterator) \ @@ -12513,11 +11923,9 @@ GrB_Index GxB_Vector_Iterator_getpmax (GxB_Iterator iterator) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // vector, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GB_Vector_Iterator_bitmap_seek (GxB_Iterator iterator, GrB_Index unused) ; // unused parameter to be removed in v8.x -GB_PUBLIC GrB_Info GxB_Vector_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; #define GB_Vector_Iterator_seek(iterator, q) \ @@ -12561,7 +11969,6 @@ GrB_Info GxB_Vector_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // vector, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GxB_Vector_Iterator_next (GxB_Iterator iterator) ; #define GB_Vector_Iterator_next(iterator) \ @@ -12603,7 +12010,6 @@ GrB_Info GxB_Vector_Iterator_next (GxB_Iterator iterator) ; // GxB_Vector_Iterator_next. Results are undefined if these conditions are not // met. -GB_PUBLIC GrB_Index GxB_Vector_Iterator_getp (GxB_Iterator iterator) ; #define GxB_Vector_Iterator_getp(iterator) \ @@ -12621,7 +12027,6 @@ GrB_Index GxB_Vector_Iterator_getp (GxB_Iterator iterator) ; // GxB_Vector_Iterator_next, with a return value of GrB_SUCCESS. Results are // undefined if these conditions are not met. -GB_PUBLIC GrB_Index GxB_Vector_Iterator_getIndex (GxB_Iterator iterator) ; #define GxB_Vector_Iterator_getIndex(iterator) \ @@ -12656,20 +12061,20 @@ GrB_Index GxB_Vector_Iterator_getIndex (GxB_Iterator iterator) ; #undef GxB_Iterator_get_FC64 #undef GxB_Iterator_get_UDT -GB_PUBLIC bool GxB_Iterator_get_BOOL (GxB_Iterator iterator) ; -GB_PUBLIC int8_t GxB_Iterator_get_INT8 (GxB_Iterator iterator) ; -GB_PUBLIC int16_t GxB_Iterator_get_INT16 (GxB_Iterator iterator) ; -GB_PUBLIC int32_t GxB_Iterator_get_INT32 (GxB_Iterator iterator) ; -GB_PUBLIC int64_t GxB_Iterator_get_INT64 (GxB_Iterator iterator) ; -GB_PUBLIC uint8_t GxB_Iterator_get_UINT8 (GxB_Iterator iterator) ; -GB_PUBLIC uint16_t GxB_Iterator_get_UINT16 (GxB_Iterator iterator) ; -GB_PUBLIC uint32_t GxB_Iterator_get_UINT32 (GxB_Iterator iterator) ; -GB_PUBLIC uint64_t GxB_Iterator_get_UINT64 (GxB_Iterator iterator) ; -GB_PUBLIC float GxB_Iterator_get_FP32 (GxB_Iterator iterator) ; -GB_PUBLIC double GxB_Iterator_get_FP64 (GxB_Iterator iterator) ; -GB_PUBLIC GxB_FC32_t GxB_Iterator_get_FC32 (GxB_Iterator iterator) ; -GB_PUBLIC GxB_FC64_t GxB_Iterator_get_FC64 (GxB_Iterator iterator) ; -GB_PUBLIC void GxB_Iterator_get_UDT (GxB_Iterator iterator, +bool GxB_Iterator_get_BOOL (GxB_Iterator iterator) ; +int8_t GxB_Iterator_get_INT8 (GxB_Iterator iterator) ; +int16_t GxB_Iterator_get_INT16 (GxB_Iterator iterator) ; +int32_t GxB_Iterator_get_INT32 (GxB_Iterator iterator) ; +int64_t GxB_Iterator_get_INT64 (GxB_Iterator iterator) ; +uint8_t GxB_Iterator_get_UINT8 (GxB_Iterator iterator) ; +uint16_t GxB_Iterator_get_UINT16 (GxB_Iterator iterator) ; +uint32_t GxB_Iterator_get_UINT32 (GxB_Iterator iterator) ; +uint64_t GxB_Iterator_get_UINT64 (GxB_Iterator iterator) ; +float GxB_Iterator_get_FP32 (GxB_Iterator iterator) ; +double GxB_Iterator_get_FP64 (GxB_Iterator iterator) ; +GxB_FC32_t GxB_Iterator_get_FC32 (GxB_Iterator iterator) ; +GxB_FC64_t GxB_Iterator_get_FC64 (GxB_Iterator iterator) ; +void GxB_Iterator_get_UDT (GxB_Iterator iterator, void *value) ; #define GB_Iterator_get(iterator, type) \ diff --git a/deps/GraphBLAS/Config/README.md.in b/deps/GraphBLAS/Config/README.md.in index 7e53c76c6a..88bd8570a6 100644 --- a/deps/GraphBLAS/Config/README.md.in +++ b/deps/GraphBLAS/Config/README.md.in @@ -27,6 +27,8 @@ See the user guide in `Doc/GraphBLAS_UserGuide.pdf` for documentation on the SuiteSparse implementation of GraphBLAS, and how to use it in your applications. +Note: memory pool has been disabled, to enable compile with _MEMPOOL defined + See http://graphblas.org for more information on GraphBLAS, including the GraphBLAS C API. See https://github.com/GraphBLAS/GraphBLAS-Pointers for additional resources on GraphBLAS. @@ -53,7 +55,7 @@ To remove all compiled files: To compile and run the demos: - make demo + make demos See the GraphBLAS/ subfolder for the Octave/MATLAB interface, which contains a README.md file with further details. diff --git a/deps/GraphBLAS/Config/alternative_Makefile.in b/deps/GraphBLAS/Config/alternative_Makefile.in new file mode 100644 index 0000000000..927cb0328e --- /dev/null +++ b/deps/GraphBLAS/Config/alternative_Makefile.in @@ -0,0 +1,154 @@ +#------------------------------------------------------------------------------- +# GraphBLAS/alternative/Makefile +#------------------------------------------------------------------------------- + +# SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +#------------------------------------------------------------------------------- + +# To compile with 8 threads: +# +# make -j8 +# +# To install: +# +# make -j8 +# sudo make install + +default: library + +VER1 = @GraphBLAS_VERSION_MAJOR@ +VER2 = @GraphBLAS_VERSION_MINOR@ +VER3 = @GraphBLAS_VERSION_SUB@ + +# pick your compiler: + CC = gcc +# CC = cc +# CC = clang +# CC = xlc +# CC = gcc-8 +# note that -mp1 is essential for icc, for proper Inf and NaN behavior: +# CC = icc -mp1 +# CC = c++ + +# when using clang +# CFLAGS += -Xclang + +SRC = ../Source/*.c ../Source/Generated1/*.c ../Source/Generated2/*.c +INC = ../Include/*.h ../Source/*.h ../Source/Template/* ../Source/Generated1/*.h ../Source/Generated2/*.h ../rmm_wrap/*.h* +SRC2 = $(notdir $(wildcard $(SRC))) +OBJ = $(SRC2:.c=.o) + +# pick OpenMP options: +# LDFLAGS = -fopenmp -lm +# LDFLAGS = -openmp -lm +CFLAGS += -fopenmp -fexceptions -fPIC + +# pick the optimization level: + CFLAGS += -O3 +# CFLAGS += -g + +ifneq ($(CC),c++) + CFLAGS += -std=c11 +endif +CPPFLAGS = -I../Include -I../Source -I../Source/Template -I../Source/Generated1 -I../Source/Generated2 -I../lz4 -I../cpu_features/include -I../cpu_features -I../cpu_features/src -I../cpu_features/include/internal -I../rmm_wrap +CFLAGS += -Wno-pragmas + +# To compile the libgraphblas_matlab library, change all occurences of +# libgraphblas to libgraphblas_matlab, below, and uncomment these 2 lines: +# CFLAGS += -DGBRENAME=1 +# CPPFLAGS += -I../GraphBLAS/rename + +# Select options for cpu_features: +# no cpu_features: +# CFLAGS += -DGBNCPUFEAT=1 +# cpu_features with getauxval (does not work on the Mac): +# CFLAGS += -DHAVE_STRONG_GETAUXVAL=1 +# cpu_features with dlfcn.h (works on the Mac): +# CFLAGS += -DHAVE_DLFCN_H=1 +# To enable X86, and AVX2 and/or AVX512 when not using cpu_features: +# CFLAGS += -DGBX86=1 +# CFLAGS += -DGBAVX2=1 +# CFLAGS += -DGBAVX512=1 + +UNAME := $(shell uname) +ifeq ($(UNAME),Darwin) + # Mac + CFLAGS += -DHAVE_DLFCN_H=1 + CFLAGS += -fno-common + SO_NAME = libgraphblas.dylib.$(VER1).$(VER2).$(VER3) + SO_NAME0 = libgraphblas.dylib + SO_NAME1 = libgraphblas.dylib.$(VER1) + SO_OPTS = $(LDFLAGS) + SO_OPTS += -dynamiclib -shared -Wl,-install_name -Wl,$(SO_NAME1) -undefined dynamic_lookup +else + # Linux + CFLAGS += -DHAVE_DLFCN_H=1 -DHAVE_STRONG_GETAUXVAL=1 + SO_NAME = libgraphblas.so.$(VER1).$(VER2).$(VER3) + SO_NAME0 = libgraphblas.so + SO_NAME1 = libgraphblas.so.$(VER1) + SO_OPTS = $(LDFLAGS) + SO_OPTS += -shared -Wl,-soname -Wl,$(SO_NAME1) +endif + +%.o: ../Source/%.c $(INC) + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $(notdir $@) + +%.o: ../Source/Generated1/%.c $(INC) + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $(notdir $@) + +%.o: ../Source/Generated2/%.c $(INC) + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $(notdir $@) + +library: $(SO_NAME) + ln -sf $(SO_NAME) $(SO_NAME0) + ln -sf $(SO_NAME) $(SO_NAME1) + +$(SO_NAME): $(OBJ) + $(CC) $(SO_OPTS) $^ -o $@ + +.KEEP: $(OBJ) + +static: libgraphblas.a + +libgraphblas.a: $(OBJ) + ar -rv $@ $^ + - ranlib $@ + +# Do "make" first, and then "sudo make install" +install: library + cp $(SO_NAME) /usr/local/lib + ln -sf /usr/local/lib/$(SO_NAME) /usr/local/lib/$(SO_NAME0) + ln -sf /usr/local/lib/$(SO_NAME) /usr/local/lib/$(SO_NAME1) + cp ../Include/GraphBLAS.h /usr/local/include + +DINC = ../Demo/Include/*.h $(INC) +DSRC = ../Demo/Source/*.c +DCPPFLAGS = $(CPPFLAGS) -I../Demo/Include +DLIBS = $(SO_NAME) -lm +DSRC2 = $(notdir $(wildcard $(DSRC))) +DOBJ = $(DSRC2:.c=.o) + +.KEEP: $(DOBJ) + +%.o: ../Demo/Source/%.c $(DINC) + $(CC) -c $(CFLAGS) $(DCPPFLAGS) $< -o $(notdir $@) + +%_demo: ../Demo/Program/%_demo.c $(SO_NAME) $(DINC) $(DOBJ) + $(CC) $(CFLAGS) $(LDFLAGS) $(DCPPFLAGS) $< $(DOBJ) $(DLIBS) -o $@ + +DEMO_PRG = $(notdir $(wildcard ../Demo/Program/*_demo.c)) +DEMO = $(DEMO_PRG:.c=) + +demos: $(DEMO) + ./altdemo + +clean: + $(RM) -f *.o *.out *_out.m *_out2.m + +distclean: clean + $(RM) -rf *.dSYM $(DEMO) libgraphblas.* + +purge: distclean + diff --git a/deps/GraphBLAS/Demo/Include/graphblas_demos.h b/deps/GraphBLAS/Demo/Include/graphblas_demos.h index e2c3e0f91d..3f9d42b65b 100644 --- a/deps/GraphBLAS/Demo/Include/graphblas_demos.h +++ b/deps/GraphBLAS/Demo/Include/graphblas_demos.h @@ -62,7 +62,6 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) -GB_PUBLIC GrB_Info read_matrix // read a double-precision matrix ( GrB_Matrix *A, // handle of matrix to create @@ -74,7 +73,6 @@ GrB_Info read_matrix // read a double-precision matrix bool printstuff // if true, print status to stdout ) ; -GB_PUBLIC GrB_Info random_matrix // create a random double-precision matrix ( GrB_Matrix *A_output, // handle of matrix to create @@ -87,7 +85,6 @@ GrB_Info random_matrix // create a random double-precision matrix bool A_complex // if true, create a Complex matrix ) ; -GB_PUBLIC GrB_Info get_matrix // get a matrix from stdin, or create random one ( GrB_Matrix *A_output, // matrix to create @@ -98,7 +95,6 @@ GrB_Info get_matrix // get a matrix from stdin, or create random one bool spones // if true, return all entries equal to 1 ) ; -GB_PUBLIC GrB_Info wathen // construct a random Wathen matrix ( GrB_Matrix *A_output, // output matrix @@ -109,14 +105,12 @@ GrB_Info wathen // construct a random Wathen matrix double *rho_given // nx-by-ny dense matrix, if NULL use random rho ) ; -GB_PUBLIC GrB_Info triu // C = triu (A,1) ( GrB_Matrix *C_output, // output matrix const GrB_Matrix A // input matrix, boolean or double ) ; -GB_PUBLIC GrB_Info isequal_type // return GrB_SUCCESS if successful ( bool *result, // true if A == B, false if A != B or error @@ -125,7 +119,6 @@ GrB_Info isequal_type // return GrB_SUCCESS if successful GrB_BinaryOp op // should be GrB_EQ_, for the type of A and B ) ; -GB_PUBLIC GrB_Info isequal // return GrB_SUCCESS if successful ( bool *result, // true if A == B, false if A != B or error @@ -139,7 +132,6 @@ GrB_Info isequal // return GrB_SUCCESS if successful // import/export test //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info import_test (GrB_Matrix *C_handle, int format, bool dump) ; //------------------------------------------------------------------------------ diff --git a/deps/GraphBLAS/Demo/Include/simple_rand.h b/deps/GraphBLAS/Demo/Include/simple_rand.h index bb3a00de4a..ec11b2e8a3 100644 --- a/deps/GraphBLAS/Demo/Include/simple_rand.h +++ b/deps/GraphBLAS/Demo/Include/simple_rand.h @@ -15,44 +15,23 @@ #ifndef SIMPLE_RAND_H #define SIMPLE_RAND_H -#ifndef GB_PUBLIC -// Exporting/importing symbols for Microsoft Visual Studio -#if ( _MSC_VER && !__INTEL_COMPILER ) -#ifdef GB_LIBRARY -// compiling SuiteSparse:GraphBLAS itself, exporting symbols to user apps -#define GB_PUBLIC extern __declspec ( dllexport ) -#else -// compiling the user application, importing symbols from SuiteSparse:GraphBLAS -#define GB_PUBLIC extern __declspec ( dllimport ) -#endif -#else -// for other compilers -#define GB_PUBLIC extern -#endif -#endif - #include #define SIMPLE_RAND_MAX 32767 // return a random number between 0 and SIMPLE_RAND_MAX -GB_PUBLIC uint64_t simple_rand (void) ; // set the seed -GB_PUBLIC void simple_rand_seed (uint64_t seed) ; // get the seed -GB_PUBLIC uint64_t simple_rand_getseed (void) ; // return a random double between 0 and 1, inclusive -GB_PUBLIC double simple_rand_x ( ) ; // return a random uint64_t -GB_PUBLIC uint64_t simple_rand_i ( ) ; #endif diff --git a/deps/GraphBLAS/Demo/Include/usercomplex.h b/deps/GraphBLAS/Demo/Include/usercomplex.h index c018544835..a0277c12af 100644 --- a/deps/GraphBLAS/Demo/Include/usercomplex.h +++ b/deps/GraphBLAS/Demo/Include/usercomplex.h @@ -14,7 +14,7 @@ // 10 binary functions, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_first , Complex_second , Complex_min , Complex_max , Complex_plus , Complex_minus , Complex_times , Complex_div , Complex_rdiv , @@ -24,7 +24,7 @@ GrB_BinaryOp Complex_first , Complex_second , Complex_min , // 6 binary comparators, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_iseq , Complex_isne , Complex_isgt , Complex_islt , Complex_isge , Complex_isle ; @@ -33,14 +33,14 @@ GrB_BinaryOp Complex_iseq , Complex_isne , // 3 binary boolean functions, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_or , Complex_and , Complex_xor ; //------------------------------------------------------------------------------ // 6 binary comparators, z=f(x,y), where CxC -> bool //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_eq , Complex_ne , Complex_gt , Complex_lt , Complex_ge , Complex_le ; @@ -49,13 +49,13 @@ GrB_BinaryOp Complex_eq , Complex_ne , // 1 binary function, z=f(x,y), where double x double -> C //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp Complex_complex ; +extern GrB_BinaryOp Complex_complex ; //------------------------------------------------------------------------------ // 5 unary functions, z=f(x) where C -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_UnaryOp Complex_identity , Complex_ainv , Complex_minv , Complex_not , Complex_conj, Complex_one , Complex_abs ; @@ -64,7 +64,7 @@ GrB_UnaryOp Complex_identity , Complex_ainv , Complex_minv , // 4 unary functions, z=f(x) where C -> double //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_UnaryOp Complex_real, Complex_imag, Complex_cabs, Complex_angle ; @@ -72,17 +72,18 @@ GrB_UnaryOp Complex_real, Complex_imag, // 2 unary functions, z=f(x) where double -> C //------------------------------------------------------------------------------ -GB_PUBLIC GrB_UnaryOp Complex_complex_real, Complex_complex_imag ; +extern GrB_UnaryOp Complex_complex_real, Complex_complex_imag ; //------------------------------------------------------------------------------ // Complex type, scalars, monoids, and semiring //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Type Complex ; -GB_PUBLIC GrB_Monoid Complex_plus_monoid, Complex_times_monoid ; -GB_PUBLIC GrB_Semiring Complex_plus_times ; -GB_PUBLIC GrB_Info Complex_init (bool builtin_complex) ; -GB_PUBLIC GrB_Info Complex_finalize ( ) ; +extern GrB_Type Complex ; +extern GrB_Monoid Complex_plus_monoid, Complex_times_monoid ; +extern GrB_Semiring Complex_plus_times ; + +GrB_Info Complex_init (bool builtin_complex) ; +GrB_Info Complex_finalize ( ) ; //------------------------------------------------------------------------------ // C++ compatibility diff --git a/deps/GraphBLAS/Demo/Program/openmp2_demo.c b/deps/GraphBLAS/Demo/Program/openmp2_demo.c new file mode 100644 index 0000000000..9689ddbb15 --- /dev/null +++ b/deps/GraphBLAS/Demo/Program/openmp2_demo.c @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// GraphBLAS/Demo/Program/openmp2_demo: example of user multithreading +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//------------------------------------------------------------------------------ + +// This demo uses OpenMP, and illustrates how GraphBLAS can be called from +// a multi-threaded user program. + +#include "GraphBLAS.h" + +#ifdef _OPENMP +#include +#endif + +#if defined __INTEL_COMPILER +#pragma warning (disable: 58 167 144 177 181 186 188 589 593 869 981 1418 1419 1572 1599 2259 2282 2557 2547 3280 ) +#elif defined __GNUC__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#if !defined ( __cplusplus ) +#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +#endif +#endif + +#define NTRIALS 1000 +#define N 6 + +#define OK(method) \ +{ \ + GrB_Info info = method ; \ + if (! (info == GrB_SUCCESS || info == GrB_NO_VALUE)) \ + { \ + fprintf (stderr, "Failure (id: %d, info: %d):\n", id, info) ; \ + /* return to caller (do not use inside critical section) */ \ + return (0) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// worker +//------------------------------------------------------------------------------ + +int worker (int id) +{ + + GrB_Matrix A = NULL ; +// printf ("\nworker %d\n", id) ; + + for (int hammer_hard = 0 ; hammer_hard < NTRIALS ; hammer_hard++) + { + OK (GrB_Matrix_free (&A)) ; + OK (GrB_Matrix_new (&A, GrB_FP64, N, N)) ; + + for (int i = 0 ; i < N ; i++) + { + for (int j = 0 ; j < N ; j++) + { + double x = (i+1)*100000 + (j+1)*1000 + id ; + OK (GrB_Matrix_setElement_FP64 (A, x, i, j)) ; + } + } + + // force completion + OK (GrB_Matrix_wait (A, GrB_MATERIALIZE)) ; + } + OK (GrB_Matrix_free (&A)) ; + + return (0) ; +} + +//------------------------------------------------------------------------------ +// openmp_demo main program +//------------------------------------------------------------------------------ + +int main (int argc, char **argv) +{ + printf ("Demo: %s:\n", argv [0]) ; + int id = 0 ; + + // start GraphBLAS + OK (GrB_init (GrB_NONBLOCKING)) ; + int nthreads ; + OK (GxB_Global_Option_get (GxB_GLOBAL_NTHREADS, &nthreads)) ; + int ver [3] ; + char *date ; + OK (GxB_Global_Option_get (GxB_LIBRARY_VERSION , ver)) ; + OK (GxB_Global_Option_get (GxB_LIBRARY_DATE , &date)) ; + printf ("openmp demo, nthreads %d (v%d.%d.%d, %s)\n", + nthreads, ver [0], ver [1], ver [2], date) ; + + int64_t free_pool_limit [64] ; + memset (free_pool_limit, 0, 64 * sizeof (int64_t)) ; + OK (GxB_Global_Option_set (GxB_NTHREADS, 1)) ; + double t1 = 0 ; + + for (int nth = 1 ; nth <= nthreads ; nth++) + { + printf ("nthreads %2d: ", nth) ; + + for (int trial = 0 ; trial <= 1 ; trial++) + { + if (trial == 0) + { + // no pool + OK (GxB_Global_Option_set (GxB_MEMORY_POOL, + free_pool_limit)) ; + } + else + { + // default pool + OK (GxB_Global_Option_set (GxB_MEMORY_POOL, NULL)) ; + } + + #ifdef _OPENMP + double t = omp_get_wtime ( ) ; + #endif + + // create the threads + #pragma omp parallel for num_threads(nth) + for (id = 0 ; id < 128 ; id++) + { + worker (id) ; + } + + #ifdef _OPENMP + t = omp_get_wtime ( ) - t ; + if (nth == 1) t1 = t ; + printf (" time: %10.4f sec speedup: %10.4f", t, t1/t) ; + #endif + } + printf ("\n") ; + } + + // finish GraphBLAS + GrB_finalize ( ) ; + + // finish OpenMP + exit (0) ; +} + diff --git a/deps/GraphBLAS/Demo/Program/reduce_demo.c b/deps/GraphBLAS/Demo/Program/reduce_demo.c index 3f337d3a7e..69272e1fb2 100644 --- a/deps/GraphBLAS/Demo/Program/reduce_demo.c +++ b/deps/GraphBLAS/Demo/Program/reduce_demo.c @@ -13,7 +13,7 @@ #endif // #define N 65536 - #define N 16384 + #define N 16382 int main (void) { diff --git a/deps/GraphBLAS/Demo/Source/get_matrix.c b/deps/GraphBLAS/Demo/Source/get_matrix.c index 200116693b..5cb99f9e6d 100644 --- a/deps/GraphBLAS/Demo/Source/get_matrix.c +++ b/deps/GraphBLAS/Demo/Source/get_matrix.c @@ -17,11 +17,8 @@ GrB_Descriptor_free (&desc) ; \ GrB_Matrix_free (&Mask) ; -#undef GB_PUBLIC -#define GB_LIBRARY #include "graphblas_demos.h" -GB_PUBLIC GrB_Info get_matrix // get a matrix from stdin, or create random one ( GrB_Matrix *A_output, // matrix to create diff --git a/deps/GraphBLAS/Demo/Source/import_test.c b/deps/GraphBLAS/Demo/Source/import_test.c index 9f6568e29d..17409d2ead 100644 --- a/deps/GraphBLAS/Demo/Source/import_test.c +++ b/deps/GraphBLAS/Demo/Source/import_test.c @@ -8,9 +8,6 @@ //------------------------------------------------------------------------------ #include "GraphBLAS.h" - -#undef GB_PUBLIC -#define GB_LIBRARY #include "graphblas_demos.h" #if defined __INTEL_COMPILER @@ -62,7 +59,6 @@ #include "../Source/GB.h" -GB_PUBLIC GrB_Info import_test (GrB_Matrix *C_handle, int format, bool dump) { diff --git a/deps/GraphBLAS/Demo/Source/isequal.c b/deps/GraphBLAS/Demo/Source/isequal.c index 0db105bf24..1af444a82b 100644 --- a/deps/GraphBLAS/Demo/Source/isequal.c +++ b/deps/GraphBLAS/Demo/Source/isequal.c @@ -20,8 +20,6 @@ // returns true if x and y are both NaN. #include "GraphBLAS.h" -#undef GB_PUBLIC -#define GB_LIBRARY #include "graphblas_demos.h" // call a GraphBLAS method and return if an error occurs @@ -41,7 +39,6 @@ // isequal_type: check two matrices, works in any GraphBLAS //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info isequal_type // return GrB_SUCCESS if successful ( bool *result, // true if A == B, false if A != B or error diff --git a/deps/GraphBLAS/Demo/Source/random_matrix.c b/deps/GraphBLAS/Demo/Source/random_matrix.c index 4793a28729..3a57f52808 100644 --- a/deps/GraphBLAS/Demo/Source/random_matrix.c +++ b/deps/GraphBLAS/Demo/Source/random_matrix.c @@ -19,15 +19,12 @@ if (J != NULL) free (J) ; \ if (X != NULL) free (X) ; -#undef GB_PUBLIC -#define GB_LIBRARY #include "graphblas_demos.h" //------------------------------------------------------------------------------ // create a random matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info random_matrix // create a random double-precision matrix ( GrB_Matrix *A_output, // handle of matrix to create diff --git a/deps/GraphBLAS/Demo/Source/read_matrix.c b/deps/GraphBLAS/Demo/Source/read_matrix.c index 8734a4835f..6d41e51ad0 100644 --- a/deps/GraphBLAS/Demo/Source/read_matrix.c +++ b/deps/GraphBLAS/Demo/Source/read_matrix.c @@ -32,8 +32,6 @@ GrB_Matrix_free (&B) ; \ GrB_Matrix_free (&C) ; -#undef GB_PUBLIC -#define GB_LIBRARY #include "graphblas_demos.h" //------------------------------------------------------------------------------ @@ -49,7 +47,6 @@ void scale2 (double *z, const double *x) // read a matrix from a file //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info read_matrix // read a double-precision or boolean matrix ( GrB_Matrix *A_output, // handle of matrix to create diff --git a/deps/GraphBLAS/Demo/Source/simple_rand.c b/deps/GraphBLAS/Demo/Source/simple_rand.c index 7d2962e39e..b9a35ea31b 100644 --- a/deps/GraphBLAS/Demo/Source/simple_rand.c +++ b/deps/GraphBLAS/Demo/Source/simple_rand.c @@ -22,12 +22,11 @@ #include "simple_rand.h" // simple_rand is not thread-safe -uint64_t simple_rand_next = 1 ; +static uint64_t simple_rand_next = 1 ; #define SIMPLE_RAND_MAX 32767 // return a random number between 0 and SIMPLE_RAND_MAX -GB_PUBLIC uint64_t simple_rand (void) { simple_rand_next = simple_rand_next * 1103515245 + 12345 ; @@ -35,21 +34,18 @@ uint64_t simple_rand (void) } // set the seed -GB_PUBLIC void simple_rand_seed (uint64_t seed) { simple_rand_next = seed ; } // get the seed -GB_PUBLIC uint64_t simple_rand_getseed (void) { return (simple_rand_next) ; } // return a random uint64_t -GB_PUBLIC uint64_t simple_rand_i ( ) { uint64_t i = 0 ; @@ -61,7 +57,6 @@ uint64_t simple_rand_i ( ) } // return a random double between 0 and 1, inclusive -GB_PUBLIC double simple_rand_x ( ) { return (((double) simple_rand_i ( )) / ((double) UINT64_MAX)) ; diff --git a/deps/GraphBLAS/Demo/Source/usercomplex.c b/deps/GraphBLAS/Demo/Source/usercomplex.c index 64964d1be3..c91c837787 100644 --- a/deps/GraphBLAS/Demo/Source/usercomplex.c +++ b/deps/GraphBLAS/Demo/Source/usercomplex.c @@ -23,8 +23,6 @@ #else #include "GraphBLAS.h" - #undef GB_PUBLIC - #define GB_LIBRARY #include "graphblas_demos.h" #if defined __INTEL_COMPILER diff --git a/deps/GraphBLAS/Demo/Source/wathen.c b/deps/GraphBLAS/Demo/Source/wathen.c index 90abd1ded2..9cb8468ba3 100644 --- a/deps/GraphBLAS/Demo/Source/wathen.c +++ b/deps/GraphBLAS/Demo/Source/wathen.c @@ -11,8 +11,6 @@ // wathen.m. #include "GraphBLAS.h" -#undef GB_PUBLIC -#define GB_LIBRARY #include "graphblas_demos.h" //------------------------------------------------------------------------------ @@ -29,7 +27,6 @@ void rho_scale (double *f, const double *e) // Wathen function //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info wathen // construct a random Wathen matrix ( GrB_Matrix *A_output, // output matrix diff --git a/deps/GraphBLAS/Doc/ChangeLog b/deps/GraphBLAS/Doc/ChangeLog index 773c94a03c..e9f6a100b4 100644 --- a/deps/GraphBLAS/Doc/ChangeLog +++ b/deps/GraphBLAS/Doc/ChangeLog @@ -1,4 +1,69 @@ -Version 7.3.0, Oct 11, 2022 +Version 7.4.4, Mar 25, 2023 + + * (47) bug fix: OpenMP atomics require seq_cst on the ARM. + Revised GB_atomics.h accordingly, and added them for all + architectures (caught by Gabor Szarnyas). + +Version 7.4.3, Jan 20, 2023 + + * debug: turned on in GrB_Matrix_removeElement by mistake. + +Version 7.4.2, Jan 17, 2023 + + * minor change to build system: for SuiteSparse v7.0.0 + * deprecation notice: in GraphBLAS v8.0.0, the ability to set the + # of threads, and chunk size, in the descriptor will be removed. + It still appears in v7.x, but will be replaced by a Context object + in v8.0.0. + +Version 7.4.1, Jan 9, 2023 + + * global free pool: disabled. Benefit for single-thread user applications + was modest, and it causes too much contention in a critical section + when the user application is multi-threaded. + * GrB_mxm: revised task creation heuristics for sparse-times-sparse for + better performance. "chunk" and "very_costly" had been tuned in v7.3.x + for sparse-times-dense but this slowed down sparse-times-sparse. The + new heuristic keeps the chunk & very_costly parameters for + sparse-times-dense but restores the prior values for + sparse-times-sparse from v7.2.0 (Aug 8, 2022). See + Source/GB_AxB_saxpy3_slice_balanced.c. + +Version 7.4.0, Dec 23, 2022 + + * added non-va_arg methods: va_arg-based GxB_get/set methods are ANSI C11 + but cause issues for cffi in Python. As a temporary workaround, new + methods have been added that do not use va_arg. The existing + GxB_get/set methods are not changed. The new methods are not in the + user guide, since all of the GxB_get/set methods will be superceded + with GrB_get/set in the v2.1 C API. At that point, all GxB_get/set + methods will become historical (kept, not deprecated, but removed from + the user guide). + +Version 7.3.3, Dec 9, 2022 + + * minor change to build system + * stdatomic.h: using #include and atomic_compare_exchange_weak + instead of GCC/clang/icx __atomic_* variants. + Added -latomic if required. + * chunk factor for C=A*B (saxpy3 method): revised for non-builtin-semirings + +Version 7.3.2, Nov 12, 2022 + + * cmake_modules: minor revision to build system, to sync + with SuiteSparse v6.0.0 + * Added option -DNOPENMP=1 to disable OpenMP parallelism + +Version 7.3.1, Oct 21, 2022 + + * workaround for Microsoft Visual Studio bug : MSC 19.2x (in vs2019) + encounters a compiler bug when compiling the FIRST_FC32 and SECOND_FC32 + binary operators. This version adds a flag that disables those + methods. The operators still work, they are just handled by the + slower generic methods. Thanks to Erik Welch, H. Vetinari, and others + in the conda-forge community for tracking this down. + +Version 7.3.0, Oct 14, 2022 * GrB_Matrix: changes to the internal data structure * minor internal changes: A->nvals for sparse/hypersparse diff --git a/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.bib b/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.bib index 8fec2de5be..28d7450008 100644 --- a/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.bib +++ b/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.bib @@ -166,8 +166,8 @@ @article{Davis22 author = {Davis, Timothy A.}, title = {Algorithm 10xx: {SuiteSparse:GraphBLAS}: Parallel Graph Algorithms in the Language of Sparse Linear Algebra}, journal = {ACM Trans. Math. Softw.}, -year = {2022}, -note = {(submitted, revised Apr 3, 2022)} +year = {2023}, +note = {(to appear)} } diff --git a/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.pdf b/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.pdf index 6405e509d3..8c58c348d7 100644 Binary files a/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.pdf and b/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.pdf differ diff --git a/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.tex b/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.tex index fff532d867..eb222788c8 100644 --- a/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.tex +++ b/deps/GraphBLAS/Doc/GraphBLAS_UserGuide.tex @@ -2017,7 +2017,7 @@ \subsection{GraphBLAS unary operators: {\sf GrB\_UnaryOp}, $z=f(x)$} %========== $\sinh^{-1}(x)$ when $x$ is complex do not compute the correct result. Thus, the unary operators \verb'GxB_ASIN_FC32', \verb'GxB_ASIN_FC64' \verb'GxB_ASINH_FC32', and \verb'GxB_ASINH_FC64' do not work properly if the MS -Visual Studio compiler is used. These functions work properly if the gcc, icc, +Visual Studio compiler is used. These functions work properly if the gcc, icx, icc, or clang compilers are used on Linux or MacOS. Integer division by zero normally terminates an application, but this is @@ -3717,8 +3717,9 @@ \subsubsection{{\sf GrB\_Scalar\_wait:} wait for a scalar} all pending computations are finished, and different user threads may simultaneously call GraphBLAS operations that use the scalar \verb's' as an input parameter. +See Section~\ref{omp_parallelism} +if GraphBLAS is compiled without OpenMP. -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Scalar\_dup:} copy a scalar} %------------------------------------------------------------------------------- @@ -4030,6 +4031,8 @@ \subsubsection{{\sf GrB\_Vector\_wait:} wait for a vector} all pending computations are finished, and different user threads may simultaneously call GraphBLAS operations that use the vector \verb'w' as an input parameter. +See Section~\ref{omp_parallelism} +if GraphBLAS is compiled without OpenMP. \newpage %------------------------------------------------------------------------------- @@ -4623,8 +4626,11 @@ \subsubsection{{\sf GrB\_Matrix\_wait:} wait for a matrix} all pending computations are finished, and different user threads may simultaneously call GraphBLAS operations that use the matrix \verb'C' as an input parameter. +See Section~\ref{omp_parallelism} +if GraphBLAS is compiled without OpenMP. %------------------------------------------------------------------------------- +\newpage \subsubsection{{\sf GrB\_Matrix\_dup:} copy a matrix} %------------------------------------------------------------------------------- \label{matrix_dup} @@ -4663,7 +4669,6 @@ \subsubsection{{\sf GrB\_Matrix\_dup:} copy a matrix} same set of values, but they do not depend on each other. Modifying one has no effect on the other. -\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_clear:} clear a matrix of all entries} %------------------------------------------------------------------------------- @@ -4685,7 +4690,7 @@ \subsubsection{{\sf GrB\_Matrix\_clear:} clear a matrix of all entries} with \verb'A (:,:) = 0' in MATLAB. The type and dimensions of \verb'A' do not change. Any pending updates to the matrix are discarded. -% \newpage +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_nrows:} return the number of rows of a matrix} %------------------------------------------------------------------------------- @@ -4869,7 +4874,7 @@ \subsubsection{{\sf GrB\_Matrix\_build:} build a matrix from a set of tuples} for assembling duplicates (summation), and it can only build double, double complex, and logical sparse matrices. -\newpage +% \newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GxB\_Matrix\_build\_Scalar:} build a matrix from a set of tuples} %------------------------------------------------------------------------------- @@ -4898,6 +4903,7 @@ \subsubsection{{\sf GxB\_Matrix\_build\_Scalar:} build a matrix from a set of tu entries in the sparsity pattern of \verb'C' are identical, and equal to the input scalar value. +\newpage %------------------------------------------------------------------------------- \subsubsection{{\sf GrB\_Matrix\_setElement:} add an entry to a matrix} %------------------------------------------------------------------------------- @@ -5157,7 +5163,7 @@ \subsubsection{{\sf GxB\_Matrix\_reshape:} reshape a matrix} bool by_col, // true if reshape by column, false if by row GrB_Index nrows_new, // new number of rows of C GrB_Index ncols_new, // new number of columns of C - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; \end{verbatim} } \end{mdframed} @@ -5211,7 +5217,7 @@ \subsubsection{{\sf GxB\_Matrix\_reshapeDup:} reshape a matrix} bool by_col, // true if reshape by column, false if by row GrB_Index nrows_new, // number of rows of C GrB_Index ncols_new, // number of columns of C - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; \end{verbatim} } \end{mdframed} @@ -5595,7 +5601,6 @@ \subsubsection{{\sf GxB\_Vector\_serialize:} serialize a vector} // input: GrB_Vector u, // vector to serialize const GrB_Descriptor desc // descriptor to select compression method - // and to control # of threads used ) ; \end{verbatim} } \end{mdframed} @@ -5650,7 +5655,7 @@ \subsubsection{{\sf GxB\_Vector\_deserialize:} deserialize a vector} GrB_Type type, // type of the vector w. See GxB_Matrix_deserialize. const void *blob, // the blob GrB_Index blob_size, // size of the blob - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; \end{verbatim} } \end{mdframed} @@ -5742,7 +5747,6 @@ \subsubsection{{\sf GxB\_Matrix\_serialize:} serialize a matrix} // input: GrB_Matrix A, // matrix to serialize const GrB_Descriptor desc // descriptor to select compression method - // and to control # of threads used ) ; \end{verbatim} } \end{mdframed} @@ -5811,7 +5815,7 @@ \subsubsection{{\sf GxB\_Matrix\_deserialize:} deserialize a matrix} // type of C. const void *blob, // the blob GrB_Index blob_size, // size of the blob - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; \end{verbatim} } \end{mdframed} @@ -7592,7 +7596,7 @@ \subsection{GraphBLAS descriptors: {\sf GrB\_Descriptor}} %===================== \begin{mdframed}[userdefinedwidth=6in] {\footnotesize \begin{verbatim} -#define GxB_NTHREADS 5 // for both GrB_Desc_field and GxB_Option_field +#define GxB_NTHREADS 5 // for GxB_Option_field #define GxB_CHUNK 7 typedef enum { @@ -7600,8 +7604,6 @@ \subsection{GraphBLAS descriptors: {\sf GrB\_Descriptor}} %===================== GrB_MASK = 1, // descriptor for the mask input of a method GrB_INP0 = 2, // descriptor for the first input of a method GrB_INP1 = 3, // descriptor for the second input of a method - GxB_DESCRIPTOR_NTHREADS = GxB_NTHREADS, // number of threads to use - GxB_DESCRIPTOR_CHUNK = GxB_CHUNK, // chunk size for small problems GxB_AxB_METHOD = 1000, // descriptor for selecting C=A*B algorithm GxB_SORT = 35 // control sort in GrB_mxm GxB_COMPRESSION = 36, // select compression for serialize @@ -7769,17 +7771,12 @@ \subsection{GraphBLAS descriptors: {\sf GrB\_Descriptor}} %===================== \end{itemize} -\item \verb'GxB_NTHREADS' controls how many threads a method uses. - By default (if set to zero, or \verb'GxB_DEFAULT'), all available threads - are used. The maximum available threads is controlled by the global - setting, which is \verb'omp_get_max_threads ( )' by default. If set to - some positive integer \verb'nthreads' less than this maximum, at most - \verb'nthreads' threads will be used. See Section~\ref{omp_parallelism} - for details. +\item \verb'GxB_NTHREADS' controls how many threads a method uses, via + the descriptor, but is deprecated. + It will be removed from the descriptor entirely in v8.0.0. -\item \verb'GxB_CHUNK' is a \verb'double' value that controls how many threads - a method uses for small problems. See Section~\ref{omp_parallelism} for - details. +\item \verb'GxB_CHUNK' is deprecated as used in the descriptor. + It will be removed from the descriptor entirely in v8.0.0. \item \verb'GxB_SORT' provides a hint to \verb'GrB_mxm', \verb'GrB_mxv', \verb'GrB_vxm', and \verb'GrB_reduce' (to vector). These methods can leave @@ -7888,7 +7885,7 @@ \subsubsection{{\sf GrB\_Descriptor\_set:} set a parameter in a descriptor} \verb'GrB_Descriptor_set' sets a descriptor field (\verb'GrB_OUTP', \verb'GrB_MASK', \verb'GrB_INP0', \verb'GrB_INP1', or \verb'GxB_AxB_METHOD') to a particular value. Use \verb'GxB_Dec_set' to set the value of -\verb'GxB_NTHREADS', \verb'GxB_CHUNK', and \verb'GxB_SORT'. +\verb'GxB_SORT'. If an error occurs, \verb'GrB_error(&err,desc)' returns details about the error. \vspace{0.2in} @@ -8040,16 +8037,6 @@ \subsubsection{{\sf GrB\_DESC\_*:} built-in descriptors} Attempts to modify them result in an error (\verb'GrB_INVALID_VALUE'); attempts to free them are silently ignored. -% \verb'GrB_NULL' is the default descriptor, with all settings at their defaults: -% \verb'OUTP': do not replace the output, -% \verb'MASK': mask is valued and not complemented, -% \verb'INP0': first input not transposed, and -% \verb'INP1': second input not transposed. -% For these pre-defined descriptors, the -% \verb'GxB_NTHREADS', -% \verb'GxB_CHUNK', and -% \verb'GxB_SORT' settings are at their default values. - \vspace{0.2in} \noindent {\footnotesize @@ -8388,10 +8375,6 @@ \section{SuiteSparse:GraphBLAS Options} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \verb'GrB_MASK' & \verb'GrB_Desc_Value' & mask option \\ \verb'GrB_INP0' & \verb'GrB_Desc_Value' & transpose input 0 \\ \verb'GrB_INP1' & \verb'GrB_Desc_Value' & transpose input 1 \\ -\verb'GxB_DESCRIPTOR_NTHREADS' & \verb'int' & number of threads to use \\ -\verb'GxB_NTHREADS' & \verb'int' & number of threads to use \\ -\verb'GxB_DESCRIPTOR_CHUNK' & \verb'double' & chunk size \\ -\verb'GxB_CHUNK' & \verb'double' & chunk size \\ \verb'GxB_AxB_METHOD' & \verb'int' & method for matrix multiply \\ \verb'GxB_SORT' & \verb'int' & lazy vs aggressive sort \\ \verb'GxB_COMPRESSION' & \verb'int' & compression for serialization \\ @@ -8433,6 +8416,7 @@ \section{SuiteSparse:GraphBLAS Options} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \verb'GxB_LIBRARY_LICENSE' & \verb'char *' & license \\ \verb'GxB_LIBRARY_COMPILE_DATE' & \verb'char *' & date of compilation \\ \verb'GxB_LIBRARY_COMPILE_TIME' & \verb'char *' & time of compilation \\ +\verb'GxB_LIBRARY_OPENMP' & \verb'bool' & true if compiled with OpenMP\\ \verb'GxB_LIBRARY_URL' & \verb'char *' & url of library \\ \verb'GxB_API_VERSION' & \verb'int [3]' & C API version \\ \verb'GxB_API_DATE' & \verb'char *' & C API date \\ @@ -8488,10 +8472,6 @@ \section{SuiteSparse:GraphBLAS Options} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \verb'GrB_MASK' & \verb'GrB_Desc_Value' & mask option \\ \verb'GrB_INP0' & \verb'GrB_Desc_Value' & transpose input 0 \\ \verb'GrB_INP1' & \verb'GrB_Desc_Value' & transpose input 1 \\ -\verb'GxB_DESCRIPTOR_NTHREADS' & \verb'int' & number of threads to use \\ -\verb'GxB_NTHREADS' & \verb'int' & number of threads to use \\ -\verb'GxB_DESCRIPTOR_CHUNK' & \verb'double' & chunk size \\ -\verb'GxB_CHUNK' & \verb'double' & chunk size \\ \verb'GxB_AxB_METHOD' & \verb'int' & method for matrix multiply \\ \verb'GxB_SORT' & \verb'int' & lazy vs aggressive sort \\ \verb'GxB_COMPRESSION' & \verb'int' & compression for serialization \\ @@ -8537,19 +8517,9 @@ \subsection{OpenMP parallelism} GxB_set (GxB_NTHREADS, nthreads_max) ; GxB_set (GxB_CHUNK, (double) 20000) ; \end{verbatim} } -\item Per operation: Most GraphBLAS operations take a \verb'GrB_Descriptor' -input, and this can be modified to set the number of threads and chunk -size for the operation that uses this descriptor. Note that \verb'chunk' -is a \verb'double'. - - {\footnotesize - \begin{verbatim} - GrB_Descriptor desc ; - GrB_Descriptor_new (&desc) - int nthreads_max = 40 ; - GxB_set (desc, GxB_NTHREADS, nthreads_max) ; - double chunk = 20000 ; - GxB_set (desc, GxB_CHUNK, chunk) ; \end{verbatim} } +\item Per operation: Setting the number of threads and the chunk +size in the descriptor is deprecated. +It will be removed entirely in v8.0.0 from the descriptor. \end{itemize} @@ -8561,15 +8531,29 @@ \subsection{OpenMP parallelism} The default for \verb'nthreads_max' is the return value from \verb'omp_get_max_threads', and the default chunk size is currently 65,536. -If a descriptor value for either parameter is left at its default, or set to -\verb'GxB_DEFAULT', then the global setting is used. This global setting may -have been modified from its default, and this modified value will be used. - For example, suppose \verb'omp_get_max_threads' reports 8 threads. If \newline \verb'GxB_set (GxB_NTHREADS, 4)' is used, then the global setting is four -threads, not eight. If a descriptor is used but its \verb'GxB_NTHREADS' is not -set, or set to \verb'GxB_DEFAULT', then any operation that uses this descriptor -will use 4 threads. +threads, not eight. + +GraphBLAS may be compiled without OpenMP, by setting \verb'-DNOPENMP=1'. +The library will be thread-safe, with one exception. \verb'GrB_wait' is +intended to provide thread-safety by flushing the cache of one user thread +so the object can be safely read by another thread. This is accomplished +with \verb'pragma omp flush', but if OpenMP is not available, this does +nothing. If OpenMP is not available or \verb'-DNOPEMP=1' is used, then +user applications need to ensure their own thread safety when one user thread +computes a result that is then read by another thread. + +You can query GraphBLAS at run time to ask if it was compiled with OpenMP: + +\begin{verbatim} + bool have_openmp ; + GxB_get (GxB_LIBRARY_OPENMP, &have_openmp) ; + if (!have_openmp) printf ("GraphBLAS not compiled with OpenMP\n") : +\end{verbatim} + +Compiling GraphBLAS without OpenMP is not recommended for installation in a +package manager (Linux, conda-forge, spack, brew, vcpkg, etc). %------------------------------------------------------------------------------- \subsection{Storing a matrix by row or by column} @@ -8816,6 +8800,7 @@ \subsection{Parameter types} GxB_LIBRARY_LICENSE = 13, // license of the library (char *) GxB_LIBRARY_COMPILE_DATE = 14, // date library was compiled (char *) GxB_LIBRARY_COMPILE_TIME = 15, // time library was compiled (char *) + GxB_LIBRARY_OPENMP = 25, // library compiled with OpenMP GxB_API_VERSION = 16, // API version (3 int's) GxB_API_DATE = 17, // date of the API (char *) GxB_API_ABOUT = 18, // about the API (char *) @@ -9117,8 +9102,8 @@ \subsection{{\sf GxB\_Desc\_set:} set a {\sf GrB\_Descriptor} value} This usage is similar to \verb'GrB_Descriptor_set', just with a name that is consistent with the other usages of this generic function. Unlike -\verb'GrB_Descriptor_set', the \verb'field' may also be \verb'GxB_NTHREADS', -\verb'GxB_CHUNK', \verb'GxB_SORT', \verb'GxB_COMPRESSION', or +\verb'GrB_Descriptor_set', the \verb'field' may also be +\verb'GxB_SORT', \verb'GxB_COMPRESSION', or \verb'GxB_IMPORT'. Refer to Sections~\ref{descriptor_set}~and~\ref{desc_set} for details. If an error occurs, \verb'GrB_error(&err,desc)' returns details about the error. @@ -9166,6 +9151,7 @@ \subsection{{\sf GxB\_Global\_Option\_get:} retrieve a global option} \verb'GxB_LIBRARY_LICENSE' & license for the library \\ \verb'GxB_LIBRARY_COMPILE_DATE' & date of compilation \\ \verb'GxB_LIBRARY_COMPILE_TIME' & time of compilation \\ + \verb'GxB_LIBRARY_OPENMP' & library compiled with OpenMP\\ \verb'GxB_LIBRARY_URL' & URL of the library \\ \hline \verb'GxB_API_VERSION' & GraphBLAS C API Specification Version \\ @@ -9304,8 +9290,6 @@ \subsection{{\sf GxB\_Desc\_get:} retrieve a {\sf GrB\_Descriptor} value} This usage is the same as \verb'GxB_Desc_get'. The \verb'field' parameter can be \verb'GrB_OUTP', \verb'GrB_MASK', \verb'GrB_INP0', \verb'GrB_INP1', \verb'GxB_AxB_METHOD', -\verb'GxB_NTHREADS', -\verb'GxB_CHUNK', \verb'GxB_SORT', \verb'GxB_COMPRESSION', or \verb'GxB_IMPORT'. @@ -9363,6 +9347,7 @@ \subsection{Summary of usage of {\sf GxB\_set} and {\sf GxB\_get}} GxB_get (GxB_LIBRARY_LICENSE, char **) ; GxB_get (GxB_LIBRARY_COMPILE_DATE, char **) ; GxB_get (GxB_LIBRARY_COMPILE_TIME, char **) ; + GxB_get (GxB_LIBRARY_OPENMP, bool *) ; GxB_get (GxB_LIBRARY_URL, char **) ; GxB_get (GxB_API_VERSION, int *) ; GxB_get (GxB_API_DATE, char **) ; @@ -9428,10 +9413,6 @@ \subsection{Summary of usage of {\sf GxB\_set} and {\sf GxB\_get}} GxB_set (GrB_Descriptor d, GxB_AxB_METHOD, GxB_AxB_SAXPY) ; GxB_set (GrB_Descriptor d, GxB_AxB_METHOD, GxB_AxB_DOT) ; GxB_get (GrB_Descriptor d, GrB_AxB_METHOD, GrB_Desc_Value *v) ; - GxB_set (GrB_Descriptor d, GxB_NTHREADS, int nthreads) ; - GxB_get (GrB_Descriptor d, GxB_NTHREADS, int *nthreads) ; - GxB_set (GrB_Descriptor d, GxB_CHUNK, double chunk) ; - GxB_get (GrB_Descriptor d, GxB_CHUNK, double *chunk) ; GxB_set (GrB_Descriptor d, GxB_SORT, sort) ; GxB_get (GrB_Descriptor d, GxB_SORT, int *sort) ; GxB_set (GrB_Descriptor d, GxB_COMPRESSION, GxB_FAST_IMPORT) ; @@ -14791,7 +14772,10 @@ \subsection{User applications using OpenMP or other threading models} GraphBLAS can also be combined with user applications that rely on MPI, the Intel TBB threading library, POSIX pthreads, Microsoft Windows threads, or any -other threading library. In all cases, GraphBLAS will be thread safe. +other threading library. If GraphBLAS itself is compiled with OpenMP, +it will be thread safe when combined with other libraries. +See Section~\ref{omp_parallelism} for thread-safety issues that can occur +if GraphBLAS is compiled without OpenMP. \newpage %------------------------------------------------------------------------------- @@ -14840,7 +14824,7 @@ \subsection{On Linux and Mac} {\small \begin{verbatim} - make CC=icx CXX=icpx JOBS=4 \end{verbatim} } + make CC=icx JOBS=4 \end{verbatim} } GraphBLAS v6.1.3 and later use the \verb'cpu_features' package by Google to determine if the target architecture supports AVX2 and/or AVX512F (on Intel @@ -14869,7 +14853,7 @@ \subsection{On Linux and Mac} make CMAKE_OPTIONS='-DGBNCPUFEAT=1 -DGBAVX2=1' JOBS=40 \end{verbatim} } After compiling the library, you can compile the demos with -\verb'make all' and then \verb'make demo' while in the top-level +\verb'make all' and then \verb'make demos' while in the top-level GraphBLAS folder. If \verb'cmake' or \verb'make' fail, it might be that your default compiler @@ -14902,7 +14886,7 @@ \subsection{On Linux and Mac} If you do not have \verb'cmake', refer to Section~\ref{altmake}. %---------------------------------------- -\subsection{More details on the Mac} +\subsection{More details on the Mac (Intel-based)} %---------------------------------------- SuiteSparse:GraphBLAS requires OpenMP for its internal parallelism, but @@ -14913,7 +14897,7 @@ \subsection{More details on the Mac} {\small \begin{verbatim} - make CC=icc CXX=icpc \end{verbatim} } + make CC=icx \end{verbatim} } The following instructions work on MacOS Big Sur (v11.3) and MacOS Monterey (12.1), using @@ -14987,6 +14971,53 @@ \subsection{More details on the Mac} cd ../../test gbtest \end{verbatim} } +%---------------------------------------- +\subsection{More details for MATLAB on the Mac (Apple Silicon based)} +%---------------------------------------- + +MATLAB on the Apple-Silicon-based Mac (M1, M2) is not yet a native ARM64 +application (as of R2022b). + +For MATLAB on the M1 Mac, you must compile the x86 version of +\verb'libgraphblas_matlab.so'. This requires the x86 version of \verb'brew'. +First, install it in \verb'/usr/local/bin/brew' with these 2 commands (the 2nd +as a single line). + +\begin{verbatim} +arch -x86_64 zsh +arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com + /Homebrew/install/master/install.sh)" +\end{verbatim} + +If you install the default arm64 \verb'brew', it is located in +\verb'/opt/homebrew/bin/brew'. I created these two aliases in my \verb'.zshrc' +file: + +\begin{verbatim} +alias brew_arm='arch -arm64 /opt/homebrew/bin/brew' +alias brew_x86='arch -x86_64 /usr/local/bin/brew' +\end{verbatim} + +Next, use \verb'brew_86' to install \verb'gcc-12' and \verb'libomp'. + +\begin{verbatim} +brew_x86 install gcc +brew_x86 install libomp +\end{verbatim} + +In the \verb'GraphBLAS/GraphBLAS' folder, do the following to compile +\verb'libgraphblas_matlab.so': + +\begin{verbatim} +make CC=/usr/local/bin/gcc-12 CXX=/usr/local/bin/g++-12 JOBS=8 +sudo make install +\end{verbatim} + +Ignore the \verb'"-arch option ignored"' warnings. + +You can now start MATLAB and install the MATLAB interface with +\verb'gbmake' as described in the previous section. + %---------------------------------------- \subsection{On the ARM64 architecture} %---------------------------------------- @@ -15024,17 +15055,20 @@ \subsection{On Microsoft Windows} SuiteSparse:GraphBLAS. \item AVX acceleration is not enabled. + +\item The ninja code generator does not work with MS Visual Studio to +build GraphBLAS, because of a limitation in cmake. \end{itemize} If you use a recent \verb'gcc' or \verb'icx' compiler on Windows other than the Microsoft Compiler (\verb'cl'), these limitations can be avoided. -The following instructions apply to Windows 10, CMake 3.16, and +The following instructions apply to Windows 10, CMake 3.19, and Visual Studio 2019, but may work for earlier versions. \begin{enumerate} -\item Install CMake 3.16 or later, if not already installed. +\item Install CMake 3.19 or later, if not already installed. See \url{https://cmake.org/} for details. \item Install Microsoft Visual Studio, if not already installed. @@ -15455,6 +15489,80 @@ \section{Release Notes} \begin{itemize} +\item Version 7.4.4, Mar 25, 2023 + + \begin{itemize} + \item (47) bug fix: OpenMP atomics require \verb'seq_cst' on the ARM. + Revised \verb'GB_atomics.h' accordingly, and added them for + all architectures (caught by Gabor Szarnyas). + \end{itemize} + +\item Version 7.4.3, Jan 20, 2023 + + \begin{itemize} + \item debug: turned on in \verb'GrB_Matrix_removeElement' by mistake. + \end{itemize} + +\item Version 7.4.2 (Jan 17, 2023) + + \begin{itemize} + \item minor change to build system: for SuiteSparse v7.0.0. + \item deprecation notice: in GraphBLAS v8.0.0, the ability to set the + number of threads, and chunk size, in the descriptor will be removed. + It still appears in v7.x, but will be replaced by a Context object + in v8.0.0. + \end{itemize} + +\item Version 7.4.1 (Dec 29, 2022) + + \begin{itemize} + \item global free pool: disabled. Benefit for single-thread user + applications was modest, and it causes too much contention in a + critical section when the user application is multi-threaded. + \item \verb'GrB_mxm': revised task creation heuristics for + sparse-times-sparse for better performance. + \end{itemize} + +\item Version 7.4.0 (Dec 23, 2022) + + \begin{itemize} + \item add non-\verb'va_arg' methods: \verb'va_arg'-based \verb'GxB_get/set' + methods are ANSI C11 but cause issues for cffi in Python. As a + temporary workaround, new methods have been added that do not use + \verb'va_arg'. The existing \verb'GxB_get/set' methods are not + changed. The new methods are not in the user guide, since all of the + \verb'GxB_get/set' methods will be superceded with \verb'GrB_get/set' + in the v2.1 C API. At that point, all \verb'GxB_get/set' methods will + become historical (kept, not deprecated, but removed from the user + guide). + \end{itemize} + +\item Version 7.3.3 (Dec 9, 2022) + + \begin{itemize} + \item \verb'stdatomic.h': using \verb'#include ' and + \verb'atomic_compare_exchange_weak' + instead of GCC/clang/icx \verb'__atomic_*' variants. + Added \verb'-latomic' if required. + \item chunk factor for C=A*B (saxpy3 method): + revised for non-builtin-semirings + \end{itemize} + +\item Version 7.3.2 (Nov 12, 2022) + + \begin{packed_itemize} + \item \verb'cmake_modules': minor revision to build system, to sync + with SuiteSparse v6.0.0 + \item Added option \verb'-DNOPENMP=1' to disable OpenMP parallelism. + \end{packed_itemize} + +\item Version 7.3.1 (Oct 21, 2022) + + \begin{packed_itemize} + \item workaround for a bug in the Microsoft Visual Studio Compiler, + MSC 19.2x (in vs2019). + \end{packed_itemize} + \item Version 7.3.0 (Oct 14, 2022) \begin{packed_itemize} @@ -16121,6 +16229,9 @@ \section{Acknowledgments} I would like to thank Joe Eaton and Corey Nolet for their collaboration on the CUDA kernels (still in progress), and for the support of NVIDIA. +I would like to thank Pat Quillen for his +collaboration and for the support of MathWorks. + I would like to thank John Eaton for his collaboration on the integration with Octave 7. @@ -16143,6 +16254,10 @@ \section{Acknowledgments} I would like to thank G{\'{a}}bor Sz{\'{a}}rnyas for porting the \verb'@GrB' interface to Octave 7 on Apple Silicon. +I would like to thank Markus M\"{u}tzel +for his help in porting the updates +to GraphBLAS v7.4.1 and SuiteSparse v7.0.0 to Windows. + I would like to thank Roi Lipman, Redis (\url{https://redislabs.com}), for our many discussions on GraphBLAS and for enabling its use in RedisGraph (\url{https://redislabs.com/redis-enterprise/technology/redisgraph/}), a graph @@ -16152,7 +16267,7 @@ \section{Acknowledgments} \url{https://redislabs.com/blog/new-redisgraph-1-0-achieves-600x-faster-performance-graph-databases/}}). SuiteSparse:GraphBLAS was developed with support from -NVIDIA, Intel, MIT Lincoln Lab, Redis, IBM, +NVIDIA, Intel, MIT Lincoln Lab, MathWorks, Redis, IBM, the National Science Foundation (1514406, 1835499), and Julia Computing. %------------------------------------------------------------------------------- diff --git a/deps/GraphBLAS/Doc/GraphBLAS_version.tex b/deps/GraphBLAS/Doc/GraphBLAS_version.tex index 8abf8ca42b..6f89da921b 100644 --- a/deps/GraphBLAS/Doc/GraphBLAS_version.tex +++ b/deps/GraphBLAS/Doc/GraphBLAS_version.tex @@ -1,5 +1,5 @@ % version of SuiteSparse:GraphBLAS \date{VERSION -7.3.0, -Oct 14, 2022} +7.4.4, +Mar 25, 2023} diff --git a/deps/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbver.c b/deps/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbver.c index 90c2d975ad..9ee8618cd8 100644 --- a/deps/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbver.c +++ b/deps/GraphBLAS/GraphBLAS/@GrB/private/mexfunctions/gbver.c @@ -51,10 +51,13 @@ void mexFunction version [0], version [1], version [2], date) ; char *compiler ; int cver [3] ; + bool have_openmp ; OK (GxB_get (GxB_COMPILER_NAME, &compiler)) ; OK (GxB_get (GxB_COMPILER_VERSION, cver)) ; - printf ("GraphBLAS compiled with %s (v%d.%d.%d)\n\n", compiler, - cver [0], cver [1], cver [2]) ; + OK (GxB_get (GxB_LIBRARY_OPENMP, &have_openmp)) ; + printf ("GraphBLAS compiled with %s (v%d.%d.%d), %s OpenMP\n", compiler, + cver [0], cver [1], cver [2], + have_openmp ? "with" : "without") ; printf ("@GrB License: Apache-2.0\n\n") ; OK (GxB_Global_Option_get (GxB_API_ABOUT, &spec)) ; printf ("Spec:\n%s\n", spec) ; diff --git a/deps/GraphBLAS/GraphBLAS/CMakeLists.txt b/deps/GraphBLAS/GraphBLAS/CMakeLists.txt index 11a6321894..9dd844253d 100644 --- a/deps/GraphBLAS/GraphBLAS/CMakeLists.txt +++ b/deps/GraphBLAS/GraphBLAS/CMakeLists.txt @@ -15,12 +15,10 @@ cmake_minimum_required ( VERSION 3.19 ) -# date version must match ../CMakeLists.txt: -# version of SuiteSparse:GraphBLAS -set ( GraphBLAS_DATE "Oct 14, 2022" ) -set ( GraphBLAS_VERSION_MAJOR 7 ) -set ( GraphBLAS_VERSION_MINOR 3 ) -set ( GraphBLAS_VERSION_SUB 0 ) +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/../cmake_modules ) + +include ( GraphBLAS_version ) message ( STATUS "Building SuiteSparse:GraphBLAS version: v" ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} @@ -36,13 +34,6 @@ set ( GraphBLAS_API_VERSION_SUB 0 ) # SuiteSparse policies #------------------------------------------------------------------------------- -set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules - ${CMAKE_SOURCE_DIR}/../cmake_modules - ${CMAKE_SOURCE_DIR}/../../SuiteSparse_config/cmake_modules - ${CMAKE_SOURCE_DIR}/../../SuiteSparse/SuiteSparse_config/cmake_modules - ) - set ( SUITESPARSE_SECOND_LEVEL true ) include ( SuiteSparsePolicy ) @@ -67,7 +58,13 @@ endif ( ) # find OpenMP and cpu_features #------------------------------------------------------------------------------- -find_package ( OpenMP ) +option ( NOPENMP "ON: do not use OpenMP. OFF (default): use OpenMP" off ) +if ( NOPENMP ) + # OpenMP has been disabled + set ( OPENMP_FOUND false ) +else ( ) + find_package ( OpenMP ) +endif ( ) if ( NOT GBNCPUFEAT ) # default: enable Google's cpu_features package @@ -120,8 +117,8 @@ else ( ) message ( STATUS "CMAKE C Flags release: " ${CMAKE_C_FLAGS_RELEASE} ) endif ( ) -message ( STATUS "CMAKE compiler ID: " ${CMAKE_C_COMPILER_ID} ) -message ( STATUS "CMAKE have OpenMP: " ${OPENMP_FOUND} ) +message ( STATUS "C compiler: ${CMAKE_C_COMPILER} ") +message ( STATUS "CMAKE have OpenMP: ${OPENMP_FOUND}" ) #------------------------------------------------------------------------------- # include directories @@ -131,9 +128,12 @@ set ( CMAKE_INCLUDE_CURRENT_DIR ON ) if ( CMAKE_CUDA_DEV ) # for CUDA development only; not for production use - include_directories ( ../Source/Template ../Source ../Include rename ../Source/Generated1 ../lz4 ../zstd ../zstd/zstd_subset ../rmm_wrap ) + include_directories ( ../Source/Template ../Source ../Include rename + ../Source/Generated1 ../lz4 ../zstd ../zstd/zstd_subset ../rmm_wrap ) else ( ) - include_directories ( ../Source/Template ../Source ../Include rename ../Source/Generated1 ../lz4 ../zstd ../zstd/zstd_subset ../rmm_wrap ../Source/Generated2 ) + include_directories ( ../Source/Template ../Source ../Include rename + ../Source/Generated1 ../lz4 ../zstd ../zstd/zstd_subset ../rmm_wrap + ../Source/Generated2 ) endif ( ) #------------------------------------------------------------------------------- @@ -205,7 +205,7 @@ else ( ) endif ( ) add_library ( graphblas_matlab SHARED ${GRAPHBLAS_SOURCES} ) -SET_TARGET_PROPERTIES ( graphblas_matlab PROPERTIES +set_target_properties ( graphblas_matlab PROPERTIES VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} SOVERSION ${GraphBLAS_VERSION_MAJOR} C_STANDARD_REQUIRED 11 @@ -224,13 +224,15 @@ endif ( ) # select the math library (not required for Microsoft Visual Studio) #------------------------------------------------------------------------------- -if ( "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" ) - set ( M_LIB "" ) -else ( ) - set ( M_LIB "m" ) +# libm: +if ( NOT WIN32 ) + target_link_libraries ( graphblas_matlab PUBLIC m ) endif ( ) -target_link_libraries ( graphblas_matlab PUBLIC ${M_LIB} ) +include ( SuiteSparseAtomic ) +if ( LIBATOMIC_REQUIRED ) + target_link_libraries ( graphblas_matlab PUBLIC atomic ) +endif ( ) #------------------------------------------------------------------------------- # add library dependencies @@ -274,30 +276,8 @@ message ( STATUS "CMAKE C flags: " ${CMAKE_C_FLAGS} ) # installation location #------------------------------------------------------------------------------- -# use "cmake -DSUITESPARSE_LOCAL=1" to install only in ../../lib and -# ../../include. - -message ( STATUS "System install libdir: ${CMAKE_INSTALL_LIBDIR}" ) -message ( STATUS "System install incdir: ${CMAKE_INSTALL_INCLUDEDIR}" ) -message ( STATUS "Local install libdir: ${SUITESPARSE_LIBDIR}" ) -message ( STATUS "Local install incdir: ${SUITESPARSE_INCLUDEDIR}" ) - -if ( NOT SUITESPARSE_LOCAL ) - # install in /usr/local/lib and /usr/local/include. - # requires "sudo make install" - message ( STATUS "Installation will be system-wide (requires 'sudo make install')" ) - install ( TARGETS graphblas_matlab - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) -endif ( ) - -if ( INSIDE_SUITESPARSE ) - # also install in SuiteSparse/lib and SuiteSparse/include; - # does not require "sudo make install", just "make install" - message ( STATUS "Installation in ../../lib and ../../include," ) - message ( STATUS " with 'make local ; make install'. No 'sudo' required." ) - install ( TARGETS graphblas_matlab - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) -endif ( ) - +install ( TARGETS graphblas_matlab + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) diff --git a/deps/GraphBLAS/GraphBLAS/Makefile b/deps/GraphBLAS/GraphBLAS/Makefile index 09d6e069c2..2495c70136 100644 --- a/deps/GraphBLAS/GraphBLAS/Makefile +++ b/deps/GraphBLAS/GraphBLAS/Makefile @@ -14,21 +14,25 @@ JOBS ?= 8 default: library -# just build the dynamic library; do not run the demo +# default is to install only in /usr/local library: - ( cd build ; cmake $(CMAKE_OPTIONS) .. ; $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DSUITESPARSE_LOCAL=1 .. && $(MAKE) --jobs=${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + +# install only in /usr/local (default) +global: + ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) # compile with -g debug: - ( cd build ; cmake -DCMAKE_BUILD_TYPE=Debug $(CMAKE_OPTIONS) .. ; $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake -DCMAKE_BUILD_TYPE=Debug $(CMAKE_OPTIONS) .. && cmake --build . -j$(JOBS) ) # just do 'make' in build; do not rerun the cmake script remake: - ( cd build ; $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake --build . -j$(JOBS) ) # just run cmake; do not compile setup: @@ -37,7 +41,7 @@ setup: # installs GraphBLAS to the install location defined by cmake, usually # /usr/local/lib and /usr/local/include install: - ( cd build ; $(MAKE) install ) + ( cd build && cmake --install . ) # remove any installed libraries and #include files uninstall: diff --git a/deps/GraphBLAS/GraphBLAS/rename/GB_rename.h b/deps/GraphBLAS/GraphBLAS/rename/GB_rename.h index a31204eb40..14e32a7a1b 100644 --- a/deps/GraphBLAS/GraphBLAS/rename/GB_rename.h +++ b/deps/GraphBLAS/GraphBLAS/rename/GB_rename.h @@ -1473,9 +1473,13 @@ #define GxB_CREAL_FC32 GxM_CREAL_FC32 #define GxB_CREAL_FC64 GxM_CREAL_FC64 #define GxB_Desc_get GxM_Desc_get +#define GxB_Desc_get_FP64 GxM_Desc_get_FP64 +#define GxB_Desc_get_INT32 GxM_Desc_get_INT32 #define GxB_Descriptor_fprint GxM_Descriptor_fprint #define GxB_Descriptor_get GxM_Descriptor_get #define GxB_Desc_set GxM_Desc_set +#define GxB_Desc_set_FP64 GxM_Desc_set_FP64 +#define GxB_Desc_set_INT32 GxM_Desc_set_INT32 #define GxB_deserialize_type_name GxM_deserialize_type_name #define GxB_DIAG GxM_DIAG #define GxB_DIV_FC32 GxM_DIV_FC32 @@ -1600,7 +1604,17 @@ #define GxB_GE_THUNK GxM_GE_THUNK #define GxB_GE_ZERO GxM_GE_ZERO #define GxB_Global_Option_get GxM_Global_Option_get +#define GxB_Global_Option_get_CHAR GxM_Global_Option_get_CHAR +#define GxB_Global_Option_get_FP64 GxM_Global_Option_get_FP64 +#define GxB_Global_Option_get_FUNCTION GxM_Global_Option_get_FUNCTION +#define GxB_Global_Option_get_INT32 GxM_Global_Option_get_INT32 +#define GxB_Global_Option_get_INT64 GxM_Global_Option_get_INT64 #define GxB_Global_Option_set GxM_Global_Option_set +#define GxB_Global_Option_set_FP64 GxM_Global_Option_set_FP64 +#define GxB_Global_Option_set_FP64_ARRAY GxM_Global_Option_set_FP64_ARRAY +#define GxB_Global_Option_set_FUNCTION GxM_Global_Option_set_FUNCTION +#define GxB_Global_Option_set_INT32 GxM_Global_Option_set_INT32 +#define GxB_Global_Option_set_INT64_ARRAY GxM_Global_Option_set_INT64_ARRAY #define GxB_GT_THUNK GxM_GT_THUNK #define GxB_GT_ZERO GxM_GT_ZERO #define GxB_HYPER_DEFAULT GxM_HYPER_DEFAULT @@ -2029,7 +2043,11 @@ #define GxB_Matrix_isStoredElement GxM_Matrix_isStoredElement #define GxB_Matrix_memoryUsage GxM_Matrix_memoryUsage #define GxB_Matrix_Option_get GxM_Matrix_Option_get +#define GxB_Matrix_Option_get_FP64 GxM_Matrix_Option_get_FP64 +#define GxB_Matrix_Option_get_INT32 GxM_Matrix_Option_get_INT32 #define GxB_Matrix_Option_set GxM_Matrix_Option_set +#define GxB_Matrix_Option_set_FP64 GxM_Matrix_Option_set_FP64 +#define GxB_Matrix_Option_set_INT32 GxM_Matrix_Option_set_INT32 #define GxB_Matrix_pack_BitmapC GxM_Matrix_pack_BitmapC #define GxB_Matrix_pack_BitmapR GxM_Matrix_pack_BitmapR #define GxB_Matrix_pack_CSC GxM_Matrix_pack_CSC @@ -3275,7 +3293,11 @@ #define GxB_Vector_isStoredElement GxM_Vector_isStoredElement #define GxB_Vector_memoryUsage GxM_Vector_memoryUsage #define GxB_Vector_Option_get GxM_Vector_Option_get +#define GxB_Vector_Option_get_FP64 GxM_Vector_Option_get_FP64 +#define GxB_Vector_Option_get_INT32 GxM_Vector_Option_get_INT32 #define GxB_Vector_Option_set GxM_Vector_Option_set +#define GxB_Vector_Option_set_FP64 GxM_Vector_Option_set_FP64 +#define GxB_Vector_Option_set_INT32 GxM_Vector_Option_set_INT32 #define GxB_Vector_pack_Bitmap GxM_Vector_pack_Bitmap #define GxB_Vector_pack_CSC GxM_Vector_pack_CSC #define GxB_Vector_pack_Full GxM_Vector_pack_Full @@ -3619,7 +3641,6 @@ #define GB_FSE_readNCount_bmi2 GM_FSE_readNCount_bmi2 #define GB_FSE_versionNumber GM_FSE_versionNumber #define GB_FSE_writeNCount GM_FSE_writeNCount -#define GB_Global GM_Global #define GB_Global_abort_function GM_Global_abort_function #define GB_Global_abort_function_set GM_Global_abort_function_set #define GB_Global_bitmap_switch_default GM_Global_bitmap_switch_default diff --git a/deps/GraphBLAS/Include/GraphBLAS.h b/deps/GraphBLAS/Include/GraphBLAS.h index 35bd805af9..8d1ab3748d 100644 --- a/deps/GraphBLAS/Include/GraphBLAS.h +++ b/deps/GraphBLAS/Include/GraphBLAS.h @@ -83,19 +83,28 @@ // compiler variations //============================================================================== -// Exporting/importing symbols for Microsoft Visual Studio - +// GB_GLOBAL: for declaring global variables visible to the user application. +// These are not used for functions, just global variables like the predefined +// operators (GrB_PLUS_FP32), types, monoids, semirings, and descriptors. #if ( _MSC_VER && !(__INTEL_COMPILER || __INTEL_CLANG_COMPILER) ) -#ifdef GB_LIBRARY -// compiling SuiteSparse:GraphBLAS itself, exporting symbols to user apps -#define GB_PUBLIC extern __declspec ( dllexport ) -#else -// compiling the user application, importing symbols from SuiteSparse:GraphBLAS -#define GB_PUBLIC extern __declspec ( dllimport ) -#endif + #if defined ( GB_DLL_EXPORT ) + // Compiling SuiteSparse:GraphBLAS as a Windows DLL, exporting symbols + // to user apps. + #define GB_GLOBAL extern __declspec ( dllexport ) + #elif defined ( GB_STATIC ) + // Compiling the user application on Windows, importing symbols from + // a static GraphBLAS library on Windows. The user application must do: + // #define GB_STATIC + // #include "GraphBLAS.h" + #define GB_GLOBAL extern + #else + // Compiling the user application on Windows, importing symbols from + // the SuiteSparse:GraphBLAS DLL. This is the default. + #define GB_GLOBAL extern __declspec ( dllimport ) + #endif #else -// for other compilers -#define GB_PUBLIC extern + // for other compilers + #define GB_GLOBAL extern #endif // GraphBLAS requires an ANSI C11 compiler for its polymorphic functions (using @@ -221,10 +230,10 @@ // The version of this implementation, and the GraphBLAS API version: #define GxB_IMPLEMENTATION_NAME "SuiteSparse:GraphBLAS" -#define GxB_IMPLEMENTATION_DATE "Oct 14, 2022" +#define GxB_IMPLEMENTATION_DATE "Mar 25, 2023" #define GxB_IMPLEMENTATION_MAJOR 7 -#define GxB_IMPLEMENTATION_MINOR 3 -#define GxB_IMPLEMENTATION_SUB 0 +#define GxB_IMPLEMENTATION_MINOR 4 +#define GxB_IMPLEMENTATION_SUB 4 #define GxB_SPEC_DATE "Nov 15, 2021" #define GxB_SPEC_MAJOR 2 #define GxB_SPEC_MINOR 0 @@ -360,13 +369,11 @@ typedef enum } GrB_Mode ; -GB_PUBLIC GrB_Info GrB_init // start up GraphBLAS ( GrB_Mode mode // blocking or non-blocking mode, no GPU ) ; -GB_PUBLIC GrB_Info GxB_init // start up GraphBLAS and also define malloc, etc ( GrB_Mode mode, // blocking or non-blocking mode, @@ -378,7 +385,6 @@ GrB_Info GxB_init // start up GraphBLAS and also define malloc, etc void (* user_free_function ) (void *) ) ; -GB_PUBLIC GrB_Info GrB_finalize (void) ; // finish GraphBLAS //============================================================================== @@ -386,7 +392,6 @@ GrB_Info GrB_finalize (void) ; // finish GraphBLAS //============================================================================== // GrB_getVersion provides a runtime access of the C API Version. -GB_PUBLIC GrB_Info GrB_getVersion // runtime access to C API version number ( unsigned int *version, // returns GRB_VERSION @@ -420,16 +425,6 @@ GrB_Info GrB_getVersion // runtime access to C API version number // // GrB_INP1: the same as GrB_INP0 but for the second input // -// GxB_NTHREADS: the maximum number of threads to use in the current method. -// If <= GxB_DEFAULT (which is zero), then the number of threads is -// determined automatically. This is the default value. -// -// GxB_CHUNK: an integer parameter that determines the number of threads to use -// for a small problem. If w is the work to be performed, and chunk is -// the value of this parameter, then the # of threads is limited to floor -// (w/chunk). The default chunk is currently 64K, but this may change in -// the future. If chunk is set to <= GxB_DEFAULT (that is, zero), the -// default is used. // // GxB_AxB_METHOD: this is a hint to SuiteSparse:GraphBLAS on which algorithm // it should use to compute C=A*B, in GrB_mxm, GrB_mxv, and GrB_vxm. @@ -494,12 +489,9 @@ typedef enum GrB_INP0 = 2, // descriptor for the first input of a method GrB_INP1 = 3, // descriptor for the second input of a method - GxB_DESCRIPTOR_NTHREADS = GxB_NTHREADS, // max number of threads to use. - // If <= GxB_DEFAULT, then GraphBLAS selects the number - // of threads automatically. - - GxB_DESCRIPTOR_CHUNK = GxB_CHUNK, // chunk size for small problems. - // If <= GxB_DEFAULT, then the default is used. + // setting NTHREADS and CHUNK in the descriptor is deprecated + GxB_DESCRIPTOR_NTHREADS = GxB_NTHREADS, // DEPRECATED + GxB_DESCRIPTOR_CHUNK = GxB_CHUNK, // DEPRECATED // GPU control (DRAFT: in progress, do not use) GxB_DESCRIPTOR_GPU_CONTROL = GxB_GPU_CONTROL, @@ -547,13 +539,11 @@ GrB_Desc_Value ; typedef struct GB_Descriptor_opaque *GrB_Descriptor ; -GB_PUBLIC GrB_Info GrB_Descriptor_new // create a new descriptor ( GrB_Descriptor *descriptor // handle of descriptor to create ) ; -GB_PUBLIC GrB_Info GrB_Descriptor_set // set a parameter in a descriptor ( GrB_Descriptor desc, // descriptor to modify @@ -561,7 +551,6 @@ GrB_Info GrB_Descriptor_set // set a parameter in a descriptor GrB_Desc_Value val // value to change it to ) ; -GB_PUBLIC GrB_Info GxB_Descriptor_get // get a parameter from a descriptor ( GrB_Desc_Value *val, // value of the parameter @@ -569,7 +558,6 @@ GrB_Info GxB_Descriptor_get // get a parameter from a descriptor GrB_Desc_Field field // parameter to query ) ; -GB_PUBLIC GrB_Info GxB_Desc_set // set a parameter in a descriptor ( GrB_Descriptor desc, // descriptor to modify @@ -577,7 +565,20 @@ GrB_Info GxB_Desc_set // set a parameter in a descriptor ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Desc_set_INT32 // set a parameter in a descriptor +( + GrB_Descriptor desc, // descriptor to modify + GrB_Desc_Field field, // parameter to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Desc_set_FP64 // set a parameter in a descriptor +( + GrB_Descriptor desc, // descriptor to modify + GrB_Desc_Field field, // parameter to change + double value // value to change it to +) ; + GrB_Info GxB_Desc_get // get a parameter from a descriptor ( GrB_Descriptor desc, // descriptor to query; NULL means defaults @@ -585,7 +586,20 @@ GrB_Info GxB_Desc_get // get a parameter from a descriptor ... // value of the parameter ) ; -GB_PUBLIC +GrB_Info GxB_Desc_get_INT32 // get a parameter from a descriptor +( + GrB_Descriptor desc, // descriptor to query; NULL is ok + GrB_Desc_Field field, // parameter to query + int32_t *value // return value of the descriptor +) ; + +GrB_Info GxB_Desc_get_FP64 // get a parameter from a descriptor +( + GrB_Descriptor desc, // descriptor to query; NULL is ok + GrB_Desc_Field field, // parameter to query + double *value // return value of the descriptor +) ; + GrB_Info GrB_Descriptor_free // free a descriptor ( GrB_Descriptor *descriptor // handle of descriptor to free @@ -593,8 +607,8 @@ GrB_Info GrB_Descriptor_free // free a descriptor // Predefined descriptors and their values: -GB_PUBLIC -GrB_Descriptor // OUTP MASK MASK INP0 INP1 +GB_GLOBAL GrB_Descriptor + // OUTP MASK MASK INP0 INP1 // structural complement // =========== ============== ========== ======== ======== @@ -656,7 +670,7 @@ GrB_DESC_RSCT0T1 ; // GrB_REPLACE GrB_STRUCTURE GrB_COMP GrB_TRAN GrB_TRAN typedef struct GB_Type_opaque *GrB_Type ; // GraphBLAS predefined types and their counterparts in pure C: -GB_PUBLIC GrB_Type +GB_GLOBAL GrB_Type GrB_BOOL , // in C: bool GrB_INT8 , // in C: int8_t GrB_INT16 , // in C: int16_t @@ -678,37 +692,54 @@ GB_PUBLIC GrB_Type #define GB_CAT(w,x,y,z) w ## x ## y ## z #define GB_CONCAT(w,x,y,z) GB_CAT (w, x, y, z) -#if GxB_STDC_VERSION >= 201112L -#define GB_CASES(p,prefix,func) \ - const bool p : GB_CONCAT ( prefix, _, func, _BOOL ), \ - bool p : GB_CONCAT ( prefix, _, func, _BOOL ), \ - const int8_t p : GB_CONCAT ( prefix, _, func, _INT8 ), \ - int8_t p : GB_CONCAT ( prefix, _, func, _INT8 ), \ - const int16_t p : GB_CONCAT ( prefix, _, func, _INT16 ), \ - int16_t p : GB_CONCAT ( prefix, _, func, _INT16 ), \ - const int32_t p : GB_CONCAT ( prefix, _, func, _INT32 ), \ - int32_t p : GB_CONCAT ( prefix, _, func, _INT32 ), \ - const int64_t p : GB_CONCAT ( prefix, _, func, _INT64 ), \ - int64_t p : GB_CONCAT ( prefix, _, func, _INT64 ), \ - const uint8_t p : GB_CONCAT ( prefix, _, func, _UINT8 ), \ - uint8_t p : GB_CONCAT ( prefix, _, func, _UINT8 ), \ - const uint16_t p : GB_CONCAT ( prefix, _, func, _UINT16 ), \ - uint16_t p : GB_CONCAT ( prefix, _, func, _UINT16 ), \ - const uint32_t p : GB_CONCAT ( prefix, _, func, _UINT32 ), \ - uint32_t p : GB_CONCAT ( prefix, _, func, _UINT32 ), \ - const uint64_t p : GB_CONCAT ( prefix, _, func, _UINT64 ), \ - uint64_t p : GB_CONCAT ( prefix, _, func, _UINT64 ), \ - const float p : GB_CONCAT ( prefix, _, func, _FP32 ), \ - float p : GB_CONCAT ( prefix, _, func, _FP32 ), \ - const double p : GB_CONCAT ( prefix, _, func, _FP64 ), \ - double p : GB_CONCAT ( prefix, _, func, _FP64 ), \ - const GxB_FC32_t p : GB_CONCAT ( GxB , _, func, _FC32 ), \ - GxB_FC32_t p : GB_CONCAT ( GxB , _, func, _FC32 ), \ - const GxB_FC64_t p : GB_CONCAT ( GxB , _, func, _FC64 ), \ - GxB_FC64_t p : GB_CONCAT ( GxB , _, func, _FC64 ), \ +// methods for C scalars of various types +#define GB_CASES(prefix,func) \ + bool : GB_CONCAT ( prefix, _, func, _BOOL ), \ + int8_t : GB_CONCAT ( prefix, _, func, _INT8 ), \ + int16_t : GB_CONCAT ( prefix, _, func, _INT16 ), \ + int32_t : GB_CONCAT ( prefix, _, func, _INT32 ), \ + int64_t : GB_CONCAT ( prefix, _, func, _INT64 ), \ + uint8_t : GB_CONCAT ( prefix, _, func, _UINT8 ), \ + uint16_t : GB_CONCAT ( prefix, _, func, _UINT16 ), \ + uint32_t : GB_CONCAT ( prefix, _, func, _UINT32 ), \ + uint64_t : GB_CONCAT ( prefix, _, func, _UINT64 ), \ + float : GB_CONCAT ( prefix, _, func, _FP32 ), \ + double : GB_CONCAT ( prefix, _, func, _FP64 ), \ + GxB_FC32_t : GB_CONCAT ( GxB , _, func, _FC32 ), \ + GxB_FC64_t : GB_CONCAT ( GxB , _, func, _FC64 ), \ + const void * : GB_CONCAT ( prefix, _, func, _UDT ), \ + void * : GB_CONCAT ( prefix, _, func, _UDT ) + +// methods for C arrays of various types +#define GB_PCASES(prefix,func) \ + const bool * : GB_CONCAT ( prefix, _, func, _BOOL ), \ + bool * : GB_CONCAT ( prefix, _, func, _BOOL ), \ + const int8_t * : GB_CONCAT ( prefix, _, func, _INT8 ), \ + int8_t * : GB_CONCAT ( prefix, _, func, _INT8 ), \ + const int16_t * : GB_CONCAT ( prefix, _, func, _INT16 ), \ + int16_t * : GB_CONCAT ( prefix, _, func, _INT16 ), \ + const int32_t * : GB_CONCAT ( prefix, _, func, _INT32 ), \ + int32_t * : GB_CONCAT ( prefix, _, func, _INT32 ), \ + const int64_t * : GB_CONCAT ( prefix, _, func, _INT64 ), \ + int64_t * : GB_CONCAT ( prefix, _, func, _INT64 ), \ + const uint8_t * : GB_CONCAT ( prefix, _, func, _UINT8 ), \ + uint8_t * : GB_CONCAT ( prefix, _, func, _UINT8 ), \ + const uint16_t * : GB_CONCAT ( prefix, _, func, _UINT16 ), \ + uint16_t * : GB_CONCAT ( prefix, _, func, _UINT16 ), \ + const uint32_t * : GB_CONCAT ( prefix, _, func, _UINT32 ), \ + uint32_t * : GB_CONCAT ( prefix, _, func, _UINT32 ), \ + const uint64_t * : GB_CONCAT ( prefix, _, func, _UINT64 ), \ + uint64_t * : GB_CONCAT ( prefix, _, func, _UINT64 ), \ + const float * : GB_CONCAT ( prefix, _, func, _FP32 ), \ + float * : GB_CONCAT ( prefix, _, func, _FP32 ), \ + const double * : GB_CONCAT ( prefix, _, func, _FP64 ), \ + double * : GB_CONCAT ( prefix, _, func, _FP64 ), \ + const GxB_FC32_t * : GB_CONCAT ( GxB , _, func, _FC32 ), \ + GxB_FC32_t * : GB_CONCAT ( GxB , _, func, _FC32 ), \ + const GxB_FC64_t * : GB_CONCAT ( GxB , _, func, _FC64 ), \ + GxB_FC64_t * : GB_CONCAT ( GxB , _, func, _FC64 ), \ const void * : GB_CONCAT ( prefix, _, func, _UDT ), \ void * : GB_CONCAT ( prefix, _, func, _UDT ) -#endif //------------------------------------------------------------------------------ // GrB_Type_new: create a new type @@ -722,7 +753,6 @@ GB_PUBLIC GrB_Type #undef GrB_Type_new #undef GrM_Type_new -GB_PUBLIC GrB_Info GRB (Type_new) // create a new GraphBLAS type ( GrB_Type *type, // handle of user type to create @@ -763,7 +793,6 @@ GrB_Info GRB (Type_new) // create a new GraphBLAS type #define GxB_MAX_NAME_LEN 128 -GB_PUBLIC GrB_Info GxB_Type_new // create a new named GraphBLAS type ( GrB_Type *type, // handle of user type to create @@ -773,7 +802,6 @@ GrB_Info GxB_Type_new // create a new named GraphBLAS type ) ; // GB_Type_new is historical: use GxB_Type_new instead -GB_PUBLIC GrB_Info GB_Type_new // not user-callable ( GrB_Type *type, // handle of user type to create @@ -781,7 +809,6 @@ GrB_Info GB_Type_new // not user-callable const char *type_name // name of the type, as "sizeof (ctype)" ) ; -GB_PUBLIC GrB_Info GxB_Type_name // return the name of a GraphBLAS type ( char *type_name, // name of the type (char array of size at least @@ -789,21 +816,18 @@ GrB_Info GxB_Type_name // return the name of a GraphBLAS type const GrB_Type type ) ; -GB_PUBLIC GrB_Info GxB_Type_size // determine the size of the type ( size_t *size, // the sizeof the type const GrB_Type type // type to determine the sizeof ) ; -GB_PUBLIC GrB_Info GxB_Type_from_name // return the built-in GrB_Type from a name ( GrB_Type *type, // built-in type, or NULL if user-defined const char *type_name // array of size at least GxB_MAX_NAME_LEN ) ; -GB_PUBLIC GrB_Info GrB_Type_free // free a user-defined type ( GrB_Type *type // handle of user-defined type to free @@ -827,7 +851,7 @@ typedef struct GB_UnaryOp_opaque *GrB_UnaryOp ; // built-in unary operators, z = f(x) //------------------------------------------------------------------------------ -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp // For these functions z=f(x), z and x have the same type. // The suffix in the name is the type of x and z. // z = x z = -x z = 1/x z = ! (x != 0) @@ -871,7 +895,7 @@ GB_PUBLIC GrB_UnaryOp GrB_LNOT ; // GxB_ABS is now in the v1.3 spec, the following names are historical: -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp // z = abs(x) GxB_ABS_BOOL, @@ -893,7 +917,7 @@ GB_PUBLIC GrB_UnaryOp // The following floating-point unary operators and their ANSI C11 equivalents, // are only defined for floating-point (real and complex) types. -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp //-------------------------------------------------------------------------- // z = f(x) where z and x have the same type (all 4 floating-point types) @@ -1009,7 +1033,6 @@ typedef void (*GxB_unary_function) (void *, const void *) ; // detection of the operator name. #undef GrB_UnaryOp_new #undef GrM_UnaryOp_new -GB_PUBLIC GrB_Info GRB (UnaryOp_new) // create a new user-defined unary operator ( GrB_UnaryOp *unaryop, // handle for the new unary operator @@ -1023,7 +1046,6 @@ GrB_Info GRB (UnaryOp_new) // create a new user-defined unary operator GxM_UnaryOp_new(op,f,z,x, GB_STR(f), NULL) // GxB_UnaryOp_new creates a named user-defined unary op. -GB_PUBLIC GrB_Info GxB_UnaryOp_new // create a new user-defined unary operator ( GrB_UnaryOp *unaryop, // handle for the new unary operator @@ -1035,7 +1057,6 @@ GrB_Info GxB_UnaryOp_new // create a new user-defined unary operator ) ; // GB_UnaryOp_new is historical: use GxB_UnaryOp_new instead -GB_PUBLIC GrB_Info GB_UnaryOp_new // not user-callable ( GrB_UnaryOp *unaryop, // handle for the new unary operator @@ -1046,13 +1067,11 @@ GrB_Info GB_UnaryOp_new // not user-callable ) ; // GxB_UnaryOp_ztype is historical. Use GxB_UnaryOp_ztype_name instead. -GB_PUBLIC GrB_Info GxB_UnaryOp_ztype // return the type of z ( GrB_Type *ztype, // return type of output z GrB_UnaryOp unaryop // unary operator ) ; -GB_PUBLIC GrB_Info GxB_UnaryOp_ztype_name // return the type_name of z ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1060,20 +1079,17 @@ GrB_Info GxB_UnaryOp_ztype_name // return the type_name of z ) ; // GxB_UnaryOp_xtype is historical. Use GxB_UnaryOp_xtype_name instead. -GB_PUBLIC GrB_Info GxB_UnaryOp_xtype // return the type of x ( GrB_Type *xtype, // return type of input x GrB_UnaryOp unaryop // unary operator ) ; -GB_PUBLIC GrB_Info GxB_UnaryOp_xtype_name // return the type_name of x ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_UnaryOp unaryop // unary operator ) ; -GB_PUBLIC GrB_Info GrB_UnaryOp_free // free a user-created unary operator ( GrB_UnaryOp *unaryop // handle of unary operator to free @@ -1096,7 +1112,7 @@ typedef struct GB_BinaryOp_opaque *GrB_BinaryOp ; // built-in binary operators, z = f(x,y), where x,y,z all have the same type //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // operators for all 13 types (including complex): @@ -1273,7 +1289,7 @@ GB_PUBLIC GrB_BinaryOp // The GxB_BSHIFT_* operators compute the arithmetic shift, and produce the // same results as the bitshift.m function, for all possible inputs. -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // z = bitshift(x,y) GxB_BSHIFT_INT8, @@ -1289,7 +1305,7 @@ GB_PUBLIC GrB_BinaryOp // z=f(x,y) where z is BOOL and the type of x,y is given by the suffix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // Six comparators z=f(x,y) return their result as boolean, but // where x and y have the same type. The suffix in their names refers to @@ -1331,7 +1347,7 @@ GB_PUBLIC GrB_BinaryOp // z=f(x,y) where z is complex and the type of x,y is given by the suffix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp // z = cmplx (x,y) GxB_CMPLX_FP32, @@ -1371,7 +1387,7 @@ GB_PUBLIC GrB_BinaryOp // are identical. If C(i,j) += t is computed where t = A(i,k)*B(k,j), then // t = k in both cases. Likewise, FIRSTJ1 and SECONDI1 are identical. -GB_PUBLIC GrB_BinaryOp +GB_GLOBAL GrB_BinaryOp GxB_FIRSTI_INT32, GxB_FIRSTI_INT64, // z = first_i(A(i,j),y) == i GxB_FIRSTI1_INT32, GxB_FIRSTI1_INT64, // z = first_i1(A(i,j),y) == i+1 @@ -1382,7 +1398,7 @@ GB_PUBLIC GrB_BinaryOp GxB_SECONDJ_INT32, GxB_SECONDJ_INT64, // z = second_j(x,B(i,j)) == j GxB_SECONDJ1_INT32, GxB_SECONDJ1_INT64 ; // z = second_j1(x,B(i,j)) == j+1 -GB_PUBLIC GrB_UnaryOp +GB_GLOBAL GrB_UnaryOp GxB_POSITIONI_INT32, GxB_POSITIONI_INT64, // z=position_i(A(i,j)) == i GxB_POSITIONI1_INT32, GxB_POSITIONI1_INT64, // z=position_i1(A(i,j)) == i+1 @@ -1399,7 +1415,7 @@ GB_PUBLIC GrB_UnaryOp // GxB_IGNORE_DUP is a special case. It is not an operator, but an indication // that any duplicates are to be ignored. -GB_PUBLIC GrB_BinaryOp GxB_IGNORE_DUP ; +GB_GLOBAL GrB_BinaryOp GxB_IGNORE_DUP ; //============================================================================== // About boolean and bitwise binary operators @@ -1488,7 +1504,6 @@ typedef void (*GxB_binary_function) (void *, const void *, const void *) ; // detection of the operator name. #undef GrB_BinaryOp_new #undef GrM_BinaryOp_new -GB_PUBLIC GrB_Info GRB (BinaryOp_new) ( GrB_BinaryOp *binaryop, // handle for the new binary operator @@ -1503,7 +1518,6 @@ GrB_Info GRB (BinaryOp_new) GxM_BinaryOp_new(op,f,z,x,y, GB_STR(f), NULL) // GxB_BinaryOp_new creates a named user-defined binary op. -GB_PUBLIC GrB_Info GxB_BinaryOp_new ( GrB_BinaryOp *op, // handle for the new binary operator @@ -1516,7 +1530,6 @@ GrB_Info GxB_BinaryOp_new ) ; // GB_BinaryOp_new is historical: use GxB_BinaryOp_new instead -GB_PUBLIC GrB_Info GB_BinaryOp_new // not user-callable ( GrB_BinaryOp *binaryop, // handle for the new binary operator @@ -1528,13 +1541,11 @@ GrB_Info GB_BinaryOp_new // not user-callable ) ; // NOTE: GxB_BinaryOp_ztype is historical. Use GxB_BinaryOp_ztype_name instead. -GB_PUBLIC GrB_Info GxB_BinaryOp_ztype // return the type of z ( GrB_Type *ztype, // return type of output z GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_ztype_name // return the type_name of z ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1542,13 +1553,11 @@ GrB_Info GxB_BinaryOp_ztype_name // return the type_name of z ) ; // NOTE: GxB_BinaryOp_xtype is historical. Use GxB_BinaryOp_xtype_name instead. -GB_PUBLIC GrB_Info GxB_BinaryOp_xtype // return the type of x ( GrB_Type *xtype, // return type of input x GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_xtype_name // return the type_name of x ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1556,20 +1565,17 @@ GrB_Info GxB_BinaryOp_xtype_name // return the type_name of x ) ; // NOTE: GxB_BinaryOp_ytype is historical. Use GxB_BinaryOp_ytype_name instead. -GB_PUBLIC GrB_Info GxB_BinaryOp_ytype // return the type of y ( GrB_Type *ytype, // return type of input y GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_ytype_name // return the type_name of y ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_BinaryOp binaryop // binary operator to query ) ; -GB_PUBLIC GrB_Info GrB_BinaryOp_free // free a user-created binary operator ( GrB_BinaryOp *binaryop // handle of binary operator to free @@ -1620,7 +1626,7 @@ typedef struct GB_SelectOp_opaque *GxB_SelectOp ; // GxB_select (C, Mask, accum, op, A, Thunk, desc) always returns a matrix C of // the same size as A (or A' if GrB_TRAN is in the descriptor). -GB_PUBLIC GxB_SelectOp +GB_GLOBAL GxB_SelectOp GxB_TRIL, // C=tril(A,thunk): returns true if ((j-i) <= thunk) GxB_TRIU, // C=triu(A,thunk): returns true if ((j-i) >= thunk) @@ -1675,7 +1681,6 @@ typedef bool (*GxB_select_function) // return true if A(i,j) is kept #undef GxB_SelectOp_new #undef GxM_SelectOp_new -GB_PUBLIC GrB_Info GXB (SelectOp_new) // create a new user-defined select operator ( GxB_SelectOp *selectop, // handle for the new select operator @@ -1689,7 +1694,6 @@ GrB_Info GXB (SelectOp_new) // create a new user-defined select operator // GB_SelectOp_new should not be called directly, but only through the // GxB_SelectOp_new macro (but use GrB_IndexUnaryOp_new instead). -GB_PUBLIC GrB_Info GB_SelectOp_new // not user-callable ( GxB_SelectOp *selectop, // handle for the new select operator @@ -1700,7 +1704,6 @@ GrB_Info GB_SelectOp_new // not user-callable ) ; // GxB_SelectOp_xtype is historical. Use a GrB_IndexUnaryOp instead. -GB_PUBLIC GrB_Info GxB_SelectOp_xtype // return the type of x ( GrB_Type *xtype, // return type of input x @@ -1708,14 +1711,12 @@ GrB_Info GxB_SelectOp_xtype // return the type of x ) ; // GxB_SelectOp_ttype is historical. Use a GrB_IndexUnaryOp instead. -GB_PUBLIC GrB_Info GxB_SelectOp_ttype // return the type of thunk ( GrB_Type *ttype, // return type of input thunk GxB_SelectOp selectop // select operator ) ; -GB_PUBLIC GrB_Info GxB_SelectOp_free // free a user-created select operator ( GxB_SelectOp *selectop // handle of select operator to free @@ -1745,7 +1746,6 @@ typedef void (*GxB_index_unary_function) #undef GrB_IndexUnaryOp_new #undef GrM_IndexUnaryOp_new -GB_PUBLIC GrB_Info GRB (IndexUnaryOp_new) // create a new user-defined IndexUnary op ( GrB_IndexUnaryOp *op, // handle for the new IndexUnary operator @@ -1760,7 +1760,6 @@ GrB_Info GRB (IndexUnaryOp_new) // create a new user-defined IndexUnary op #define GrM_IndexUnaryOp_new(op,f,z,x,y) \ GxM_IndexUnaryOp_new(op,f,z,x,y, GB_STR(f), NULL) -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_new // create a named user-created IndexUnaryOp ( GrB_IndexUnaryOp *op, // handle for the new IndexUnary operator @@ -1772,7 +1771,6 @@ GrB_Info GxB_IndexUnaryOp_new // create a named user-created IndexUnaryOp const char *idxop_defn // definition of the user function ) ; -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_ztype_name // return the type_name of z ( char *type_name, // user array of size GxB_MAX_NAME_LEN @@ -1782,21 +1780,18 @@ GrB_Info GxB_IndexUnaryOp_ztype_name // return the type_name of z // For TRIL, TRIU, DIAG, OFFDIAG, COLLE, COLGT, ROWLE, and ROWGT, // the xtype_name is an empty string (""), since these functions do not depend // on the type of the matrix input. -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_xtype_name // return the type_name of x ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_IndexUnaryOp op // select operator ) ; -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_ytype_name // return the type_name of the scalary y ( char *type_name, // user array of size GxB_MAX_NAME_LEN const GrB_IndexUnaryOp op // select operator ) ; -GB_PUBLIC GrB_Info GrB_IndexUnaryOp_free // free a user-created IndexUnaryOp ( GrB_IndexUnaryOp *op // handle of IndexUnary to free @@ -1810,7 +1805,7 @@ GrB_Info GrB_IndexUnaryOp_free // free a user-created IndexUnaryOp // of type int64_t. The scalar y has the type corresponding to the suffix // of the name of the operator. -GB_PUBLIC GrB_IndexUnaryOp +GB_GLOBAL GrB_IndexUnaryOp //-------------------------------------------------------------------------- // Result has the integer type INT32 or INT64, the same as the suffix @@ -1915,7 +1910,6 @@ GB_PUBLIC GrB_IndexUnaryOp typedef struct GB_Monoid_opaque *GrB_Monoid ; -GB_PUBLIC GrB_Info GrB_Monoid_new_BOOL // create a new boolean monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1923,7 +1917,6 @@ GrB_Info GrB_Monoid_new_BOOL // create a new boolean monoid bool identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT8 // create a new int8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1931,7 +1924,6 @@ GrB_Info GrB_Monoid_new_INT8 // create a new int8 monoid int8_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT8 // create a new uint8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1939,7 +1931,6 @@ GrB_Info GrB_Monoid_new_UINT8 // create a new uint8 monoid uint8_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT16 // create a new int16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1947,7 +1938,6 @@ GrB_Info GrB_Monoid_new_INT16 // create a new int16 monoid int16_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT16 // create a new uint16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1955,7 +1945,6 @@ GrB_Info GrB_Monoid_new_UINT16 // create a new uint16 monoid uint16_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT32 // create a new int32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1963,7 +1952,6 @@ GrB_Info GrB_Monoid_new_INT32 // create a new int32 monoid int32_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT32 // create a new uint32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1971,7 +1959,6 @@ GrB_Info GrB_Monoid_new_UINT32 // create a new uint32 monoid uint32_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_INT64 // create a new int64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1979,7 +1966,6 @@ GrB_Info GrB_Monoid_new_INT64 // create a new int64 monoid int64_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UINT64 // create a new uint64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1987,7 +1973,6 @@ GrB_Info GrB_Monoid_new_UINT64 // create a new uint64 monoid uint64_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_FP32 // create a new float monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -1995,7 +1980,6 @@ GrB_Info GrB_Monoid_new_FP32 // create a new float monoid float identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_FP64 // create a new double monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2003,7 +1987,6 @@ GrB_Info GrB_Monoid_new_FP64 // create a new double monoid double identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_new_FC32 // create a new float complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2011,7 +1994,6 @@ GrB_Info GxB_Monoid_new_FC32 // create a new float complex monoid GxB_FC32_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_new_FC64 // create a new double complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2019,7 +2001,6 @@ GrB_Info GxB_Monoid_new_FC64 // create a new double complex monoid GxB_FC64_t identity // identity value of the monoid ) ; -GB_PUBLIC GrB_Info GrB_Monoid_new_UDT // create a monoid with a user-defined type ( GrB_Monoid *monoid, // handle of monoid to create @@ -2031,7 +2012,6 @@ GrB_Info GrB_Monoid_new_UDT // create a monoid with a user-defined type /* -GB_PUBLIC GrB_Info GrB_Monoid_new // create a monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2046,7 +2026,7 @@ GrB_Info GrB_Monoid_new // create a monoid _Generic \ ( \ (identity), \ - GB_CASES (, GrB, Monoid_new) \ + GB_CASES (GrB, Monoid_new) \ ) \ (monoid, op, identity) #endif @@ -2056,7 +2036,6 @@ GrB_Info GrB_Monoid_new // create a monoid // no terminal value (and in this case, it is identical to GrB_Monoid_new). // The terminal value, if not NULL, must have the same type as the identity. -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_BOOL // create a new boolean monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2065,7 +2044,6 @@ GrB_Info GxB_Monoid_terminal_new_BOOL // create a new boolean monoid bool terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT8 // create a new int8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2074,7 +2052,6 @@ GrB_Info GxB_Monoid_terminal_new_INT8 // create a new int8 monoid int8_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT8 // create a new uint8 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2083,7 +2060,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT8 // create a new uint8 monoid uint8_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT16 // create a new int16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2092,7 +2068,6 @@ GrB_Info GxB_Monoid_terminal_new_INT16 // create a new int16 monoid int16_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT16 // create a new uint16 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2101,7 +2076,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT16 // create a new uint16 monoid uint16_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT32 // create a new int32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2110,7 +2084,6 @@ GrB_Info GxB_Monoid_terminal_new_INT32 // create a new int32 monoid int32_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT32 // create a new uint32 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2119,7 +2092,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT32 // create a new uint32 monoid uint32_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_INT64 // create a new int64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2128,7 +2100,6 @@ GrB_Info GxB_Monoid_terminal_new_INT64 // create a new int64 monoid int64_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UINT64 // create a new uint64 monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2137,7 +2108,6 @@ GrB_Info GxB_Monoid_terminal_new_UINT64 // create a new uint64 monoid uint64_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FP32 // create a new float monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2146,7 +2116,6 @@ GrB_Info GxB_Monoid_terminal_new_FP32 // create a new float monoid float terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FP64 // create a new double monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2155,7 +2124,6 @@ GrB_Info GxB_Monoid_terminal_new_FP64 // create a new double monoid double terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FC32 // create a new float complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2164,7 +2132,6 @@ GrB_Info GxB_Monoid_terminal_new_FC32 // create a new float complex monoid GxB_FC32_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_FC64 // create a new double complex monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2173,7 +2140,6 @@ GrB_Info GxB_Monoid_terminal_new_FC64 // create a new double complex monoid GxB_FC64_t terminal // terminal value of the monoid ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new_UDT // create a monoid with a user type ( GrB_Monoid *monoid, // handle of monoid to create @@ -2186,7 +2152,6 @@ GrB_Info GxB_Monoid_terminal_new_UDT // create a monoid with a user type /* -GB_PUBLIC GrB_Info GxB_Monoid_terminal_new // create a monoid ( GrB_Monoid *monoid, // handle of monoid to create @@ -2202,26 +2167,23 @@ GrB_Info GxB_Monoid_terminal_new // create a monoid _Generic \ ( \ (identity), \ - GB_CASES (, GxB, Monoid_terminal_new) \ + GB_CASES (GxB, Monoid_terminal_new) \ ) \ (monoid, op, identity, terminal) #endif -GB_PUBLIC GrB_Info GxB_Monoid_operator // return the monoid operator ( GrB_BinaryOp *op, // returns the binary op of the monoid GrB_Monoid monoid // monoid to query ) ; -GB_PUBLIC GrB_Info GxB_Monoid_identity // return the monoid identity ( void *identity, // returns the identity of the monoid GrB_Monoid monoid // monoid to query ) ; -GB_PUBLIC GrB_Info GxB_Monoid_terminal // return the monoid terminal ( bool *has_terminal, // true if the monoid has a terminal value @@ -2230,7 +2192,6 @@ GrB_Info GxB_Monoid_terminal // return the monoid terminal GrB_Monoid monoid // monoid to query ) ; -GB_PUBLIC GrB_Info GrB_Monoid_free // free a user-created monoid ( GrB_Monoid *monoid // handle of monoid to free @@ -2242,7 +2203,6 @@ GrB_Info GrB_Monoid_free // free a user-created monoid typedef struct GB_Semiring_opaque *GrB_Semiring ; -GB_PUBLIC GrB_Info GrB_Semiring_new // create a semiring ( GrB_Semiring *semiring, // handle of semiring to create @@ -2250,21 +2210,18 @@ GrB_Info GrB_Semiring_new // create a semiring GrB_BinaryOp multiply // multiply operator of the semiring ) ; -GB_PUBLIC GrB_Info GxB_Semiring_add // return the add monoid of a semiring ( GrB_Monoid *add, // returns add monoid of the semiring GrB_Semiring semiring // semiring to query ) ; -GB_PUBLIC GrB_Info GxB_Semiring_multiply // return multiply operator of a semiring ( GrB_BinaryOp *multiply, // returns multiply operator of the semiring GrB_Semiring semiring // semiring to query ) ; -GB_PUBLIC GrB_Info GrB_Semiring_free // free a user-created semiring ( GrB_Semiring *semiring // handle of semiring to free @@ -2283,27 +2240,23 @@ typedef struct GB_Scalar_opaque *GrB_Scalar ; // use this instead // These methods create, free, copy, and clear a GrB_Scalar. The nvals, // and type methods return basic information about a GrB_Scalar. -GB_PUBLIC GrB_Info GrB_Scalar_new // create a new GrB_Scalar with no entry ( GrB_Scalar *s, // handle of GrB_Scalar to create GrB_Type type // type of GrB_Scalar to create ) ; -GB_PUBLIC GrB_Info GrB_Scalar_dup // make an exact copy of a GrB_Scalar ( GrB_Scalar *s, // handle of output GrB_Scalar to create const GrB_Scalar t // input GrB_Scalar to copy ) ; -GB_PUBLIC GrB_Info GrB_Scalar_clear // clear a GrB_Scalar of its entry ( // type remains unchanged. GrB_Scalar s // GrB_Scalar to clear ) ; -GB_PUBLIC GrB_Info GrB_Scalar_nvals // get the number of entries in a GrB_Scalar ( GrB_Index *nvals, // GrB_Scalar has nvals entries (0 or 1) @@ -2311,13 +2264,11 @@ GrB_Info GrB_Scalar_nvals // get the number of entries in a GrB_Scalar ) ; // NOTE: GxB_Scalar_type is historical. Use GxB_Scalar_type_name instead. -GB_PUBLIC GrB_Info GxB_Scalar_type // get the type of a GrB_Scalar ( GrB_Type *type, // returns the type of the GrB_Scalar const GrB_Scalar s // GrB_Scalar to query ) ; -GB_PUBLIC GrB_Info GxB_Scalar_type_name // return the name of the type of a scalar ( char *type_name, // name of the type (char array of size at least @@ -2325,25 +2276,23 @@ GrB_Info GxB_Scalar_type_name // return the name of the type of a scalar const GrB_Scalar s // GrB_Scalar to query ) ; -GB_PUBLIC GrB_Info GxB_Scalar_memoryUsage // return # of bytes used for a scalar ( size_t *size, // # of bytes used by the scalar s const GrB_Scalar s // GrB_Scalar to query ) ; -GB_PUBLIC GrB_Info GrB_Scalar_free // free a GrB_Scalar ( GrB_Scalar *s // handle of GrB_Scalar to free ) ; // historical names identical to GrB_Scalar_methods above: -GB_PUBLIC GrB_Info GxB_Scalar_new (GrB_Scalar *s, GrB_Type type) ; -GB_PUBLIC GrB_Info GxB_Scalar_dup (GrB_Scalar *s, const GrB_Scalar t) ; -GB_PUBLIC GrB_Info GxB_Scalar_clear (GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_nvals (GrB_Index *nvals, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_free (GrB_Scalar *s) ; +GrB_Info GxB_Scalar_new (GrB_Scalar *s, GrB_Type type) ; +GrB_Info GxB_Scalar_dup (GrB_Scalar *s, const GrB_Scalar t) ; +GrB_Info GxB_Scalar_clear (GrB_Scalar s) ; +GrB_Info GxB_Scalar_nvals (GrB_Index *nvals, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_free (GrB_Scalar *s) ; //------------------------------------------------------------------------------ // GrB_Scalar_setElement @@ -2352,98 +2301,84 @@ GB_PUBLIC GrB_Info GxB_Scalar_free (GrB_Scalar *s) ; // Set a single GrB_Scalar s, from a user scalar x: s = x, typecasting from the // type of x to the type of w as needed. -GB_PUBLIC GrB_Info GrB_Scalar_setElement_BOOL // s = x ( GrB_Scalar s, // GrB_Scalar to modify bool x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT8 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int8_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT8 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint8_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT16 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int16_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT16 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint16_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int32_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint32_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_INT64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify int64_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UINT64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify uint64_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_FP32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify float x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_FP64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify double x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FC32 // s = x ( GrB_Scalar s, // GrB_Scalar to modify GxB_FC32_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FC64 // s = x ( GrB_Scalar s, // GrB_Scalar to modify GxB_FC64_t x // user scalar to assign to s ) ; -GB_PUBLIC GrB_Info GrB_Scalar_setElement_UDT // s = x ( GrB_Scalar s, // GrB_Scalar to modify @@ -2451,25 +2386,24 @@ GrB_Info GrB_Scalar_setElement_UDT // s = x ) ; // historical names identical to GrB_Scalar_methods above: -GB_PUBLIC GrB_Info GxB_Scalar_setElement_BOOL (GrB_Scalar s, bool x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT8 (GrB_Scalar s, int8_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT16 (GrB_Scalar s, int16_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT32 (GrB_Scalar s, int32_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_INT64 (GrB_Scalar s, int64_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT8 (GrB_Scalar s, uint8_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT16 (GrB_Scalar s, uint16_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT32 (GrB_Scalar s, uint32_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UINT64 (GrB_Scalar s, uint64_t x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FP32 (GrB_Scalar s, float x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_FP64 (GrB_Scalar s, double x) ; -GB_PUBLIC GrB_Info GxB_Scalar_setElement_UDT (GrB_Scalar s, void *x) ; +GrB_Info GxB_Scalar_setElement_BOOL (GrB_Scalar s, bool x) ; +GrB_Info GxB_Scalar_setElement_INT8 (GrB_Scalar s, int8_t x) ; +GrB_Info GxB_Scalar_setElement_INT16 (GrB_Scalar s, int16_t x) ; +GrB_Info GxB_Scalar_setElement_INT32 (GrB_Scalar s, int32_t x) ; +GrB_Info GxB_Scalar_setElement_INT64 (GrB_Scalar s, int64_t x) ; +GrB_Info GxB_Scalar_setElement_UINT8 (GrB_Scalar s, uint8_t x) ; +GrB_Info GxB_Scalar_setElement_UINT16 (GrB_Scalar s, uint16_t x) ; +GrB_Info GxB_Scalar_setElement_UINT32 (GrB_Scalar s, uint32_t x) ; +GrB_Info GxB_Scalar_setElement_UINT64 (GrB_Scalar s, uint64_t x) ; +GrB_Info GxB_Scalar_setElement_FP32 (GrB_Scalar s, float x) ; +GrB_Info GxB_Scalar_setElement_FP64 (GrB_Scalar s, double x) ; +GrB_Info GxB_Scalar_setElement_UDT (GrB_Scalar s, void *x) ; // Type-generic version: x can be any supported C type or void * for a // user-defined type. /* -GB_PUBLIC GrB_Info GrB_Scalar_setElement // s = x ( GrB_Scalar s, // GrB_Scalar to modify @@ -2483,7 +2417,7 @@ GrB_Info GrB_Scalar_setElement // s = x _Generic \ ( \ (x), \ - GB_CASES (, GrB, Scalar_setElement) \ + GB_CASES (GrB, Scalar_setElement) \ ) \ (s, x) @@ -2497,98 +2431,84 @@ GrB_Info GrB_Scalar_setElement // s = x // Extract a single entry from a GrB_Scalar, x = s, typecasting from the type // of s to the type of x as needed. -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_BOOL // x = s ( bool *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT8 // x = s ( int8_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT8 // x = s ( uint8_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT16 // x = s ( int16_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT16 // x = s ( uint16_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT32 // x = s ( int32_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT32 // x = s ( uint32_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_INT64 // x = s ( int64_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UINT64 // x = s ( uint64_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_FP32 // x = s ( float *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_FP64 // x = s ( double *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FC32 // x = s ( GxB_FC32_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FC64 // x = s ( GxB_FC64_t *x, // user scalar extracted const GrB_Scalar s // GrB_Scalar to extract an entry from ) ; -GB_PUBLIC GrB_Info GrB_Scalar_extractElement_UDT // x = s ( void *x, // user scalar extracted @@ -2596,25 +2516,24 @@ GrB_Info GrB_Scalar_extractElement_UDT // x = s ) ; // historical names identical to GrB_Scalar_methods above: -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_BOOL (bool *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT8 (int8_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT16 (int16_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT32 (int32_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_INT64 (int64_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT8 (uint8_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT16 (uint16_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT32 (uint32_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UINT64 (uint64_t *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FP32 (float *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_FP64 (double *x, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GxB_Scalar_extractElement_UDT (void *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_BOOL (bool *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT8 (int8_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT16 (int16_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT32 (int32_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_INT64 (int64_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT8 (uint8_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT16 (uint16_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT32 (uint32_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UINT64 (uint64_t *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_FP32 (float *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_FP64 (double *x, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_extractElement_UDT (void *x, const GrB_Scalar s) ; // Type-generic version: x can be a pointer to any supported C type or void * // for a user-defined type. /* -GB_PUBLIC GrB_Info GrB_Scalar_extractElement // x = s ( *x, // user scalar extracted @@ -2628,7 +2547,7 @@ GrB_Info GrB_Scalar_extractElement // x = s _Generic \ ( \ (x), \ - GB_CASES (*, GrB, Scalar_extractElement) \ + GB_PCASES (GrB, Scalar_extractElement) \ ) \ (x, s) @@ -2644,7 +2563,6 @@ typedef struct GB_Vector_opaque *GrB_Vector ; // These methods create, free, copy, and clear a vector. The size, nvals, // and type methods return basic information about a vector. -GB_PUBLIC GrB_Info GrB_Vector_new // create a new vector with no entries ( GrB_Vector *v, // handle of vector to create @@ -2653,27 +2571,23 @@ GrB_Info GrB_Vector_new // create a new vector with no entries // (n must be <= GrB_INDEX_MAX+1) ) ; -GB_PUBLIC GrB_Info GrB_Vector_dup // make an exact copy of a vector ( GrB_Vector *w, // handle of output vector to create const GrB_Vector u // input vector to copy ) ; -GB_PUBLIC GrB_Info GrB_Vector_clear // clear a vector of all entries; ( // type and dimension remain unchanged. GrB_Vector v // vector to clear ) ; -GB_PUBLIC GrB_Info GrB_Vector_size // get the dimension of a vector ( GrB_Index *n, // vector dimension is n-by-1 const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GrB_Vector_nvals // get the number of entries in a vector ( GrB_Index *nvals, // vector has nvals entries @@ -2681,13 +2595,11 @@ GrB_Info GrB_Vector_nvals // get the number of entries in a vector ) ; // NOTE: GxB_Vector_type is historical. Use GxB_Vector_type_name instead. -GB_PUBLIC GrB_Info GxB_Vector_type // get the type of a vector ( GrB_Type *type, // returns the type of the vector const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GxB_Vector_type_name // return the name of the type of a vector ( char *type_name, // name of the type (char array of size at least @@ -2695,21 +2607,18 @@ GrB_Info GxB_Vector_type_name // return the name of the type of a vector const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GxB_Vector_memoryUsage // return # of bytes used for a vector ( size_t *size, // # of bytes used by the vector v const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GxB_Vector_iso // return iso status of a vector ( bool *iso, // true if the vector is iso-valued const GrB_Vector v // vector to query ) ; -GB_PUBLIC GrB_Info GrB_Vector_free // free a vector ( GrB_Vector *v // handle of vector to free @@ -2722,7 +2631,6 @@ GrB_Info GrB_Vector_free // free a vector // GrB_Vector_build: w = sparse (I,1,X), but using any // associative operator to assemble duplicate entries. -GB_PUBLIC GrB_Info GrB_Vector_build_BOOL // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2732,7 +2640,6 @@ GrB_Info GrB_Vector_build_BOOL // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT8 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2742,7 +2649,6 @@ GrB_Info GrB_Vector_build_INT8 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT8 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2752,7 +2658,6 @@ GrB_Info GrB_Vector_build_UINT8 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT16 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2762,7 +2667,6 @@ GrB_Info GrB_Vector_build_INT16 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT16 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2772,7 +2676,6 @@ GrB_Info GrB_Vector_build_UINT16 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2782,7 +2685,6 @@ GrB_Info GrB_Vector_build_INT32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2792,7 +2694,6 @@ GrB_Info GrB_Vector_build_UINT32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_INT64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2802,7 +2703,6 @@ GrB_Info GrB_Vector_build_INT64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UINT64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2812,7 +2712,6 @@ GrB_Info GrB_Vector_build_UINT64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_FP32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2822,7 +2721,6 @@ GrB_Info GrB_Vector_build_FP32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_FP64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2832,7 +2730,6 @@ GrB_Info GrB_Vector_build_FP64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Vector_build_FC32 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2842,7 +2739,6 @@ GrB_Info GxB_Vector_build_FC32 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Vector_build_FC64 // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2852,7 +2748,6 @@ GrB_Info GxB_Vector_build_FC64 // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Vector_build_UDT // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2862,7 +2757,6 @@ GrB_Info GrB_Vector_build_UDT // build a vector from (I,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Vector_build_Scalar // build a vector from (i,scalar) tuples ( GrB_Vector w, // vector to build @@ -2876,7 +2770,6 @@ GrB_Info GxB_Vector_build_Scalar // build a vector from (i,scalar) tuples /* -GB_PUBLIC GrB_Info GrB_Vector_build // build a vector from (I,X) tuples ( GrB_Vector w, // vector to build @@ -2893,7 +2786,7 @@ GrB_Info GrB_Vector_build // build a vector from (I,X) tuples _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Vector_build) \ + GB_PCASES (GrB, Vector_build) \ ) \ (w, I, ((const void *) (X)), nvals, dup) #endif @@ -2905,7 +2798,6 @@ GrB_Info GrB_Vector_build // build a vector from (I,X) tuples // Set a single scalar in a vector, w(i) = x, typecasting from the type of x to // the type of w as needed. -GB_PUBLIC GrB_Info GrB_Vector_setElement_BOOL // w(i) = x ( GrB_Vector w, // vector to modify @@ -2913,7 +2805,6 @@ GrB_Info GrB_Vector_setElement_BOOL // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT8 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2921,7 +2812,6 @@ GrB_Info GrB_Vector_setElement_INT8 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT8 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2929,7 +2819,6 @@ GrB_Info GrB_Vector_setElement_UINT8 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT16 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2937,7 +2826,6 @@ GrB_Info GrB_Vector_setElement_INT16 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT16 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2945,7 +2833,6 @@ GrB_Info GrB_Vector_setElement_UINT16 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2953,7 +2840,6 @@ GrB_Info GrB_Vector_setElement_INT32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2961,7 +2847,6 @@ GrB_Info GrB_Vector_setElement_UINT32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_INT64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2969,7 +2854,6 @@ GrB_Info GrB_Vector_setElement_INT64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UINT64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2977,7 +2861,6 @@ GrB_Info GrB_Vector_setElement_UINT64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_FP32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2985,7 +2868,6 @@ GrB_Info GrB_Vector_setElement_FP32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_FP64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -2993,7 +2875,6 @@ GrB_Info GrB_Vector_setElement_FP64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_setElement_FC32 // w(i) = x ( GrB_Vector w, // vector to modify @@ -3001,7 +2882,6 @@ GrB_Info GxB_Vector_setElement_FC32 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_setElement_FC64 // w(i) = x ( GrB_Vector w, // vector to modify @@ -3009,7 +2889,6 @@ GrB_Info GxB_Vector_setElement_FC64 // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_UDT // w(i) = x ( GrB_Vector w, // vector to modify @@ -3017,7 +2896,6 @@ GrB_Info GrB_Vector_setElement_UDT // w(i) = x GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_setElement_Scalar // w(i) = x ( GrB_Vector w, // vector to modify @@ -3030,7 +2908,6 @@ GrB_Info GrB_Vector_setElement_Scalar // w(i) = x /* -GB_PUBLIC GrB_Info GrB_Vector_setElement // w(i) = x ( GrB_Vector w, // vector to modify @@ -3045,7 +2922,7 @@ GrB_Info GrB_Vector_setElement // w(i) = x _Generic \ ( \ (x), \ - GB_CASES (, GrB, Vector_setElement), \ + GB_CASES (GrB, Vector_setElement), \ default: GrB_Vector_setElement_Scalar \ ) \ (w, x, i) @@ -3058,7 +2935,6 @@ GrB_Info GrB_Vector_setElement // w(i) = x // Extract a single entry from a vector, x = v(i), typecasting from the type of // v to the type of x as needed. -GB_PUBLIC GrB_Info GrB_Vector_extractElement_BOOL // x = v(i) ( bool *x, // scalar extracted @@ -3066,7 +2942,6 @@ GrB_Info GrB_Vector_extractElement_BOOL // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT8 // x = v(i) ( int8_t *x, // scalar extracted @@ -3074,7 +2949,6 @@ GrB_Info GrB_Vector_extractElement_INT8 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT8 // x = v(i) ( uint8_t *x, // scalar extracted @@ -3082,7 +2956,6 @@ GrB_Info GrB_Vector_extractElement_UINT8 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT16 // x = v(i) ( int16_t *x, // scalar extracted @@ -3090,7 +2963,6 @@ GrB_Info GrB_Vector_extractElement_INT16 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT16 // x = v(i) ( uint16_t *x, // scalar extracted @@ -3098,7 +2970,6 @@ GrB_Info GrB_Vector_extractElement_UINT16 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT32 // x = v(i) ( int32_t *x, // scalar extracted @@ -3106,7 +2977,6 @@ GrB_Info GrB_Vector_extractElement_INT32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT32 // x = v(i) ( uint32_t *x, // scalar extracted @@ -3114,7 +2984,6 @@ GrB_Info GrB_Vector_extractElement_UINT32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_INT64 // x = v(i) ( int64_t *x, // scalar extracted @@ -3122,7 +2991,6 @@ GrB_Info GrB_Vector_extractElement_INT64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UINT64 // x = v(i) ( uint64_t *x, // scalar extracted @@ -3130,7 +2998,6 @@ GrB_Info GrB_Vector_extractElement_UINT64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_FP32 // x = v(i) ( float *x, // scalar extracted @@ -3138,7 +3005,6 @@ GrB_Info GrB_Vector_extractElement_FP32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_FP64 // x = v(i) ( double *x, // scalar extracted @@ -3146,7 +3012,6 @@ GrB_Info GrB_Vector_extractElement_FP64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractElement_FC32 // x = v(i) ( GxB_FC32_t *x, // scalar extracted @@ -3154,7 +3019,6 @@ GrB_Info GxB_Vector_extractElement_FC32 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractElement_FC64 // x = v(i) ( GxB_FC64_t *x, // scalar extracted @@ -3162,7 +3026,6 @@ GrB_Info GxB_Vector_extractElement_FC64 // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_UDT // x = v(i) ( void *x, // scalar extracted @@ -3170,7 +3033,6 @@ GrB_Info GrB_Vector_extractElement_UDT // x = v(i) GrB_Index i // row index ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractElement_Scalar // x = v(i) ( GrB_Scalar x, // scalar extracted @@ -3183,7 +3045,6 @@ GrB_Info GrB_Vector_extractElement_Scalar // x = v(i) /* -GB_PUBLIC GrB_Info GrB_Vector_extractElement // x = v(i) ( *x, // scalar extracted @@ -3198,7 +3059,7 @@ GrB_Info GrB_Vector_extractElement // x = v(i) _Generic \ ( \ (x), \ - GB_CASES (*, GrB, Vector_extractElement), \ + GB_PCASES (GrB, Vector_extractElement), \ default: GrB_Vector_extractElement_Scalar \ ) \ (x, v, i) @@ -3208,7 +3069,6 @@ GrB_Info GrB_Vector_extractElement // x = v(i) // of the vector v, as a stored element. It does not return the value. It // returns GrB_SUCCESS if the element is present, or GrB_NO_VALUE otherwise. -GB_PUBLIC GrB_Info GxB_Vector_isStoredElement // determine if v(i) is a stored element ( const GrB_Vector v, // vector to check @@ -3221,7 +3081,6 @@ GrB_Info GxB_Vector_isStoredElement // determine if v(i) is a stored element // GrB_Vector_removeElement (v,i) removes the element v(i) from the vector v. -GB_PUBLIC GrB_Info GrB_Vector_removeElement ( GrB_Vector v, // vector to remove an element from @@ -3237,7 +3096,6 @@ GrB_Info GrB_Vector_removeElement // example, to extract just the row indices, pass I as non-NULL, and X as NULL. // This is like [I,~,~] = find (v). -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_BOOL // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3246,7 +3104,6 @@ GrB_Info GrB_Vector_extractTuples_BOOL // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT8 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3255,7 +3112,6 @@ GrB_Info GrB_Vector_extractTuples_INT8 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT8 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3264,7 +3120,6 @@ GrB_Info GrB_Vector_extractTuples_UINT8 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT16 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3273,7 +3128,6 @@ GrB_Info GrB_Vector_extractTuples_INT16 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT16 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3282,7 +3136,6 @@ GrB_Info GrB_Vector_extractTuples_UINT16 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3291,7 +3144,6 @@ GrB_Info GrB_Vector_extractTuples_INT32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3300,7 +3152,6 @@ GrB_Info GrB_Vector_extractTuples_UINT32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_INT64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3309,7 +3160,6 @@ GrB_Info GrB_Vector_extractTuples_INT64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UINT64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3318,7 +3168,6 @@ GrB_Info GrB_Vector_extractTuples_UINT64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_FP32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3327,7 +3176,6 @@ GrB_Info GrB_Vector_extractTuples_FP32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_FP64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3336,7 +3184,6 @@ GrB_Info GrB_Vector_extractTuples_FP64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractTuples_FC32 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3345,7 +3192,6 @@ GrB_Info GxB_Vector_extractTuples_FC32 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Vector_extractTuples_FC64 // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3354,7 +3200,6 @@ GrB_Info GxB_Vector_extractTuples_FC64 // [I,~,X] = find (v) const GrB_Vector v // vector to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Vector_extractTuples_UDT // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3368,7 +3213,6 @@ GrB_Info GrB_Vector_extractTuples_UDT // [I,~,X] = find (v) /* -GB_PUBLIC GrB_Info GrB_Vector_extractTuples // [I,~,X] = find (v) ( GrB_Index *I, // array for returning row indices of tuples @@ -3384,7 +3228,7 @@ GrB_Info GrB_Vector_extractTuples // [I,~,X] = find (v) _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Vector_extractTuples) \ + GB_PCASES (GrB, Vector_extractTuples) \ ) \ (I, X, nvals, v) #endif @@ -3398,7 +3242,6 @@ typedef struct GB_Matrix_opaque *GrB_Matrix ; // These methods create, free, copy, and clear a matrix. The nrows, ncols, // nvals, and type methods return basic information about a matrix. -GB_PUBLIC GrB_Info GrB_Matrix_new // create a new matrix with no entries ( GrB_Matrix *A, // handle of matrix to create @@ -3407,34 +3250,29 @@ GrB_Info GrB_Matrix_new // create a new matrix with no entries GrB_Index ncols // (nrows and ncols must be <= GrB_INDEX_MAX+1) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_dup // make an exact copy of a matrix ( GrB_Matrix *C, // handle of output matrix to create const GrB_Matrix A // input matrix to copy ) ; -GB_PUBLIC GrB_Info GrB_Matrix_clear // clear a matrix of all entries; ( // type and dimensions remain unchanged GrB_Matrix A // matrix to clear ) ; -GB_PUBLIC GrB_Info GrB_Matrix_nrows // get the number of rows of a matrix ( GrB_Index *nrows, // matrix has nrows rows const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GrB_Matrix_ncols // get the number of columns of a matrix ( GrB_Index *ncols, // matrix has ncols columns const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GrB_Matrix_nvals // get the number of entries in a matrix ( GrB_Index *nvals, // matrix has nvals entries @@ -3442,13 +3280,11 @@ GrB_Info GrB_Matrix_nvals // get the number of entries in a matrix ) ; // NOTE: GxB_Matrix_type is historical. Use GxB_Matrix_type_name instead. -GB_PUBLIC GrB_Info GxB_Matrix_type // get the type of a matrix ( GrB_Type *type, // returns the type of the matrix const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GxB_Matrix_type_name // return the name of the type of a matrix ( char *type_name, // name of the type (char array of size at least @@ -3456,21 +3292,18 @@ GrB_Info GxB_Matrix_type_name // return the name of the type of a matrix const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GxB_Matrix_memoryUsage // return # of bytes used for a matrix ( size_t *size, // # of bytes used by the matrix A const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GxB_Matrix_iso // return iso status of a matrix ( bool *iso, // true if the matrix is iso-valued const GrB_Matrix A // matrix to query ) ; -GB_PUBLIC GrB_Info GrB_Matrix_free // free a matrix ( GrB_Matrix *A // handle of matrix to free @@ -3483,7 +3316,6 @@ GrB_Info GrB_Matrix_free // free a matrix // GrB_Matrix_build: C = sparse (I,J,X), but using any // associative operator to assemble duplicate entries. -GB_PUBLIC GrB_Info GrB_Matrix_build_BOOL // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3494,7 +3326,6 @@ GrB_Info GrB_Matrix_build_BOOL // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT8 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3505,7 +3336,6 @@ GrB_Info GrB_Matrix_build_INT8 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT8 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3516,7 +3346,6 @@ GrB_Info GrB_Matrix_build_UINT8 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT16 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3527,7 +3356,6 @@ GrB_Info GrB_Matrix_build_INT16 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT16 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3538,7 +3366,6 @@ GrB_Info GrB_Matrix_build_UINT16 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3549,7 +3376,6 @@ GrB_Info GrB_Matrix_build_INT32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3560,7 +3386,6 @@ GrB_Info GrB_Matrix_build_UINT32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_INT64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3571,7 +3396,6 @@ GrB_Info GrB_Matrix_build_INT64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UINT64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3582,7 +3406,6 @@ GrB_Info GrB_Matrix_build_UINT64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_FP32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3593,7 +3416,6 @@ GrB_Info GrB_Matrix_build_FP32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_FP64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3604,7 +3426,6 @@ GrB_Info GrB_Matrix_build_FP64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Matrix_build_FC32 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3615,7 +3436,6 @@ GrB_Info GxB_Matrix_build_FC32 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Matrix_build_FC64 // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3626,7 +3446,6 @@ GrB_Info GxB_Matrix_build_FC64 // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GrB_Matrix_build_UDT // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3637,7 +3456,6 @@ GrB_Info GrB_Matrix_build_UDT // build a matrix from (I,J,X) tuples const GrB_BinaryOp dup // binary function to assemble duplicates ) ; -GB_PUBLIC GrB_Info GxB_Matrix_build_Scalar // build a matrix from (I,J,scalar) tuples ( GrB_Matrix C, // matrix to build @@ -3652,7 +3470,6 @@ GrB_Info GxB_Matrix_build_Scalar // build a matrix from (I,J,scalar) tuples /* -GB_PUBLIC GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples ( GrB_Matrix C, // matrix to build @@ -3670,7 +3487,7 @@ GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Matrix_build) \ + GB_PCASES (GrB, Matrix_build) \ ) \ (C, I, J, ((const void *) (X)), nvals, dup) #endif @@ -3682,7 +3499,6 @@ GrB_Info GrB_Matrix_build // build a matrix from (I,J,X) tuples // Set a single entry in a matrix, C(i,j) = x, typecasting // from the type of x to the type of C, as needed. -GB_PUBLIC GrB_Info GrB_Matrix_setElement_BOOL // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3691,7 +3507,6 @@ GrB_Info GrB_Matrix_setElement_BOOL // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT8 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3700,7 +3515,6 @@ GrB_Info GrB_Matrix_setElement_INT8 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT8 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3709,7 +3523,6 @@ GrB_Info GrB_Matrix_setElement_UINT8 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT16 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3718,7 +3531,6 @@ GrB_Info GrB_Matrix_setElement_INT16 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT16 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3727,7 +3539,6 @@ GrB_Info GrB_Matrix_setElement_UINT16 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3736,7 +3547,6 @@ GrB_Info GrB_Matrix_setElement_INT32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3745,7 +3555,6 @@ GrB_Info GrB_Matrix_setElement_UINT32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_INT64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3754,7 +3563,6 @@ GrB_Info GrB_Matrix_setElement_INT64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UINT64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3763,7 +3571,6 @@ GrB_Info GrB_Matrix_setElement_UINT64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_FP32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3772,7 +3579,6 @@ GrB_Info GrB_Matrix_setElement_FP32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_FP64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3781,7 +3587,6 @@ GrB_Info GrB_Matrix_setElement_FP64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_setElement_FC32 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3790,7 +3595,6 @@ GrB_Info GxB_Matrix_setElement_FC32 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_setElement_FC64 // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3799,7 +3603,6 @@ GrB_Info GxB_Matrix_setElement_FC64 // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_UDT // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3808,7 +3611,6 @@ GrB_Info GrB_Matrix_setElement_UDT // C (i,j) = x GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_setElement_Scalar // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3822,7 +3624,6 @@ GrB_Info GrB_Matrix_setElement_Scalar // C (i,j) = x /* -GB_PUBLIC GrB_Info GrB_Matrix_setElement // C (i,j) = x ( GrB_Matrix C, // matrix to modify @@ -3838,7 +3639,7 @@ GrB_Info GrB_Matrix_setElement // C (i,j) = x _Generic \ ( \ (x), \ - GB_CASES (, GrB, Matrix_setElement), \ + GB_CASES (GrB, Matrix_setElement), \ default: GrB_Matrix_setElement_Scalar \ ) \ (C, x, i, j) @@ -3851,7 +3652,6 @@ GrB_Info GrB_Matrix_setElement // C (i,j) = x // Extract a single entry from a matrix, x = A(i,j), typecasting from the type // of A to the type of x, as needed. -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_BOOL // x = A(i,j) ( bool *x, // extracted scalar @@ -3860,7 +3660,6 @@ GrB_Info GrB_Matrix_extractElement_BOOL // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT8 // x = A(i,j) ( int8_t *x, // extracted scalar @@ -3869,7 +3668,6 @@ GrB_Info GrB_Matrix_extractElement_INT8 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT8 // x = A(i,j) ( uint8_t *x, // extracted scalar @@ -3878,7 +3676,6 @@ GrB_Info GrB_Matrix_extractElement_UINT8 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT16 // x = A(i,j) ( int16_t *x, // extracted scalar @@ -3887,7 +3684,6 @@ GrB_Info GrB_Matrix_extractElement_INT16 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT16 // x = A(i,j) ( uint16_t *x, // extracted scalar @@ -3896,7 +3692,6 @@ GrB_Info GrB_Matrix_extractElement_UINT16 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT32 // x = A(i,j) ( int32_t *x, // extracted scalar @@ -3905,7 +3700,6 @@ GrB_Info GrB_Matrix_extractElement_INT32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT32 // x = A(i,j) ( uint32_t *x, // extracted scalar @@ -3914,7 +3708,6 @@ GrB_Info GrB_Matrix_extractElement_UINT32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_INT64 // x = A(i,j) ( int64_t *x, // extracted scalar @@ -3923,7 +3716,6 @@ GrB_Info GrB_Matrix_extractElement_INT64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UINT64 // x = A(i,j) ( uint64_t *x, // extracted scalar @@ -3932,7 +3724,6 @@ GrB_Info GrB_Matrix_extractElement_UINT64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_FP32 // x = A(i,j) ( float *x, // extracted scalar @@ -3941,7 +3732,6 @@ GrB_Info GrB_Matrix_extractElement_FP32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_FP64 // x = A(i,j) ( double *x, // extracted scalar @@ -3950,7 +3740,6 @@ GrB_Info GrB_Matrix_extractElement_FP64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractElement_FC32 // x = A(i,j) ( GxB_FC32_t *x, // extracted scalar @@ -3959,7 +3748,6 @@ GrB_Info GxB_Matrix_extractElement_FC32 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractElement_FC64 // x = A(i,j) ( GxB_FC64_t *x, // extracted scalar @@ -3968,7 +3756,6 @@ GrB_Info GxB_Matrix_extractElement_FC64 // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_UDT // x = A(i,j) ( void *x, // extracted scalar @@ -3977,7 +3764,6 @@ GrB_Info GrB_Matrix_extractElement_UDT // x = A(i,j) GrB_Index j // column index ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractElement_Scalar // x = A(i,j) ( GrB_Scalar x, // extracted scalar @@ -3991,7 +3777,6 @@ GrB_Info GrB_Matrix_extractElement_Scalar // x = A(i,j) /* -GB_PUBLIC GrB_Info GrB_Matrix_extractElement // x = A(i,j) ( *x, // extracted scalar @@ -4007,7 +3792,7 @@ GrB_Info GrB_Matrix_extractElement // x = A(i,j) _Generic \ ( \ (x), \ - GB_CASES (*, GrB, Matrix_extractElement), \ + GB_PCASES (GrB, Matrix_extractElement), \ default: GrB_Matrix_extractElement_Scalar \ ) \ (x, A, i, j) @@ -4017,7 +3802,6 @@ GrB_Info GrB_Matrix_extractElement // x = A(i,j) // of the matrix A, as a stored element. It does not return the value. It // returns GrB_SUCCESS if the element is present, or GrB_NO_VALUE otherwise. -GB_PUBLIC GrB_Info GxB_Matrix_isStoredElement // determine if A(i,j) is a stored element ( const GrB_Matrix A, // matrix to check @@ -4031,7 +3815,6 @@ GrB_Info GxB_Matrix_isStoredElement // determine if A(i,j) is a stored element // GrB_Matrix_removeElement (A,i,j) removes the entry A(i,j) from the matrix A. -GB_PUBLIC GrB_Info GrB_Matrix_removeElement ( GrB_Matrix C, // matrix to remove entry from @@ -4048,7 +3831,6 @@ GrB_Info GrB_Matrix_removeElement // For example, to extract just the row and col indices, pass I and J as // non-NULL, and X as NULL. This is like [I,J,~] = find (A). -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_BOOL // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4058,7 +3840,6 @@ GrB_Info GrB_Matrix_extractTuples_BOOL // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT8 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4068,7 +3849,6 @@ GrB_Info GrB_Matrix_extractTuples_INT8 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT8 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4078,7 +3858,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT8 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT16 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4088,7 +3867,6 @@ GrB_Info GrB_Matrix_extractTuples_INT16 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT16 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4098,7 +3876,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT16 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4108,7 +3885,6 @@ GrB_Info GrB_Matrix_extractTuples_INT32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4118,7 +3894,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_INT64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4128,7 +3903,6 @@ GrB_Info GrB_Matrix_extractTuples_INT64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UINT64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4138,7 +3912,6 @@ GrB_Info GrB_Matrix_extractTuples_UINT64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_FP32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4148,7 +3921,6 @@ GrB_Info GrB_Matrix_extractTuples_FP32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_FP64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4158,7 +3930,6 @@ GrB_Info GrB_Matrix_extractTuples_FP64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractTuples_FC32 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4168,7 +3939,6 @@ GrB_Info GxB_Matrix_extractTuples_FC32 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GxB_Matrix_extractTuples_FC64 // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4178,7 +3948,6 @@ GrB_Info GxB_Matrix_extractTuples_FC64 // [I,J,X] = find (A) const GrB_Matrix A // matrix to extract tuples from ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples_UDT // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4193,7 +3962,6 @@ GrB_Info GrB_Matrix_extractTuples_UDT // [I,J,X] = find (A) /* -GB_PUBLIC GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) ( GrB_Index *I, // array for returning row indices of tuples @@ -4210,7 +3978,7 @@ GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) _Generic \ ( \ (X), \ - GB_CASES (*, GrB, Matrix_extractTuples) \ + GB_PCASES (GrB, Matrix_extractTuples) \ ) \ (I, J, X, nvals, A) #endif @@ -4246,7 +4014,6 @@ GrB_Info GrB_Matrix_extractTuples // [I,J,X] = find (A) // or by column, bitmap switch, hyper switch, and sparsity control) are // unchanged. -GB_PUBLIC GrB_Info GxB_Matrix_concat // concatenate a 2D array of matrices ( GrB_Matrix C, // input/output matrix for results @@ -4266,7 +4033,6 @@ GrB_Info GxB_Matrix_concat // concatenate a 2D array of matrices // number of columns of A. The type of each tile is the same as the type of A; // no typecasting is done. -GB_PUBLIC GrB_Info GxB_Matrix_split // split a matrix into 2D array of matrices ( GrB_Matrix *Tiles, // 2D row-major array of size m-by-n @@ -4291,7 +4057,6 @@ GrB_Info GxB_Matrix_split // split a matrix into 2D array of matrices // diagonal of C, with C(i-k,i) = v(i). C is constructed with the same type // as v. -GB_PUBLIC GrB_Info GrB_Matrix_diag // build a diagonal matrix from a vector ( GrB_Matrix *C, // output matrix @@ -4306,13 +4071,12 @@ GrB_Info GrB_Matrix_diag // build a diagonal matrix from a vector // C by GxB_Matrix_Option_set (format by row or by column, bitmap switch, hyper // switch, and sparsity control) are unchanged. -GB_PUBLIC GrB_Info GxB_Matrix_diag // construct a diagonal matrix from a vector ( GrB_Matrix C, // output matrix const GrB_Vector v, // input vector int64_t k, - const GrB_Descriptor desc // to specify # of threads + const GrB_Descriptor desc ) ; // GxB_Vector_diag extracts a vector v from an input matrix A, which may be @@ -4331,7 +4095,6 @@ GrB_Info GxB_Matrix_diag // construct a diagonal matrix from a vector // typecasted into the type of v. Any settings made to v by // GxB_Vector_Option_set (bitmap switch and sparsity control) are unchanged. -GB_PUBLIC GrB_Info GxB_Vector_diag // extract a diagonal from a matrix, as a vector ( GrB_Vector v, // output vector @@ -4390,6 +4153,7 @@ typedef enum // for global options or matrix options GxB_API_URL = 19, // URL for the API (char *) GxB_COMPILER_VERSION = 23, // compiler version (3 int's) GxB_COMPILER_NAME = 24, // compiler name (char *) + GxB_LIBRARY_OPENMP = 25, // library compiled with OpenMP //------------------------------------------------------------ // for GxB_Global_Option_get/set only: @@ -4439,14 +4203,14 @@ typedef enum } GxB_Format_Value ; -// The default format is by row. These constants are defined as GB_PUBLIC +// The default format is by row. These constants are defined as GB_GLOBAL // const, so that if SuiteSparse:GraphBLAS is recompiled with a different // default format, and the application is relinked but not recompiled, it will // acquire the new default values. -GB_PUBLIC const GxB_Format_Value GxB_FORMAT_DEFAULT ; +GB_GLOBAL const GxB_Format_Value GxB_FORMAT_DEFAULT ; // the default hyper_switch parameter -GB_PUBLIC const double GxB_HYPER_DEFAULT ; +GB_GLOBAL const double GxB_HYPER_DEFAULT ; // GxB_SPARSITY_CONTROL can be any sum or bitwise OR of these 4 values: #define GxB_HYPERSPARSE 1 // store matrix in hypersparse form @@ -4519,9 +4283,8 @@ GB_PUBLIC const double GxB_HYPER_DEFAULT ; // a matrix always stays hypersparse, or always stays non-hypersparse, // respectively. -GB_PUBLIC const double GxB_ALWAYS_HYPER, GxB_NEVER_HYPER ; +GB_GLOBAL const double GxB_ALWAYS_HYPER, GxB_NEVER_HYPER ; -GB_PUBLIC GrB_Info GxB_Matrix_Option_set // set an option in a matrix ( GrB_Matrix A, // matrix to modify @@ -4529,7 +4292,20 @@ GrB_Info GxB_Matrix_Option_set // set an option in a matrix ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Matrix_Option_set_INT32 // set an option in a matrix +( + GrB_Matrix A, // matrix to modify + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Matrix_Option_set_FP64 // set an option in a matrix +( + GrB_Matrix A, // matrix to modify + GxB_Option_Field field, // option to change + double value // value to change it to +) ; + GrB_Info GxB_Matrix_Option_get // gets the current option of a matrix ( GrB_Matrix A, // matrix to query @@ -4537,7 +4313,20 @@ GrB_Info GxB_Matrix_Option_get // gets the current option of a matrix ... // return value of the matrix option ) ; -GB_PUBLIC +GrB_Info GxB_Matrix_Option_get_INT32 // gets the current option of a matrix +( + GrB_Matrix A, // matrix to query + GxB_Option_Field field, // option to query + int32_t *value // return value of the matrix option +) ; + +GrB_Info GxB_Matrix_Option_get_FP64 // gets the current option of a matrix +( + GrB_Matrix A, // matrix to query + GxB_Option_Field field, // option to query + double *value // return value of the matrix option +) ; + GrB_Info GxB_Vector_Option_set // set an option in a vector ( GrB_Vector A, // vector to modify @@ -4545,7 +4334,20 @@ GrB_Info GxB_Vector_Option_set // set an option in a vector ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Vector_Option_set_INT32 // set an option in a vector +( + GrB_Vector v, // vector to modify + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Vector_Option_set_FP64 // set an option in a vector +( + GrB_Vector v, // vector to modify + GxB_Option_Field field, // option to change + double value // value to change it to +) ; + GrB_Info GxB_Vector_Option_get // gets the current option of a vector ( GrB_Vector A, // vector to query @@ -4553,6 +4355,20 @@ GrB_Info GxB_Vector_Option_get // gets the current option of a vector ... // return value of the vector option ) ; +GrB_Info GxB_Vector_Option_get_INT32 // gets the current option of a vector +( + GrB_Vector v, // vector to query + GxB_Option_Field field, // option to query + int32_t *value // return value of the vector option +) ; + +GrB_Info GxB_Vector_Option_get_FP64 // gets the current option of a vector +( + GrB_Vector v, // vector to query + GxB_Option_Field field, // option to query + double *value // return value of the vector option +) ; + // GxB_Global_Option_set controls the global defaults used when a new matrix is // created. GrB_init defines the following initial settings: // @@ -4568,20 +4384,78 @@ GrB_Info GxB_Vector_Option_get // gets the current option of a vector // global settings via GxB_Global_Option_set has no effect on matrices already // created. -GB_PUBLIC GrB_Info GxB_Global_Option_set // set a global default option ( GxB_Option_Field field, // option to change ... // value to change it to ) ; -GB_PUBLIC +GrB_Info GxB_Global_Option_set_INT32 // set a global default option +( + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_FP64 // set a global default option +( + GxB_Option_Field field, // option to change + double value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_FP64_ARRAY // set a global default option +( + GxB_Option_Field field, // option to change + double *value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_INT64_ARRAY // set a global default option +( + GxB_Option_Field field, // option to change + int64_t *value // value to change it to +) ; + +GrB_Info GxB_Global_Option_set_FUNCTION // set a global default option +( + GxB_Option_Field field, // option to change + void *value // value to change it to +) ; + GrB_Info GxB_Global_Option_get // gets the current global default option ( GxB_Option_Field field, // option to query ... // return value of the global option ) ; +GrB_Info GxB_Global_Option_get_INT32 // gets the current global option +( + GxB_Option_Field field, // option to query + int32_t *value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_FP64 // gets the current global option +( + GxB_Option_Field field, // option to query + double *value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_INT64 // gets the current global option +( + GxB_Option_Field field, // option to query + int64_t *value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_CHAR // gets the current global option +( + GxB_Option_Field field, // option to query + char **value // return value of the global option +) ; + +GrB_Info GxB_Global_Option_get_FUNCTION // gets the current global option +( + GxB_Option_Field field, // option to query + void **value // return value of the global option +) ; + //------------------------------------------------------------------------------ // GxB_set and GxB_get //------------------------------------------------------------------------------ @@ -4594,8 +4468,7 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set and GxB_get are generic methods that and set or query the options in // a GrB_Matrix, a GrB_Descriptor, or in the global options. They can be used -// with the following syntax. Note that GxB_NTHREADS can be used for both the -// global nthreads_max, and for the # of threads in the descriptor. +// with the following syntax. // To set/get the global options: // @@ -4699,12 +4572,6 @@ GrB_Info GxB_Global_Option_get // gets the current global default option // GxB_set (GrB_Descriptor d, GxB_AxB_METHOD, GxB_AxB_DOT) ; // GxB_get (GrB_Descriptor d, GrB_AxB_METHOD, GrB_Desc_Value *v) ; // -// GxB_set (GrB_Descriptor d, GxB_NTHREADS, nthreads) ; -// GxB_get (GrB_Descriptor d, GxB_NTHREADS, int *nthreads) ; -// -// GxB_set (GrB_Descriptor d, GxB_CHUNK, double chunk) ; -// GxB_get (GrB_Descriptor d, GxB_CHUNK, double *chunk) ; -// // GxB_set (GrB_Descriptor d, GxB_SORT, int sort) ; // GxB_get (GrB_Descriptor d, GxB_SORT, int *sort) ; // @@ -4731,16 +4598,11 @@ GrB_Info GxB_Global_Option_get // gets the current global default option _Generic \ ( \ (arg1), \ - const int : GxB_Global_Option_get , \ - int : GxB_Global_Option_get , \ - const GxB_Option_Field : GxB_Global_Option_get , \ - GxB_Option_Field : GxB_Global_Option_get , \ - const GrB_Vector : GxB_Vector_Option_get , \ - GrB_Vector : GxB_Vector_Option_get , \ - const GrB_Matrix : GxB_Matrix_Option_get , \ - GrB_Matrix : GxB_Matrix_Option_get , \ - const GrB_Descriptor : GxB_Desc_get , \ - GrB_Descriptor : GxB_Desc_get \ + int : GxB_Global_Option_get , \ + GxB_Option_Field : GxB_Global_Option_get , \ + GrB_Vector : GxB_Vector_Option_get , \ + GrB_Matrix : GxB_Matrix_Option_get , \ + GrB_Descriptor : GxB_Desc_get \ ) \ (arg1, __VA_ARGS__) #endif @@ -4787,17 +4649,17 @@ GrB_WaitMode ; // Finish all pending work in a specific object. -GB_PUBLIC GrB_Info GrB_Type_wait (GrB_Type type , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_UnaryOp_wait (GrB_UnaryOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_BinaryOp_wait (GrB_BinaryOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GxB_SelectOp_wait (GxB_SelectOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_IndexUnaryOp_wait (GrB_IndexUnaryOp op , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Monoid_wait (GrB_Monoid monoid , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Semiring_wait (GrB_Semiring semiring, GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Descriptor_wait (GrB_Descriptor desc , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Scalar_wait (GrB_Scalar s , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Vector_wait (GrB_Vector v , GrB_WaitMode waitmode) ; -GB_PUBLIC GrB_Info GrB_Matrix_wait (GrB_Matrix A , GrB_WaitMode waitmode) ; +GrB_Info GrB_Type_wait (GrB_Type type , GrB_WaitMode waitmode); +GrB_Info GrB_UnaryOp_wait (GrB_UnaryOp op , GrB_WaitMode waitmode); +GrB_Info GrB_BinaryOp_wait (GrB_BinaryOp op , GrB_WaitMode waitmode); +GrB_Info GxB_SelectOp_wait (GxB_SelectOp op , GrB_WaitMode waitmode); +GrB_Info GrB_IndexUnaryOp_wait (GrB_IndexUnaryOp op , GrB_WaitMode waitmode); +GrB_Info GrB_Monoid_wait (GrB_Monoid monoid , GrB_WaitMode waitmode); +GrB_Info GrB_Semiring_wait (GrB_Semiring semiring, GrB_WaitMode waitmode); +GrB_Info GrB_Descriptor_wait (GrB_Descriptor desc , GrB_WaitMode waitmode); +GrB_Info GrB_Scalar_wait (GrB_Scalar s , GrB_WaitMode waitmode); +GrB_Info GrB_Vector_wait (GrB_Vector v , GrB_WaitMode waitmode); +GrB_Info GrB_Matrix_wait (GrB_Matrix A , GrB_WaitMode waitmode); // GrB_wait (object,waitmode) polymorphic function: #if GxB_STDC_VERSION >= 201112L @@ -4821,7 +4683,7 @@ GB_PUBLIC GrB_Info GrB_Matrix_wait (GrB_Matrix A , GrB_WaitMode #endif // NOTE: GxB_Scalar_wait is historical; use GrB_Scalar_wait instead -GB_PUBLIC GrB_Info GxB_Scalar_wait (GrB_Scalar *s) ; +GrB_Info GxB_Scalar_wait (GrB_Scalar *s) ; //============================================================================== // GrB_error: error handling @@ -4832,19 +4694,19 @@ GB_PUBLIC GrB_Info GxB_Scalar_wait (GrB_Scalar *s) ; // null-terminated string. The string returned by GrB_error is owned by // the GraphBLAS library and must not be free'd. -GB_PUBLIC GrB_Info GrB_Type_error (const char **error, const GrB_Type type) ; -GB_PUBLIC GrB_Info GrB_UnaryOp_error (const char **error, const GrB_UnaryOp op) ; -GB_PUBLIC GrB_Info GrB_BinaryOp_error (const char **error, const GrB_BinaryOp op) ; -GB_PUBLIC GrB_Info GxB_SelectOp_error (const char **error, const GxB_SelectOp op) ; -GB_PUBLIC GrB_Info GrB_IndexUnaryOp_error (const char **error, const GrB_IndexUnaryOp op) ; -GB_PUBLIC GrB_Info GrB_Monoid_error (const char **error, const GrB_Monoid monoid) ; -GB_PUBLIC GrB_Info GrB_Semiring_error (const char **error, const GrB_Semiring semiring) ; -GB_PUBLIC GrB_Info GrB_Scalar_error (const char **error, const GrB_Scalar s) ; -GB_PUBLIC GrB_Info GrB_Vector_error (const char **error, const GrB_Vector v) ; -GB_PUBLIC GrB_Info GrB_Matrix_error (const char **error, const GrB_Matrix A) ; -GB_PUBLIC GrB_Info GrB_Descriptor_error (const char **error, const GrB_Descriptor d) ; +GrB_Info GrB_Type_error (const char **error, const GrB_Type type) ; +GrB_Info GrB_UnaryOp_error (const char **error, const GrB_UnaryOp op) ; +GrB_Info GrB_BinaryOp_error (const char **error, const GrB_BinaryOp op) ; +GrB_Info GxB_SelectOp_error (const char **error, const GxB_SelectOp op) ; +GrB_Info GrB_IndexUnaryOp_error (const char **error, const GrB_IndexUnaryOp op) ; +GrB_Info GrB_Monoid_error (const char **error, const GrB_Monoid monoid) ; +GrB_Info GrB_Semiring_error (const char **error, const GrB_Semiring semiring) ; +GrB_Info GrB_Scalar_error (const char **error, const GrB_Scalar s) ; +GrB_Info GrB_Vector_error (const char **error, const GrB_Vector v) ; +GrB_Info GrB_Matrix_error (const char **error, const GrB_Matrix A) ; +GrB_Info GrB_Descriptor_error (const char **error, const GrB_Descriptor d) ; // GxB_Scalar_error is historical: use GrB_Scalar_error instead -GB_PUBLIC GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar s) ; +GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar s) ; // GrB_error (error,object) polymorphic function: #if GxB_STDC_VERSION >= 201112L @@ -4852,27 +4714,16 @@ GB_PUBLIC GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar _Generic \ ( \ (object), \ - const GrB_Type : GrB_Type_error , \ GrB_Type : GrB_Type_error , \ - const GrB_UnaryOp : GrB_UnaryOp_error , \ GrB_UnaryOp : GrB_UnaryOp_error , \ - const GrB_BinaryOp : GrB_BinaryOp_error , \ GrB_BinaryOp : GrB_BinaryOp_error , \ - const GxB_SelectOp : GxB_SelectOp_error , \ GxB_SelectOp : GxB_SelectOp_error , \ - const GrB_IndexUnaryOp : GrB_IndexUnaryOp_error , \ GrB_IndexUnaryOp : GrB_IndexUnaryOp_error , \ - const GrB_Monoid : GrB_Monoid_error , \ GrB_Monoid : GrB_Monoid_error , \ - const GrB_Semiring : GrB_Semiring_error , \ GrB_Semiring : GrB_Semiring_error , \ - const GrB_Scalar : GrB_Scalar_error , \ GrB_Scalar : GrB_Scalar_error , \ - const GrB_Vector : GrB_Vector_error , \ GrB_Vector : GrB_Vector_error , \ - const GrB_Matrix : GrB_Matrix_error , \ GrB_Matrix : GrB_Matrix_error , \ - const GrB_Descriptor : GrB_Descriptor_error , \ GrB_Descriptor : GrB_Descriptor_error \ ) \ (error, object) @@ -4882,7 +4733,6 @@ GB_PUBLIC GrB_Info GxB_Scalar_error (const char **error, const GrB_Scalar // GrB_mxm, vxm, mxv: matrix multiplication over a semiring //============================================================================== -GB_PUBLIC GrB_Info GrB_mxm // C = accum (C, A*B) ( GrB_Matrix C, // input/output matrix for results @@ -4894,7 +4744,6 @@ GrB_Info GrB_mxm // C = accum (C, A*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_vxm // w' = accum (w, u'*A) ( GrB_Vector w, // input/output vector for results @@ -4906,7 +4755,6 @@ GrB_Info GrB_vxm // w' = accum (w, u'*A) const GrB_Descriptor desc // descriptor for w, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_mxv // w = accum (w, A*u) ( GrB_Vector w, // input/output vector for results @@ -4926,7 +4774,6 @@ GrB_Info GrB_mxv // w = accum (w, A*u) // product, and where pairs of elements in two matrices (or vectors) are // pairwise "multiplied" with C(i,j) = mult (A(i,j),B(i,j)). -GB_PUBLIC GrB_Info GrB_Vector_eWiseMult_Semiring // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results @@ -4938,7 +4785,6 @@ GrB_Info GrB_Vector_eWiseMult_Semiring // w = accum (w, u.*v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseMult_Monoid // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results @@ -4950,7 +4796,6 @@ GrB_Info GrB_Vector_eWiseMult_Monoid // w = accum (w, u.*v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseMult_BinaryOp // w = accum (w, u.*v) ( GrB_Vector w, // input/output vector for results @@ -4962,7 +4807,6 @@ GrB_Info GrB_Vector_eWiseMult_BinaryOp // w = accum (w, u.*v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseMult_Semiring // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results @@ -4974,7 +4818,6 @@ GrB_Info GrB_Matrix_eWiseMult_Semiring // C = accum (C, A.*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseMult_Monoid // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results @@ -4986,7 +4829,6 @@ GrB_Info GrB_Matrix_eWiseMult_Monoid // C = accum (C, A.*B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) ( GrB_Matrix C, // input/output matrix for results @@ -5010,22 +4852,16 @@ GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Matrix_eWiseMult_Semiring , \ GrB_Semiring : GrB_Matrix_eWiseMult_Semiring , \ - const GrB_Monoid : GrB_Matrix_eWiseMult_Monoid , \ GrB_Monoid : GrB_Matrix_eWiseMult_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_eWiseMult_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_eWiseMult_BinaryOp \ ), \ GrB_Vector : \ _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Vector_eWiseMult_Semiring , \ GrB_Semiring : GrB_Vector_eWiseMult_Semiring , \ - const GrB_Monoid : GrB_Vector_eWiseMult_Monoid , \ GrB_Monoid : GrB_Vector_eWiseMult_Monoid , \ - const GrB_BinaryOp : GrB_Vector_eWiseMult_BinaryOp , \ GrB_BinaryOp : GrB_Vector_eWiseMult_BinaryOp \ ) \ ) \ @@ -5039,7 +4875,6 @@ GrB_Info GrB_Matrix_eWiseMult_BinaryOp // C = accum (C, A.*B) // GrB_eWiseAdd computes C = accum (C, A+B), where pairs of elements in // two matrices (or two vectors) are pairwise "added". -GB_PUBLIC GrB_Info GrB_Vector_eWiseAdd_Semiring // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5051,7 +4886,6 @@ GrB_Info GrB_Vector_eWiseAdd_Semiring // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseAdd_Monoid // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5063,7 +4897,6 @@ GrB_Info GrB_Vector_eWiseAdd_Monoid // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_eWiseAdd_BinaryOp // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5075,7 +4908,6 @@ GrB_Info GrB_Vector_eWiseAdd_BinaryOp // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseAdd_Semiring // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5087,7 +4919,6 @@ GrB_Info GrB_Matrix_eWiseAdd_Semiring // C = accum (C, A+B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseAdd_Monoid // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5099,7 +4930,6 @@ GrB_Info GrB_Matrix_eWiseAdd_Monoid // C = accum (C, A+B) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5120,22 +4950,16 @@ GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Matrix_eWiseAdd_Semiring , \ GrB_Semiring : GrB_Matrix_eWiseAdd_Semiring , \ - const GrB_Monoid : GrB_Matrix_eWiseAdd_Monoid , \ GrB_Monoid : GrB_Matrix_eWiseAdd_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_eWiseAdd_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_eWiseAdd_BinaryOp \ ), \ GrB_Vector : \ _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Vector_eWiseAdd_Semiring , \ GrB_Semiring : GrB_Vector_eWiseAdd_Semiring , \ - const GrB_Monoid : GrB_Vector_eWiseAdd_Monoid , \ GrB_Monoid : GrB_Vector_eWiseAdd_Monoid , \ - const GrB_BinaryOp : GrB_Vector_eWiseAdd_BinaryOp , \ GrB_BinaryOp : GrB_Vector_eWiseAdd_BinaryOp \ ) \ ) \ @@ -5168,7 +4992,6 @@ GrB_Info GrB_Matrix_eWiseAdd_BinaryOp // C = accum (C, A+B) // else if B(i,j) is present but not A(i,j) // C(i,j) = alpha + B(i,j) -GB_PUBLIC GrB_Info GxB_Vector_eWiseUnion // w = accum (w, u+v) ( GrB_Vector w, // input/output vector for results @@ -5182,7 +5005,6 @@ GrB_Info GxB_Vector_eWiseUnion // w = accum (w, u+v) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_eWiseUnion // C = accum (C, A+B) ( GrB_Matrix C, // input/output matrix for results @@ -5201,9 +5023,7 @@ GrB_Info GxB_Matrix_eWiseUnion // C = accum (C, A+B) _Generic \ ( \ (C), \ - const GrB_Matrix : GxB_Matrix_eWiseUnion , \ GrB_Matrix : GxB_Matrix_eWiseUnion , \ - const GrB_Vector : GxB_Vector_eWiseUnion , \ GrB_Vector : GxB_Vector_eWiseUnion \ ) \ (C, Mask, accum, op, A, alpha, B, beta, desc) @@ -5219,7 +5039,7 @@ GrB_Info GxB_Matrix_eWiseUnion // C = accum (C, A+B) // To extract all rows of a matrix or vector, as in A (:,J), use I=GrB_ALL as // the input argument. For all columns of a matrix, use J=GrB_ALL. -GB_PUBLIC const uint64_t *GrB_ALL ; +GB_GLOBAL const uint64_t *GrB_ALL ; // To extract a range of rows and columns, I and J can be a list of 2 or 3 // indices that defines a range (begin:end) or a strided range (begin:inc:end). @@ -5253,7 +5073,6 @@ GB_PUBLIC const uint64_t *GrB_ALL ; // I [GxB_INC ] = 2 ; // the magnitude of the increment // I [GxB_END ] = 1 ; // the end of the sequence -GB_PUBLIC GrB_Info GrB_Vector_extract // w = accum (w, u(I)) ( GrB_Vector w, // input/output vector for results @@ -5265,7 +5084,6 @@ GrB_Info GrB_Vector_extract // w = accum (w, u(I)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_extract // C = accum (C, A(I,J)) ( GrB_Matrix C, // input/output matrix for results @@ -5279,7 +5097,6 @@ GrB_Info GrB_Matrix_extract // C = accum (C, A(I,J)) const GrB_Descriptor desc // descriptor for C, Mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) ( GrB_Vector w, // input/output matrix for results @@ -5311,9 +5128,7 @@ GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) _Generic \ ( \ (arg4), \ - const GrB_Vector : GrB_Vector_extract , \ GrB_Vector : GrB_Vector_extract , \ - const GrB_Matrix : GrB_Col_extract , \ GrB_Matrix : GrB_Col_extract \ ), \ GrB_Matrix : GrB_Matrix_extract \ @@ -5368,7 +5183,6 @@ GrB_Info GrB_Col_extract // w = accum (w, A(I,j)) // GxB_Col_subassign C(I,j) += u m same size as column vector u. // u is |I|-by-1, j is a scalar. -GB_PUBLIC GrB_Info GxB_Vector_subassign // w(I) = accum (w(I),u) ( GrB_Vector w, // input/output matrix for results @@ -5380,7 +5194,6 @@ GrB_Info GxB_Vector_subassign // w(I) = accum (w(I),u) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign // C(I,J) = accum (C(I,J),A) ( GrB_Matrix C, // input/output matrix for results @@ -5394,7 +5207,6 @@ GrB_Info GxB_Matrix_subassign // C(I,J) = accum (C(I,J),A) const GrB_Descriptor desc // descriptor for C(I,J), Mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Col_subassign // C(I,j) = accum (C(I,j),u) ( GrB_Matrix C, // input/output matrix for results @@ -5407,7 +5219,6 @@ GrB_Info GxB_Col_subassign // C(I,j) = accum (C(I,j),u) const GrB_Descriptor desc // descriptor for C(I,j) and mask ) ; -GB_PUBLIC GrB_Info GxB_Row_subassign // C(i,J) = accum (C(i,J),u') ( GrB_Matrix C, // input/output matrix for results @@ -5428,7 +5239,6 @@ GrB_Info GxB_Row_subassign // C(i,J) = accum (C(i,J),u') // scalar x is implicitly expanded into a vector u of size ni-by-1, with each // entry in u equal to x, and then w(I) = accum(w(I),u) is done. -GB_PUBLIC GrB_Info GxB_Vector_subassign_BOOL // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5440,7 +5250,6 @@ GrB_Info GxB_Vector_subassign_BOOL // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5452,7 +5261,6 @@ GrB_Info GxB_Vector_subassign_INT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5464,7 +5272,6 @@ GrB_Info GxB_Vector_subassign_UINT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5476,7 +5283,6 @@ GrB_Info GxB_Vector_subassign_INT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5488,7 +5294,6 @@ GrB_Info GxB_Vector_subassign_UINT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5500,7 +5305,6 @@ GrB_Info GxB_Vector_subassign_INT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5512,7 +5316,6 @@ GrB_Info GxB_Vector_subassign_UINT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_INT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5524,7 +5327,6 @@ GrB_Info GxB_Vector_subassign_INT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UINT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5536,7 +5338,6 @@ GrB_Info GxB_Vector_subassign_UINT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FP32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5548,7 +5349,6 @@ GrB_Info GxB_Vector_subassign_FP32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FP64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5560,7 +5360,6 @@ GrB_Info GxB_Vector_subassign_FP64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FC32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5572,7 +5371,6 @@ GrB_Info GxB_Vector_subassign_FC32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_FC64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5584,7 +5382,6 @@ GrB_Info GxB_Vector_subassign_FC64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_UDT // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5596,7 +5393,6 @@ GrB_Info GxB_Vector_subassign_UDT // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w(I) and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_subassign_Scalar // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5616,7 +5412,6 @@ GrB_Info GxB_Vector_subassign_Scalar // w(I) = accum (w(I),x) // scalar x is implicitly expanded into a matrix A of size ni-by-nj, with each // entry in A equal to x, and then C(I,J) = accum(C(I,J),A) is done. -GB_PUBLIC GrB_Info GxB_Matrix_subassign_BOOL // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5630,7 +5425,6 @@ GrB_Info GxB_Matrix_subassign_BOOL // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5644,7 +5438,6 @@ GrB_Info GxB_Matrix_subassign_INT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5658,7 +5451,6 @@ GrB_Info GxB_Matrix_subassign_UINT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5672,7 +5464,6 @@ GrB_Info GxB_Matrix_subassign_INT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5686,7 +5477,6 @@ GrB_Info GxB_Matrix_subassign_UINT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5700,7 +5490,6 @@ GrB_Info GxB_Matrix_subassign_INT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5714,7 +5503,6 @@ GrB_Info GxB_Matrix_subassign_UINT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_INT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5728,7 +5516,6 @@ GrB_Info GxB_Matrix_subassign_INT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UINT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5742,7 +5529,6 @@ GrB_Info GxB_Matrix_subassign_UINT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FP32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5756,7 +5542,6 @@ GrB_Info GxB_Matrix_subassign_FP32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FP64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5770,7 +5555,6 @@ GrB_Info GxB_Matrix_subassign_FP64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FC32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5784,7 +5568,6 @@ GrB_Info GxB_Matrix_subassign_FC32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_FC64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5798,7 +5581,6 @@ GrB_Info GxB_Matrix_subassign_FC64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5812,7 +5594,6 @@ GrB_Info GxB_Matrix_subassign_UDT // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C(I,J) and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -5849,26 +5630,16 @@ GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),x) _Generic \ ( \ (arg4), \ - GB_CASES (, GxB, Vector_subassign) , \ - const GrB_Scalar : GxB_Vector_subassign_Scalar, \ - GrB_Scalar : GxB_Vector_subassign_Scalar, \ + GB_CASES (GxB, Vector_subassign) , \ + GrB_Scalar : GxB_Vector_subassign_Scalar, \ default: GxB_Vector_subassign \ ), \ default: \ _Generic \ ( \ (arg4), \ - GB_CASES (, GxB, Matrix_subassign) , \ - const GrB_Scalar : GxB_Matrix_subassign_Scalar, \ - GrB_Scalar : GxB_Matrix_subassign_Scalar, \ - const GrB_Vector : \ - _Generic \ - ( \ - (arg5), \ - const GrB_Index *: GxB_Col_subassign , \ - GrB_Index *: GxB_Col_subassign , \ - default: GxB_Row_subassign \ - ), \ + GB_CASES (GxB, Matrix_subassign) , \ + GrB_Scalar : GxB_Matrix_subassign_Scalar, \ GrB_Vector : \ _Generic \ ( \ @@ -5890,7 +5661,6 @@ GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),x) // Assign entries in a matrix or vector; C(I,J) = A. // Each of these can be used with their generic name, GrB_assign. -GB_PUBLIC GrB_Info GrB_Vector_assign // w(I) = accum (w(I),u) ( GrB_Vector w, // input/output matrix for results @@ -5902,7 +5672,6 @@ GrB_Info GrB_Vector_assign // w(I) = accum (w(I),u) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign // C(I,J) = accum (C(I,J),A) ( GrB_Matrix C, // input/output matrix for results @@ -5916,7 +5685,6 @@ GrB_Info GrB_Matrix_assign // C(I,J) = accum (C(I,J),A) const GrB_Descriptor desc // descriptor for C, Mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Col_assign // C(I,j) = accum (C(I,j),u) ( GrB_Matrix C, // input/output matrix for results @@ -5929,7 +5697,6 @@ GrB_Info GrB_Col_assign // C(I,j) = accum (C(I,j),u) const GrB_Descriptor desc // descriptor for C(:,j) and mask ) ; -GB_PUBLIC GrB_Info GrB_Row_assign // C(i,J) = accum (C(i,J),u') ( GrB_Matrix C, // input/output matrix for results @@ -5950,7 +5717,6 @@ GrB_Info GrB_Row_assign // C(i,J) = accum (C(i,J),u') // scalar x is implicitly expanded into a vector u of size ni-by-1, with each // entry in u equal to x, and then w(I) = accum(w(I),u) is done. -GB_PUBLIC GrB_Info GrB_Vector_assign_BOOL // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5962,7 +5728,6 @@ GrB_Info GrB_Vector_assign_BOOL // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5974,7 +5739,6 @@ GrB_Info GrB_Vector_assign_INT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT8 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5986,7 +5750,6 @@ GrB_Info GrB_Vector_assign_UINT8 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -5998,7 +5761,6 @@ GrB_Info GrB_Vector_assign_INT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT16 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6010,7 +5772,6 @@ GrB_Info GrB_Vector_assign_UINT16 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6022,7 +5783,6 @@ GrB_Info GrB_Vector_assign_INT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6034,7 +5794,6 @@ GrB_Info GrB_Vector_assign_UINT32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_INT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6046,7 +5805,6 @@ GrB_Info GrB_Vector_assign_INT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UINT64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6058,7 +5816,6 @@ GrB_Info GrB_Vector_assign_UINT64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_FP32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6070,7 +5827,6 @@ GrB_Info GrB_Vector_assign_FP32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_FP64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6082,7 +5838,6 @@ GrB_Info GrB_Vector_assign_FP64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_assign_FC32 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6094,7 +5849,6 @@ GrB_Info GxB_Vector_assign_FC32 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_assign_FC64 // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6106,7 +5860,6 @@ GrB_Info GxB_Vector_assign_FC64 // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_UDT // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6118,7 +5871,6 @@ GrB_Info GrB_Vector_assign_UDT // w(I) = accum (w(I),x) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_assign_Scalar // w(I) = accum (w(I),x) ( GrB_Vector w, // input/output vector for results @@ -6138,7 +5890,6 @@ GrB_Info GrB_Vector_assign_Scalar // w(I) = accum (w(I),x) // scalar x is implicitly expanded into a matrix A of size ni-by-nj, with each // entry in A equal to x, and then C(I,J) = accum(C(I,J),A) is done. -GB_PUBLIC GrB_Info GrB_Matrix_assign_BOOL // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6152,7 +5903,6 @@ GrB_Info GrB_Matrix_assign_BOOL // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6166,7 +5916,6 @@ GrB_Info GrB_Matrix_assign_INT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT8 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6180,7 +5929,6 @@ GrB_Info GrB_Matrix_assign_UINT8 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6194,7 +5942,6 @@ GrB_Info GrB_Matrix_assign_INT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT16 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6208,7 +5955,6 @@ GrB_Info GrB_Matrix_assign_UINT16 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6222,7 +5968,6 @@ GrB_Info GrB_Matrix_assign_INT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6236,7 +5981,6 @@ GrB_Info GrB_Matrix_assign_UINT32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_INT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6250,7 +5994,6 @@ GrB_Info GrB_Matrix_assign_INT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UINT64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6264,7 +6007,6 @@ GrB_Info GrB_Matrix_assign_UINT64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_FP32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6278,7 +6020,6 @@ GrB_Info GrB_Matrix_assign_FP32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_FP64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6292,7 +6033,6 @@ GrB_Info GrB_Matrix_assign_FP64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_assign_FC32 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6306,7 +6046,6 @@ GrB_Info GxB_Matrix_assign_FC32 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_assign_FC64 // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6320,7 +6059,6 @@ GrB_Info GxB_Matrix_assign_FC64 // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6334,7 +6072,6 @@ GrB_Info GrB_Matrix_assign_UDT // C(I,J) = accum (C(I,J),x) const GrB_Descriptor desc // descriptor for C and Mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),x) ( GrB_Matrix C, // input/output matrix for results @@ -6371,26 +6108,16 @@ GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),x) _Generic \ ( \ (arg4), \ - GB_CASES (, GrB, Vector_assign) , \ - const GrB_Scalar : GrB_Vector_assign_Scalar , \ - GrB_Scalar : GrB_Vector_assign_Scalar , \ + GB_CASES (GrB, Vector_assign) , \ + GrB_Scalar : GrB_Vector_assign_Scalar , \ default: GrB_Vector_assign \ ), \ default: \ _Generic \ ( \ (arg4), \ - GB_CASES (, GrB, Matrix_assign) , \ - const GrB_Scalar : GrB_Matrix_assign_Scalar , \ - GrB_Scalar : GrB_Matrix_assign_Scalar , \ - const GrB_Vector : \ - _Generic \ - ( \ - (arg5), \ - const GrB_Index *: GrB_Col_assign , \ - GrB_Index *: GrB_Col_assign , \ - default: GrB_Row_assign \ - ), \ + GB_CASES (GrB, Matrix_assign) , \ + GrB_Scalar : GrB_Matrix_assign_Scalar , \ GrB_Vector : \ _Generic \ ( \ @@ -6412,7 +6139,6 @@ GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),x) // Apply a unary, index_unary, or binary operator to entries in a matrix or // vector, C = accum (C, op (A)). -GB_PUBLIC GrB_Info GrB_Vector_apply // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6423,7 +6149,6 @@ GrB_Info GrB_Vector_apply // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') ( GrB_Matrix C, // input/output matrix for results @@ -6441,7 +6166,6 @@ GrB_Info GrB_Matrix_apply // C = accum (C, op(A)) or op(A') // Apply a binary operator to the entries in a vector, binding the first // input to a scalar x, w = accum (w, op (x,u)). -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_Scalar // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6454,7 +6178,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_Scalar // w = accum (w, op(x,u)) ) ; // historical: identical to GxB_Vector_apply_BinaryOp1st -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp1st // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6466,7 +6189,6 @@ GrB_Info GxB_Vector_apply_BinaryOp1st // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_BOOL // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6478,7 +6200,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_BOOL // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT8 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6490,7 +6211,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT8 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT16 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6502,7 +6222,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT16 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6514,7 +6233,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_INT64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6526,7 +6244,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_INT64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT8 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6538,7 +6255,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT8 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT16 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6550,7 +6266,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT16 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6562,7 +6277,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UINT64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6574,7 +6288,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UINT64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_FP32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6586,7 +6299,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_FP32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_FP64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6598,7 +6310,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_FP64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp1st_FC32 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6610,7 +6321,6 @@ GrB_Info GxB_Vector_apply_BinaryOp1st_FC32 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp1st_FC64 // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6622,7 +6332,6 @@ GrB_Info GxB_Vector_apply_BinaryOp1st_FC64 // w = accum (w, op(x,u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp1st_UDT // w = accum (w, op(x,u)) ( GrB_Vector w, // input/output vector for results @@ -6641,7 +6350,6 @@ GrB_Info GrB_Vector_apply_BinaryOp1st_UDT // w = accum (w, op(x,u)) // Apply a binary operator to the entries in a vector, binding the second // input to a scalar y, w = accum (w, op (u,y)). -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_Scalar // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6654,7 +6362,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_Scalar // w = accum (w, op(u,y)) ) ; // historical: identical to GrB_Vector_apply_BinaryOp2nd_Scalar -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp2nd // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6666,7 +6373,6 @@ GrB_Info GxB_Vector_apply_BinaryOp2nd // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_BOOL // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6678,7 +6384,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_BOOL // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT8 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6690,7 +6395,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT8 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT16 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6702,7 +6406,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT16 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6714,7 +6417,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_INT64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6726,7 +6428,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_INT64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT8 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6738,7 +6439,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT8 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT16 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6750,7 +6450,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT16 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6762,7 +6461,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6774,7 +6472,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UINT64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_FP32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6786,7 +6483,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_FP32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_FP64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6798,7 +6494,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_FP64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp2nd_FC32 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6810,7 +6505,6 @@ GrB_Info GxB_Vector_apply_BinaryOp2nd_FC32 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_BinaryOp2nd_FC64 // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6822,7 +6516,6 @@ GrB_Info GxB_Vector_apply_BinaryOp2nd_FC64 // w = accum (w, op(u,y)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_BinaryOp2nd_UDT // w = accum (w, op(u,y)) ( GrB_Vector w, // input/output vector for results @@ -6840,7 +6533,6 @@ GrB_Info GrB_Vector_apply_BinaryOp2nd_UDT // w = accum (w, op(u,y)) // Apply a GrB_IndexUnaryOp to the entries in a vector -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_Scalar // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6852,7 +6544,6 @@ GrB_Info GrB_Vector_apply_IndexOp_Scalar // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_BOOL // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6864,7 +6555,6 @@ GrB_Info GrB_Vector_apply_IndexOp_BOOL // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6876,7 +6566,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6888,7 +6577,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6900,7 +6588,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_INT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6912,7 +6599,6 @@ GrB_Info GrB_Vector_apply_IndexOp_INT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6924,7 +6610,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6936,7 +6621,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6948,7 +6632,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UINT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6960,7 +6643,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UINT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_FP32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6972,7 +6654,6 @@ GrB_Info GrB_Vector_apply_IndexOp_FP32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_FP64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6984,7 +6665,6 @@ GrB_Info GrB_Vector_apply_IndexOp_FP64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_IndexOp_FC32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -6996,7 +6676,6 @@ GrB_Info GxB_Vector_apply_IndexOp_FC32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_apply_IndexOp_FC64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7008,7 +6687,6 @@ GrB_Info GxB_Vector_apply_IndexOp_FC64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_apply_IndexOp_UDT // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7027,7 +6705,6 @@ GrB_Info GrB_Vector_apply_IndexOp_UDT // w = accum (w, op(u)) // Apply a binary operator to the entries in a matrix, binding the first input // to a scalar x, C = accum (C, op (x,A)), or op(x,A'). -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_Scalar // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7040,7 +6717,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_Scalar // C=accum(C,op(x,A)) ) ; // historical: identical to GrB_Matrix_apply_BinaryOp1st_Scalar -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp1st // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7052,7 +6728,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp1st // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_BOOL // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7064,7 +6739,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_BOOL // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT8 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7076,7 +6750,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT8 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT16 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7088,7 +6761,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT16 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7100,7 +6772,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_INT64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7112,7 +6783,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_INT64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT8 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7124,7 +6794,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT8 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT16 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7136,7 +6805,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT16 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7148,7 +6816,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7160,7 +6827,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UINT64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_FP32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7172,7 +6838,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_FP32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_FP64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7184,7 +6849,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_FP64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp1st_FC32 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7196,7 +6860,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp1st_FC32 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp1st_FC64 // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7208,7 +6871,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp1st_FC64 // C=accum(C,op(x,A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp1st_UDT // C=accum(C,op(x,A)) ( GrB_Matrix C, // input/output matrix for results @@ -7227,7 +6889,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp1st_UDT // C=accum(C,op(x,A)) // Apply a binary operator to the entries in a matrix, binding the second input // to a scalar y, C = accum (C, op (A,y)), or op(A',y). -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_Scalar // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7240,7 +6901,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_Scalar // C=accum(C,op(A,y)) ) ; // historical: identical to GrB_Matrix_apply_BinaryOp2nd_Scalar -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp2nd // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7252,7 +6912,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp2nd // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_BOOL // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7264,7 +6923,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_BOOL // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT8 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7276,7 +6934,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT8 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT16 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7288,7 +6945,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT16 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7300,7 +6956,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7312,7 +6967,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_INT64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT8 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7324,7 +6978,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT8 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT16 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7336,7 +6989,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT16 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7348,7 +7000,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7360,7 +7011,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UINT64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7372,7 +7022,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7384,7 +7033,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_FP64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC32 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7396,7 +7044,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC32 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC64 // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7408,7 +7055,6 @@ GrB_Info GxB_Matrix_apply_BinaryOp2nd_FC64 // C=accum(C,op(A,y)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_BinaryOp2nd_UDT // C=accum(C,op(A,y)) ( GrB_Matrix C, // input/output matrix for results @@ -7426,7 +7072,6 @@ GrB_Info GrB_Matrix_apply_BinaryOp2nd_UDT // C=accum(C,op(A,y)) // Apply a GrB_IndexUnaryOp to the entries in a matrix. -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_Scalar // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7438,7 +7083,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_Scalar // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_BOOL // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7450,7 +7094,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_BOOL // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7462,7 +7105,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7474,7 +7116,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7486,7 +7127,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_INT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7498,7 +7138,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_INT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7510,7 +7149,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7522,7 +7160,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7534,7 +7171,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UINT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7546,7 +7182,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UINT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_FP32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7558,7 +7193,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_FP32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_FP64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7570,7 +7204,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_FP64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_IndexOp_FC32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7582,7 +7215,6 @@ GrB_Info GxB_Matrix_apply_IndexOp_FC32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_apply_IndexOp_FC64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7594,7 +7226,6 @@ GrB_Info GxB_Matrix_apply_IndexOp_FC64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7632,14 +7263,13 @@ GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) _Generic \ ( \ (x), \ - const GrB_Scalar: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp1st_Scalar), \ - GrB_Scalar: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp1st_Scalar), \ - GB_CASES (, GrB, GB_CONCAT ( kind, _apply_BinaryOp1st,, )) , \ + GrB_Scalar: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp1st_Scalar), \ + GB_CASES (GrB, GB_CONCAT ( kind, _apply_BinaryOp1st,, )) , \ default: \ _Generic \ ( \ (y), \ - GB_CASES (, GrB, GB_CONCAT ( kind , _apply_BinaryOp2nd,, )), \ + GB_CASES (GrB, GB_CONCAT ( kind , _apply_BinaryOp2nd,, )), \ default: GB_CONCAT ( GrB,_,kind,_apply_BinaryOp2nd_Scalar) \ ) \ ) @@ -7648,7 +7278,7 @@ GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) _Generic \ ( \ (y), \ - GB_CASES (, GrB, GB_CONCAT ( kind, _apply_IndexOp,, )), \ + GB_CASES (GrB, GB_CONCAT ( kind, _apply_IndexOp,, )), \ default: GB_CONCAT ( GrB, _, kind, _apply_IndexOp_Scalar) \ ) @@ -7684,7 +7314,6 @@ GrB_Info GrB_Matrix_apply_IndexOp_UDT // C=accum(C,op(A)) // vector select using an IndexUnaryOp //------------------------------------------- -GB_PUBLIC GrB_Info GrB_Vector_select_Scalar // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7696,7 +7325,6 @@ GrB_Info GrB_Vector_select_Scalar // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_BOOL // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7708,7 +7336,6 @@ GrB_Info GrB_Vector_select_BOOL // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7720,7 +7347,6 @@ GrB_Info GrB_Vector_select_INT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7732,7 +7358,6 @@ GrB_Info GrB_Vector_select_INT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7744,7 +7369,6 @@ GrB_Info GrB_Vector_select_INT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_INT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7756,7 +7380,6 @@ GrB_Info GrB_Vector_select_INT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT8 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7768,7 +7391,6 @@ GrB_Info GrB_Vector_select_UINT8 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT16 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7780,7 +7402,6 @@ GrB_Info GrB_Vector_select_UINT16 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7792,7 +7413,6 @@ GrB_Info GrB_Vector_select_UINT32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UINT64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7804,7 +7424,6 @@ GrB_Info GrB_Vector_select_UINT64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_FP32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7816,7 +7435,6 @@ GrB_Info GrB_Vector_select_FP32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_FP64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7828,7 +7446,6 @@ GrB_Info GrB_Vector_select_FP64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_select_FC32 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7840,7 +7457,6 @@ GrB_Info GxB_Vector_select_FC32 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Vector_select_FC64 // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7852,7 +7468,6 @@ GrB_Info GxB_Vector_select_FC64 // w = accum (w, op(u)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GrB_Vector_select_UDT // w = accum (w, op(u)) ( GrB_Vector w, // input/output vector for results @@ -7868,7 +7483,6 @@ GrB_Info GrB_Vector_select_UDT // w = accum (w, op(u)) // matrix select using an IndexUnaryOp //------------------------------------------- -GB_PUBLIC GrB_Info GrB_Matrix_select_Scalar // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7880,7 +7494,6 @@ GrB_Info GrB_Matrix_select_Scalar // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_BOOL // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7892,7 +7505,6 @@ GrB_Info GrB_Matrix_select_BOOL // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7904,7 +7516,6 @@ GrB_Info GrB_Matrix_select_INT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7916,7 +7527,6 @@ GrB_Info GrB_Matrix_select_INT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7928,7 +7538,6 @@ GrB_Info GrB_Matrix_select_INT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_INT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7940,7 +7549,6 @@ GrB_Info GrB_Matrix_select_INT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT8 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7952,7 +7560,6 @@ GrB_Info GrB_Matrix_select_UINT8 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT16 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7964,7 +7571,6 @@ GrB_Info GrB_Matrix_select_UINT16 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7976,7 +7582,6 @@ GrB_Info GrB_Matrix_select_UINT32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UINT64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -7988,7 +7593,6 @@ GrB_Info GrB_Matrix_select_UINT64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_FP32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8000,7 +7604,6 @@ GrB_Info GrB_Matrix_select_FP32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_FP64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8012,7 +7615,6 @@ GrB_Info GrB_Matrix_select_FP64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_select_FC32 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8024,7 +7626,6 @@ GrB_Info GxB_Matrix_select_FC32 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GxB_Matrix_select_FC64 // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8036,7 +7637,6 @@ GrB_Info GxB_Matrix_select_FC64 // C=accum(C,op(A)) const GrB_Descriptor desc // descriptor for C, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_select_UDT // C=accum(C,op(A)) ( GrB_Matrix C, // input/output matrix for results @@ -8063,14 +7663,14 @@ GrB_Info GrB_Matrix_select_UDT // C=accum(C,op(A)) _Generic \ ( \ (y), \ - GB_CASES (, GrB, Vector_select), \ + GB_CASES (GrB, Vector_select), \ default: GrB_Vector_select_Scalar \ ), \ GrB_Matrix : \ _Generic \ ( \ (y), \ - GB_CASES (, GrB, Matrix_select), \ + GB_CASES (GrB, Matrix_select), \ default: GrB_Matrix_select_Scalar \ ) \ ) \ @@ -8083,7 +7683,6 @@ GrB_Info GrB_Matrix_select_UDT // C=accum(C,op(A)) // GrB_select and with the GrB_IndexUnaryOp operators should be used instead. -GB_PUBLIC GrB_Info GxB_Vector_select // w = accum (w, op(u,k)) ( GrB_Vector w, // input/output vector for results @@ -8095,7 +7694,6 @@ GrB_Info GxB_Vector_select // w = accum (w, op(u,k)) const GrB_Descriptor desc // descriptor for w and mask ) ; -GB_PUBLIC GrB_Info GxB_Matrix_select // C = accum (C, op(A,k)) or op(A',k) ( GrB_Matrix C, // input/output matrix for results @@ -8138,7 +7736,6 @@ GrB_Info GxB_Matrix_select // C = accum (C, op(A,k)) or op(A',k) // LOR, LAND, LXOR, EQ BOOL // BOR, BAND, BXOR, BXNOR UINT* -GB_PUBLIC GrB_Info GrB_Matrix_reduce_Monoid // w = accum (w,reduce(A)) ( GrB_Vector w, // input/output vector for results @@ -8149,7 +7746,6 @@ GrB_Info GrB_Matrix_reduce_Monoid // w = accum (w,reduce(A)) const GrB_Descriptor desc // descriptor for w, mask, and A ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_BinaryOp // w = accum (w,reduce(A)) ( GrB_Vector w, // input/output vector for results @@ -8166,7 +7762,6 @@ GrB_Info GrB_Matrix_reduce_BinaryOp // w = accum (w,reduce(A)) // Reduce entries in a vector to a scalar, c = accum (c, reduce_to_scalar(u)) -GB_PUBLIC GrB_Info GrB_Vector_reduce_BOOL // c = accum (c, reduce_to_scalar (u)) ( bool *c, // result scalar @@ -8176,7 +7771,6 @@ GrB_Info GrB_Vector_reduce_BOOL // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT8 // c = accum (c, reduce_to_scalar (u)) ( int8_t *c, // result scalar @@ -8186,7 +7780,6 @@ GrB_Info GrB_Vector_reduce_INT8 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT8 // c = accum (c, reduce_to_scalar (u)) ( uint8_t *c, // result scalar @@ -8196,7 +7789,6 @@ GrB_Info GrB_Vector_reduce_UINT8 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT16 // c = accum (c, reduce_to_scalar (u)) ( int16_t *c, // result scalar @@ -8206,7 +7798,6 @@ GrB_Info GrB_Vector_reduce_INT16 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT16 // c = accum (c, reduce_to_scalar (u)) ( uint16_t *c, // result scalar @@ -8216,7 +7807,6 @@ GrB_Info GrB_Vector_reduce_UINT16 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT32 // c = accum (c, reduce_to_scalar (u)) ( int32_t *c, // result scalar @@ -8226,7 +7816,6 @@ GrB_Info GrB_Vector_reduce_INT32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT32 // c = accum (c, reduce_to_scalar (u)) ( uint32_t *c, // result scalar @@ -8236,7 +7825,6 @@ GrB_Info GrB_Vector_reduce_UINT32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_INT64 // c = accum (c, reduce_to_scalar (u)) ( int64_t *c, // result scalar @@ -8246,7 +7834,6 @@ GrB_Info GrB_Vector_reduce_INT64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UINT64 // c = accum (c, reduce_to_scalar (u)) ( uint64_t *c, // result scalar @@ -8256,7 +7843,6 @@ GrB_Info GrB_Vector_reduce_UINT64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_FP32 // c = accum (c, reduce_to_scalar (u)) ( float *c, // result scalar @@ -8266,7 +7852,6 @@ GrB_Info GrB_Vector_reduce_FP32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_FP64 // c = accum (c, reduce_to_scalar (u)) ( double *c, // result scalar @@ -8276,7 +7861,6 @@ GrB_Info GrB_Vector_reduce_FP64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_reduce_FC32 // c = accum (c, reduce_to_scalar (u)) ( GxB_FC32_t *c, // result scalar @@ -8286,7 +7870,6 @@ GrB_Info GxB_Vector_reduce_FC32 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_reduce_FC64 // c = accum (c, reduce_to_scalar (u)) ( GxB_FC64_t *c, // result scalar @@ -8296,7 +7879,6 @@ GrB_Info GxB_Vector_reduce_FC64 // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_UDT // c = accum (c, reduce_to_scalar (u)) ( void *c, // result scalar @@ -8306,7 +7888,6 @@ GrB_Info GrB_Vector_reduce_UDT // c = accum (c, reduce_to_scalar (u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(u)) ( GrB_Scalar c, // result scalar @@ -8316,7 +7897,6 @@ GrB_Info GrB_Vector_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(u)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Vector_reduce_BinaryOp_Scalar ( GrB_Scalar c, // result scalar @@ -8332,7 +7912,6 @@ GrB_Info GrB_Vector_reduce_BinaryOp_Scalar // Reduce entries in a matrix to a scalar, c = accum (c, reduce_to_scalar(A)) -GB_PUBLIC GrB_Info GrB_Matrix_reduce_BOOL // c = accum (c, reduce_to_scalar (A)) ( bool *c, // result scalar @@ -8342,7 +7921,6 @@ GrB_Info GrB_Matrix_reduce_BOOL // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT8 // c = accum (c, reduce_to_scalar (A)) ( int8_t *c, // result scalar @@ -8352,7 +7930,6 @@ GrB_Info GrB_Matrix_reduce_INT8 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT8 // c = accum (c, reduce_to_scalar (A)) ( uint8_t *c, // result scalar @@ -8362,7 +7939,6 @@ GrB_Info GrB_Matrix_reduce_UINT8 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT16 // c = accum (c, reduce_to_scalar (A)) ( int16_t *c, // result scalar @@ -8372,7 +7948,6 @@ GrB_Info GrB_Matrix_reduce_INT16 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT16 // c = accum (c, reduce_to_scalar (A)) ( uint16_t *c, // result scalar @@ -8382,7 +7957,6 @@ GrB_Info GrB_Matrix_reduce_UINT16 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT32 // c = accum (c, reduce_to_scalar (A)) ( int32_t *c, // result scalar @@ -8392,7 +7966,6 @@ GrB_Info GrB_Matrix_reduce_INT32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT32 // c = accum (c, reduce_to_scalar (A)) ( uint32_t *c, // result scalar @@ -8402,7 +7975,6 @@ GrB_Info GrB_Matrix_reduce_UINT32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_INT64 // c = accum (c, reduce_to_scalar (A)) ( int64_t *c, // result scalar @@ -8412,7 +7984,6 @@ GrB_Info GrB_Matrix_reduce_INT64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UINT64 // c = accum (c, reduce_to_scalar (A)) ( uint64_t *c, // result scalar @@ -8422,7 +7993,6 @@ GrB_Info GrB_Matrix_reduce_UINT64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_FP32 // c = accum (c, reduce_to_scalar (A)) ( float *c, // result scalar @@ -8432,7 +8002,6 @@ GrB_Info GrB_Matrix_reduce_FP32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_FP64 // c = accum (c, reduce_to_scalar (A)) ( double *c, // result scalar @@ -8442,7 +8011,6 @@ GrB_Info GrB_Matrix_reduce_FP64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_reduce_FC32 // c = accum (c, reduce_to_scalar (A)) ( GxB_FC32_t *c, // result scalar @@ -8452,7 +8020,6 @@ GrB_Info GxB_Matrix_reduce_FC32 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_reduce_FC64 // c = accum (c, reduce_to_scalar (A)) ( GxB_FC64_t *c, // result scalar @@ -8462,7 +8029,6 @@ GrB_Info GxB_Matrix_reduce_FC64 // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_UDT // c = accum (c, reduce_to_scalar (A)) ( void *c, // result scalar @@ -8472,7 +8038,6 @@ GrB_Info GrB_Matrix_reduce_UDT // c = accum (c, reduce_to_scalar (A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(A)) ( GrB_Scalar c, // result scalar @@ -8482,7 +8047,6 @@ GrB_Info GrB_Matrix_reduce_Monoid_Scalar // c = accum(c,reduce_to_scalar(A)) const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar ( GrB_Scalar S, // result scalar @@ -8516,14 +8080,12 @@ GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar _Generic \ ( \ (c), \ - GB_CASES (*, GrB, GB_CONCAT ( kind, _reduce,, )), \ + GB_PCASES (GrB, GB_CONCAT ( kind, _reduce,, )), \ default: \ _Generic \ ( \ (op), \ - const GrB_BinaryOp : \ - GB_CONCAT (GrB,_,kind,_reduce_BinaryOp_Scalar),\ - GrB_BinaryOp : \ + GrB_BinaryOp : \ GB_CONCAT (GrB,_,kind,_reduce_BinaryOp_Scalar),\ default: GB_CONCAT (GrB,_,kind,_reduce_Monoid_Scalar) \ ) \ @@ -8533,13 +8095,9 @@ GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar _Generic \ ( \ (arg4), \ - const GrB_Vector : GB_REDUCE_TO_SCALAR (Vector, arg1, arg3), \ GrB_Vector : GB_REDUCE_TO_SCALAR (Vector, arg1, arg3), \ - const GrB_Matrix : GB_REDUCE_TO_SCALAR (Matrix, arg1, arg3), \ GrB_Matrix : GB_REDUCE_TO_SCALAR (Matrix, arg1, arg3), \ - const GrB_Monoid : GrB_Matrix_reduce_Monoid , \ GrB_Monoid : GrB_Matrix_reduce_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_reduce_BinaryOp \ ) \ (arg1, arg2, arg3, arg4, __VA_ARGS__) @@ -8549,7 +8107,6 @@ GrB_Info GrB_Matrix_reduce_BinaryOp_Scalar // GrB_transpose: matrix transpose //============================================================================== -GB_PUBLIC GrB_Info GrB_transpose // C = accum (C, A') ( GrB_Matrix C, // input/output matrix for results @@ -8564,7 +8121,6 @@ GrB_Info GrB_transpose // C = accum (C, A') //============================================================================== // GxB_kron is historical; use GrB_kronecker instead -GB_PUBLIC GrB_Info GxB_kron // C = accum(C,kron(A,B)) (historical) ( GrB_Matrix C, // input/output matrix for results @@ -8576,7 +8132,6 @@ GrB_Info GxB_kron // C = accum(C,kron(A,B)) (historical) const GrB_Descriptor desc // descriptor for C, Mask, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_kronecker_BinaryOp // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results @@ -8588,7 +8143,6 @@ GrB_Info GrB_Matrix_kronecker_BinaryOp // C = accum (C, kron(A,B)) const GrB_Descriptor desc // descriptor for C, M, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_kronecker_Monoid // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results @@ -8600,7 +8154,6 @@ GrB_Info GrB_Matrix_kronecker_Monoid // C = accum (C, kron(A,B)) const GrB_Descriptor desc // descriptor for C, M, A, and B ) ; -GB_PUBLIC GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) ( GrB_Matrix C, // input/output matrix for results @@ -8617,11 +8170,8 @@ GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) _Generic \ ( \ (op), \ - const GrB_Semiring : GrB_Matrix_kronecker_Semiring , \ GrB_Semiring : GrB_Matrix_kronecker_Semiring , \ - const GrB_Monoid : GrB_Matrix_kronecker_Monoid , \ GrB_Monoid : GrB_Matrix_kronecker_Monoid , \ - const GrB_BinaryOp : GrB_Matrix_kronecker_BinaryOp , \ GrB_BinaryOp : GrB_Matrix_kronecker_BinaryOp \ ) \ (C, Mask, accum, op, A, B, desc) @@ -8632,7 +8182,7 @@ GrB_Info GrB_Matrix_kronecker_Semiring // C = accum (C, kron(A,B)) // GrB_Monoid: built-in monoids //============================================================================== -GB_PUBLIC GrB_Monoid +GB_GLOBAL GrB_Monoid //-------------------------------------------------------------------------- // 10 MIN monoids: (not for complex types) @@ -8909,7 +8459,7 @@ GB_PUBLIC GrB_Monoid // identical, as are FIRSTJ1 and SECONDI1. These semirings still appear as // predefined, for convenience. -GB_PUBLIC GrB_Semiring +GB_GLOBAL GrB_Semiring //------------------------------------------------------------------------------ // 1000 non-Boolean semirings where all types are the same, given by suffix _T @@ -9402,7 +8952,7 @@ GB_PUBLIC GrB_Semiring // GxB_* semirings corresponding to the equivalent GrB_* semiring are // historical. -GB_PUBLIC GrB_Semiring +GB_GLOBAL GrB_Semiring //-------------------------------------------------------------------------- // 20 semirings with PLUS monoids @@ -9576,7 +9126,6 @@ GB_PUBLIC GrB_Semiring // If the dimensions decrease, entries that fall outside the resized matrix or // vector are deleted. -GB_PUBLIC GrB_Info GrB_Matrix_resize // change the size of a matrix ( GrB_Matrix C, // matrix to modify @@ -9584,7 +9133,6 @@ GrB_Info GrB_Matrix_resize // change the size of a matrix GrB_Index ncols_new // new number of columns in matrix ) ; -GB_PUBLIC GrB_Info GrB_Vector_resize // change the size of a vector ( GrB_Vector w, // vector to modify @@ -9592,7 +9140,6 @@ GrB_Info GrB_Vector_resize // change the size of a vector ) ; // GxB_*_resize are identical to the GrB_*resize methods above -GB_PUBLIC GrB_Info GxB_Matrix_resize // change the size of a matrix (historical) ( GrB_Matrix C, // matrix to modify @@ -9600,7 +9147,6 @@ GrB_Info GxB_Matrix_resize // change the size of a matrix (historical) GrB_Index ncols_new // new number of columns in matrix ) ; -GB_PUBLIC GrB_Info GxB_Vector_resize // change the size of a vector (historical) ( GrB_Vector w, // vector to modify @@ -9689,7 +9235,6 @@ typedef enum } GxB_Print_Level ; -GB_PUBLIC GrB_Info GxB_Type_fprint // print and check a GrB_Type ( GrB_Type type, // object to print and check @@ -9698,7 +9243,6 @@ GrB_Info GxB_Type_fprint // print and check a GrB_Type FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_UnaryOp_fprint // print and check a GrB_UnaryOp ( GrB_UnaryOp unaryop, // object to print and check @@ -9707,7 +9251,6 @@ GrB_Info GxB_UnaryOp_fprint // print and check a GrB_UnaryOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_BinaryOp_fprint // print and check a GrB_BinaryOp ( GrB_BinaryOp binaryop, // object to print and check @@ -9716,7 +9259,6 @@ GrB_Info GxB_BinaryOp_fprint // print and check a GrB_BinaryOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_IndexUnaryOp_fprint // print and check a GrB_IndexUnaryOp ( GrB_IndexUnaryOp op, // object to print and check @@ -9725,7 +9267,6 @@ GrB_Info GxB_IndexUnaryOp_fprint // print and check a GrB_IndexUnaryOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_SelectOp_fprint // print and check a GxB_SelectOp ( GxB_SelectOp selectop, // object to print and check @@ -9734,7 +9275,6 @@ GrB_Info GxB_SelectOp_fprint // print and check a GxB_SelectOp FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Monoid_fprint // print and check a GrB_Monoid ( GrB_Monoid monoid, // object to print and check @@ -9743,7 +9283,6 @@ GrB_Info GxB_Monoid_fprint // print and check a GrB_Monoid FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Semiring_fprint // print and check a GrB_Semiring ( GrB_Semiring semiring, // object to print and check @@ -9752,7 +9291,6 @@ GrB_Info GxB_Semiring_fprint // print and check a GrB_Semiring FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Descriptor_fprint // print and check a GrB_Descriptor ( GrB_Descriptor descriptor, // object to print and check @@ -9761,7 +9299,6 @@ GrB_Info GxB_Descriptor_fprint // print and check a GrB_Descriptor FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Matrix_fprint // print and check a GrB_Matrix ( GrB_Matrix A, // object to print and check @@ -9770,7 +9307,6 @@ GrB_Info GxB_Matrix_fprint // print and check a GrB_Matrix FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Vector_fprint // print and check a GrB_Vector ( GrB_Vector v, // object to print and check @@ -9779,7 +9315,6 @@ GrB_Info GxB_Vector_fprint // print and check a GrB_Vector FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GxB_Scalar_fprint // print and check a GrB_Scalar ( GrB_Scalar s, // object to print and check @@ -9793,27 +9328,16 @@ GrB_Info GxB_Scalar_fprint // print and check a GrB_Scalar _Generic \ ( \ (object), \ - const GrB_Type : GxB_Type_fprint , \ GrB_Type : GxB_Type_fprint , \ - const GrB_UnaryOp : GxB_UnaryOp_fprint , \ GrB_UnaryOp : GxB_UnaryOp_fprint , \ - const GrB_BinaryOp : GxB_BinaryOp_fprint , \ GrB_BinaryOp : GxB_BinaryOp_fprint , \ - const GrB_IndexUnaryOp : GxB_IndexUnaryOp_fprint , \ GrB_IndexUnaryOp : GxB_IndexUnaryOp_fprint , \ - const GxB_SelectOp : GxB_SelectOp_fprint , \ GxB_SelectOp : GxB_SelectOp_fprint , \ - const GrB_Monoid : GxB_Monoid_fprint , \ GrB_Monoid : GxB_Monoid_fprint , \ - const GrB_Semiring : GxB_Semiring_fprint , \ GrB_Semiring : GxB_Semiring_fprint , \ - const GrB_Scalar : GxB_Scalar_fprint , \ GrB_Scalar : GxB_Scalar_fprint , \ - const GrB_Vector : GxB_Vector_fprint , \ GrB_Vector : GxB_Vector_fprint , \ - const GrB_Matrix : GxB_Matrix_fprint , \ GrB_Matrix : GxB_Matrix_fprint , \ - const GrB_Descriptor : GxB_Descriptor_fprint , \ GrB_Descriptor : GxB_Descriptor_fprint \ ) \ (object, GB_STR(object), pr, f) @@ -9917,7 +9441,6 @@ GrB_Info GxB_Scalar_fprint // print and check a GrB_Scalar // GxB_Matrix_pack_CSR: pack a CSR matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_CSR // historical: use GxB_Matrix_pack_CSR ( GrB_Matrix *A, // handle of matrix to create @@ -9936,7 +9459,6 @@ GrB_Info GxB_Matrix_import_CSR // historical: use GxB_Matrix_pack_CSR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_CSR // pack a CSR matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -9972,7 +9494,6 @@ GrB_Info GxB_Matrix_pack_CSR // pack a CSR matrix // GxB_Matrix_pack_CSC: pack a CSC matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_CSC // historical: use GxB_Matrix_pack_CSC ( GrB_Matrix *A, // handle of matrix to create @@ -9991,7 +9512,6 @@ GrB_Info GxB_Matrix_import_CSC // historical: use GxB_Matrix_pack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_CSC // pack a CSC matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10027,7 +9547,6 @@ GrB_Info GxB_Matrix_pack_CSC // pack a CSC matrix // GxB_Matrix_pack_HyperCSR: pack a hypersparse CSR matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_HyperCSR // historical: use GxB_Matrix_pack_HyperCSR ( GrB_Matrix *A, // handle of matrix to create @@ -10049,7 +9568,6 @@ GrB_Info GxB_Matrix_import_HyperCSR // historical: use GxB_Matrix_pack_HyperCSR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_HyperCSR // pack a hypersparse CSR matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10095,7 +9613,6 @@ GrB_Info GxB_Matrix_pack_HyperCSR // pack a hypersparse CSR matrix // GxB_Matrix_pack_HyperCSC: pack a hypersparse CSC matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_HyperCSC // historical: use GxB_Matrix_pack_HyperCSC ( GrB_Matrix *A, // handle of matrix to create @@ -10117,7 +9634,6 @@ GrB_Info GxB_Matrix_import_HyperCSC // historical: use GxB_Matrix_pack_HyperCSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_HyperCSC // pack a hypersparse CSC matrix ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10164,7 +9680,6 @@ GrB_Info GxB_Matrix_pack_HyperCSC // pack a hypersparse CSC matrix // GxB_Matrix_pack_BitmapR: pack a bitmap matrix, held by row //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_BitmapR // historical: use GxB_Matrix_pack_BitmapR ( GrB_Matrix *A, // handle of matrix to create @@ -10181,7 +9696,6 @@ GrB_Info GxB_Matrix_import_BitmapR // historical: use GxB_Matrix_pack_BitmapR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_BitmapR // pack a bitmap matrix, held by row ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10209,7 +9723,6 @@ GrB_Info GxB_Matrix_pack_BitmapR // pack a bitmap matrix, held by row // GxB_Matrix_pack_BitmapC: pack a bitmap matrix, held by column //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_BitmapC // historical: use GxB_Matrix_pack_BitmapC ( GrB_Matrix *A, // handle of matrix to create @@ -10226,7 +9739,6 @@ GrB_Info GxB_Matrix_import_BitmapC // historical: use GxB_Matrix_pack_BitmapC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_BitmapC // pack a bitmap matrix, held by column ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10254,7 +9766,6 @@ GrB_Info GxB_Matrix_pack_BitmapC // pack a bitmap matrix, held by column // GxB_Matrix_pack_FullR: pack a full matrix, held by row //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_FullR // historical: use GxB_Matrix_pack_FullR ( GrB_Matrix *A, // handle of matrix to create @@ -10268,7 +9779,6 @@ GrB_Info GxB_Matrix_import_FullR // historical: use GxB_Matrix_pack_FullR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_FullR // pack a full matrix, held by row ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10290,7 +9800,6 @@ GrB_Info GxB_Matrix_pack_FullR // pack a full matrix, held by row // GxB_Matrix_pack_FullC: pack a full matrix, held by column //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Matrix_import_FullC // historical: use GxB_Matrix_pack_FullC ( GrB_Matrix *A, // handle of matrix to create @@ -10304,7 +9813,6 @@ GrB_Info GxB_Matrix_import_FullC // historical: use GxB_Matrix_pack_FullC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_pack_FullC // pack a full matrix, held by column ( GrB_Matrix A, // matrix to create (type, nrows, ncols unchanged) @@ -10326,7 +9834,6 @@ GrB_Info GxB_Matrix_pack_FullC // pack a full matrix, held by column // GxB_Vector_pack_CSC: import/pack a vector in CSC format //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Vector_import_CSC // historical: use GxB_Vector_pack_CSC ( GrB_Vector *v, // handle of vector to create @@ -10343,7 +9850,6 @@ GrB_Info GxB_Vector_import_CSC // historical: use GxB_Vector_pack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_pack_CSC // pack a vector in CSC format ( GrB_Vector v, // vector to create (type and length unchanged) @@ -10366,7 +9872,6 @@ GrB_Info GxB_Vector_pack_CSC // pack a vector in CSC format // GxB_Vector_pack_Bitmap: pack a vector in bitmap format //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Vector_import_Bitmap // historical: GxB_Vector_pack_Bitmap ( GrB_Vector *v, // handle of vector to create @@ -10382,7 +9887,6 @@ GrB_Info GxB_Vector_import_Bitmap // historical: GxB_Vector_pack_Bitmap const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_pack_Bitmap // pack a bitmap vector ( GrB_Vector v, // vector to create (type and length unchanged) @@ -10403,7 +9907,6 @@ GrB_Info GxB_Vector_pack_Bitmap // pack a bitmap vector // GxB_Vector_pack_Full: pack a vector in full format //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GxB_Vector_import_Full // historical: use GxB_Vector_pack_Full ( GrB_Vector *v, // handle of vector to create @@ -10416,7 +9919,6 @@ GrB_Info GxB_Vector_import_Full // historical: use GxB_Vector_pack_Full const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_pack_Full // pack a full vector ( GrB_Vector v, // vector to create (type and length unchanged) @@ -10467,7 +9969,6 @@ GrB_Info GxB_Vector_pack_Full // pack a full vector // If the export/unpack is not successful, the export/unpack functions do not // modify matrix or vector and the user arrays are returned as NULL. -GB_PUBLIC GrB_Info GxB_Matrix_export_CSR // historical: use GxB_Matrix_unpack_CSR ( GrB_Matrix *A, // handle of matrix to export and free @@ -10485,7 +9986,6 @@ GrB_Info GxB_Matrix_export_CSR // historical: use GxB_Matrix_unpack_CSR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_CSR // unpack a CSR matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10500,7 +10000,6 @@ GrB_Info GxB_Matrix_unpack_CSR // unpack a CSR matrix const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_CSC // historical: use GxB_Matrix_unpack_CSC ( GrB_Matrix *A, // handle of matrix to export and free @@ -10518,7 +10017,6 @@ GrB_Info GxB_Matrix_export_CSC // historical: use GxB_Matrix_unpack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_CSC // unpack a CSC matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10533,8 +10031,7 @@ GrB_Info GxB_Matrix_unpack_CSC // unpack a CSC matrix const GrB_Descriptor desc ) ; -GB_PUBLIC -GrB_Info GxB_Matrix_export_HyperCSR // historical: use GxB_Matrix_unpack_HyperCSR +GrB_Info GxB_Matrix_export_HyperCSR //historical: use GxB_Matrix_unpack_HyperCSR ( GrB_Matrix *A, // handle of matrix to export and free GrB_Type *type, // type of matrix exported @@ -10554,7 +10051,6 @@ GrB_Info GxB_Matrix_export_HyperCSR // historical: use GxB_Matrix_unpack_HyperCS const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_HyperCSR // unpack a hypersparse CSR matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10572,8 +10068,7 @@ GrB_Info GxB_Matrix_unpack_HyperCSR // unpack a hypersparse CSR matrix const GrB_Descriptor desc ) ; -GB_PUBLIC -GrB_Info GxB_Matrix_export_HyperCSC // historical: use GxB_Matrix_unpack_HyperCSC +GrB_Info GxB_Matrix_export_HyperCSC //historical: use GxB_Matrix_unpack_HyperCSC ( GrB_Matrix *A, // handle of matrix to export and free GrB_Type *type, // type of matrix exported @@ -10593,7 +10088,6 @@ GrB_Info GxB_Matrix_export_HyperCSC // historical: use GxB_Matrix_unpack_HyperCS const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_HyperCSC // unpack a hypersparse CSC matrix ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10611,7 +10105,6 @@ GrB_Info GxB_Matrix_unpack_HyperCSC // unpack a hypersparse CSC matrix const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_BitmapR // historical: use GxB_Matrix_unpack_BitmapR ( GrB_Matrix *A, // handle of matrix to export and free @@ -10627,7 +10120,6 @@ GrB_Info GxB_Matrix_export_BitmapR // historical: use GxB_Matrix_unpack_BitmapR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_BitmapR // unpack a bitmap matrix, by row ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10640,7 +10132,6 @@ GrB_Info GxB_Matrix_unpack_BitmapR // unpack a bitmap matrix, by row const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_BitmapC // historical: use GxB_Matrix_unpack_BitmapC ( GrB_Matrix *A, // handle of matrix to export and free @@ -10656,7 +10147,6 @@ GrB_Info GxB_Matrix_export_BitmapC // historical: use GxB_Matrix_unpack_BitmapC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_BitmapC // unpack a bitmap matrix, by col ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10669,7 +10159,6 @@ GrB_Info GxB_Matrix_unpack_BitmapC // unpack a bitmap matrix, by col const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FullR // historical: use GxB_Matrix_unpack_FullR ( GrB_Matrix *A, // handle of matrix to export and free @@ -10682,7 +10171,6 @@ GrB_Info GxB_Matrix_export_FullR // historical: use GxB_Matrix_unpack_FullR const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_FullR // unpack a full matrix, by row ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10692,7 +10180,6 @@ GrB_Info GxB_Matrix_unpack_FullR // unpack a full matrix, by row const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FullC // historical: use GxB_Matrix_unpack_FullC ( GrB_Matrix *A, // handle of matrix to export and free @@ -10705,7 +10192,6 @@ GrB_Info GxB_Matrix_export_FullC // historical: use GxB_Matrix_unpack_FullC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_unpack_FullC // unpack a full matrix, by column ( GrB_Matrix A, // matrix to unpack (type, nrows, ncols unchanged) @@ -10715,7 +10201,6 @@ GrB_Info GxB_Matrix_unpack_FullC // unpack a full matrix, by column const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_export_CSC // historical: use GxB_Vector_unpack_CSC ( GrB_Vector *v, // handle of vector to export and free @@ -10731,7 +10216,6 @@ GrB_Info GxB_Vector_export_CSC // historical: use GxB_Vector_unpack_CSC const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_unpack_CSC // unpack a CSC vector ( GrB_Vector v, // vector to unpack (type and length unchanged) @@ -10745,7 +10229,6 @@ GrB_Info GxB_Vector_unpack_CSC // unpack a CSC vector const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_export_Bitmap // historical: use GxB_Vector_unpack_Bitmap ( GrB_Vector *v, // handle of vector to export and free @@ -10760,7 +10243,6 @@ GrB_Info GxB_Vector_export_Bitmap // historical: use GxB_Vector_unpack_Bitmap const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_unpack_Bitmap // unpack a bitmap vector ( GrB_Vector v, // vector to unpack (type and length unchanged) @@ -10773,7 +10255,6 @@ GrB_Info GxB_Vector_unpack_Bitmap // unpack a bitmap vector const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_export_Full // historical: use GxB_Vector_unpack_Full ( GrB_Vector *v, // handle of vector to export and free @@ -10785,7 +10266,6 @@ GrB_Info GxB_Vector_export_Full // historical: use GxB_Vector_unpack_Full const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Vector_unpack_Full // unpack a full vector ( GrB_Vector v, // vector to unpack (type and length unchanged) @@ -10842,7 +10322,6 @@ GrB_Info GxB_Vector_unpack_Full // unpack a full vector // matrix A, and then GrB_Matrix_wait (A) is called, a new hyper_hash matrix is // constructed for A. -GB_PUBLIC GrB_Info GxB_unpack_HyperHash // move A->Y into Y ( GrB_Matrix A, // matrix to modify @@ -10879,7 +10358,6 @@ GrB_Info GxB_unpack_HyperHash // move A->Y into Y // modified after they were exported/unpacked by // GxB_Matrix_(export/unpack)_Hyper(CSR/CSC). -GB_PUBLIC GrB_Info GxB_pack_HyperHash // move Y into A->Y ( GrB_Matrix A, // matrix to modify @@ -10915,7 +10393,6 @@ typedef enum } GrB_Format ; -GB_PUBLIC GrB_Info GrB_Matrix_import_BOOL // import a GrB_BOOL matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10931,7 +10408,6 @@ GrB_Info GrB_Matrix_import_BOOL // import a GrB_BOOL matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT8 // import a GrB_INT8 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10947,7 +10423,6 @@ GrB_Info GrB_Matrix_import_INT8 // import a GrB_INT8 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT16 // import a GrB_INT16 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10963,7 +10438,6 @@ GrB_Info GrB_Matrix_import_INT16 // import a GrB_INT16 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT32 // import a GrB_INT32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10979,7 +10453,6 @@ GrB_Info GrB_Matrix_import_INT32 // import a GrB_INT32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_INT64 // import a GrB_INT64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -10995,7 +10468,6 @@ GrB_Info GrB_Matrix_import_INT64 // import a GrB_INT64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT8 // import a GrB_UINT8 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11011,7 +10483,6 @@ GrB_Info GrB_Matrix_import_UINT8 // import a GrB_UINT8 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT16 // import a GrB_UINT16 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11027,7 +10498,6 @@ GrB_Info GrB_Matrix_import_UINT16 // import a GrB_UINT16 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT32 // import a GrB_UINT32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11043,7 +10513,6 @@ GrB_Info GrB_Matrix_import_UINT32 // import a GrB_UINT32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UINT64 // import a GrB_UINT64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11059,7 +10528,6 @@ GrB_Info GrB_Matrix_import_UINT64 // import a GrB_UINT64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_FP32 // import a GrB_FP32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11075,7 +10543,6 @@ GrB_Info GrB_Matrix_import_FP32 // import a GrB_FP32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_FP64 // import a GrB_FP64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11091,7 +10558,6 @@ GrB_Info GrB_Matrix_import_FP64 // import a GrB_FP64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GxB_Matrix_import_FC32 // import a GxB_FC32 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11107,7 +10573,6 @@ GrB_Info GxB_Matrix_import_FC32 // import a GxB_FC32 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GxB_Matrix_import_FC64 // import a GxB_FC64 matrix ( GrB_Matrix *A, // handle of matrix to create @@ -11123,7 +10588,6 @@ GrB_Info GxB_Matrix_import_FC64 // import a GxB_FC64 matrix GrB_Format format // import format ) ; -GB_PUBLIC GrB_Info GrB_Matrix_import_UDT // import a matrix with a user-defined type ( GrB_Matrix *A, // handle of matrix to create @@ -11144,7 +10608,7 @@ GrB_Info GrB_Matrix_import_UDT // import a matrix with a user-defined type _Generic \ ( \ (Ax), \ - GB_CASES (*, GrB, Matrix_import) \ + GB_PCASES (GrB, Matrix_import) \ ) \ (A, type, nrows, ncols, Ap, Ai, Ax, Ap_len, Ai_len, Ax_len, fmt) #endif @@ -11154,7 +10618,6 @@ GrB_Info GrB_Matrix_import_UDT // import a matrix with a user-defined type // On output, these 3 values are modified to be the # of entries copied // into those 3 arrays. -GB_PUBLIC GrB_Info GrB_Matrix_export_BOOL // export a GrB_BOOL matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11167,7 +10630,6 @@ GrB_Info GrB_Matrix_export_BOOL // export a GrB_BOOL matrix GrB_Matrix A // matrix to export (must be of type GrB_BOOL) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT8 // export a GrB_INT8 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11180,7 +10642,6 @@ GrB_Info GrB_Matrix_export_INT8 // export a GrB_INT8 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT8) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT16 // export a GrB_INT16 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11193,7 +10654,6 @@ GrB_Info GrB_Matrix_export_INT16 // export a GrB_INT16 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT16) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT32 // export a GrB_INT32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11206,7 +10666,6 @@ GrB_Info GrB_Matrix_export_INT32 // export a GrB_INT32 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT32) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_INT64 // export a GrB_INT64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11219,7 +10678,6 @@ GrB_Info GrB_Matrix_export_INT64 // export a GrB_INT64 matrix GrB_Matrix A // matrix to export (must be of type GrB_INT64) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT8 // export a GrB_UINT8 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11232,7 +10690,6 @@ GrB_Info GrB_Matrix_export_UINT8 // export a GrB_UINT8 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT8) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT16 // export a GrB_UINT16 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11245,7 +10702,6 @@ GrB_Info GrB_Matrix_export_UINT16 // export a GrB_UINT16 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT16) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT32 // export a GrB_UINT32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11258,7 +10714,6 @@ GrB_Info GrB_Matrix_export_UINT32 // export a GrB_UINT32 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT32) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UINT64 // export a GrB_UINT64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11271,7 +10726,6 @@ GrB_Info GrB_Matrix_export_UINT64 // export a GrB_UINT64 matrix GrB_Matrix A // matrix to export (must be of type GrB_UINT64) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_FP32 // export a GrB_FP32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11284,7 +10738,6 @@ GrB_Info GrB_Matrix_export_FP32 // export a GrB_FP32 matrix GrB_Matrix A // matrix to export (must be of type GrB_FP32) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_FP64 // export a GrB_FP64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11297,7 +10750,6 @@ GrB_Info GrB_Matrix_export_FP64 // export a GrB_FP64 matrix GrB_Matrix A // matrix to export (must be of type GrB_FP64) ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FC32 // export a GrB_FC32 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11310,7 +10762,6 @@ GrB_Info GxB_Matrix_export_FC32 // export a GrB_FC32 matrix GrB_Matrix A // matrix to export (must be of type GrB_FC32) ) ; -GB_PUBLIC GrB_Info GxB_Matrix_export_FC64 // export a GrB_FC64 matrix ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11323,7 +10774,6 @@ GrB_Info GxB_Matrix_export_FC64 // export a GrB_FC64 matrix GrB_Matrix A // matrix to export (must be of type GrB_FC64) ) ; -GB_PUBLIC GrB_Info GrB_Matrix_export_UDT // export a matrix with a user-defined type ( GrB_Index *Ap, // pointers for CSR, CSC, column indices for COO @@ -11341,12 +10791,11 @@ GrB_Info GrB_Matrix_export_UDT // export a matrix with a user-defined type _Generic \ ( \ (Ax), \ - GB_CASES (*, GrB, Matrix_export) \ + GB_PCASES (GrB, Matrix_export) \ ) \ (Ap, Ai, Ax, Ap_len, Ai_len, Ax_len, fmt, A) #endif -GB_PUBLIC GrB_Info GrB_Matrix_exportSize // determine sizes of user arrays for export ( GrB_Index *Ap_len, // # of entries required for Ap (not # of bytes) @@ -11356,7 +10805,6 @@ GrB_Info GrB_Matrix_exportSize // determine sizes of user arrays for export GrB_Matrix A // matrix to export ) ; -GB_PUBLIC GrB_Info GrB_Matrix_exportHint // suggest the best export format ( GrB_Format *format, // export format @@ -11498,7 +10946,6 @@ GrB_Info GrB_Matrix_exportHint // suggest the best export format // positive but unrecognized, the default is used (GxB_COMPRESSION_ZSTD, // level 1). -GB_PUBLIC GrB_Info GxB_Matrix_serialize // serialize a GrB_Matrix to a blob ( // output: @@ -11507,10 +10954,8 @@ GrB_Info GxB_Matrix_serialize // serialize a GrB_Matrix to a blob // input: GrB_Matrix A, // matrix to serialize const GrB_Descriptor desc // descriptor to select compression method - // and to control # of threads used ) ; -GB_PUBLIC GrB_Info GrB_Matrix_serialize // serialize a GrB_Matrix to a blob ( // output: @@ -11522,7 +10967,6 @@ GrB_Info GrB_Matrix_serialize // serialize a GrB_Matrix to a blob GrB_Matrix A // matrix to serialize ) ; -GB_PUBLIC GrB_Info GxB_Vector_serialize // serialize a GrB_Vector to a blob ( // output: @@ -11531,10 +10975,8 @@ GrB_Info GxB_Vector_serialize // serialize a GrB_Vector to a blob // input: GrB_Vector u, // vector to serialize const GrB_Descriptor desc // descriptor to select compression method - // and to control # of threads used ) ; -GB_PUBLIC GrB_Info GrB_Matrix_serializeSize // estimate the size of a blob ( // output: @@ -11545,10 +10987,8 @@ GrB_Info GrB_Matrix_serializeSize // estimate the size of a blob ) ; // The GrB* and GxB* deserialize methods are nearly identical. The GxB* -// deserialize methods simply add the descriptor, which allows for optional -// control of the # of threads used to deserialize the blob. +// deserialize methods simply add the descriptor. -GB_PUBLIC GrB_Info GxB_Matrix_deserialize // deserialize blob into a GrB_Matrix ( // output: @@ -11560,10 +11000,9 @@ GrB_Info GxB_Matrix_deserialize // deserialize blob into a GrB_Matrix // type of C. const void *blob, // the blob GrB_Index blob_size, // size of the blob - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GrB_Matrix_deserialize // deserialize blob into a GrB_Matrix ( // output: @@ -11577,7 +11016,6 @@ GrB_Info GrB_Matrix_deserialize // deserialize blob into a GrB_Matrix GrB_Index blob_size // size of the blob ) ; -GB_PUBLIC GrB_Info GxB_Vector_deserialize // deserialize blob into a GrB_Vector ( // output: @@ -11589,7 +11027,7 @@ GrB_Info GxB_Vector_deserialize // deserialize blob into a GrB_Vector // type of w. const void *blob, // the blob GrB_Index blob_size, // size of the blob - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; // GxB_deserialize_type_name extracts the type_name of the GrB_Type of the @@ -11600,7 +11038,6 @@ GrB_Info GxB_Vector_deserialize // deserialize blob into a GrB_Vector // holds a matrix of a built-in type, the name is returned as "bool" for // GrB_BOOL, "uint8_t" for GrB_UINT8, "float complex" for GxB_FC32, etc. // See GxB_Type_name to convert this name into a GrB_Type. -GB_PUBLIC GrB_Info GxB_deserialize_type_name // return the type name of a blob ( // output: @@ -11615,7 +11052,6 @@ GrB_Info GxB_deserialize_type_name // return the type name of a blob // GxB_Vector_sort and GxB_Matrix_sort: sort a matrix or vector //============================================================================== -GB_PUBLIC GrB_Info GxB_Vector_sort ( // output: @@ -11627,7 +11063,6 @@ GrB_Info GxB_Vector_sort const GrB_Descriptor desc ) ; -GB_PUBLIC GrB_Info GxB_Matrix_sort ( // output: @@ -11675,7 +11110,6 @@ GrB_Info GxB_Matrix_sort // The format of the input matrix (by row or by column) is unchanged; this // format need not match the by_col input parameter. -GB_PUBLIC GrB_Info GxB_Matrix_reshape // reshape a GrB_Matrix in place ( // input/output: @@ -11684,7 +11118,7 @@ GrB_Info GxB_Matrix_reshape // reshape a GrB_Matrix in place bool by_col, // true if reshape by column, false if by row GrB_Index nrows_new, // new number of rows of C GrB_Index ncols_new, // new number of columns of C - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; // GxB_Matrix_reshapeDup reshapes a matrix into another matrix. @@ -11695,7 +11129,6 @@ GrB_Info GxB_Matrix_reshape // reshape a GrB_Matrix in place // determines the format of the output matrix C, which need not match the // by_col input parameter. -GB_PUBLIC GrB_Info GxB_Matrix_reshapeDup // reshape a GrB_Matrix into another GrB_Matrix ( // output: @@ -11705,7 +11138,7 @@ GrB_Info GxB_Matrix_reshapeDup // reshape a GrB_Matrix into another GrB_Matrix bool by_col, // true if reshape by column, false if by row GrB_Index nrows_new, // number of rows of C GrB_Index ncols_new, // number of columns of C - const GrB_Descriptor desc // to control # of threads used + const GrB_Descriptor desc ) ; //============================================================================== @@ -11826,10 +11259,10 @@ struct GB_Iterator_opaque typedef struct GB_Iterator_opaque *GxB_Iterator ; // GxB_Iterator_new: create a new iterator, not attached to any matrix/vector -GB_PUBLIC GrB_Info GxB_Iterator_new (GxB_Iterator *iterator) ; +GrB_Info GxB_Iterator_new (GxB_Iterator *iterator) ; // GxB_Iterator_free: free an iterator -GB_PUBLIC GrB_Info GxB_Iterator_free (GxB_Iterator *iterator) ; +GrB_Info GxB_Iterator_free (GxB_Iterator *iterator) ; //============================================================================== // GB_Iterator_*: implements user-callable GxB_*Iterator_* methods @@ -11842,7 +11275,7 @@ GB_PUBLIC GrB_Info GxB_Iterator_free (GxB_Iterator *iterator) ; // GB_Iterator_attach: attach a row/col/entry iterator to a matrix //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Iterator_attach +GrB_Info GB_Iterator_attach ( GxB_Iterator iterator, // iterator to attach to the matrix A GrB_Matrix A, // matrix to attach @@ -11854,7 +11287,7 @@ GB_PUBLIC GrB_Info GB_Iterator_attach // GB_Iterator_rc_seek: seek a row/col iterator to a particular vector //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Iterator_rc_seek +GrB_Info GB_Iterator_rc_seek ( GxB_Iterator iterator, GrB_Index j, @@ -11865,7 +11298,7 @@ GB_PUBLIC GrB_Info GB_Iterator_rc_seek // GB_Iterator_rc_bitmap_next: move a row/col iterator to next entry in bitmap //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Iterator_rc_bitmap_next (GxB_Iterator iterator) ; +GrB_Info GB_Iterator_rc_bitmap_next (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ // GB_Iterator_rc_knext: move a row/col iterator to the next vector @@ -12016,7 +11449,6 @@ GB_PUBLIC GrB_Info GB_Iterator_rc_bitmap_next (GxB_Iterator iterator) ; // If successful, the row iterator is attached to the matrix, but not to any // specific row. Use GxB_rowIterator_*seek* to move the iterator to a row. -GB_PUBLIC GrB_Info GxB_rowIterator_attach ( GxB_Iterator iterator, @@ -12046,7 +11478,6 @@ GrB_Info GxB_rowIterator_attach // kount == m. If A is hypersparse, kount is the # of vectors held in the data // structure for the matrix, some of which may be empty, and kount <= m. -GB_PUBLIC GrB_Index GxB_rowIterator_kount (GxB_Iterator iterator) ; #define GxB_rowIterator_kount(iterator) \ @@ -12081,7 +11512,6 @@ GrB_Index GxB_rowIterator_kount (GxB_Iterator iterator) ; // the first entry in A(row,:), and GxB_Iterator_get* can // return its value. -GB_PUBLIC GrB_Info GxB_rowIterator_seekRow (GxB_Iterator iterator, GrB_Index row) ; #define GxB_rowIterator_seekRow(iterator, row) \ @@ -12101,7 +11531,6 @@ GrB_Info GxB_rowIterator_seekRow (GxB_Iterator iterator, GrB_Index row) ; // More precisely, k is in the range 0 to kount-1, where kount is the value // returned by GxB_rowIterator_kount. -GB_PUBLIC GrB_Info GxB_rowIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; #define GxB_rowIterator_kseek(iterator, k) \ @@ -12125,7 +11554,6 @@ GrB_Info GxB_rowIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; // The method is always successful, and the return conditions are identical to // the return conditions of GxB_rowIterator_seekRow. -GB_PUBLIC GrB_Info GxB_rowIterator_nextRow (GxB_Iterator iterator) ; #define GxB_rowIterator_nextRow(iterator) \ @@ -12148,7 +11576,6 @@ GrB_Info GxB_rowIterator_nextRow (GxB_Iterator iterator) ; // GrB_SUCCESS: If the row iterator has been moved to the next entry in // A(row,:). -GB_PUBLIC GrB_Info GxB_rowIterator_nextCol (GxB_Iterator iterator) ; #define GxB_rowIterator_nextCol(iterator) \ @@ -12169,7 +11596,6 @@ GrB_Info GxB_rowIterator_nextCol (GxB_Iterator iterator) ; // GxB_rowIterator_*seek* has not been called, but this does not mean the // iterator is positioned at row zero. -GB_PUBLIC GrB_Index GxB_rowIterator_getRowIndex (GxB_Iterator iterator) ; #define GxB_rowIterator_getRowIndex(iterator) \ @@ -12187,7 +11613,6 @@ GrB_Index GxB_rowIterator_getRowIndex (GxB_Iterator iterator) ; // GxB_rowIterator_*seek* or GxB_rowIterator_*next*, must have returned // GrB_SUCCESS. Results are undefined if this condition is not met. -GB_PUBLIC GrB_Index GxB_rowIterator_getColIndex (GxB_Iterator iterator) ; #define GxB_rowIterator_getColIndex(iterator) \ @@ -12211,7 +11636,6 @@ GrB_Index GxB_rowIterator_getColIndex (GxB_Iterator iterator) ; #undef GxB_colIterator_getRowIndex // GxB_colIterator_attach: attach a column iterator to a matrix -GB_PUBLIC GrB_Info GxB_colIterator_attach ( GxB_Iterator iterator, @@ -12224,7 +11648,6 @@ GrB_Info GxB_colIterator_attach ) // GxB_colIterator_kount: return # of nonempty columns of the matrix -GB_PUBLIC GrB_Index GxB_colIterator_kount (GxB_Iterator iterator) ; #define GxB_colIterator_kount(iterator) \ ( \ @@ -12232,7 +11655,6 @@ GrB_Index GxB_colIterator_kount (GxB_Iterator iterator) ; ) // GxB_colIterator_seekCol: move a column iterator to A(:,col) -GB_PUBLIC GrB_Info GxB_colIterator_seekCol (GxB_Iterator iterator, GrB_Index col) ; #define GxB_colIterator_seekCol(iterator, col) \ ( \ @@ -12240,7 +11662,6 @@ GrB_Info GxB_colIterator_seekCol (GxB_Iterator iterator, GrB_Index col) ; ) // GxB_colIterator_kseek: move a column iterator to kth non-empty column of A -GB_PUBLIC GrB_Info GxB_colIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; #define GxB_colIterator_kseek(iterator, k) \ ( \ @@ -12248,7 +11669,6 @@ GrB_Info GxB_colIterator_kseek (GxB_Iterator iterator, GrB_Index k) ; ) // GxB_colIterator_nextCol: move a column iterator to first entry of next column -GB_PUBLIC GrB_Info GxB_colIterator_nextCol (GxB_Iterator iterator) ; #define GxB_colIterator_nextCol(iterator) \ ( \ @@ -12256,7 +11676,6 @@ GrB_Info GxB_colIterator_nextCol (GxB_Iterator iterator) ; ) // GxB_colIterator_nextRow: move a column iterator to next entry in column -GB_PUBLIC GrB_Info GxB_colIterator_nextRow (GxB_Iterator iterator) ; #define GxB_colIterator_nextRow(iterator) \ ( \ @@ -12264,7 +11683,6 @@ GrB_Info GxB_colIterator_nextRow (GxB_Iterator iterator) ; ) // GxB_colIterator_getColIndex: return the column index of current entry -GB_PUBLIC GrB_Index GxB_colIterator_getColIndex (GxB_Iterator iterator) ; #define GxB_colIterator_getColIndex(iterator) \ ( \ @@ -12272,7 +11690,6 @@ GrB_Index GxB_colIterator_getColIndex (GxB_Iterator iterator) ; ) // GxB_colIterator_getRowIndex: return the row index of current entry -GB_PUBLIC GrB_Index GxB_colIterator_getRowIndex (GxB_Iterator iterator) ; #define GxB_colIterator_getRowIndex(iterator) \ ( \ @@ -12328,7 +11745,6 @@ GrB_Index GxB_colIterator_getRowIndex (GxB_Iterator iterator) ; // specific entry. Use GxB_Matrix_Iterator_*seek* to move the iterator to a // particular entry. -GB_PUBLIC GrB_Info GxB_Matrix_Iterator_attach ( GxB_Iterator iterator, @@ -12349,7 +11765,6 @@ GrB_Info GxB_Matrix_Iterator_attach // to nvals(A). For an m-by-n bitmap matrix, pmax=m*n, or pmax=0 if the // matrix has no entries. -GB_PUBLIC GrB_Index GxB_Matrix_Iterator_getpmax (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ @@ -12367,7 +11782,6 @@ GrB_Index GxB_Matrix_Iterator_getpmax (GxB_Iterator iterator) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // matrix, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GxB_Matrix_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; //------------------------------------------------------------------------------ @@ -12383,7 +11797,6 @@ GrB_Info GxB_Matrix_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // matrix, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GxB_Matrix_Iterator_next (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ @@ -12396,7 +11809,6 @@ GrB_Info GxB_Matrix_Iterator_next (GxB_Iterator iterator) ; // GxB_Matrix_Iterator_next. Results are undefined if these conditions are not // met. -GB_PUBLIC GrB_Index GxB_Matrix_Iterator_getp (GxB_Iterator iterator) ; //------------------------------------------------------------------------------ @@ -12409,7 +11821,6 @@ GrB_Index GxB_Matrix_Iterator_getp (GxB_Iterator iterator) ; // GxB_Matrix_Iterator_next, with a return value of GrB_SUCCESS. Results are // undefined if these conditions are not met. -GB_PUBLIC void GxB_Matrix_Iterator_getIndex ( GxB_Iterator iterator, @@ -12471,7 +11882,7 @@ single thread iteration of a whole vector, one entry at at time // specific entry. Use GxB_Vector_Iterator_seek to move the iterator to a // particular entry. -GB_PUBLIC GrB_Info GxB_Vector_Iterator_attach +GrB_Info GxB_Vector_Iterator_attach ( GxB_Iterator iterator, GrB_Vector v, @@ -12490,7 +11901,6 @@ GB_PUBLIC GrB_Info GxB_Vector_Iterator_attach // pmax >= nvals(v). For sparse and full vectors, pmax is equal to nvals(v). // For a size-m bitmap vector, pmax=m, or pmax=0 if the vector has no entries. -GB_PUBLIC GrB_Index GxB_Vector_Iterator_getpmax (GxB_Iterator iterator) ; #define GxB_Vector_Iterator_getpmax(iterator) \ @@ -12513,11 +11923,9 @@ GrB_Index GxB_Vector_Iterator_getpmax (GxB_Iterator iterator) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // vector, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GB_Vector_Iterator_bitmap_seek (GxB_Iterator iterator, GrB_Index unused) ; // unused parameter to be removed in v8.x -GB_PUBLIC GrB_Info GxB_Vector_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; #define GB_Vector_Iterator_seek(iterator, q) \ @@ -12561,7 +11969,6 @@ GrB_Info GxB_Vector_Iterator_seek (GxB_Iterator iterator, GrB_Index p) ; // Returns GrB_SUCCESS if the iterator is at an entry that exists in the // vector, or GxB_EXHAUSTED if the iterator is exhausted. -GB_PUBLIC GrB_Info GxB_Vector_Iterator_next (GxB_Iterator iterator) ; #define GB_Vector_Iterator_next(iterator) \ @@ -12603,7 +12010,6 @@ GrB_Info GxB_Vector_Iterator_next (GxB_Iterator iterator) ; // GxB_Vector_Iterator_next. Results are undefined if these conditions are not // met. -GB_PUBLIC GrB_Index GxB_Vector_Iterator_getp (GxB_Iterator iterator) ; #define GxB_Vector_Iterator_getp(iterator) \ @@ -12621,7 +12027,6 @@ GrB_Index GxB_Vector_Iterator_getp (GxB_Iterator iterator) ; // GxB_Vector_Iterator_next, with a return value of GrB_SUCCESS. Results are // undefined if these conditions are not met. -GB_PUBLIC GrB_Index GxB_Vector_Iterator_getIndex (GxB_Iterator iterator) ; #define GxB_Vector_Iterator_getIndex(iterator) \ @@ -12656,20 +12061,20 @@ GrB_Index GxB_Vector_Iterator_getIndex (GxB_Iterator iterator) ; #undef GxB_Iterator_get_FC64 #undef GxB_Iterator_get_UDT -GB_PUBLIC bool GxB_Iterator_get_BOOL (GxB_Iterator iterator) ; -GB_PUBLIC int8_t GxB_Iterator_get_INT8 (GxB_Iterator iterator) ; -GB_PUBLIC int16_t GxB_Iterator_get_INT16 (GxB_Iterator iterator) ; -GB_PUBLIC int32_t GxB_Iterator_get_INT32 (GxB_Iterator iterator) ; -GB_PUBLIC int64_t GxB_Iterator_get_INT64 (GxB_Iterator iterator) ; -GB_PUBLIC uint8_t GxB_Iterator_get_UINT8 (GxB_Iterator iterator) ; -GB_PUBLIC uint16_t GxB_Iterator_get_UINT16 (GxB_Iterator iterator) ; -GB_PUBLIC uint32_t GxB_Iterator_get_UINT32 (GxB_Iterator iterator) ; -GB_PUBLIC uint64_t GxB_Iterator_get_UINT64 (GxB_Iterator iterator) ; -GB_PUBLIC float GxB_Iterator_get_FP32 (GxB_Iterator iterator) ; -GB_PUBLIC double GxB_Iterator_get_FP64 (GxB_Iterator iterator) ; -GB_PUBLIC GxB_FC32_t GxB_Iterator_get_FC32 (GxB_Iterator iterator) ; -GB_PUBLIC GxB_FC64_t GxB_Iterator_get_FC64 (GxB_Iterator iterator) ; -GB_PUBLIC void GxB_Iterator_get_UDT (GxB_Iterator iterator, +bool GxB_Iterator_get_BOOL (GxB_Iterator iterator) ; +int8_t GxB_Iterator_get_INT8 (GxB_Iterator iterator) ; +int16_t GxB_Iterator_get_INT16 (GxB_Iterator iterator) ; +int32_t GxB_Iterator_get_INT32 (GxB_Iterator iterator) ; +int64_t GxB_Iterator_get_INT64 (GxB_Iterator iterator) ; +uint8_t GxB_Iterator_get_UINT8 (GxB_Iterator iterator) ; +uint16_t GxB_Iterator_get_UINT16 (GxB_Iterator iterator) ; +uint32_t GxB_Iterator_get_UINT32 (GxB_Iterator iterator) ; +uint64_t GxB_Iterator_get_UINT64 (GxB_Iterator iterator) ; +float GxB_Iterator_get_FP32 (GxB_Iterator iterator) ; +double GxB_Iterator_get_FP64 (GxB_Iterator iterator) ; +GxB_FC32_t GxB_Iterator_get_FC32 (GxB_Iterator iterator) ; +GxB_FC64_t GxB_Iterator_get_FC64 (GxB_Iterator iterator) ; +void GxB_Iterator_get_UDT (GxB_Iterator iterator, void *value) ; #define GB_Iterator_get(iterator, type) \ diff --git a/deps/GraphBLAS/Makefile b/deps/GraphBLAS/Makefile index 09fef58885..34299e6822 100644 --- a/deps/GraphBLAS/Makefile +++ b/deps/GraphBLAS/Makefile @@ -26,33 +26,37 @@ JOBS ?= 8 default: library -# just build the dynamic library, but not the demos +# default is to install only in /usr/local library: - ( cd build && cmake $(CMAKE_OPTIONS) .. && $(MAKE) --jobs=$(JOBS) ) - -# enable CUDA (NOTE: not ready for production use) -cuda: - ( cd build && cmake $(CMAKE_OPTIONS) -DENABLE_CUDA=1 .. && $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DSUITESPARSE_LOCAL=1 .. && $(MAKE) --jobs=${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + +# install only in /usr/local (default) +global: + ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) + +# enable CUDA (NOTE: not ready for production use) +cuda: + ( cd build && cmake $(CMAKE_OPTIONS) -DENABLE_CUDA=1 .. && cmake --build . -j$(JOBS) ) # compile with -g debug: - ( cd build && cmake -DCMAKE_BUILD_TYPE=Debug $(CMAKE_OPTIONS) .. && $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake -DCMAKE_BUILD_TYPE=Debug $(CMAKE_OPTIONS) .. && cmake --build . -j$(JOBS) ) # build the dynamic library and the demos all: - ( cd build && cmake $(CMAKE_OPTIONS) -DDEMO=1 .. && $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake $(CMAKE_OPTIONS) -DDEMO=1 .. && cmake --build . -j$(JOBS) ) # run the demos -demo: all +demos: all ( cd Demo && ./demo ) # just do 'make' in build; do not rerun the cmake script remake: - ( cd build && $(MAKE) --jobs=$(JOBS) ) + ( cd build && cmake --build . -j$(JOBS) ) # just run cmake; do not compile setup: @@ -60,15 +64,12 @@ setup: # build both the static and dynamic libraries; do not run the demo static: - ( cd build && cmake $(CMAKE_OPTIONS) -DBUILD_GRB_STATIC_LIBRARY=1 .. && $(MAKE) --jobs=$(JOBS) ) - -static_only: - ( cd build && cmake $(CMAKE_OPTIONS) -DBUILD_GRB_STATIC_LIBRARY=1 .. && $(MAKE) --jobs=$(JOBS) graphblas_static ) + ( cd build && cmake $(CMAKE_OPTIONS) -DBUILD_GRB_STATIC_LIBRARY=1 .. && cmake --build . -j$(JOBS) ) # installs GraphBLAS to the install location defined by cmake, usually # /usr/local/lib and /usr/local/include install: - ( cd build && $(MAKE) install ) + ( cd build && cmake --install . ) # create the Doc/GraphBLAS_UserGuide.pdf docs: @@ -76,7 +77,7 @@ docs: # compile the CUDA kernels gpu: - ( cd CUDA && $(MAKE) ) + ( cd CUDA && cmake --build . -j${JOBS} ) # remove any installed libraries and #include files uninstall: diff --git a/deps/GraphBLAS/README.md b/deps/GraphBLAS/README.md index bfbb2c7873..006efe59cc 100644 --- a/deps/GraphBLAS/README.md +++ b/deps/GraphBLAS/README.md @@ -4,7 +4,7 @@ SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. SPDX-License-Identifier: Apache-2.0 -VERSION 7.3.0, Oct 14, 2022 +VERSION 7.4.4, Mar 25, 2023 SuiteSparse:GraphBLAS is a complete implementation of the GraphBLAS standard, which defines a set of sparse matrix operations on an extended algebra of @@ -27,6 +27,8 @@ See the user guide in `Doc/GraphBLAS_UserGuide.pdf` for documentation on the SuiteSparse implementation of GraphBLAS, and how to use it in your applications. +Note: memory pool has been disabled, to enable compile with _MEMPOOL defined + See http://graphblas.org for more information on GraphBLAS, including the GraphBLAS C API. See https://github.com/GraphBLAS/GraphBLAS-Pointers for additional resources on GraphBLAS. @@ -53,7 +55,7 @@ To remove all compiled files: To compile and run the demos: - make demo + make demos See the GraphBLAS/ subfolder for the Octave/MATLAB interface, which contains a README.md file with further details. diff --git a/deps/GraphBLAS/Source/GB_AxB_dot2.c b/deps/GraphBLAS/Source/GB_AxB_dot2.c index 13591410e5..02dee91e07 100644 --- a/deps/GraphBLAS/Source/GB_AxB_dot2.c +++ b/deps/GraphBLAS/Source/GB_AxB_dot2.c @@ -41,7 +41,6 @@ #include "GB_AxB__include2.h" #endif -GB_PUBLIC GrB_Info GB_AxB_dot2 // C=A'*B or C<#M>=A'*B, dot product method ( GrB_Matrix C, // output matrix, static header diff --git a/deps/GraphBLAS/Source/GB_AxB_dot3.c b/deps/GraphBLAS/Source/GB_AxB_dot3.c index 3c52e234c9..881137070e 100644 --- a/deps/GraphBLAS/Source/GB_AxB_dot3.c +++ b/deps/GraphBLAS/Source/GB_AxB_dot3.c @@ -31,7 +31,6 @@ GB_phybix_free (C) ; \ } -GB_PUBLIC GrB_Info GB_AxB_dot3 // C = A'*B using dot product method ( GrB_Matrix C, // output matrix, static header diff --git a/deps/GraphBLAS/Source/GB_AxB_meta.c b/deps/GraphBLAS/Source/GB_AxB_meta.c index d167edcbb8..ce11568019 100644 --- a/deps/GraphBLAS/Source/GB_AxB_meta.c +++ b/deps/GraphBLAS/Source/GB_AxB_meta.c @@ -38,7 +38,6 @@ #include "GB_mxm.h" #include "GB_transpose.h" -GB_PUBLIC GrB_Info GB_AxB_meta // C=A*B meta algorithm ( GrB_Matrix C, // output, static header (if not in-place) diff --git a/deps/GraphBLAS/Source/GB_AxB_saxpy3.c b/deps/GraphBLAS/Source/GB_AxB_saxpy3.c index 1c2f7244dc..d1c2b6a806 100644 --- a/deps/GraphBLAS/Source/GB_AxB_saxpy3.c +++ b/deps/GraphBLAS/Source/GB_AxB_saxpy3.c @@ -300,6 +300,7 @@ GrB_Info GB_AxB_saxpy3 // C = A*B using Gustavson+Hash // the general case. This may select a single task for a single thread // anyway, but this decision would be based on the analysis. info = GB_AxB_saxpy3_slice_balanced (C, M, Mask_comp, A, B, AxB_method, + builtin_semiring, &SaxpyTasks, &SaxpyTasks_size, &apply_mask, &M_in_place, &ntasks, &nfine, &nthreads, Context) ; } diff --git a/deps/GraphBLAS/Source/GB_AxB_saxpy3.h b/deps/GraphBLAS/Source/GB_AxB_saxpy3.h index 429eb9fb24..5285ff777b 100644 --- a/deps/GraphBLAS/Source/GB_AxB_saxpy3.h +++ b/deps/GraphBLAS/Source/GB_AxB_saxpy3.h @@ -78,7 +78,6 @@ GB_saxpy3task_struct ; // GB_AxB_saxpy3_flopcount: compute flops for GB_AxB_saxpy3 //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_AxB_saxpy3_flopcount ( int64_t *Mwork, // amount of work to handle the mask M @@ -117,6 +116,7 @@ GrB_Info GB_AxB_saxpy3_slice_balanced const GrB_Matrix A, // input matrix A const GrB_Matrix B, // input matrix B GrB_Desc_Value AxB_method, // Default, Gustavson, or Hash + bool builtin_semiring, // if true, semiring is builtin // outputs GB_saxpy3task_struct **SaxpyTasks_handle, size_t *SaxpyTasks_size_handle, diff --git a/deps/GraphBLAS/Source/GB_AxB_saxpy3_flopcount.c b/deps/GraphBLAS/Source/GB_AxB_saxpy3_flopcount.c index 6f33f920f5..e731c5afc7 100644 --- a/deps/GraphBLAS/Source/GB_AxB_saxpy3_flopcount.c +++ b/deps/GraphBLAS/Source/GB_AxB_saxpy3_flopcount.c @@ -76,7 +76,6 @@ GB_WERK_POP (B_ek_slicing, int64_t) ; \ } -GB_PUBLIC GrB_Info GB_AxB_saxpy3_flopcount ( int64_t *Mwork, // amount of work to handle the mask M diff --git a/deps/GraphBLAS/Source/GB_AxB_saxpy3_slice_balanced.c b/deps/GraphBLAS/Source/GB_AxB_saxpy3_slice_balanced.c index eb7f21e0f2..7814850eca 100644 --- a/deps/GraphBLAS/Source/GB_AxB_saxpy3_slice_balanced.c +++ b/deps/GraphBLAS/Source/GB_AxB_saxpy3_slice_balanced.c @@ -196,6 +196,7 @@ GrB_Info GB_AxB_saxpy3_slice_balanced const GrB_Matrix A, // input matrix A const GrB_Matrix B, // input matrix B GrB_Desc_Value AxB_method, // Default, Gustavson, or Hash + bool builtin_semiring, // if true, semiring is builtin // outputs GB_saxpy3task_struct **SaxpyTasks_handle, size_t *SaxpyTasks_size_handle, @@ -240,7 +241,12 @@ GrB_Info GB_AxB_saxpy3_slice_balanced //-------------------------------------------------------------------------- GB_GET_NTHREADS_MAX (nthreads_max, chunk, Context) ; - chunk = chunk * 8 ; + bool bitmap_or_full = (GB_IS_FULL (A) || GB_IS_BITMAP (A) + || GB_IS_FULL (B) || GB_IS_BITMAP (B)) ; + if (builtin_semiring && bitmap_or_full) + { + chunk = chunk * 8 ; + } //-------------------------------------------------------------------------- // define result and workspace @@ -449,7 +455,17 @@ GrB_Info GB_AxB_saxpy3_slice_balanced double target_fine_size = target_task_size / GB_FINE_WORK ; target_fine_size = GB_IMAX (target_fine_size, chunk) ; double very_costly = GB_Global_hack_get (0) ; // modified for testing - if (very_costly <= GxB_DEFAULT) very_costly = 8 ; // default is 8 + if (very_costly <= GxB_DEFAULT) + { + if (bitmap_or_full) + { + very_costly = 8 ; // default is 8 if A and/or B are full/bitmap + } + else + { + very_costly = 2 ; // default is 2 otherwise + } + } //-------------------------------------------------------------------------- // determine # of parallel tasks diff --git a/deps/GraphBLAS/Source/GB_BinaryOp_check.c b/deps/GraphBLAS/Source/GB_BinaryOp_check.c index 3fcabf6040..a854373d32 100644 --- a/deps/GraphBLAS/Source/GB_BinaryOp_check.c +++ b/deps/GraphBLAS/Source/GB_BinaryOp_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_BinaryOp_check // check a GraphBLAS binary operator ( const GrB_BinaryOp op, // GraphBLAS operator to print and check diff --git a/deps/GraphBLAS/Source/GB_Descriptor_check.c b/deps/GraphBLAS/Source/GB_Descriptor_check.c index 9a96042566..90f981ffe7 100644 --- a/deps/GraphBLAS/Source/GB_Descriptor_check.c +++ b/deps/GraphBLAS/Source/GB_Descriptor_check.c @@ -92,7 +92,6 @@ static GrB_Info GB_dc // GB_Descriptor_check //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_Descriptor_check // check a GraphBLAS descriptor ( const GrB_Descriptor D, // GraphBLAS descriptor to print and check diff --git a/deps/GraphBLAS/Source/GB_Descriptor_get.c b/deps/GraphBLAS/Source/GB_Descriptor_get.c index dd2b4013b4..b77b9160d6 100644 --- a/deps/GraphBLAS/Source/GB_Descriptor_get.c +++ b/deps/GraphBLAS/Source/GB_Descriptor_get.c @@ -76,7 +76,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_Descriptor_get // get the contents of a descriptor ( const GrB_Descriptor desc, // descriptor to query, may be NULL diff --git a/deps/GraphBLAS/Source/GB_Descriptor_get.h b/deps/GraphBLAS/Source/GB_Descriptor_get.h index f6f772c10d..7830f32d4f 100644 --- a/deps/GraphBLAS/Source/GB_Descriptor_get.h +++ b/deps/GraphBLAS/Source/GB_Descriptor_get.h @@ -10,7 +10,6 @@ #ifndef GB_DESCRIPTOR_GET_H #define GB_DESCRIPTOR_GET_H -GB_PUBLIC GrB_Info GB_Descriptor_get // get the contents of a descriptor ( const GrB_Descriptor desc, // descriptor to query, may be NULL diff --git a/deps/GraphBLAS/Source/GB_Global.c b/deps/GraphBLAS/Source/GB_Global.c index 5661e2b9e1..b207683d0c 100644 --- a/deps/GraphBLAS/Source/GB_Global.c +++ b/deps/GraphBLAS/Source/GB_Global.c @@ -158,9 +158,7 @@ typedef struct } GB_Global_struct ; -GB_PUBLIC GB_Global_struct GB_Global ; - -GB_Global_struct GB_Global = +static GB_Global_struct GB_Global = { // GraphBLAS mode @@ -372,13 +370,11 @@ GrB_Mode GB_Global_mode_get (void) // GrB_init_called //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_GrB_init_called_set (bool GrB_init_called) { GB_Global.GrB_init_called = GrB_init_called ; } -GB_PUBLIC bool GB_Global_GrB_init_called_get (void) { return (GB_Global.GrB_init_called) ; @@ -393,7 +389,6 @@ bool GB_Global_GrB_init_called_get (void) // Once these two flags are set, they are saved in the GB_Global struct, and // can then be queried later by GB_Global_cpu_features_avx*. -GB_PUBLIC void GB_Global_cpu_features_query (void) { #if GBX86 @@ -453,13 +448,11 @@ void GB_Global_cpu_features_query (void) #endif } -GB_PUBLIC bool GB_Global_cpu_features_avx2 (void) { return (GB_Global.cpu_features_avx2) ; } -GB_PUBLIC bool GB_Global_cpu_features_avx512f (void) { return (GB_Global.cpu_features_avx512f) ; @@ -469,13 +462,11 @@ bool GB_Global_cpu_features_avx512f (void) // nthreads_max //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_nthreads_max_set (int nthreads_max) { GB_Global.nthreads_max = GB_IMAX (nthreads_max, 1) ; } -GB_PUBLIC int GB_Global_nthreads_max_get (void) { return (GB_Global.nthreads_max) ; @@ -485,7 +476,6 @@ int GB_Global_nthreads_max_get (void) // OpenMP max_threads //------------------------------------------------------------------------------ -GB_PUBLIC int GB_Global_omp_get_max_threads (void) { return (GB_OPENMP_MAX_THREADS) ; @@ -495,14 +485,12 @@ int GB_Global_omp_get_max_threads (void) // chunk //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_chunk_set (double chunk) { if (chunk <= GxB_DEFAULT) chunk = GB_CHUNK_DEFAULT ; GB_Global.chunk = fmax (chunk, 1) ; } -GB_PUBLIC double GB_Global_chunk_get (void) { return (GB_Global.chunk) ; @@ -512,13 +500,11 @@ double GB_Global_chunk_get (void) // hyper_switch //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_hyper_switch_set (float hyper_switch) { GB_Global.hyper_switch = hyper_switch ; } -GB_PUBLIC float GB_Global_hyper_switch_get (void) { return (GB_Global.hyper_switch) ; @@ -528,7 +514,6 @@ float GB_Global_hyper_switch_get (void) // bitmap_switch //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_bitmap_switch_set (int k, float b) { k = GB_IMAX (k, 0) ; @@ -536,7 +521,6 @@ void GB_Global_bitmap_switch_set (int k, float b) GB_Global.bitmap_switch [k] = b ; } -GB_PUBLIC float GB_Global_bitmap_switch_get (int k) { k = GB_IMAX (k, 0) ; @@ -544,7 +528,6 @@ float GB_Global_bitmap_switch_get (int k) return (GB_Global.bitmap_switch [k]) ; } -GB_PUBLIC float GB_Global_bitmap_switch_matrix_get (int64_t vlen, int64_t vdim) { int64_t d = GB_IMIN (vlen, vdim) ; @@ -558,7 +541,6 @@ float GB_Global_bitmap_switch_matrix_get (int64_t vlen, int64_t vdim) return (GB_Global.bitmap_switch [7]) ; } -GB_PUBLIC void GB_Global_bitmap_switch_default (void) { GB_Global.bitmap_switch [0] = GB_BITSWITCH_1 ; @@ -589,13 +571,11 @@ bool GB_Global_is_csc_get (void) // abort_function //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_abort_function_set (void (* abort_function) (void)) { GB_Global.abort_function = abort_function ; } -GB_PUBLIC void GB_Global_abort_function (void) { GB_Global.abort_function ( ) ; @@ -608,7 +588,6 @@ void GB_Global_abort_function (void) // These functions keep a separate record of the pointers to all allocated // blocks of memory and their sizes, just for sanity checks. -GB_PUBLIC void GB_Global_memtable_dump (void) { #ifdef GB_DEBUG @@ -623,20 +602,17 @@ void GB_Global_memtable_dump (void) #endif } -GB_PUBLIC int GB_Global_memtable_n (void) { return (GB_Global.nmemtable) ; } -GB_PUBLIC void GB_Global_memtable_clear (void) { GB_Global.nmemtable = 0 ; } // add a pointer to the table of malloc'd blocks -GB_PUBLIC void GB_Global_memtable_add (void *p, size_t size) { if (p == NULL) return ; @@ -645,6 +621,7 @@ void GB_Global_memtable_add (void *p, size_t size) GB_ATOMIC_UPDATE GB_Global.nmalloc++ ; } + #ifdef GB_DEBUG bool fail = false ; #ifdef GB_MEMDUMP @@ -680,13 +657,14 @@ void GB_Global_memtable_add (void *p, size_t size) GB_Global_memtable_dump ( ) ; #endif #endif + } // get the size of a malloc'd block -GB_PUBLIC size_t GB_Global_memtable_size (void *p) { size_t size = 0 ; + #ifdef GB_DEBUG if (p == NULL) return (0) ; bool found = false ; @@ -710,14 +688,15 @@ size_t GB_Global_memtable_size (void *p) ASSERT (0) ; } #endif + return (size) ; } // test if a malloc'd block is in the table -GB_PUBLIC bool GB_Global_memtable_find (void *p) { bool found = false ; + #ifdef GB_DEBUG if (p == NULL) return (false) ; #pragma omp critical(GB_memtable) @@ -733,11 +712,11 @@ bool GB_Global_memtable_find (void *p) } } #endif + return (found) ; } // remove a pointer from the table of malloc'd blocks -GB_PUBLIC void GB_Global_memtable_remove (void *p) { if (p == NULL) return ; @@ -746,6 +725,7 @@ void GB_Global_memtable_remove (void *p) GB_ATOMIC_UPDATE GB_Global.nmalloc-- ; } + #ifdef GB_DEBUG bool found = false ; #ifdef GB_MEMDUMP @@ -777,6 +757,7 @@ void GB_Global_memtable_remove (void *p) GB_Global_memtable_dump ( ) ; #endif #endif + } //------------------------------------------------------------------------------ @@ -874,13 +855,11 @@ void GB_Global_free_function (void *p) // malloc_is_thread_safe //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_malloc_is_thread_safe_set (bool malloc_is_thread_safe) { GB_Global.malloc_is_thread_safe = malloc_is_thread_safe ; } -GB_PUBLIC bool GB_Global_malloc_is_thread_safe_get (void) { return (GB_Global.malloc_is_thread_safe) ; @@ -890,7 +869,6 @@ bool GB_Global_malloc_is_thread_safe_get (void) // malloc_tracking //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_malloc_tracking_set (bool malloc_tracking) { GB_Global.malloc_tracking = malloc_tracking ; @@ -911,7 +889,6 @@ void GB_Global_nmalloc_clear (void) GB_Global.nmalloc = 0 ; } -GB_PUBLIC int64_t GB_Global_nmalloc_get (void) { int64_t nmalloc ; @@ -924,7 +901,6 @@ int64_t GB_Global_nmalloc_get (void) // malloc_debug //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_malloc_debug_set (bool malloc_debug) { GB_ATOMIC_WRITE @@ -943,7 +919,6 @@ bool GB_Global_malloc_debug_get (void) // malloc_debug_count //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_malloc_debug_count_set (int64_t malloc_debug_count) { GB_ATOMIC_WRITE @@ -965,13 +940,11 @@ bool GB_Global_malloc_debug_count_decrement (void) // hack: for setting an internal flag for testing and development only //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_hack_set (int k, int64_t hack) { GB_Global.hack [k] = hack ; } -GB_PUBLIC int64_t GB_Global_hack_get (int k) { return (GB_Global.hack [k]) ; @@ -986,31 +959,26 @@ void GB_Global_burble_set (bool burble) GB_Global.burble = burble ; } -GB_PUBLIC bool GB_Global_burble_get (void) { return (GB_Global.burble) ; } -GB_PUBLIC GB_printf_function_t GB_Global_printf_get (void) { return (GB_Global.printf_func) ; } -GB_PUBLIC GB_flush_function_t GB_Global_flush_get (void) { return (GB_Global.flush_func) ; } -GB_PUBLIC void GB_Global_printf_set (GB_printf_function_t pr_func) { GB_Global.printf_func = pr_func ; } -GB_PUBLIC void GB_Global_flush_set (GB_flush_function_t fl_func) { GB_Global.flush_func = fl_func ; @@ -1020,13 +988,11 @@ void GB_Global_flush_set (GB_flush_function_t fl_func) // for printing matrices in 1-based index notation (@GrB and Julia) //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_print_one_based_set (bool onebased) { GB_Global.print_one_based = onebased ; } -GB_PUBLIC bool GB_Global_print_one_based_get (void) { return (GB_Global.print_one_based) ; @@ -1036,13 +1002,11 @@ bool GB_Global_print_one_based_get (void) // for printing matrix in @GrB interface //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_print_mem_shallow_set (bool mem_shallow) { GB_Global.print_mem_shallow = mem_shallow ; } -GB_PUBLIC bool GB_Global_print_mem_shallow_get (void) { return (GB_Global.print_mem_shallow) ; @@ -1181,7 +1145,6 @@ bool GB_Global_gpu_device_properties_get (int device) // timing: for code development only //------------------------------------------------------------------------------ -GB_PUBLIC void GB_Global_timing_clear_all (void) { for (int k = 0 ; k < 40 ; k++) @@ -1190,25 +1153,21 @@ void GB_Global_timing_clear_all (void) } } -GB_PUBLIC void GB_Global_timing_clear (int k) { GB_Global.timing [k] = 0 ; } -GB_PUBLIC void GB_Global_timing_set (int k, double t) { GB_Global.timing [k] = t ; } -GB_PUBLIC void GB_Global_timing_add (int k, double t) { GB_Global.timing [k] += t ; } -GB_PUBLIC double GB_Global_timing_get (int k) { return (GB_Global.timing [k]) ; @@ -1223,36 +1182,44 @@ double GB_Global_timing_get (int k) #define GB_NEXT(p) ((void **) p) [0] // free_pool_init: initialize the free_pool -GB_PUBLIC void GB_Global_free_pool_init (bool clear) { #ifdef _OPENMP - #pragma omp critical(GB_free_pool) + if (clear) { - if (clear) + // clear the free pool + #pragma omp critical(GB_free_pool) { - // clear the free pool for (int k = 0 ; k < 64 ; k++) { GB_Global.free_pool [k] = NULL ; GB_Global.free_pool_nblocks [k] = 0 ; } } - // set the default free_pool_limit - for (int k = 0 ; k < 64 ; k++) - { - GB_Global.free_pool_limit [k] = 0 ; - } - int64_t n = 16384 ; - for (int k = 3 ; k <= 8 ; k++) - { - GB_Global.free_pool_limit [k] = n ; - } - for (int k = 9 ; k <= 19 ; k++) - { - n = n/2 ; - GB_Global.free_pool_limit [k] = n ; - } + #pragma omp flush + } + // set the default free_pool_limit + for (int k = 0 ; k < 3 ; k++) + { + GB_ATOMIC_WRITE + GB_Global.free_pool_limit [k] = 0 ; + } + int64_t n = 16384 ; + for (int k = 3 ; k <= 8 ; k++) + { + GB_ATOMIC_WRITE + GB_Global.free_pool_limit [k] = n ; + } + for (int k = 9 ; k <= 19 ; k++) + { + n = n/2 ; + GB_ATOMIC_WRITE + GB_Global.free_pool_limit [k] = n ; + } + for (int k = 20 ; k < 64 ; k++) + { + GB_ATOMIC_WRITE + GB_Global.free_pool_limit [k] = 0 ; } #else // OpenMP not available: disable the free pool @@ -1277,10 +1244,9 @@ static inline void GB_Global_free_pool_check (void *p, int k, char *where) #endif // free_pool_get: get a block from the free_pool, or return NULL if none -GB_PUBLIC void *GB_Global_free_pool_get (int k) { - #ifdef _OPENMP + #if defined _MEMPOOL && defined _OPENMP void *p = NULL ; ASSERT (k >= 3 && k < 64) ; #pragma omp critical(GB_free_pool) @@ -1309,25 +1275,28 @@ void *GB_Global_free_pool_get (int k) } // free_pool_put: put a block in the free_pool, unless it is full -GB_PUBLIC bool GB_Global_free_pool_put (void *p, int k) { - #ifdef _OPENMP + #if defined _MEMPOOL && defined _OPENMP #ifdef GB_DEBUG GB_Global_free_pool_check (p, k, "put") ; #endif bool returned_to_pool = false ; - #pragma omp critical(GB_free_pool) + int64_t limit ; + GB_ATOMIC_READ + limit = GB_Global.free_pool_limit [k] ; + if (limit > 0) { - returned_to_pool = - (GB_Global.free_pool_nblocks [k] < - GB_Global.free_pool_limit [k]) ; - if (returned_to_pool) + #pragma omp critical(GB_free_pool) { - // add the block to the head of the free_pool list - GB_Global.free_pool_nblocks [k]++ ; - GB_NEXT (p) = GB_Global.free_pool [k] ; - GB_Global.free_pool [k] = p ; + returned_to_pool = (GB_Global.free_pool_nblocks [k] < limit) ; + if (returned_to_pool) + { + // add the block to the head of the free_pool list + GB_Global.free_pool_nblocks [k]++ ; + GB_NEXT (p) = GB_Global.free_pool [k] ; + GB_Global.free_pool [k] = p ; + } } } return (returned_to_pool) ; @@ -1337,10 +1306,9 @@ bool GB_Global_free_pool_put (void *p, int k) } // free_pool_dump: check the validity of the free_pool -GB_PUBLIC void GB_Global_free_pool_dump (int pr) { - #ifdef _OPENMP + #if defined _MEMPOOL && defined _OPENMP #ifdef GB_DEBUG bool fail = false ; #pragma omp critical(GB_free_pool) @@ -1348,7 +1316,9 @@ void GB_Global_free_pool_dump (int pr) for (int k = 0 ; k < 64 && !fail ; k++) { int64_t nblocks = GB_Global.free_pool_nblocks [k] ; - int64_t limit = GB_Global.free_pool_limit [k] ; + int64_t limit ; + GB_ATOMIC_READ + limit = GB_Global.free_pool_limit [k] ; if (nblocks != 0 && pr > 0) { printf ("pool %2d: " GBd " blocks, " GBd " limit\n", @@ -1380,49 +1350,37 @@ void GB_Global_free_pool_dump (int pr) } // free_pool_limit_get: get the limit on the # of blocks in the kth pool -GB_PUBLIC int64_t GB_Global_free_pool_limit_get (int k) +{ + int64_t limit ; + if (k < 3) return (0) ; + GB_ATOMIC_READ + limit = GB_Global.free_pool_limit [k] ; + return (limit) ; +} + +// free_pool_limit_set: set the limit on the # of blocks in the kth pool +void GB_Global_free_pool_limit_set (int64_t *limit) { #ifdef _OPENMP - int64_t nblocks = 0 ; - if (k >= 3 && k < 64) + for (int k = 3 ; k < 64 ; k++) { - #pragma omp critical(GB_free_pool) - { - nblocks = GB_Global.free_pool_limit [k] ; - } + GB_ATOMIC_WRITE + GB_Global.free_pool_limit [k] = limit [k] ; } - return (nblocks) ; #else - return (0) ; + for (int k = 0 ; k < 64 ; k++) + { + GB_Global.free_pool_limit [k] = 0 ; + } #endif } -// free_pool_limit_set: set the limit on the # of blocks in the kth pool -GB_PUBLIC -void GB_Global_free_pool_limit_set (int k, int64_t nblocks) -{ - if (k >= 3 && k < 64) - { - #ifdef _OPENMP - #pragma omp critical(GB_free_pool) - { - GB_Global.free_pool_limit [k] = nblocks ; - } - #else - { - GB_Global.free_pool_limit [k] = 0 ; - } - #endif - } -} - // free_pool_nblocks_total: total # of blocks in free_pool (for debug only) -GB_PUBLIC int64_t GB_Global_free_pool_nblocks_total (void) { int64_t nblocks = 0 ; - #ifdef _OPENMP + #if defined _MEMPOOL && defined _OPENMP #pragma omp critical(GB_free_pool) { for (int k = 0 ; k < 64 ; k++) @@ -1438,7 +1396,6 @@ int64_t GB_Global_free_pool_nblocks_total (void) // get_wtime: return current wallclock time //------------------------------------------------------------------------------ -GB_PUBLIC double GB_Global_get_wtime (void) { return (GB_OPENMP_GET_WTIME) ; diff --git a/deps/GraphBLAS/Source/GB_Global.h b/deps/GraphBLAS/Source/GB_Global.h index eaf3ce52bd..02e77f54e2 100644 --- a/deps/GraphBLAS/Source/GB_Global.h +++ b/deps/GraphBLAS/Source/GB_Global.h @@ -14,132 +14,124 @@ #ifndef GB_GLOBAL_H #define GB_GLOBAL_H -GB_PUBLIC void GB_Global_cpu_features_query (void) ; -GB_PUBLIC bool GB_Global_cpu_features_avx2 (void) ; -GB_PUBLIC bool GB_Global_cpu_features_avx512f (void) ; +void GB_Global_cpu_features_query (void) ; +bool GB_Global_cpu_features_avx2 (void) ; +bool GB_Global_cpu_features_avx512f (void) ; -GB_PUBLIC void GB_Global_mode_set (GrB_Mode mode) ; - GrB_Mode GB_Global_mode_get (void) ; +void GB_Global_mode_set (GrB_Mode mode) ; +GrB_Mode GB_Global_mode_get (void) ; - void GB_Global_sort_set (int sort) ; - int GB_Global_sort_get (void) ; +void GB_Global_sort_set (int sort) ; +int GB_Global_sort_get (void) ; -GB_PUBLIC void GB_Global_GrB_init_called_set (bool GrB_init_called) ; -GB_PUBLIC bool GB_Global_GrB_init_called_get (void) ; +void GB_Global_GrB_init_called_set (bool GrB_init_called) ; +bool GB_Global_GrB_init_called_get (void) ; -GB_PUBLIC void GB_Global_nthreads_max_set (int nthreads_max) ; -GB_PUBLIC int GB_Global_nthreads_max_get (void) ; +void GB_Global_nthreads_max_set (int nthreads_max) ; +int GB_Global_nthreads_max_get (void) ; -GB_PUBLIC int GB_Global_omp_get_max_threads (void) ; +int GB_Global_omp_get_max_threads (void) ; -GB_PUBLIC void GB_Global_chunk_set (double chunk) ; -GB_PUBLIC double GB_Global_chunk_get (void) ; +void GB_Global_chunk_set (double chunk) ; +double GB_Global_chunk_get (void) ; -GB_PUBLIC void GB_Global_hyper_switch_set (float hyper_switch) ; -GB_PUBLIC float GB_Global_hyper_switch_get (void) ; +void GB_Global_hyper_switch_set (float hyper_switch) ; +float GB_Global_hyper_switch_get (void) ; -GB_PUBLIC void GB_Global_bitmap_switch_set (int k, float b) ; -GB_PUBLIC float GB_Global_bitmap_switch_get (int k) ; -GB_PUBLIC float GB_Global_bitmap_switch_matrix_get +void GB_Global_bitmap_switch_set (int k, float b) ; +float GB_Global_bitmap_switch_get (int k) ; +float GB_Global_bitmap_switch_matrix_get (int64_t vlen, int64_t vdim) ; -GB_PUBLIC void GB_Global_bitmap_switch_default (void) ; +void GB_Global_bitmap_switch_default (void) ; - void GB_Global_is_csc_set (bool is_csc) ; - bool GB_Global_is_csc_get (void) ; +void GB_Global_is_csc_set (bool is_csc) ; +bool GB_Global_is_csc_get (void) ; -GB_PUBLIC void GB_Global_abort_function_set +void GB_Global_abort_function_set (void (* abort_function) (void)) ; -GB_PUBLIC void GB_Global_abort_function (void) ; - - void GB_Global_malloc_function_set - (void * (* malloc_function) (size_t)) ; - void * GB_Global_malloc_function (size_t size) ; - void GB_Global_realloc_function_set - (void * (* realloc_function) (void *, size_t)) ; - void * GB_Global_realloc_function (void *p, size_t size) ; - bool GB_Global_have_realloc_function (void) ; - void GB_Global_free_function_set - (void (* free_function) (void *)) ; - void GB_Global_free_function (void *p) ; - -GB_PUBLIC void GB_Global_malloc_is_thread_safe_set - (bool malloc_is_thread_safe) ; -GB_PUBLIC bool GB_Global_malloc_is_thread_safe_get (void) ; - -GB_PUBLIC void GB_Global_malloc_tracking_set (bool malloc_tracking) ; - bool GB_Global_malloc_tracking_get (void) ; - - void GB_Global_nmalloc_clear (void) ; -GB_PUBLIC int64_t GB_Global_nmalloc_get (void) ; - -GB_PUBLIC void GB_Global_malloc_debug_set (bool malloc_debug) ; -GB_PUBLIC bool GB_Global_malloc_debug_get (void) ; - -GB_PUBLIC void GB_Global_malloc_debug_count_set - (int64_t malloc_debug_count) ; - bool GB_Global_malloc_debug_count_decrement (void) ; - -GB_PUBLIC void GB_Global_hack_set (int k, int64_t hack) ; -GB_PUBLIC int64_t GB_Global_hack_get (int k) ; - - void GB_Global_burble_set (bool burble) ; -GB_PUBLIC bool GB_Global_burble_get (void) ; - -GB_PUBLIC void GB_Global_print_one_based_set (bool onebased) ; -GB_PUBLIC bool GB_Global_print_one_based_get (void) ; - -GB_PUBLIC void GB_Global_print_mem_shallow_set (bool mem_shallow) ; -GB_PUBLIC bool GB_Global_print_mem_shallow_get (void) ; - - void GB_Global_gpu_control_set (GrB_Desc_Value value) ; - GrB_Desc_Value GB_Global_gpu_control_get (void); - void GB_Global_gpu_chunk_set (double gpu_chunk) ; - double GB_Global_gpu_chunk_get (void) ; - bool GB_Global_gpu_count_set (bool enable_cuda) ; - int GB_Global_gpu_count_get (void) ; - size_t GB_Global_gpu_memorysize_get (int device) ; - int GB_Global_gpu_sm_get (int device) ; - bool GB_Global_gpu_device_pool_size_set - (int device, size_t size) ; - bool GB_Global_gpu_device_max_pool_size_set - (int device, size_t size) ; - bool GB_Global_gpu_device_memory_resource_set - (int device, void *resource) ; - void* GB_Global_gpu_device_memory_resource_get - (int device) ; - bool GB_Global_gpu_device_properties_get (int device) ; - -GB_PUBLIC void GB_Global_timing_clear_all (void) ; -GB_PUBLIC void GB_Global_timing_clear (int k) ; -GB_PUBLIC void GB_Global_timing_set (int k, double t) ; -GB_PUBLIC void GB_Global_timing_add (int k, double t) ; -GB_PUBLIC double GB_Global_timing_get (int k) ; - -GB_PUBLIC int GB_Global_memtable_n (void) ; -GB_PUBLIC void GB_Global_memtable_dump (void) ; -GB_PUBLIC void GB_Global_memtable_clear (void) ; -GB_PUBLIC void GB_Global_memtable_add (void *p, size_t size) ; -GB_PUBLIC size_t GB_Global_memtable_size (void *p) ; -GB_PUBLIC void GB_Global_memtable_remove (void *p) ; -GB_PUBLIC bool GB_Global_memtable_find (void *p) ; - -GB_PUBLIC void GB_Global_free_pool_init (bool clear) ; -GB_PUBLIC void *GB_Global_free_pool_get (int k) ; -GB_PUBLIC bool GB_Global_free_pool_put (void *p, int k) ; -GB_PUBLIC void GB_Global_free_pool_dump (int pr) ; -GB_PUBLIC int64_t GB_Global_free_pool_limit_get (int k) ; -GB_PUBLIC void GB_Global_free_pool_limit_set (int k, int64_t nblocks) ; -GB_PUBLIC int64_t GB_Global_free_pool_nblocks_total (void) ; +void GB_Global_abort_function (void) ; + +void GB_Global_malloc_function_set (void * (* malloc_function) (size_t)) ; +void * GB_Global_malloc_function (size_t size) ; +void GB_Global_realloc_function_set + (void * (* realloc_function) (void *, size_t)) ; +void * GB_Global_realloc_function (void *p, size_t size) ; +bool GB_Global_have_realloc_function (void) ; +void GB_Global_free_function_set (void (* free_function) (void *)) ; +void GB_Global_free_function (void *p) ; + +void GB_Global_malloc_is_thread_safe_set (bool malloc_is_thread_safe) ; +bool GB_Global_malloc_is_thread_safe_get (void) ; + +void GB_Global_malloc_tracking_set (bool malloc_tracking) ; +bool GB_Global_malloc_tracking_get (void) ; + +void GB_Global_nmalloc_clear (void) ; +int64_t GB_Global_nmalloc_get (void) ; + +void GB_Global_malloc_debug_set (bool malloc_debug) ; +bool GB_Global_malloc_debug_get (void) ; + +void GB_Global_malloc_debug_count_set (int64_t malloc_debug_count) ; +bool GB_Global_malloc_debug_count_decrement (void) ; + +void GB_Global_hack_set (int k, int64_t hack) ; +int64_t GB_Global_hack_get (int k) ; + +void GB_Global_burble_set (bool burble) ; +bool GB_Global_burble_get (void) ; + +void GB_Global_print_one_based_set (bool onebased) ; +bool GB_Global_print_one_based_get (void) ; + +void GB_Global_print_mem_shallow_set (bool mem_shallow) ; +bool GB_Global_print_mem_shallow_get (void) ; + +void GB_Global_gpu_control_set (GrB_Desc_Value value) ; +GrB_Desc_Value GB_Global_gpu_control_get (void); +void GB_Global_gpu_chunk_set (double gpu_chunk) ; +double GB_Global_gpu_chunk_get (void) ; +bool GB_Global_gpu_count_set (bool enable_cuda) ; +int GB_Global_gpu_count_get (void) ; +size_t GB_Global_gpu_memorysize_get (int device) ; +int GB_Global_gpu_sm_get (int device) ; +bool GB_Global_gpu_device_pool_size_set (int device, size_t size) ; +bool GB_Global_gpu_device_max_pool_size_set (int device, size_t size) ; +bool GB_Global_gpu_device_memory_resource_set (int device, void *resource) ; +void* GB_Global_gpu_device_memory_resource_get (int device) ; +bool GB_Global_gpu_device_properties_get (int device) ; + +void GB_Global_timing_clear_all (void) ; +void GB_Global_timing_clear (int k) ; +void GB_Global_timing_set (int k, double t) ; +void GB_Global_timing_add (int k, double t) ; +double GB_Global_timing_get (int k) ; + +int GB_Global_memtable_n (void) ; +void GB_Global_memtable_dump (void) ; +void GB_Global_memtable_clear (void) ; +void GB_Global_memtable_add (void *p, size_t size) ; +size_t GB_Global_memtable_size (void *p) ; +void GB_Global_memtable_remove (void *p) ; +bool GB_Global_memtable_find (void *p) ; + +void GB_Global_free_pool_init (bool clear) ; +void *GB_Global_free_pool_get (int k) ; +bool GB_Global_free_pool_put (void *p, int k) ; +void GB_Global_free_pool_dump (int pr) ; +int64_t GB_Global_free_pool_limit_get (int k) ; +void GB_Global_free_pool_limit_set (int64_t *limit) ; +int64_t GB_Global_free_pool_nblocks_total (void) ; typedef int (* GB_flush_function_t) (void) ; typedef int (* GB_printf_function_t) (const char *restrict format, ...) ; -GB_PUBLIC GB_printf_function_t GB_Global_printf_get (void) ; -GB_PUBLIC void GB_Global_printf_set (GB_printf_function_t p) ; +GB_printf_function_t GB_Global_printf_get (void) ; +void GB_Global_printf_set (GB_printf_function_t p) ; -GB_PUBLIC GB_flush_function_t GB_Global_flush_get (void) ; -GB_PUBLIC void GB_Global_flush_set (GB_flush_function_t p) ; +GB_flush_function_t GB_Global_flush_get (void) ; +void GB_Global_flush_set (GB_flush_function_t p) ; -GB_PUBLIC double GB_Global_get_wtime (void) ; +double GB_Global_get_wtime (void) ; #endif diff --git a/deps/GraphBLAS/Source/GB_IndexUnaryOp_check.c b/deps/GraphBLAS/Source/GB_IndexUnaryOp_check.c index 3da6dddda5..6dfde956b0 100644 --- a/deps/GraphBLAS/Source/GB_IndexUnaryOp_check.c +++ b/deps/GraphBLAS/Source/GB_IndexUnaryOp_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_IndexUnaryOp_check // check a GraphBLAS index_unary operator ( const GrB_IndexUnaryOp op, // GraphBLAS operator to print and check diff --git a/deps/GraphBLAS/Source/GB_Matrix_check.c b/deps/GraphBLAS/Source/GB_Matrix_check.c index 05fac29be7..f071b77536 100644 --- a/deps/GraphBLAS/Source/GB_Matrix_check.c +++ b/deps/GraphBLAS/Source/GB_Matrix_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_Matrix_check // check a GraphBLAS matrix ( const GrB_Matrix A, // GraphBLAS matrix to print and check diff --git a/deps/GraphBLAS/Source/GB_Monoid_check.c b/deps/GraphBLAS/Source/GB_Monoid_check.c index 1faccb706f..f53c5d998b 100644 --- a/deps/GraphBLAS/Source/GB_Monoid_check.c +++ b/deps/GraphBLAS/Source/GB_Monoid_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_Monoid_check // check a GraphBLAS monoid ( const GrB_Monoid monoid, // GraphBLAS monoid to print and check diff --git a/deps/GraphBLAS/Source/GB_SelectOp_check.c b/deps/GraphBLAS/Source/GB_SelectOp_check.c index 7e48c53aba..137c60e9b3 100644 --- a/deps/GraphBLAS/Source/GB_SelectOp_check.c +++ b/deps/GraphBLAS/Source/GB_SelectOp_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_SelectOp_check // check a GraphBLAS select operator ( const GxB_SelectOp op, // GraphBLAS operator to print and check diff --git a/deps/GraphBLAS/Source/GB_Semiring_check.c b/deps/GraphBLAS/Source/GB_Semiring_check.c index 10d6596e90..76b9f1e4fa 100644 --- a/deps/GraphBLAS/Source/GB_Semiring_check.c +++ b/deps/GraphBLAS/Source/GB_Semiring_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_Semiring_check // check a GraphBLAS semiring ( const GrB_Semiring semiring, // GraphBLAS semiring to print and check diff --git a/deps/GraphBLAS/Source/GB_Type_check.c b/deps/GraphBLAS/Source/GB_Type_check.c index ad0492359d..7e8e614015 100644 --- a/deps/GraphBLAS/Source/GB_Type_check.c +++ b/deps/GraphBLAS/Source/GB_Type_check.c @@ -14,7 +14,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_Type_check // check a GraphBLAS Type ( const GrB_Type type, // GraphBLAS type to print and check diff --git a/deps/GraphBLAS/Source/GB_Type_compatible.c b/deps/GraphBLAS/Source/GB_Type_compatible.c index 57325a7e28..6ffb588cb4 100644 --- a/deps/GraphBLAS/Source/GB_Type_compatible.c +++ b/deps/GraphBLAS/Source/GB_Type_compatible.c @@ -12,7 +12,6 @@ #include "GB.h" -GB_PUBLIC bool GB_Type_compatible // check if two types can be typecast ( const GrB_Type atype, diff --git a/deps/GraphBLAS/Source/GB_UnaryOp_check.c b/deps/GraphBLAS/Source/GB_UnaryOp_check.c index 9df8c16be5..bc0a5be484 100644 --- a/deps/GraphBLAS/Source/GB_UnaryOp_check.c +++ b/deps/GraphBLAS/Source/GB_UnaryOp_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_UnaryOp_check // check a GraphBLAS unary operator ( const GrB_UnaryOp op, // GraphBLAS operator to print and check diff --git a/deps/GraphBLAS/Source/GB_Vector_check.c b/deps/GraphBLAS/Source/GB_Vector_check.c index 69ce131c26..4302cad395 100644 --- a/deps/GraphBLAS/Source/GB_Vector_check.c +++ b/deps/GraphBLAS/Source/GB_Vector_check.c @@ -11,7 +11,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_Vector_check // check a GraphBLAS vector ( const GrB_Vector v, // GraphBLAS vector to print and check diff --git a/deps/GraphBLAS/Source/GB_aliased.c b/deps/GraphBLAS/Source/GB_aliased.c index 9967d8c7e8..64a183c702 100644 --- a/deps/GraphBLAS/Source/GB_aliased.c +++ b/deps/GraphBLAS/Source/GB_aliased.c @@ -17,7 +17,6 @@ // true if pointers p1 and p2 are aliased and not NULL #define GB_POINTER_ALIASED(p1,p2) ((p1) == (p2) && (p1) != NULL) -GB_PUBLIC bool GB_aliased // determine if A and B are aliased ( GrB_Matrix A, // input A matrix diff --git a/deps/GraphBLAS/Source/GB_aliased.h b/deps/GraphBLAS/Source/GB_aliased.h index d1f5f1c652..bdd6d85107 100644 --- a/deps/GraphBLAS/Source/GB_aliased.h +++ b/deps/GraphBLAS/Source/GB_aliased.h @@ -15,7 +15,6 @@ // more restrictive. // GB_aliased also checks the content of A and B -GB_PUBLIC bool GB_aliased // determine if A and B are aliased ( GrB_Matrix A, // input A matrix @@ -23,7 +22,6 @@ bool GB_aliased // determine if A and B are aliased ) ; // matrices returned to the user are never shallow; internal matrices may be -GB_PUBLIC bool GB_is_shallow // true if any component of A is shallow ( GrB_Matrix A // matrix to query diff --git a/deps/GraphBLAS/Source/GB_apply.h b/deps/GraphBLAS/Source/GB_apply.h index bc28cb2f97..8ff0ecffe2 100644 --- a/deps/GraphBLAS/Source/GB_apply.h +++ b/deps/GraphBLAS/Source/GB_apply.h @@ -42,7 +42,6 @@ GrB_Info GB_apply_op // apply a unary op, idxunop, or binop, Cx = op (A) GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_shallow_op // create shallow matrix and apply operator ( GrB_Matrix C, // output C, of type op*->ztype, static header diff --git a/deps/GraphBLAS/Source/GB_atomics.h b/deps/GraphBLAS/Source/GB_atomics.h index f65791076f..bfb4e04e78 100644 --- a/deps/GraphBLAS/Source/GB_atomics.h +++ b/deps/GraphBLAS/Source/GB_atomics.h @@ -2,12 +2,13 @@ // GB_atomics.h: definitions for atomic operations //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2023, All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 //------------------------------------------------------------------------------ // All atomic operations used by SuiteSparse:GraphBLAS appear in this file. +// OpenMP 4.0 or later is preferred. // These atomic operations assume either an ANSI C11 compiler that supports // OpenMP 3.1 or later, or Microsoft Visual Studio on 64-bit Windows (which @@ -23,23 +24,23 @@ //------------------------------------------------------------------------------ // Whenever possible, the OpenMP pragma is used with a clause (as introduced in -// OpenMP 3.1), as follow: +// OpenMP 4.0), as follows: // -// #pragma omp atomic [clause] +// #pragma omp atomic seq_cst [clause] // // where [clause] is read, write, update, or capture. // // Microsoft Visual Studio only supports OpenMP 2.0, which does not have the -// [clause]. Without the [clause], #pragma omp atomic is like -// #pragma omp atomic update, but the expression can only be one of: -// +// [clause]. Without the [clause], #pragma omp atomic is like +// #pragma omp atomic seq_cst update, but the expression can only be one of: +// // x binop= expression // x++ // ++x // x-- // --x // -// where binop is one of these operators: + * - / & ^ | << >> +// where binop is one of these operators: + * - / & ^ | << >> // // OpenMP 3.0 and later support additional options for the "update" clause, // but SuiteSparse:GraphBLAS uses only this form: @@ -53,19 +54,18 @@ // types INTx, UINTx, FP32, FP64 (for x = 8, 16, 32, and 64). For the boolean // monoids, only the BOOL type is used. // -// As a result, the atomic updates are the same for gcc and icc (which support -// OpenMP 3.0 or later) with the "update" clause. For MS Visual Studio, the +// As a result, the atomic updates are the same for gcc and icx (which support +// OpenMP 4.0 or later) with the "update" clause. For MS Visual Studio, the // "update" clause is removed since it supports OpenMP 2.0. #if ( _OPENMP >= 201307 ) - // OpenMP 4.0 or later - // #define GB_ATOMIC_UPDATE GB_PRAGMA (omp atomic update seq_cst) - #define GB_ATOMIC_UPDATE GB_PRAGMA (omp atomic update) + // OpenMP 4.0 or later: seq_cst added + #define GB_ATOMIC_UPDATE GB_PRAGMA (omp atomic seq_cst update) #elif ( _OPENMP >= 201107 ) - // OpenMP 3.1 + // OpenMP 3.1: no seq_cst keyword #define GB_ATOMIC_UPDATE GB_PRAGMA (omp atomic update) #elif ( _OPENMP >= 199810 ) @@ -102,9 +102,15 @@ #define GB_ATOMIC_READ #define GB_ATOMIC_WRITE +#elif ( _OPENMP >= 201307 ) + + // OpenMP 4.0 and later have atomic reads and writes, and seq_cst + #define GB_ATOMIC_READ GB_PRAGMA (omp atomic seq_cst read) + #define GB_ATOMIC_WRITE GB_PRAGMA (omp atomic seq_cst write) + #elif ( _OPENMP >= 201107 ) - // OpenMP 3.1 and later have atomic reads and writes + // OpenMP 3.1 and later have atomic reads and writes, but no seq_cst clause #define GB_ATOMIC_READ GB_PRAGMA (omp atomic read) #define GB_ATOMIC_WRITE GB_PRAGMA (omp atomic write) @@ -146,14 +152,14 @@ // { result = target ; target |= value ; } for int64_t // { result = target++ ; } for int64_t // -// OpenMP 3.1 and later supports atomic captures with a "capture" clause: +// OpenMP 3.1 and later supports atomic captures with a "capture" clause: // -// #pragma omp atomic capture +// #pragma omp atomic seq_cst capture // { result = target ; target = value ; } // // or with a binary operator // -// #pragma omp atomic capture +// #pragma omp atomic seq_cst capture // { result = target ; target binop= value ; } // // MS Visual Studio supports only OpenMP 2.0, and does not support any @@ -165,13 +171,12 @@ #if ( _OPENMP >= 201307 ) - // OpenMP 4.0 or later - // #define GB_ATOMIC_CAPTURE GB_PRAGMA (omp atomic capture seq_cst) - #define GB_ATOMIC_CAPTURE GB_PRAGMA (omp atomic capture) + // OpenMP 4.0 or later: added seq_cst feature + #define GB_ATOMIC_CAPTURE GB_PRAGMA (omp atomic seq_cst capture) #elif ( _OPENMP >= 201107 ) - // OpenMP 3.1 + // OpenMP 3.1: no seq_cst clause #define GB_ATOMIC_CAPTURE GB_PRAGMA (omp atomic capture) #elif ( _OPENMP >= 199810 ) @@ -380,19 +385,17 @@ // Type punning is used to extend these signed integer types to unsigned // integers of the same number of bytes, and to float and double. -#if GB_COMPILER_MSC +//------------------------------------------------------------------------------ +// GB_PUN: type punning +//------------------------------------------------------------------------------ - //-------------------------------------------------------------------------- - // GB_PUN: type punning - //-------------------------------------------------------------------------- +// With type punning, a value is treated as a different type, but with no +// typecasting. The address of the variable is first typecasted to a (type *) +// pointer, and then the pointer is dereferenced. - // With type punning, a value is treated as a different type, but with no - // typecasting. The address of the variable is first typecasted to a (type - // *) pointer, and then the pointer is dereferenced. Type punning is only - // needed to extend the atomic compare/exchange functions for Microsoft - // Visual Studio. +#define GB_PUN(type,value) (*((type *) (&(value)))) - #define GB_PUN(type,value) (*((type *) (&(value)))) +#if GB_COMPILER_MSC //-------------------------------------------------------------------------- // compare/exchange for MS Visual Studio @@ -436,29 +439,32 @@ // compare/exchange for gcc, icc, and clang on x86 and Power8/9 //-------------------------------------------------------------------------- - // the compare/exchange function is generic for any type - #define GB_ATOMIC_COMPARE_EXCHANGE_X(target, expected, desired) \ - __atomic_compare_exchange (target, &expected, &desired, \ - true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) \ + #include // bool, int8_t, and uint8_t #define GB_ATOMIC_COMPARE_EXCHANGE_8(target, expected, desired) \ - GB_ATOMIC_COMPARE_EXCHANGE_X(target, expected, desired) + atomic_compare_exchange_weak \ + ((volatile _Atomic uint8_t *) (target), \ + (uint8_t *) (&(expected)), GB_PUN (uint8_t , desired)) // int16_t and uint16_t #define GB_ATOMIC_COMPARE_EXCHANGE_16(target, expected, desired) \ - GB_ATOMIC_COMPARE_EXCHANGE_X (target, expected, desired) + atomic_compare_exchange_weak \ + ((volatile _Atomic uint16_t *) (target), \ + (uint16_t *) (&(expected)), GB_PUN (uint16_t, desired)) // float, int32_t, and uint32_t #define GB_ATOMIC_COMPARE_EXCHANGE_32(target, expected, desired) \ - GB_ATOMIC_COMPARE_EXCHANGE_X (target, expected, desired) + atomic_compare_exchange_weak \ + ((volatile _Atomic uint32_t *) (target), \ + (uint32_t *) (&(expected)), GB_PUN (uint32_t, desired)) // double, int64_t, and uint64_t #define GB_ATOMIC_COMPARE_EXCHANGE_64(target, expected, desired) \ - GB_ATOMIC_COMPARE_EXCHANGE_X (target, expected, desired) - + atomic_compare_exchange_weak \ + ((volatile _Atomic uint64_t *) (target), \ + (uint64_t *) (&(expected)), GB_PUN (uint64_t, desired)) #endif - #endif diff --git a/deps/GraphBLAS/Source/GB_binop.h b/deps/GraphBLAS/Source/GB_binop.h index 51eec6a24f..11b00c3bca 100644 --- a/deps/GraphBLAS/Source/GB_binop.h +++ b/deps/GraphBLAS/Source/GB_binop.h @@ -35,7 +35,6 @@ GrB_BinaryOp GB_flip_binop // flip a binary operator bool *flipxy // true on input, set to false if op is flipped ) ; -GB_PUBLIC GB_Opcode GB_boolean_rename // renamed opcode ( const GB_Opcode opcode // opcode to rename diff --git a/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.c b/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.c index d7dac2e417..faa5aeaef0 100644 --- a/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.c +++ b/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.c @@ -23,7 +23,6 @@ // TODO: also pass in the user's C and the accum operator, and done_in_place, // like GB_AxB_dot4. -GB_PUBLIC // for testing only GrB_Info GB_bitmap_AxB_saxpy // C = A*B where C is bitmap ( GrB_Matrix C, // output matrix, static header diff --git a/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.h b/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.h index 4f6eb63efb..38743e5258 100644 --- a/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.h +++ b/deps/GraphBLAS/Source/GB_bitmap_AxB_saxpy.h @@ -11,7 +11,6 @@ #define GB_AXB_BITMAP_SAXPY_H #include "GB_mxm.h" -GB_PUBLIC // for testing only GrB_Info GB_bitmap_AxB_saxpy // C = A*B where C is bitmap ( GrB_Matrix C, // output matrix, static header diff --git a/deps/GraphBLAS/Source/GB_bitmap_assign_methods.h b/deps/GraphBLAS/Source/GB_bitmap_assign_methods.h index f2fb38a8b2..992186f793 100644 --- a/deps/GraphBLAS/Source/GB_bitmap_assign_methods.h +++ b/deps/GraphBLAS/Source/GB_bitmap_assign_methods.h @@ -395,7 +395,6 @@ GrB_Info GB_bitmap_assign_noM_accum_whole GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_bitmap_assign_noM_noaccum ( // input/output: diff --git a/deps/GraphBLAS/Source/GB_bitmap_assign_noM_noaccum.c b/deps/GraphBLAS/Source/GB_bitmap_assign_noM_noaccum.c index b6484e5fd8..53802664d0 100644 --- a/deps/GraphBLAS/Source/GB_bitmap_assign_noM_noaccum.c +++ b/deps/GraphBLAS/Source/GB_bitmap_assign_noM_noaccum.c @@ -38,7 +38,6 @@ #define GB_FREE_ALL ; -GB_PUBLIC GrB_Info GB_bitmap_assign_noM_noaccum ( // input/output: diff --git a/deps/GraphBLAS/Source/GB_bix_alloc.c b/deps/GraphBLAS/Source/GB_bix_alloc.c index 96505ee4a9..9e088d8d71 100644 --- a/deps/GraphBLAS/Source/GB_bix_alloc.c +++ b/deps/GraphBLAS/Source/GB_bix_alloc.c @@ -16,7 +16,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_bix_alloc // allocate A->b, A->i, and A->x space in a matrix ( GrB_Matrix A, // matrix to allocate space for diff --git a/deps/GraphBLAS/Source/GB_bix_free.c b/deps/GraphBLAS/Source/GB_bix_free.c index 14b9f9054a..f5d129a864 100644 --- a/deps/GraphBLAS/Source/GB_bix_free.c +++ b/deps/GraphBLAS/Source/GB_bix_free.c @@ -12,7 +12,6 @@ #include "GB_Pending.h" -GB_PUBLIC void GB_bix_free // free A->b, A->i, and A->x of a matrix ( GrB_Matrix A // matrix with content to free diff --git a/deps/GraphBLAS/Source/GB_block.c b/deps/GraphBLAS/Source/GB_block.c index a9a8a3a35e..3d5413d60d 100644 --- a/deps/GraphBLAS/Source/GB_block.c +++ b/deps/GraphBLAS/Source/GB_block.c @@ -11,7 +11,6 @@ #define GB_FREE_ALL ; -GB_PUBLIC GrB_Info GB_block // apply all pending computations if blocking mode enabled ( GrB_Matrix A, diff --git a/deps/GraphBLAS/Source/GB_calloc_memory.c b/deps/GraphBLAS/Source/GB_calloc_memory.c index 69718609c2..4709c11081 100644 --- a/deps/GraphBLAS/Source/GB_calloc_memory.c +++ b/deps/GraphBLAS/Source/GB_calloc_memory.c @@ -29,9 +29,10 @@ static inline void *GB_calloc_helper // determine the next higher power of 2 size_t size_requested = (*size) ; (*size) = GB_IMAX (*size, 8) ; - int k = GB_CEIL_LOG2 (*size) ; +#if 0 // if available, get the block from the pool + int k = GB_CEIL_LOG2 (*size) ; if (GB_Global_free_pool_limit_get (k) > 0) { // round up the size to the nearest power of two @@ -43,6 +44,7 @@ static inline void *GB_calloc_helper } if (p == NULL) +#endif { // no block in the free_pool, so allocate it p = GB_Global_malloc_function (*size) ; @@ -69,7 +71,6 @@ static inline void *GB_calloc_helper // GB_calloc_memory //------------------------------------------------------------------------------ -GB_PUBLIC void *GB_calloc_memory // pointer to allocated block of memory ( size_t nitems, // number of items to allocate @@ -96,7 +97,8 @@ void *GB_calloc_memory // pointer to allocated block of memory size_of_item = GB_IMAX (1, size_of_item) ; bool ok = GB_size_t_multiply (&size, nitems, size_of_item) ; - if (!ok || nitems > GB_NMAX || size_of_item > GB_NMAX) + if (!ok || (((uint64_t) nitems) > GB_NMAX) + || (((uint64_t) size_of_item) > GB_NMAX)) { // overflow (*size_allocated) = 0 ; diff --git a/deps/GraphBLAS/Source/GB_cast.h b/deps/GraphBLAS/Source/GB_cast.h index 3defc5e589..ee370b07c8 100644 --- a/deps/GraphBLAS/Source/GB_cast.h +++ b/deps/GraphBLAS/Source/GB_cast.h @@ -65,7 +65,6 @@ static inline void GB_cast_one // z = 1 with typecasting zcode //------------------------------------------------------------------------------ -GB_PUBLIC void GB_cast_array // typecast an array ( GB_void *Cx, // output array diff --git a/deps/GraphBLAS/Source/GB_cast_array.c b/deps/GraphBLAS/Source/GB_cast_array.c index f6b40e3fe3..1e389db0ea 100644 --- a/deps/GraphBLAS/Source/GB_cast_array.c +++ b/deps/GraphBLAS/Source/GB_cast_array.c @@ -17,7 +17,6 @@ #include "GB_unop__include.h" #endif -GB_PUBLIC void GB_cast_array // typecast an array ( GB_void *Cx, // output array diff --git a/deps/GraphBLAS/Source/GB_cast_factory.c b/deps/GraphBLAS/Source/GB_cast_factory.c index 167d624a44..1721506584 100644 --- a/deps/GraphBLAS/Source/GB_cast_factory.c +++ b/deps/GraphBLAS/Source/GB_cast_factory.c @@ -17,7 +17,6 @@ #include "GB.h" -GB_PUBLIC GB_cast_function GB_cast_factory // returns pointer to function to cast x to z ( const GB_Type_code code1, // the type of z, the output value diff --git a/deps/GraphBLAS/Source/GB_casting.h b/deps/GraphBLAS/Source/GB_casting.h index 55adbb8e84..70756b260c 100644 --- a/deps/GraphBLAS/Source/GB_casting.h +++ b/deps/GraphBLAS/Source/GB_casting.h @@ -18,7 +18,6 @@ typedef void (*GB_cast_function) (void *, const void *, size_t) ; -GB_PUBLIC GB_cast_function GB_cast_factory // returns pointer to function to cast x to z ( const GB_Type_code code1, // the type of z, the output value diff --git a/deps/GraphBLAS/Source/GB_check.h b/deps/GraphBLAS/Source/GB_check.h index 4ac765746c..9e57e66fb7 100644 --- a/deps/GraphBLAS/Source/GB_check.h +++ b/deps/GraphBLAS/Source/GB_check.h @@ -18,7 +18,6 @@ #define GB4 GxB_SHORT_VERBOSE #define GB5 GxB_COMPLETE_VERBOSE -GB_PUBLIC GrB_Info GB_entry_check // print a single value ( const GrB_Type type, // type of value to print @@ -27,7 +26,6 @@ GrB_Info GB_entry_check // print a single value FILE *f // file to print to ) ; -GB_PUBLIC GrB_Info GB_code_check // print and check an entry using a type code ( const GB_Type_code code, // type code of value to print @@ -36,7 +34,6 @@ GrB_Info GB_code_check // print and check an entry using a type code FILE *f // file to print to ) ; -GB_PUBLIC GrB_Info GB_Type_check // check a GraphBLAS Type ( const GrB_Type type, // GraphBLAS type to print and check @@ -45,7 +42,6 @@ GrB_Info GB_Type_check // check a GraphBLAS Type FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_UnaryOp_check // check a GraphBLAS unary operator ( const GrB_UnaryOp op, // GraphBLAS operator to print and check @@ -54,7 +50,6 @@ GrB_Info GB_UnaryOp_check // check a GraphBLAS unary operator FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_BinaryOp_check // check a GraphBLAS binary operator ( const GrB_BinaryOp op, // GraphBLAS operator to print and check @@ -63,7 +58,6 @@ GrB_Info GB_BinaryOp_check // check a GraphBLAS binary operator FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_IndexUnaryOp_check // check a GraphBLAS index_unary operator ( const GrB_IndexUnaryOp op, // GraphBLAS operator to print and check @@ -72,7 +66,6 @@ GrB_Info GB_IndexUnaryOp_check // check a GraphBLAS index_unary operator FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_SelectOp_check // check a GraphBLAS select operator ( const GxB_SelectOp op, // GraphBLAS operator to print and check @@ -81,7 +74,6 @@ GrB_Info GB_SelectOp_check // check a GraphBLAS select operator FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_Operator_check // check a GraphBLAS operator ( const GB_Operator op, // GraphBLAS operator to print and check @@ -90,7 +82,6 @@ GrB_Info GB_Operator_check // check a GraphBLAS operator FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_Monoid_check // check a GraphBLAS monoid ( const GrB_Monoid monoid, // GraphBLAS monoid to print and check @@ -99,7 +90,6 @@ GrB_Info GB_Monoid_check // check a GraphBLAS monoid FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_Semiring_check // check a GraphBLAS semiring ( const GrB_Semiring semiring, // GraphBLAS semiring to print and check @@ -108,7 +98,6 @@ GrB_Info GB_Semiring_check // check a GraphBLAS semiring FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_Descriptor_check // check a GraphBLAS descriptor ( const GrB_Descriptor D, // GraphBLAS descriptor to print and check @@ -117,7 +106,6 @@ GrB_Info GB_Descriptor_check // check a GraphBLAS descriptor FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_matvec_check // check a GraphBLAS matrix or vector ( const GrB_Matrix A, // GraphBLAS matrix to print and check @@ -128,7 +116,6 @@ GrB_Info GB_matvec_check // check a GraphBLAS matrix or vector const char *kind // "matrix" or "vector" ) ; -GB_PUBLIC GrB_Info GB_Matrix_check // check a GraphBLAS matrix ( const GrB_Matrix A, // GraphBLAS matrix to print and check @@ -137,7 +124,6 @@ GrB_Info GB_Matrix_check // check a GraphBLAS matrix FILE *f // file for output ) ; -GB_PUBLIC GrB_Info GB_Vector_check // check a GraphBLAS vector ( const GrB_Vector v, // GraphBLAS vector to print and check diff --git a/deps/GraphBLAS/Source/GB_code_check.c b/deps/GraphBLAS/Source/GB_code_check.c index db0170e530..c038c826f9 100644 --- a/deps/GraphBLAS/Source/GB_code_check.c +++ b/deps/GraphBLAS/Source/GB_code_check.c @@ -47,7 +47,6 @@ } \ } -GB_PUBLIC GrB_Info GB_code_check // print an entry using a type code ( const GB_Type_code code, // type code of value to print diff --git a/deps/GraphBLAS/Source/GB_code_size.c b/deps/GraphBLAS/Source/GB_code_size.c index e35b827a16..b2d3668134 100644 --- a/deps/GraphBLAS/Source/GB_code_size.c +++ b/deps/GraphBLAS/Source/GB_code_size.c @@ -11,7 +11,6 @@ #include "GB.h" -GB_PUBLIC size_t GB_code_size // return the size of a type, given its code ( const GB_Type_code code, // input code of the type to find the size of diff --git a/deps/GraphBLAS/Source/GB_code_string.c b/deps/GraphBLAS/Source/GB_code_string.c index 2bbc5729b7..a09754455f 100644 --- a/deps/GraphBLAS/Source/GB_code_string.c +++ b/deps/GraphBLAS/Source/GB_code_string.c @@ -11,7 +11,6 @@ #include "GB.h" -GB_PUBLIC char *GB_code_string // return a static string for a type name ( const GB_Type_code code // code to convert to string diff --git a/deps/GraphBLAS/Source/GB_code_type.c b/deps/GraphBLAS/Source/GB_code_type.c index ef5ab67704..8c86f2251b 100644 --- a/deps/GraphBLAS/Source/GB_code_type.c +++ b/deps/GraphBLAS/Source/GB_code_type.c @@ -16,7 +16,6 @@ #include "GB.h" -GB_PUBLIC GrB_Type GB_code_type // return the GrB_Type corresponding to the code ( const GB_Type_code code, // type code to convert diff --git a/deps/GraphBLAS/Source/GB_compatible.h b/deps/GraphBLAS/Source/GB_compatible.h index 8163d930df..4bd05a0ecb 100644 --- a/deps/GraphBLAS/Source/GB_compatible.h +++ b/deps/GraphBLAS/Source/GB_compatible.h @@ -10,7 +10,6 @@ #ifndef GB_COMPATIBLE_H #define GB_COMPATIBLE_H -GB_PUBLIC bool GB_Type_compatible // check if two types can be typecast ( const GrB_Type atype, diff --git a/deps/GraphBLAS/Source/GB_compiler.h b/deps/GraphBLAS/Source/GB_compiler.h index 48cd5ac4f8..bd6bbe8629 100644 --- a/deps/GraphBLAS/Source/GB_compiler.h +++ b/deps/GraphBLAS/Source/GB_compiler.h @@ -10,6 +10,14 @@ #ifndef GB_COMPILER_H #define GB_COMPILER_H +#define GB_COMPILER_NVCC 0 +#define GB_COMPILER_ICX 0 +#define GB_COMPILER_ICC 0 +#define GB_COMPILER_CLANG 0 +#define GB_COMPILER_GCC 0 +#define GB_COMPILER_MSC 0 +#define GB_COMPILER_XLC 0 + //------------------------------------------------------------------------------ // determine which compiler is in use //------------------------------------------------------------------------------ @@ -17,14 +25,8 @@ #if defined ( __NVCC__ ) // NVIDIA nvcc compiler + #undef GB_COMPILER_NVCC #define GB_COMPILER_NVCC 1 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR __CUDACC_VER_MAJOR__ #define GB_COMPILER_MINOR __CUDACC_VER_MINOR__ @@ -34,14 +36,8 @@ #elif defined ( __INTEL_CLANG_COMPILER ) // Intel icx compiler, 2022.0.0 based on clang/llvm 14.0.0 - #define GB_COMPILER_NVCC 0 + #undef GB_COMPILER_ICX #define GB_COMPILER_ICX 1 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR __INTEL_CLANG_COMPILER #define GB_COMPILER_MINOR 0 @@ -51,14 +47,8 @@ #elif defined ( __INTEL_COMPILER ) // Intel icc compiler: 2021.5.0 uses "gcc 7.5 mode" - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 + #undef GB_COMPILER_ICC #define GB_COMPILER_ICC 1 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR __INTEL_COMPILER #define GB_COMPILER_MINOR __INTEL_COMPILER_UPDATE @@ -68,14 +58,8 @@ #elif defined ( __clang__ ) // clang - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 + #undef GB_COMPILER_CLANG #define GB_COMPILER_CLANG 1 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR __clang_major__ #define GB_COMPILER_MINOR __clang_minor__ @@ -85,14 +69,8 @@ #elif defined ( __xlC__ ) // xlc - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 + #undef GB_COMPILER_XLC #define GB_COMPILER_XLC 1 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR ( __xlC__ / 256 ) #define GB_COMPILER_MINOR ( __xlC__ - 256 * GB_COMPILER_MAJOR) @@ -102,14 +80,8 @@ #elif defined ( __GNUC__ ) // gcc - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 + #undef GB_COMPILER_GCC #define GB_COMPILER_GCC 1 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR __GNUC__ #define GB_COMPILER_MINOR __GNUC_MINOR__ @@ -119,55 +91,18 @@ #elif defined ( _MSC_VER ) - // Microsoft Visual Studio - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 + // Microsoft Visual Studio (cl compiler) + #undef GB_COMPILER_MSC #define GB_COMPILER_MSC 1 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 #define GB_COMPILER_MAJOR ( _MSC_VER / 100 ) #define GB_COMPILER_MINOR ( _MSC_VER - 100 * GB_COMPILER_MAJOR) #define GB_COMPILER_SUB 0 #define GB_COMPILER_NAME "Microsoft Visual Studio " GB_XSTR (_MSC_VER) -#elif defined ( __MINGW32__ ) || defined ( __MINGW64__ ) - - // MinGW (32-bit or 64-bit) - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 1 - - #if defined ( __MINGW32__ ) - #define GB_COMPILER_MAJOR ( __MINGW32_MAJOR_VERSION ) - #define GB_COMPILER_MINOR ( __MINGW32_MINOR_VERSION ) - #else - #define GB_COMPILER_MAJOR ( __MINGW64_MAJOR_VERSION ) - #define GB_COMPILER_MINOR ( __MINGW64_MINOR_VERSION ) - #endif - #define GB_COMPILER_SUB 0 - #define GB_COMPILER_NAME "MinGW" - #else // other compiler - #define GB_COMPILER_NVCC 0 - #define GB_COMPILER_ICX 0 - #define GB_COMPILER_ICC 0 - #define GB_COMPILER_CLANG 0 - #define GB_COMPILER_GCC 0 - #define GB_COMPILER_MSC 0 - #define GB_COMPILER_XLC 0 - #define GB_COMPILER_MINGW 0 - #define GB_COMPILER_MAJOR 0 #define GB_COMPILER_MINOR 0 #define GB_COMPILER_SUB 0 @@ -175,6 +110,30 @@ #endif +//------------------------------------------------------------------------------ +// MINGW system, for Windows +//------------------------------------------------------------------------------ + +#if defined ( __MINGW32__ ) + // MinGW (32-bit or 64-bit): using gcc, clang, or other compilers. + #define GB_MINGW 1 +#else + #define GB_MINGW 0 +#endif + +//------------------------------------------------------------------------------ +// Workaround for compiler bug in Microsoft Visual Studio 2019 +//------------------------------------------------------------------------------ + +// The GB_COMPILER_MSC_2019_OR_NEWER flag disables the FIRST_FC32 and +// SECOND_FC32 binary operators for the MS Visual Studio 2019 or newer compilers +// (MSC versions 19.20 or newer). It's possible that the compiler bug will be +// fixed in later versions of the MSC. In that case, an upper version bound +// should be added to this macro. + +#define GB_COMPILER_MSC_2019_OR_NEWER ( GB_COMPILER_MSC \ + && (GB_COMPILER_MAJOR == 19) && (GB_COMPILER_MINOR >= 20)) + //------------------------------------------------------------------------------ // malloc.h: required include file for Microsoft Visual Studio //------------------------------------------------------------------------------ diff --git a/deps/GraphBLAS/Source/GB_context.h b/deps/GraphBLAS/Source/GB_context.h index 66d3f52d7d..306439242a 100644 --- a/deps/GraphBLAS/Source/GB_context.h +++ b/deps/GraphBLAS/Source/GB_context.h @@ -110,7 +110,6 @@ typedef GB_Context_struct *GB_Context ; // GrB_error (&error, A) ; // printf ("%s", error) ; -GB_PUBLIC const char *GB_status_code (GrB_Info info) ; // maximum size of the error logger string diff --git a/deps/GraphBLAS/Source/GB_control.h b/deps/GraphBLAS/Source/GB_control.h index 950d2d94bd..a4dc7bd323 100644 --- a/deps/GraphBLAS/Source/GB_control.h +++ b/deps/GraphBLAS/Source/GB_control.h @@ -2392,4 +2392,3 @@ #define GxB_NO_TIMES_SECONDJ_INT64 1 #define GxB_NO_TIMES_SECONDJ1_INT32 1 #define GxB_NO_TIMES_SECONDJ1_INT64 1 - diff --git a/deps/GraphBLAS/Source/GB_convert.h b/deps/GraphBLAS/Source/GB_convert.h index fc96a336e2..cffc411fd6 100644 --- a/deps/GraphBLAS/Source/GB_convert.h +++ b/deps/GraphBLAS/Source/GB_convert.h @@ -62,7 +62,6 @@ static inline int GB_sparsity (GrB_Matrix A) } } -GB_PUBLIC GrB_Info GB_convert_hyper_to_sparse // convert hypersparse to sparse ( GrB_Matrix A, // matrix to convert from hypersparse to sparse @@ -70,7 +69,6 @@ GrB_Info GB_convert_hyper_to_sparse // convert hypersparse to sparse GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_convert_sparse_to_hyper // convert from sparse to hypersparse ( GrB_Matrix A, // matrix to convert to hypersparse @@ -150,7 +148,6 @@ GrB_Info GB_convert_any_to_bitmap // convert to bitmap GB_Context Context ) ; -GB_PUBLIC void GB_convert_any_to_full // convert any matrix to full ( GrB_Matrix A // matrix to convert to full diff --git a/deps/GraphBLAS/Source/GB_convert_any_to_full.c b/deps/GraphBLAS/Source/GB_convert_any_to_full.c index b77318dd40..a1d9b5cfd3 100644 --- a/deps/GraphBLAS/Source/GB_convert_any_to_full.c +++ b/deps/GraphBLAS/Source/GB_convert_any_to_full.c @@ -14,7 +14,6 @@ #include "GB.h" -GB_PUBLIC void GB_convert_any_to_full // convert any matrix to full ( GrB_Matrix A // matrix to convert to full diff --git a/deps/GraphBLAS/Source/GB_convert_hyper_to_sparse.c b/deps/GraphBLAS/Source/GB_convert_hyper_to_sparse.c index 4ace91d12e..060447ff3e 100644 --- a/deps/GraphBLAS/Source/GB_convert_hyper_to_sparse.c +++ b/deps/GraphBLAS/Source/GB_convert_hyper_to_sparse.c @@ -21,7 +21,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_convert_hyper_to_sparse // convert hypersparse to sparse ( GrB_Matrix A, // matrix to convert to non-hypersparse diff --git a/deps/GraphBLAS/Source/GB_cpu_features.h b/deps/GraphBLAS/Source/GB_cpu_features.h index 5e6d89d41b..95aaf8dd9e 100644 --- a/deps/GraphBLAS/Source/GB_cpu_features.h +++ b/deps/GraphBLAS/Source/GB_cpu_features.h @@ -59,7 +59,7 @@ // rely on Google's cpu_features package for run-time tests //------------------------------------------------------------------------------ -#if GB_COMPILER_MSC || GB_COMPILER_NVCC || GB_COMPILER_MINGW +#if defined (_WIN32) || GB_COMPILER_NVCC // entirely disable cpu_features for MS Visual Studio, nvcc, and MinGW #undef GBNCPUFEAT #define GBNCPUFEAT 1 diff --git a/deps/GraphBLAS/Source/GB_cumsum.c b/deps/GraphBLAS/Source/GB_cumsum.c index 83acdd2d6c..a8a71dc531 100644 --- a/deps/GraphBLAS/Source/GB_cumsum.c +++ b/deps/GraphBLAS/Source/GB_cumsum.c @@ -18,7 +18,6 @@ #include "GB.h" -GB_PUBLIC void GB_cumsum // cumulative sum of an array ( int64_t *restrict count, // size n+1, input/output diff --git a/deps/GraphBLAS/Source/GB_cumsum.h b/deps/GraphBLAS/Source/GB_cumsum.h index 9721f46124..f86d04d244 100644 --- a/deps/GraphBLAS/Source/GB_cumsum.h +++ b/deps/GraphBLAS/Source/GB_cumsum.h @@ -10,7 +10,6 @@ #ifndef GB_CUMSUM_H #define GB_CUMSUM_H -GB_PUBLIC void GB_cumsum // cumulative sum of an array ( int64_t *restrict count, // size n+1, input/output diff --git a/deps/GraphBLAS/Source/GB_dealloc_memory.c b/deps/GraphBLAS/Source/GB_dealloc_memory.c index c8d97da615..65852326fe 100644 --- a/deps/GraphBLAS/Source/GB_dealloc_memory.c +++ b/deps/GraphBLAS/Source/GB_dealloc_memory.c @@ -15,7 +15,6 @@ #include "GB.h" -GB_PUBLIC void GB_dealloc_memory // free memory, return to free_pool or free it ( // input/output @@ -27,6 +26,8 @@ void GB_dealloc_memory // free memory, return to free_pool or free it if (p != NULL && (*p) != NULL) { + +#if 0 bool returned_to_free_pool = false ; if (GB_IS_POWER_OF_TWO (size_allocated)) @@ -61,6 +62,22 @@ void GB_dealloc_memory // free memory, return to free_pool or free it #endif (*p) = NULL ; +#else + +// GB_free_memory (p, size_allocated) ; + + ASSERT (size_allocated == GB_Global_memtable_size (*p)) ; + #ifdef GB_MEMDUMP + printf ("\nhard free %p %ld\n", *p, size_allocated) ; + #endif + GB_Global_free_function (*p) ; + #ifdef GB_MEMDUMP + GB_Global_free_pool_dump (2) ; GB_Global_memtable_dump ( ) ; + #endif + (*p) = NULL ; + +#endif + } } diff --git a/deps/GraphBLAS/Source/GB_deserialize.c b/deps/GraphBLAS/Source/GB_deserialize.c index 71026dd3d0..c7f6a91cf2 100644 --- a/deps/GraphBLAS/Source/GB_deserialize.c +++ b/deps/GraphBLAS/Source/GB_deserialize.c @@ -51,10 +51,11 @@ GrB_Info GB_deserialize // deserialize a matrix from a blob return (GrB_INVALID_OBJECT) ; } - GB_BLOB_READ (blob_size2, size_t) ; + GB_BLOB_READ (blob_size2, uint64_t) ; GB_BLOB_READ (typecode, int32_t) ; + uint64_t blob_size1 = (uint64_t) blob_size ; - if (blob_size != blob_size2 + if (blob_size1 != blob_size2 || typecode < GB_BOOL_code || typecode > GB_UDT_code || (typecode == GB_UDT_code && blob_size < GB_BLOB_HEADER_SIZE + GxB_MAX_NAME_LEN)) diff --git a/deps/GraphBLAS/Source/GB_entry_check.c b/deps/GraphBLAS/Source/GB_entry_check.c index c09f7066e4..50c6c89569 100644 --- a/deps/GraphBLAS/Source/GB_entry_check.c +++ b/deps/GraphBLAS/Source/GB_entry_check.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_entry_check // print a single value ( const GrB_Type type, // type of value to print diff --git a/deps/GraphBLAS/Source/GB_free_memory.c b/deps/GraphBLAS/Source/GB_free_memory.c index 4cf4e7264c..c912cea1e9 100644 --- a/deps/GraphBLAS/Source/GB_free_memory.c +++ b/deps/GraphBLAS/Source/GB_free_memory.c @@ -14,7 +14,6 @@ #include "GB.h" -GB_PUBLIC void GB_free_memory // free memory, bypassing the free_pool ( // input/output diff --git a/deps/GraphBLAS/Source/GB_helper.h b/deps/GraphBLAS/Source/GB_helper.h index c359ac4f5d..2786d8353e 100644 --- a/deps/GraphBLAS/Source/GB_helper.h +++ b/deps/GraphBLAS/Source/GB_helper.h @@ -15,9 +15,8 @@ #include "GB.h" -GB_PUBLIC double GB_helper0 (void) ; +double GB_helper0 (void) ; -GB_PUBLIC void GB_helper1 // convert zero-based indices to one-based ( double *restrict I_double, // output array @@ -25,14 +24,12 @@ void GB_helper1 // convert zero-based indices to one-based int64_t nvals // size of input and output arrays ) ; -GB_PUBLIC void GB_helper1i // convert zero-based indices to one-based ( int64_t *restrict I, // input/output array int64_t nvals // size of input/output array ) ; -GB_PUBLIC bool GB_helper3 // return true if OK, false on error ( int64_t *restrict List, // size len, output array @@ -41,7 +38,6 @@ bool GB_helper3 // return true if OK, false on error int64_t *List_max // also compute the max entry in the list ) ; -GB_PUBLIC bool GB_helper3i // return true if OK, false on error ( int64_t *restrict List, // size len, output array @@ -50,7 +46,6 @@ bool GB_helper3i // return true if OK, false on error int64_t *List_max // also compute the max entry in the list ) ; -GB_PUBLIC bool GB_helper4 // return true if OK, false on error ( const GrB_Index *restrict I, // array of size len @@ -58,7 +53,6 @@ bool GB_helper4 // return true if OK, false on error GrB_Index *List_max // find max (I) + 1 ) ; -GB_PUBLIC void GB_helper5 // construct pattern of S ( GrB_Index *restrict Si, // array of size anz @@ -71,14 +65,12 @@ void GB_helper5 // construct pattern of S const GrB_Index anz ) ; -GB_PUBLIC void GB_helper7 // Kx = uint64 (0:mnz-1) ( uint64_t *restrict Kx, // array of size mnz const GrB_Index mnz ) ; -GB_PUBLIC void GB_helper8 ( GB_void *C, // output array of size nvals * s @@ -87,7 +79,6 @@ void GB_helper8 size_t s // size of each scalar ) ; -GB_PUBLIC double GB_helper10 // norm (x-y,p), or -1 on error ( GB_void *x_arg, // float or double, depending on type parameter diff --git a/deps/GraphBLAS/Source/GB_hyper.h b/deps/GraphBLAS/Source/GB_hyper.h index af5f515ffe..675323f70e 100644 --- a/deps/GraphBLAS/Source/GB_hyper.h +++ b/deps/GraphBLAS/Source/GB_hyper.h @@ -10,7 +10,6 @@ #ifndef GB_HYPER_H #define GB_HYPER_H -GB_PUBLIC int64_t GB_nvec_nonempty // return # of non-empty vectors ( const GrB_Matrix A, // input matrix to examine diff --git a/deps/GraphBLAS/Source/GB_hyper_hash_free.c b/deps/GraphBLAS/Source/GB_hyper_hash_free.c index f91309b224..9e66aa7b08 100644 --- a/deps/GraphBLAS/Source/GB_hyper_hash_free.c +++ b/deps/GraphBLAS/Source/GB_hyper_hash_free.c @@ -13,7 +13,6 @@ #include "GB.h" -GB_PUBLIC void GB_hyper_hash_free // free the A->Y hyper_hash of a matrix ( GrB_Matrix A // matrix with content to free diff --git a/deps/GraphBLAS/Source/GB_ij.h b/deps/GraphBLAS/Source/GB_ij.h index 7d5536d67b..93a3a2db08 100644 --- a/deps/GraphBLAS/Source/GB_ij.h +++ b/deps/GraphBLAS/Source/GB_ij.h @@ -12,7 +12,6 @@ #include "GB.h" -GB_PUBLIC void GB_ijlength // get the length and kind of an index list I ( const GrB_Index *I, // list of indices (actual or implicit) diff --git a/deps/GraphBLAS/Source/GB_is_shallow.c b/deps/GraphBLAS/Source/GB_is_shallow.c index 2706ecfcaa..5e34ae663a 100644 --- a/deps/GraphBLAS/Source/GB_is_shallow.c +++ b/deps/GraphBLAS/Source/GB_is_shallow.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC bool GB_is_shallow // true if any component of A is shallow ( GrB_Matrix A // matrix to query diff --git a/deps/GraphBLAS/Source/GB_iso.h b/deps/GraphBLAS/Source/GB_iso.h index 64d3e94dca..024bca73fd 100644 --- a/deps/GraphBLAS/Source/GB_iso.h +++ b/deps/GraphBLAS/Source/GB_iso.h @@ -41,7 +41,6 @@ void GB_iso_unop // Cx [0] = unop (A), binop (s,A) or binop (A,s) GrB_Scalar scalar // input scalar ) ; -GB_PUBLIC GrB_Info GB_convert_any_to_non_iso // convert iso matrix to non-iso ( GrB_Matrix A, // input/output matrix @@ -49,7 +48,6 @@ GrB_Info GB_convert_any_to_non_iso // convert iso matrix to non-iso GB_Context Contest ) ; -GB_PUBLIC GrB_Info GB_convert_any_to_iso // convert non-iso matrix to iso ( GrB_Matrix A, // input/output matrix @@ -66,7 +64,6 @@ void GB_iso_expand // expand an iso scalar into an entire array GB_Context Context ) ; -GB_PUBLIC bool GB_iso_check // return true if A is iso, false otherwise ( const GrB_Matrix A, // matrix to reduce diff --git a/deps/GraphBLAS/Source/GB_ix_realloc.c b/deps/GraphBLAS/Source/GB_ix_realloc.c index e38ebb082c..12c5f04650 100644 --- a/deps/GraphBLAS/Source/GB_ix_realloc.c +++ b/deps/GraphBLAS/Source/GB_ix_realloc.c @@ -13,7 +13,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_ix_realloc // reallocate space in a matrix ( GrB_Matrix A, // matrix to allocate space for diff --git a/deps/GraphBLAS/Source/GB_make_shallow.c b/deps/GraphBLAS/Source/GB_make_shallow.c index 69f86b084f..271157877b 100644 --- a/deps/GraphBLAS/Source/GB_make_shallow.c +++ b/deps/GraphBLAS/Source/GB_make_shallow.c @@ -10,7 +10,7 @@ #include "GB.h" #include "GB_make_shallow.h" -GB_PUBLIC void GB (make_shallow) (GrB_Matrix A) +void GB (make_shallow) (GrB_Matrix A) { if (A == NULL) return ; A->p_shallow = (A->p != NULL) ; diff --git a/deps/GraphBLAS/Source/GB_make_shallow.h b/deps/GraphBLAS/Source/GB_make_shallow.h index f3dde1029a..b4275874a9 100644 --- a/deps/GraphBLAS/Source/GB_make_shallow.h +++ b/deps/GraphBLAS/Source/GB_make_shallow.h @@ -9,6 +9,6 @@ #ifndef GB_MAKE_SHALLOW_H #define GB_MAKE_SHALLOW_H -GB_PUBLIC void GB (make_shallow) (GrB_Matrix A) ; +void GB (make_shallow) (GrB_Matrix A) ; #endif diff --git a/deps/GraphBLAS/Source/GB_malloc_memory.c b/deps/GraphBLAS/Source/GB_malloc_memory.c index 7db210239b..9945e75954 100644 --- a/deps/GraphBLAS/Source/GB_malloc_memory.c +++ b/deps/GraphBLAS/Source/GB_malloc_memory.c @@ -26,9 +26,10 @@ static inline void *GB_malloc_helper // determine the next higher power of 2 (*size) = GB_IMAX (*size, 8) ; - int k = GB_CEIL_LOG2 (*size) ; +#if 0 // if available, get the block from the pool + int k = GB_CEIL_LOG2 (*size) ; if (GB_Global_free_pool_limit_get (k) > 0) { // round up the size to the nearest power of two @@ -40,6 +41,7 @@ static inline void *GB_malloc_helper } if (p == NULL) +#endif { // no block in the free_pool, so allocate it p = GB_Global_malloc_function (*size) ; @@ -59,7 +61,6 @@ static inline void *GB_malloc_helper // GB_malloc_memory //------------------------------------------------------------------------------ -GB_PUBLIC void *GB_malloc_memory // pointer to allocated block of memory ( size_t nitems, // number of items to allocate @@ -85,7 +86,8 @@ void *GB_malloc_memory // pointer to allocated block of memory size_of_item = GB_IMAX (1, size_of_item) ; bool ok = GB_size_t_multiply (&size, nitems, size_of_item) ; - if (!ok || nitems > GB_NMAX || size_of_item > GB_NMAX) + if (!ok || (((uint64_t) nitems) > GB_NMAX) + || (((uint64_t) size_of_item) > GB_NMAX)) { // overflow (*size_allocated) = 0 ; diff --git a/deps/GraphBLAS/Source/GB_matvec_check.c b/deps/GraphBLAS/Source/GB_matvec_check.c index c8d9e096e7..373fd1936b 100644 --- a/deps/GraphBLAS/Source/GB_matvec_check.c +++ b/deps/GraphBLAS/Source/GB_matvec_check.c @@ -9,8 +9,8 @@ // for code development only: #ifdef GBCUDA -// CUDA kernels enabled: turn on developer flag -#define GB_DEVELOPER 1 +// when CUDA kernels enabled: +#define GB_DEVELOPER 0 #else // in production: turn off developer flag #define GB_DEVELOPER 0 @@ -20,7 +20,6 @@ #include "GB.h" #include "GB_hash.h" -GB_PUBLIC GrB_Info GB_matvec_check // check a GraphBLAS matrix or vector ( const GrB_Matrix A, // GraphBLAS matrix to print and check @@ -300,7 +299,7 @@ GrB_Info GB_matvec_check // check a GraphBLAS matrix or vector int64_t nallocs ; size_t mem_deep, mem_shallow, memsize ; - GB_memoryUsage (&nallocs, &mem_deep, &mem_shallow, A) ; + GB_memoryUsage (&nallocs, &mem_deep, &mem_shallow, A, true) ; memsize = mem_deep + (pr_mem_shallow ? mem_shallow : 0) ; #if GB_DEVELOPER diff --git a/deps/GraphBLAS/Source/GB_memory.h b/deps/GraphBLAS/Source/GB_memory.h index 9258277469..b28c402803 100644 --- a/deps/GraphBLAS/Source/GB_memory.h +++ b/deps/GraphBLAS/Source/GB_memory.h @@ -19,10 +19,10 @@ void GB_memoryUsage // count # allocated blocks and their sizes int64_t *nallocs, // # of allocated memory blocks size_t *mem_deep, // # of bytes in blocks owned by this matrix size_t *mem_shallow, // # of bytes in blocks owned by another matrix - const GrB_Matrix A // matrix to query + const GrB_Matrix A, // matrix to query + bool count_hyper_hash // if true, include A->Y ) ; -GB_PUBLIC void *GB_calloc_memory // pointer to allocated block of memory ( size_t nitems, // number of items to allocate @@ -32,7 +32,6 @@ void *GB_calloc_memory // pointer to allocated block of memory GB_Context Context ) ; -GB_PUBLIC void *GB_malloc_memory // pointer to allocated block of memory ( size_t nitems, // number of items to allocate @@ -41,7 +40,6 @@ void *GB_malloc_memory // pointer to allocated block of memory size_t *size_allocated // # of bytes actually allocated ) ; -GB_PUBLIC void *GB_realloc_memory // pointer to reallocated block of memory, or // to original block if the realloc failed. ( @@ -55,7 +53,6 @@ void *GB_realloc_memory // pointer to reallocated block of memory, or GB_Context Context ) ; -GB_PUBLIC void GB_free_memory // free memory, bypassing the free_pool ( // input/output @@ -64,7 +61,6 @@ void GB_free_memory // free memory, bypassing the free_pool size_t size_allocated // # of bytes actually allocated ) ; -GB_PUBLIC void GB_dealloc_memory // free memory, return to free_pool or free it ( // input/output @@ -73,7 +69,6 @@ void GB_dealloc_memory // free memory, return to free_pool or free it size_t size_allocated // # of bytes actually allocated ) ; -GB_PUBLIC void GB_free_pool_finalize (void) ; void *GB_xalloc_memory // return the newly-allocated space diff --git a/deps/GraphBLAS/Source/GB_memoryUsage.c b/deps/GraphBLAS/Source/GB_memoryUsage.c index d6aa2aef1f..ba1265cb5f 100644 --- a/deps/GraphBLAS/Source/GB_memoryUsage.c +++ b/deps/GraphBLAS/Source/GB_memoryUsage.c @@ -14,7 +14,8 @@ void GB_memoryUsage // count # allocated blocks and their sizes int64_t *nallocs, // # of allocated memory blocks size_t *mem_deep, // # of bytes in blocks owned by this matrix size_t *mem_shallow, // # of bytes in blocks owned by another matrix - const GrB_Matrix A // matrix to query + const GrB_Matrix A, // matrix to query + bool count_hyper_hash // if true, include A->Y ) { @@ -139,12 +140,12 @@ void GB_memoryUsage // count # allocated blocks and their sizes (*mem_deep) += Pending->x_size ; } - if (A->Y != NULL) + if (count_hyper_hash && A->Y != NULL) { int64_t Y_nallocs = 0 ; size_t Y_mem_deep = 0 ; size_t Y_mem_shallow = 0 ; - GB_memoryUsage (&Y_nallocs, &Y_mem_deep, &Y_mem_shallow, A->Y) ; + GB_memoryUsage (&Y_nallocs, &Y_mem_deep, &Y_mem_shallow, A->Y, false) ; if (A->Y_shallow) { // all of A->Y is shallow diff --git a/deps/GraphBLAS/Source/GB_msort_1.c b/deps/GraphBLAS/Source/GB_msort_1.c index ca226c2cd7..cd62da0eaf 100644 --- a/deps/GraphBLAS/Source/GB_msort_1.c +++ b/deps/GraphBLAS/Source/GB_msort_1.c @@ -282,7 +282,6 @@ static void GB_msort_1_merge // GB_msort_1: parallel mergesort //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_msort_1 // sort array A of size 1-by-n ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_msort_2.c b/deps/GraphBLAS/Source/GB_msort_2.c index 0c4e8e6b3b..b5269a6cc0 100644 --- a/deps/GraphBLAS/Source/GB_msort_2.c +++ b/deps/GraphBLAS/Source/GB_msort_2.c @@ -294,7 +294,6 @@ static void GB_msort_2_merge // GB_msort_2: parallel mergesort //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_msort_2 // sort array A of size 2-by-n, using 2 keys (A [0:1][]) ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_msort_3.c b/deps/GraphBLAS/Source/GB_msort_3.c index 0f30e32dd2..e48ba82f93 100644 --- a/deps/GraphBLAS/Source/GB_msort_3.c +++ b/deps/GraphBLAS/Source/GB_msort_3.c @@ -305,7 +305,6 @@ static void GB_msort_3_merge // GB_msort_3: parallel mergesort //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Info GB_msort_3 // sort array A of size 3-by-n, using 3 keys (A [0:2][]) ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_multiply.h b/deps/GraphBLAS/Source/GB_multiply.h index 9cb58829a8..045c7f0678 100644 --- a/deps/GraphBLAS/Source/GB_multiply.h +++ b/deps/GraphBLAS/Source/GB_multiply.h @@ -10,7 +10,6 @@ #ifndef GB_MULTIPLY_H #define GB_MULTIPLY_H -GB_PUBLIC bool GB_int64_multiply // true if ok, false if overflow ( GrB_Index *restrict c, // c = a*b, or zero if overflow occurs @@ -18,7 +17,6 @@ bool GB_int64_multiply // true if ok, false if overflow const int64_t b ) ; -GB_PUBLIC bool GB_size_t_multiply // true if ok, false if overflow ( size_t *c, // c = a*b, or zero if overflow occurs diff --git a/deps/GraphBLAS/Source/GB_mxm.h b/deps/GraphBLAS/Source/GB_mxm.h index 50cd22ded1..fb8076174d 100644 --- a/deps/GraphBLAS/Source/GB_mxm.h +++ b/deps/GraphBLAS/Source/GB_mxm.h @@ -50,7 +50,6 @@ GrB_Info GB_AxB_dot // dot product (multiple methods) GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_AxB_meta // C=A*B meta algorithm ( GrB_Matrix C, // output, static header (if not in-place) @@ -114,7 +113,6 @@ bool GB_AxB_semiring_builtin // true if semiring is builtin GB_Type_code *zcode // type code for z output ) ; -GB_PUBLIC GrB_Info GB_AxB_dot2 // C=A'*B or C=A'*B, dot product method ( GrB_Matrix C, // output matrix, static header @@ -137,7 +135,6 @@ bool GB_is_diagonal // true if A is diagonal GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_AxB_dot3 // C = A'*B using dot product method ( GrB_Matrix C, // output matrix, static header diff --git a/deps/GraphBLAS/Source/GB_new.c b/deps/GraphBLAS/Source/GB_new.c index 0429bec80d..9165b5b8fb 100644 --- a/deps/GraphBLAS/Source/GB_new.c +++ b/deps/GraphBLAS/Source/GB_new.c @@ -33,7 +33,6 @@ #include "GB.h" -GB_PUBLIC GrB_Info GB_new // create matrix, except for indices & values ( GrB_Matrix *Ahandle, // handle of matrix to create diff --git a/deps/GraphBLAS/Source/GB_new.h b/deps/GraphBLAS/Source/GB_new.h index 7667564f0d..ca935541ea 100644 --- a/deps/GraphBLAS/Source/GB_new.h +++ b/deps/GraphBLAS/Source/GB_new.h @@ -18,7 +18,6 @@ typedef enum // input parameter to GB_new and GB_new_bix } GB_Ap_code ; -GB_PUBLIC GrB_Info GB_Matrix_new // create a new matrix with no entries ( GrB_Matrix *A, // handle of matrix to create @@ -28,7 +27,6 @@ GrB_Info GB_Matrix_new // create a new matrix with no entries GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_new // create matrix, except for indices & values ( GrB_Matrix *Ahandle, // handle of matrix to create @@ -64,7 +62,6 @@ GrB_Info GB_new_bix // create a new matrix, incl. A->b, A->i, A->x GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_bix_alloc // allocate A->b, A->i, and A->x space in a matrix ( GrB_Matrix A, // matrix to allocate space for @@ -77,7 +74,6 @@ GrB_Info GB_bix_alloc // allocate A->b, A->i, and A->x space in a matrix GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_ix_realloc // reallocate space in a matrix ( GrB_Matrix A, // matrix to allocate space for @@ -85,19 +81,16 @@ GrB_Info GB_ix_realloc // reallocate space in a matrix GB_Context Context ) ; -GB_PUBLIC void GB_bix_free // free A->b, A->i, and A->x of a matrix ( GrB_Matrix A // matrix with content to free ) ; -GB_PUBLIC void GB_phy_free // free A->p, A->h, and A->Y of a matrix ( GrB_Matrix A // matrix with content to free ) ; -GB_PUBLIC void GB_hyper_hash_free // free the A->Y hyper_hash of a matrix ( GrB_Matrix A // matrix with content to free diff --git a/deps/GraphBLAS/Source/GB_nnz.h b/deps/GraphBLAS/Source/GB_nnz.h index ee33063ab5..8b24ab32eb 100644 --- a/deps/GraphBLAS/Source/GB_nnz.h +++ b/deps/GraphBLAS/Source/GB_nnz.h @@ -30,22 +30,22 @@ // GB_nnz(A): # of entries in any matrix: includes zombies for hypersparse // and sparse, but excluding entries flagged as not present in a bitmap. - GB_PUBLIC int64_t GB_nnz (GrB_Matrix A) ; + int64_t GB_nnz (GrB_Matrix A) ; // GB_nnz_full(A): # of entries in A if A is full - GB_PUBLIC int64_t GB_nnz_full (GrB_Matrix A) ; + int64_t GB_nnz_full (GrB_Matrix A) ; // GB_nnz_held(A): # of entries held in the data structure, including // zombies and all entries in a bitmap. For hypersparse, sparse, and full, // GB_nnz(A) and GB_nnz_held(A) are the same. For bitmap, GB_nnz_held(A) // is the same as the # of entries in a full matrix (# rows times # // columns). - GB_PUBLIC int64_t GB_nnz_held (GrB_Matrix A) ; + int64_t GB_nnz_held (GrB_Matrix A) ; // GB_nnz_max(A): max number of entries that can be held in a matrix. // For iso full matrices, GB_nnz_max(A) can be less than GB_nnz_full(A), // and is typically 1. - GB_PUBLIC int64_t GB_nnz_max (GrB_Matrix A) ; + int64_t GB_nnz_max (GrB_Matrix A) ; #endif diff --git a/deps/GraphBLAS/Source/GB_nvec_nonempty.c b/deps/GraphBLAS/Source/GB_nvec_nonempty.c index e0cd93a434..68b2ec233a 100644 --- a/deps/GraphBLAS/Source/GB_nvec_nonempty.c +++ b/deps/GraphBLAS/Source/GB_nvec_nonempty.c @@ -12,7 +12,6 @@ #include "GB.h" -GB_PUBLIC int64_t GB_nvec_nonempty // return # of non-empty vectors ( const GrB_Matrix A, // input matrix to examine diff --git a/deps/GraphBLAS/Source/GB_op.h b/deps/GraphBLAS/Source/GB_op.h index f9afb4d2a8..cde438f6a1 100644 --- a/deps/GraphBLAS/Source/GB_op.h +++ b/deps/GraphBLAS/Source/GB_op.h @@ -15,7 +15,6 @@ GrB_Info GB_Op_free // free a user-created op GB_Operator *op_handle // handle of operator to free ) ; -GB_PUBLIC bool GB_op_is_second // return true if op is SECOND, of the right type ( GrB_BinaryOp op, diff --git a/deps/GraphBLAS/Source/GB_op_is_second.c b/deps/GraphBLAS/Source/GB_op_is_second.c index acf25f9b06..82d7db20d9 100644 --- a/deps/GraphBLAS/Source/GB_op_is_second.c +++ b/deps/GraphBLAS/Source/GB_op_is_second.c @@ -9,7 +9,6 @@ #include "GB.h" -GB_PUBLIC bool GB_op_is_second // return true if op is SECOND, of the right type ( GrB_BinaryOp op, diff --git a/deps/GraphBLAS/Source/GB_opaque.h b/deps/GraphBLAS/Source/GB_opaque.h index e6cd65a265..f7a9705561 100644 --- a/deps/GraphBLAS/Source/GB_opaque.h +++ b/deps/GraphBLAS/Source/GB_opaque.h @@ -364,7 +364,7 @@ int64_t GB_positional_offset // return the positional thunk ) ; // for internal use only -GB_PUBLIC GrB_IndexUnaryOp GxB_FLIPDIAGINDEX_INT32, GxB_FLIPDIAGINDEX_INT64 ; +GB_GLOBAL GrB_IndexUnaryOp GxB_FLIPDIAGINDEX_INT32, GxB_FLIPDIAGINDEX_INT64 ; //------------------------------------------------------------------------------ // opaque content of GraphBLAS objects diff --git a/deps/GraphBLAS/Source/GB_phy_free.c b/deps/GraphBLAS/Source/GB_phy_free.c index f043fca9af..f3aa217cde 100644 --- a/deps/GraphBLAS/Source/GB_phy_free.c +++ b/deps/GraphBLAS/Source/GB_phy_free.c @@ -13,7 +13,6 @@ #include "GB.h" -GB_PUBLIC void GB_phy_free // free A->p, A->h, and A->Y of a matrix ( GrB_Matrix A // matrix with content to free diff --git a/deps/GraphBLAS/Source/GB_pslice.c b/deps/GraphBLAS/Source/GB_pslice.c index 413dab1189..aaa42d64b1 100644 --- a/deps/GraphBLAS/Source/GB_pslice.c +++ b/deps/GraphBLAS/Source/GB_pslice.c @@ -113,7 +113,6 @@ static void GB_pslice_worker // GB_pslice: partition Ap for a set of tasks //------------------------------------------------------------------------------ -GB_PUBLIC void GB_pslice // slice Ap ( int64_t *restrict Slice, // size ntasks+1 diff --git a/deps/GraphBLAS/Source/GB_qsort_1.c b/deps/GraphBLAS/Source/GB_qsort_1.c index d056863b42..5b5ecbf1ea 100644 --- a/deps/GraphBLAS/Source/GB_qsort_1.c +++ b/deps/GraphBLAS/Source/GB_qsort_1.c @@ -39,7 +39,6 @@ #include "GB_qsort_template.c" -GB_PUBLIC void GB_qsort_1 // sort array A of size 1-by-n ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_qsort_1b.c b/deps/GraphBLAS/Source/GB_qsort_1b.c index da9e9ba4d7..e3af53c197 100644 --- a/deps/GraphBLAS/Source/GB_qsort_1b.c +++ b/deps/GraphBLAS/Source/GB_qsort_1b.c @@ -48,7 +48,6 @@ #include "GB_qsort_template.c" -GB_PUBLIC void GB_qsort_1b // sort array A of size 2-by-n, using 1 key (A [0][]) ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_qsort_2.c b/deps/GraphBLAS/Source/GB_qsort_2.c index 94102076bf..e7eb43b710 100644 --- a/deps/GraphBLAS/Source/GB_qsort_2.c +++ b/deps/GraphBLAS/Source/GB_qsort_2.c @@ -41,7 +41,6 @@ #include "GB_qsort_template.c" -GB_PUBLIC void GB_qsort_2 // sort array A of size 2-by-n, using 2 keys (A [0:1][]) ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_qsort_3.c b/deps/GraphBLAS/Source/GB_qsort_3.c index a292cea970..f093ad4f55 100644 --- a/deps/GraphBLAS/Source/GB_qsort_3.c +++ b/deps/GraphBLAS/Source/GB_qsort_3.c @@ -43,7 +43,6 @@ #include "GB_qsort_template.c" -GB_PUBLIC void GB_qsort_3 // sort array A of size 3-by-n, using 3 keys (A [0:2][]) ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_realloc_memory.c b/deps/GraphBLAS/Source/GB_realloc_memory.c index 708c7f11e8..24512c0798 100644 --- a/deps/GraphBLAS/Source/GB_realloc_memory.c +++ b/deps/GraphBLAS/Source/GB_realloc_memory.c @@ -40,7 +40,6 @@ #include "GB.h" -GB_PUBLIC void *GB_realloc_memory // pointer to reallocated block of memory, or // to original block if the reallocation failed. ( @@ -84,7 +83,8 @@ void *GB_realloc_memory // pointer to reallocated block of memory, or (*ok) = GB_size_t_multiply (&newsize, nitems_new, size_of_item) && GB_size_t_multiply (&oldsize, nitems_old, size_of_item) ; - if (!(*ok) || nitems_new > GB_NMAX || size_of_item > GB_NMAX) + if (!(*ok) || (((uint64_t) nitems_new) > GB_NMAX) + || (((uint64_t) size_of_item) > GB_NMAX)) { // overflow (*ok) = false ; @@ -112,9 +112,9 @@ void *GB_realloc_memory // pointer to reallocated block of memory, or void *pnew = NULL ; size_t newsize_allocated = GB_IMAX (newsize, 8) ; - int k = GB_CEIL_LOG2 (newsize_allocated) ; - if (!GB_Global_have_realloc_function ( ) || - (GB_Global_free_pool_limit_get (k) > 0)) +// int k = GB_CEIL_LOG2 (newsize_allocated) ; + if (!GB_Global_have_realloc_function ( ) /* || + (GB_Global_free_pool_limit_get (k) > 0) */) { //---------------------------------------------------------------------- diff --git a/deps/GraphBLAS/Source/GB_serialize.c b/deps/GraphBLAS/Source/GB_serialize.c index 24be802d41..f42ba67e6e 100644 --- a/deps/GraphBLAS/Source/GB_serialize.c +++ b/deps/GraphBLAS/Source/GB_serialize.c @@ -156,7 +156,7 @@ GrB_Info GB_serialize // serialize a matrix into a blob ASSERT (A->nzombies == 0) ; ASSERT (!A->jumbled) ; GrB_Type atype = A->type ; - size_t typesize = atype->size ; + int64_t typesize = atype->size ; int32_t typecode = (int32_t) (atype->code) ; int64_t anz = GB_nnz (A) ; int64_t anz_held = GB_nnz_held (A) ; @@ -298,7 +298,11 @@ GrB_Info GB_serialize // serialize a matrix into a blob int32_t sparsity_iso_csc = (4 * sparsity) + (iso ? 2 : 0) + (A->is_csc ? 1 : 0) ; - GB_BLOB_WRITE (blob_size_required, size_t) ; + // size_t is 32 bits if GraphBLAS is compiled in ILP32 mode, + // so write a 64-bit blob size, regardless of the size of size_t + uint64_t blob_size_required64 = (uint64_t) blob_size_required ; + GB_BLOB_WRITE (blob_size_required64, uint64_t) ; + GB_BLOB_WRITE (typecode, int32_t) ; GB_BLOB_WRITE (version, int32_t) ; GB_BLOB_WRITE (vlen, int64_t) ; diff --git a/deps/GraphBLAS/Source/GB_serialize.h b/deps/GraphBLAS/Source/GB_serialize.h index 8abe791ae6..cc727ea20d 100644 --- a/deps/GraphBLAS/Source/GB_serialize.h +++ b/deps/GraphBLAS/Source/GB_serialize.h @@ -107,7 +107,7 @@ GrB_Info GB_deserialize_from_blob ) ; #define GB_BLOB_HEADER_SIZE \ - sizeof (size_t) /* blob_size */ \ + sizeof (uint64_t) /* blob_size */ \ + 11 * sizeof (int64_t) /* vlen, vdim, nvec, nvec_nonempty, */ \ /* nvals, typesize, A[phbix]_len */ \ + 14 * sizeof (int32_t) /* version, typecode, sparsity_control, */ \ diff --git a/deps/GraphBLAS/Source/GB_shallow_copy.c b/deps/GraphBLAS/Source/GB_shallow_copy.c index 44aa73df3a..26989b4857 100644 --- a/deps/GraphBLAS/Source/GB_shallow_copy.c +++ b/deps/GraphBLAS/Source/GB_shallow_copy.c @@ -28,7 +28,6 @@ #define GB_FREE_ALL ; -GB_PUBLIC GrB_Info GB_shallow_copy // create a purely shallow matrix ( GrB_Matrix C, // output matrix C, with a static header diff --git a/deps/GraphBLAS/Source/GB_shallow_op.c b/deps/GraphBLAS/Source/GB_shallow_op.c index 24260911f9..ff28cdd17c 100644 --- a/deps/GraphBLAS/Source/GB_shallow_op.c +++ b/deps/GraphBLAS/Source/GB_shallow_op.c @@ -28,7 +28,6 @@ #define GB_FREE_ALL GB_phybix_free (C) ; -GB_PUBLIC GrB_Info GB_shallow_op // create shallow matrix and apply operator ( GrB_Matrix C, // output C, of type op*->ztype, static header diff --git a/deps/GraphBLAS/Source/GB_size_t_multiply.c b/deps/GraphBLAS/Source/GB_size_t_multiply.c index 68be4d06b6..2ab0828238 100644 --- a/deps/GraphBLAS/Source/GB_size_t_multiply.c +++ b/deps/GraphBLAS/Source/GB_size_t_multiply.c @@ -11,7 +11,6 @@ #include "GB.h" -GB_PUBLIC bool GB_size_t_multiply // true if ok, false if overflow ( size_t *c, // c = a*b, or zero if overflow occurs diff --git a/deps/GraphBLAS/Source/GB_slice.h b/deps/GraphBLAS/Source/GB_slice.h index 60ddaa5fa5..87fccb5d05 100644 --- a/deps/GraphBLAS/Source/GB_slice.h +++ b/deps/GraphBLAS/Source/GB_slice.h @@ -10,7 +10,6 @@ #ifndef GB_SLICE_H #define GB_SLICE_H -GB_PUBLIC void GB_pslice // slice Ap ( int64_t *restrict Slice, // size ntasks+1 diff --git a/deps/GraphBLAS/Source/GB_sort.h b/deps/GraphBLAS/Source/GB_sort.h index 0e0fb7a094..ab01a44076 100644 --- a/deps/GraphBLAS/Source/GB_sort.h +++ b/deps/GraphBLAS/Source/GB_sort.h @@ -18,7 +18,6 @@ #define GB_BASECASE (64 * 1024) -GB_PUBLIC void GB_qsort_1b // sort array A of size 2-by-n, using 1 key (A [0][]) ( int64_t *restrict A_0, // size n array @@ -62,14 +61,12 @@ void GB_qsort_1b_size16 // GB_qsort_1b with A_1 with sizeof = 16 const int64_t n ) ; -GB_PUBLIC void GB_qsort_1 // sort array A of size 1-by-n ( int64_t *restrict A_0, // size n array const int64_t n ) ; -GB_PUBLIC void GB_qsort_2 // sort array A of size 2-by-n, using 2 keys (A [0:1][]) ( int64_t *restrict A_0, // size n array @@ -77,7 +74,6 @@ void GB_qsort_2 // sort array A of size 2-by-n, using 2 keys (A [0:1][]) const int64_t n ) ; -GB_PUBLIC void GB_qsort_3 // sort array A of size 3-by-n, using 3 keys (A [0:2][]) ( int64_t *restrict A_0, // size n array @@ -86,7 +82,6 @@ void GB_qsort_3 // sort array A of size 3-by-n, using 3 keys (A [0:2][]) const int64_t n ) ; -GB_PUBLIC GrB_Info GB_msort_1 // sort array A of size 1-by-n ( int64_t *restrict A_0, // size n array @@ -94,7 +89,6 @@ GrB_Info GB_msort_1 // sort array A of size 1-by-n int nthreads // # of threads to use ) ; -GB_PUBLIC GrB_Info GB_msort_2 // sort array A of size 2-by-n, using 2 keys (A [0:1][]) ( int64_t *restrict A_0, // size n array @@ -103,7 +97,6 @@ GrB_Info GB_msort_2 // sort array A of size 2-by-n, using 2 keys (A [0:1][]) int nthreads // # of threads to use ) ; -GB_PUBLIC GrB_Info GB_msort_3 // sort array A of size 3-by-n, using 3 keys (A [0:2][]) ( int64_t *restrict A_0, // size n array diff --git a/deps/GraphBLAS/Source/GB_status_code.c b/deps/GraphBLAS/Source/GB_status_code.c index 3515c3bd4b..29de7a169e 100644 --- a/deps/GraphBLAS/Source/GB_status_code.c +++ b/deps/GraphBLAS/Source/GB_status_code.c @@ -11,7 +11,6 @@ #include "GB.h" -GB_PUBLIC const char *GB_status_code (GrB_Info info) { switch (info) diff --git a/deps/GraphBLAS/Source/GB_subref.c b/deps/GraphBLAS/Source/GB_subref.c index 2fd3b5f202..1376cb02b9 100644 --- a/deps/GraphBLAS/Source/GB_subref.c +++ b/deps/GraphBLAS/Source/GB_subref.c @@ -88,7 +88,6 @@ #include "GB_subref.h" -GB_PUBLIC GrB_Info GB_subref // C = A(I,J): either symbolic or numeric ( // output diff --git a/deps/GraphBLAS/Source/GB_subref.h b/deps/GraphBLAS/Source/GB_subref.h index 58fa6d8297..7822bd9ae8 100644 --- a/deps/GraphBLAS/Source/GB_subref.h +++ b/deps/GraphBLAS/Source/GB_subref.h @@ -11,7 +11,6 @@ #define GB_SUBREF_H #include "GB_ij.h" -GB_PUBLIC GrB_Info GB_subref // C = A(I,J): either symbolic or numeric ( // output diff --git a/deps/GraphBLAS/Source/GB_task_struct.h b/deps/GraphBLAS/Source/GB_task_struct.h index 3fca55cdbb..a9d4036802 100644 --- a/deps/GraphBLAS/Source/GB_task_struct.h +++ b/deps/GraphBLAS/Source/GB_task_struct.h @@ -101,7 +101,6 @@ GrB_Info GB_ewise_slice GB_Context Context ) ; -GB_PUBLIC void GB_slice_vector ( // output: return i, pA, and pB diff --git a/deps/GraphBLAS/Source/GB_transpose.h b/deps/GraphBLAS/Source/GB_transpose.h index 5f0745de3a..7b712b4cc9 100644 --- a/deps/GraphBLAS/Source/GB_transpose.h +++ b/deps/GraphBLAS/Source/GB_transpose.h @@ -35,7 +35,6 @@ GrB_Info GB_transpose // C=A', C=(ctype)A' or C=op(A') GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_transpose_in_place // C=A', no change of type, no operators ( GrB_Matrix C, // output matrix C, possibly modified in-place @@ -98,7 +97,6 @@ void GB_transpose_op // transpose, typecast, and apply operator to a matrix int nthreads // # of threads to use ) ; -GB_PUBLIC GrB_Info GB_shallow_copy // create a purely shallow matrix ( GrB_Matrix C, // output matrix C, with a static header diff --git a/deps/GraphBLAS/Source/GB_type.h b/deps/GraphBLAS/Source/GB_type.h index 5aedf9e561..14a765c3f1 100644 --- a/deps/GraphBLAS/Source/GB_type.h +++ b/deps/GraphBLAS/Source/GB_type.h @@ -25,21 +25,18 @@ GrB_Info GB_matvec_type_name // return the name of the type of a matrix GB_Context Context ) ; -GB_PUBLIC size_t GB_code_size // return the size of a type, given its code ( const GB_Type_code code, // input code of the type to find the size of const size_t usize // known size of user-defined type ) ; -GB_PUBLIC GrB_Type GB_code_type // return the GrB_Type corresponding to the code ( const GB_Type_code code, // type code to convert const GrB_Type type // user type if code is GB_UDT_code ) ; -GB_PUBLIC char *GB_code_string // return a static string for a type name ( const GB_Type_code code // code to convert to string diff --git a/deps/GraphBLAS/Source/GB_wait.c b/deps/GraphBLAS/Source/GB_wait.c index 86d86803fc..82687b4e66 100644 --- a/deps/GraphBLAS/Source/GB_wait.c +++ b/deps/GraphBLAS/Source/GB_wait.c @@ -56,7 +56,6 @@ #include "GB_jappend.h" #include "GB_atomics.h" -GB_PUBLIC GrB_Info GB_wait // finish all pending computations ( GrB_Matrix A, // matrix with pending computations diff --git a/deps/GraphBLAS/Source/GB_wait.h b/deps/GraphBLAS/Source/GB_wait.h index b6bae1a07e..b67f9599cb 100644 --- a/deps/GraphBLAS/Source/GB_wait.h +++ b/deps/GraphBLAS/Source/GB_wait.h @@ -10,14 +10,12 @@ #ifndef GB_WAIT_H #define GB_WAIT_H -GB_PUBLIC GrB_Info GB_block // apply all pending computations if blocking mode enabled ( GrB_Matrix A, GB_Context Context ) ; -GB_PUBLIC GrB_Info GB_wait // finish all pending computations ( GrB_Matrix A, // matrix with pending computations diff --git a/deps/GraphBLAS/Source/Generated2/GB_binop__first_fc32.c b/deps/GraphBLAS/Source/Generated2/GB_binop__first_fc32.c index 970f661bb5..de4edb9247 100644 --- a/deps/GraphBLAS/Source/Generated2/GB_binop__first_fc32.c +++ b/deps/GraphBLAS/Source/Generated2/GB_binop__first_fc32.c @@ -118,7 +118,7 @@ // disable this operator and use the generic case if these conditions hold #define GB_DISABLE \ - (GxB_NO_FIRST || GxB_NO_FC32 || GxB_NO_FIRST_FC32) + (GxB_NO_FIRST || GxB_NO_FC32 || GxB_NO_FIRST_FC32 || GB_COMPILER_MSC_2019_OR_NEWER) //------------------------------------------------------------------------------ // C += A+B, all 3 matrices dense diff --git a/deps/GraphBLAS/Source/Generated2/GB_binop__second_fc32.c b/deps/GraphBLAS/Source/Generated2/GB_binop__second_fc32.c index 243adbfea9..e607d20029 100644 --- a/deps/GraphBLAS/Source/Generated2/GB_binop__second_fc32.c +++ b/deps/GraphBLAS/Source/Generated2/GB_binop__second_fc32.c @@ -118,7 +118,7 @@ // disable this operator and use the generic case if these conditions hold #define GB_DISABLE \ - (GxB_NO_SECOND || GxB_NO_FC32 || GxB_NO_SECOND_FC32) + (GxB_NO_SECOND || GxB_NO_FC32 || GxB_NO_SECOND_FC32 || GB_COMPILER_MSC_2019_OR_NEWER) //------------------------------------------------------------------------------ // C += A+B, all 3 matrices dense diff --git a/deps/GraphBLAS/Source/GrB_Matrix_assign_scalar.c b/deps/GraphBLAS/Source/GrB_Matrix_assign_scalar.c index e4d8aa6936..e0940ee75b 100644 --- a/deps/GraphBLAS/Source/GrB_Matrix_assign_scalar.c +++ b/deps/GraphBLAS/Source/GrB_Matrix_assign_scalar.c @@ -80,7 +80,6 @@ GB_ASSIGN_SCALAR (GrB, void * , UDT , ) #define GB_FREE_ALL GB_Matrix_free (&S) ; #include "GB_static_header.h" -GB_PUBLIC GrB_Info GrB_Matrix_assign_Scalar // C(I,J) = accum (C(I,J),s) ( GrB_Matrix C, // input/output matrix for results diff --git a/deps/GraphBLAS/Source/GrB_Matrix_removeElement.c b/deps/GraphBLAS/Source/GrB_Matrix_removeElement.c index 113859492f..67b0f908dd 100644 --- a/deps/GraphBLAS/Source/GrB_Matrix_removeElement.c +++ b/deps/GraphBLAS/Source/GrB_Matrix_removeElement.c @@ -9,7 +9,6 @@ // Removes a single entry, C (row,col), from the matrix C. -#define GB_DEBUG #include "GB.h" #define GB_FREE_ALL ; diff --git a/deps/GraphBLAS/Source/GrB_Vector_assign_scalar.c b/deps/GraphBLAS/Source/GrB_Vector_assign_scalar.c index 15c59713b2..e349fadaa9 100644 --- a/deps/GraphBLAS/Source/GrB_Vector_assign_scalar.c +++ b/deps/GraphBLAS/Source/GrB_Vector_assign_scalar.c @@ -73,7 +73,6 @@ GB_ASSIGN_SCALAR (GrB, void * , UDT , ) #define GB_FREE_ALL GB_Matrix_free (&S) ; #include "GB_static_header.h" -GB_PUBLIC GrB_Info GrB_Vector_assign_Scalar // w(I) = accum (w(I),s) ( GrB_Vector w, // input/output matrix for results diff --git a/deps/GraphBLAS/Source/GxB_Desc_get.c b/deps/GraphBLAS/Source/GxB_Desc_get.c index db5d29e89f..85bbbb4a02 100644 --- a/deps/GraphBLAS/Source/GxB_Desc_get.c +++ b/deps/GraphBLAS/Source/GxB_Desc_get.c @@ -7,8 +7,143 @@ //------------------------------------------------------------------------------ +// GxB_Desc_get is a single va_arg-based method for any descriptor option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Desc_get_INT32 int32_t scalars +// GxB_Desc_get_FP64 double scalars + #include "GB.h" +//------------------------------------------------------------------------------ +// GxB_Desc_get_INT32: get a descriptor option (int32_t) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Desc_get_INT32 // get a parameter from a descriptor +( + GrB_Descriptor desc, // descriptor to query; NULL is ok + GrB_Desc_Field field, // parameter to query + int32_t *value // return value of the descriptor +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Desc_get_INT32 (desc, field, &value)") ; + GB_RETURN_IF_FAULTY (desc) ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the parameter + //-------------------------------------------------------------------------- + + switch (field) + { + case GrB_OUTP : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->out) ; + break ; + + case GrB_MASK : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->mask) ; + break ; + + case GrB_INP0 : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->in0) ; + break ; + + case GrB_INP1 : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->in1) ; + break ; + + case GxB_DESCRIPTOR_NTHREADS : // DEPRECATED + + (*value) = (int32_t) ((desc == NULL) ? + GxB_DEFAULT : desc->nthreads_max) ; + break ; + + case GxB_AxB_METHOD : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->axb) ; + break ; + + case GxB_SORT : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->do_sort); + break ; + + case GxB_COMPRESSION : + + (*value) = (int32_t) ((desc == NULL) ? + GxB_DEFAULT : desc->compression) ; + break ; + + case GxB_IMPORT : + + (*value) = (int32_t) ((desc == NULL) ? GxB_DEFAULT : desc->import) ; + if ((*value) != GxB_DEFAULT) (*value) = GxB_SECURE_IMPORT ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Desc_get_FP64: get a descriptor option (double) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Desc_get_FP64 // get a parameter from a descriptor +( + GrB_Descriptor desc, // descriptor to query; NULL is ok + GrB_Desc_Field field, // parameter to query + double *value // return value of the descriptor +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Desc_get_FP64 (desc, field, &value)") ; + GB_RETURN_IF_FAULTY (desc) ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the parameter + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_DESCRIPTOR_CHUNK : // DEPRECATED + + (*value) = (double) ((desc == NULL) ? GxB_DEFAULT : desc->chunk) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Desc_get: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Desc_get // get a parameter from a descriptor ( GrB_Descriptor desc, // descriptor to query; NULL is ok @@ -76,7 +211,7 @@ GrB_Info GxB_Desc_get // get a parameter from a descriptor } break ; - case GxB_DESCRIPTOR_NTHREADS : // same as GxB_NTHREADS + case GxB_DESCRIPTOR_NTHREADS : // DEPRECATED { va_start (ap, field) ; @@ -88,7 +223,7 @@ GrB_Info GxB_Desc_get // get a parameter from a descriptor } break ; - case GxB_DESCRIPTOR_CHUNK : // same as GxB_CHUNK + case GxB_DESCRIPTOR_CHUNK : // DEPRECATED { va_start (ap, field) ; @@ -110,7 +245,7 @@ GrB_Info GxB_Desc_get // get a parameter from a descriptor } break ; - case GxB_SORT : + case GxB_SORT : { va_start (ap, field) ; diff --git a/deps/GraphBLAS/Source/GxB_Desc_set.c b/deps/GraphBLAS/Source/GxB_Desc_set.c index 7743cd3817..af37234346 100644 --- a/deps/GraphBLAS/Source/GxB_Desc_set.c +++ b/deps/GraphBLAS/Source/GxB_Desc_set.c @@ -12,8 +12,211 @@ // in the spec, the type is the same as GrB_Descriptor_set (a scalar of // type GrB_Desc_Value). +// GxB_Desc_set is a single va_arg-based method for any descriptor option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Desc_set_INT32 int32_t scalars +// GxB_Desc_set_FP64 double scalars + #include "GB.h" +//------------------------------------------------------------------------------ +// GxB_Desc_set_INT32: set a descriptor option (int32_t) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Desc_set_INT32 // set a parameter in a descriptor +( + GrB_Descriptor desc, // descriptor to modify + GrB_Desc_Field field, // parameter to change + int32_t value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + if (desc != NULL && desc->header_size == 0) + { + // built-in descriptors may not be modified + return (GrB_INVALID_VALUE) ; + } + + GB_WHERE (desc, "GxB_Desc_set_INT32 (desc, field, value)") ; + GB_RETURN_IF_NULL_OR_FAULTY (desc) ; + ASSERT_DESCRIPTOR_OK (desc, "desc to set", GB0) ; + + //-------------------------------------------------------------------------- + // set the parameter + //-------------------------------------------------------------------------- + + int mask = (int) desc->mask ; + + switch (field) + { + + case GrB_OUTP : + + if (! (value == GxB_DEFAULT || value == GrB_REPLACE)) + { + GB_ERROR (GrB_INVALID_VALUE, + "invalid descriptor value [%d] for GrB_OUTP field;\n" + "must be GxB_DEFAULT [%d] or GrB_REPLACE [%d]", + value, (int) GxB_DEFAULT, (int) GrB_REPLACE) ; + } + desc->out = (GrB_Desc_Value) value ; + break ; + + case GrB_MASK : + + if (! (value == GxB_DEFAULT || + value == GrB_COMP || + value == GrB_STRUCTURE || + value == (GrB_COMP + GrB_STRUCTURE))) + { + GB_ERROR (GrB_INVALID_VALUE, + "invalid descriptor value [%d] for GrB_MASK field;\n" + "must be GxB_DEFAULT [%d], GrB_COMP [%d],\n" + "GrB_STRUCTURE [%d], or GrB_COMP+GrB_STRUCTURE [%d]", + value, (int) GxB_DEFAULT, (int) GrB_COMP, + (int) GrB_STRUCTURE, + (int) (GrB_COMP + GrB_STRUCTURE)) ; + } + int mask = (int) desc->mask ; + switch (value) + { + case GrB_COMP : mask |= GrB_COMP ; break ; + case GrB_STRUCTURE : mask |= GrB_STRUCTURE ; break ; + default : mask = value ; break ; + } + desc->mask = (GrB_Desc_Value) mask ; + break ; + + case GrB_INP0 : + + if (! (value == GxB_DEFAULT || value == GrB_TRAN)) + { + GB_ERROR (GrB_INVALID_VALUE, + "invalid descriptor value [%d] for GrB_INP0 field;\n" + "must be GxB_DEFAULT [%d] or GrB_TRAN [%d]", + value, (int) GxB_DEFAULT, (int) GrB_TRAN) ; + } + desc->in0 = (GrB_Desc_Value) value ; + break ; + + case GrB_INP1 : + + if (! (value == GxB_DEFAULT || value == GrB_TRAN)) + { + GB_ERROR (GrB_INVALID_VALUE, + "invalid descriptor value [%d] for GrB_INP1 field;\n" + "must be GxB_DEFAULT [%d] or GrB_TRAN [%d]", + value, (int) GxB_DEFAULT, (int) GrB_TRAN) ; + } + desc->in1 = (GrB_Desc_Value) value ; + break ; + + case GxB_DESCRIPTOR_NTHREADS : // DEPRECATED + + desc->nthreads_max = value ; + break ; + + case GxB_AxB_METHOD : + + if (! (value == GxB_DEFAULT || value == GxB_AxB_GUSTAVSON + || value == GxB_AxB_DOT + || value == GxB_AxB_HASH || value == GxB_AxB_SAXPY)) + { + GB_ERROR (GrB_INVALID_VALUE, + "invalid descriptor value [%d] for GrB_AxB_METHOD" + " field;\nmust be GxB_DEFAULT [%d], GxB_AxB_GUSTAVSON" + " [%d]\nGxB_AxB_DOT [%d]" + " GxB_AxB_HASH [%d] or GxB_AxB_SAXPY [%d]", + value, (int) GxB_DEFAULT, (int) GxB_AxB_GUSTAVSON, + (int) GxB_AxB_DOT, + (int) GxB_AxB_HASH, (int) GxB_AxB_SAXPY) ; + } + desc->axb = (GrB_Desc_Value) value ; + break ; + + case GxB_SORT : + + desc->do_sort = value ; + break ; + + case GxB_COMPRESSION : + + desc->compression = value ; + break ; + + case GxB_IMPORT : + + // In case the user application does not check the return value + // of this method, an error condition is never returned. + desc->import = + (value == GxB_DEFAULT) ? GxB_FAST_IMPORT : GxB_SECURE_IMPORT ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Desc_set_FP64: set a descriptor option (double scalar) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Desc_set_FP64 // set a parameter in a descriptor +( + GrB_Descriptor desc, // descriptor to modify + GrB_Desc_Field field, // parameter to change + double value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + if (desc != NULL && desc->header_size == 0) + { + // built-in descriptors may not be modified + return (GrB_INVALID_VALUE) ; + } + + GB_WHERE (desc, "GxB_Desc_set_FP64 (desc, field, value)") ; + GB_RETURN_IF_NULL_OR_FAULTY (desc) ; + ASSERT_DESCRIPTOR_OK (desc, "desc to set", GB0) ; + + //-------------------------------------------------------------------------- + // set the parameter + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_DESCRIPTOR_CHUNK : // DEPRECATED + + desc->chunk = value ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + + +//------------------------------------------------------------------------------ +// GxB_Desc_set: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Desc_set // set a parameter in a descriptor ( GrB_Descriptor desc, // descriptor to modify @@ -126,7 +329,7 @@ GrB_Info GxB_Desc_set // set a parameter in a descriptor } break ; - case GxB_DESCRIPTOR_NTHREADS : // same as GxB_NTHREADS + case GxB_DESCRIPTOR_NTHREADS : // DEPRECATED { va_start (ap, field) ; @@ -135,7 +338,7 @@ GrB_Info GxB_Desc_set // set a parameter in a descriptor } break ; - case GxB_DESCRIPTOR_CHUNK : // same as GxB_CHUNK + case GxB_DESCRIPTOR_CHUNK : // DEPRECATED { va_start (ap, field) ; @@ -167,7 +370,7 @@ GrB_Info GxB_Desc_set // set a parameter in a descriptor } break ; - case GxB_SORT : + case GxB_SORT : { va_start (ap, field) ; @@ -203,10 +406,9 @@ GrB_Info GxB_Desc_set // set a parameter in a descriptor GB_ERROR (GrB_INVALID_VALUE, "invalid descriptor field [%d], must be one of:\n" "GrB_OUTP [%d], GrB_MASK [%d], GrB_INP0 [%d], GrB_INP1 [%d]\n" - "GxB_NTHREADS [%d], GxB_CHUNK [%d], GxB_AxB_METHOD [%d]\n" - "GxB_SORT [%d], or GxB_COMPRESSION [%d]\n", + "GxB_AxB_METHOD [%d], GxB_SORT [%d], or GxB_COMPRESSION [%d]\n", (int) field, (int) GrB_OUTP, (int) GrB_MASK, (int) GrB_INP0, - (int) GrB_INP1, (int) GxB_NTHREADS, (int) GxB_CHUNK, + (int) GrB_INP1, (int) GxB_AxB_METHOD, (int) GxB_SORT, (int) GxB_COMPRESSION) ; } diff --git a/deps/GraphBLAS/Source/GxB_Global_Option_get.c b/deps/GraphBLAS/Source/GxB_Global_Option_get.c index a20458a261..efb5587e7e 100644 --- a/deps/GraphBLAS/Source/GxB_Global_Option_get.c +++ b/deps/GraphBLAS/Source/GxB_Global_Option_get.c @@ -7,8 +7,349 @@ //------------------------------------------------------------------------------ +// GxB_Global_Option_get is a single va_arg-based method for any global option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Global_Option_get_INT32 int32_t scalars or arrays +// GxB_Global_Option_get_FP64 double scalars or arrays +// GxB_Global_Option_get_INT64 int64_t scalars or arrays +// GxB_Global_Option_get_CHAR strings +// GxB_Global_Option_get_FUNCTION function pointers (as void **) + #include "GB.h" +//------------------------------------------------------------------------------ +// GxB_Global_Option_get_INT32: get global options (int32_t scalars or arrays) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_get_INT32 // gets the current global option +( + GxB_Option_Field field, // option to query + int32_t *value // return value of the global option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_get_INT32 (field, &value)") ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_GLOBAL_NTHREADS : // same as GxB_NTHREADS + + (*value) = (int32_t) GB_Global_nthreads_max_get ( ) ; + break ; + + case GxB_API_VERSION : + + value [0] = GxB_SPEC_MAJOR ; + value [1] = GxB_SPEC_MINOR ; + value [2] = GxB_SPEC_SUB ; + break ; + + case GxB_LIBRARY_VERSION : + + value [0] = GxB_IMPLEMENTATION_MAJOR ; + value [1] = GxB_IMPLEMENTATION_MINOR ; + value [2] = GxB_IMPLEMENTATION_SUB ; + break ; + + case GxB_COMPILER_VERSION : + + value [0] = GB_COMPILER_MAJOR ; + value [1] = GB_COMPILER_MINOR ; + value [2] = GB_COMPILER_SUB ; + break ; + + case GxB_MODE : + + (*value) = (int32_t) GB_Global_mode_get ( ) ; + break ; + + case GxB_FORMAT : + + (*value) = (int32_t) (GB_Global_is_csc_get ( )) ? + GxB_BY_COL : GxB_BY_ROW ; + break ; + + case GxB_GLOBAL_GPU_CONTROL : // same as GxB_GPU_CONTROL + + (*value) = (int32_t) GB_Global_gpu_control_get ( ) ; + break ; + + case GxB_BURBLE : + + (*value) = (int32_t) GB_Global_burble_get ( ) ; + break ; + + case GxB_LIBRARY_OPENMP : + + #ifdef _OPENMP + (*value) = (int32_t) true ; + #else + (*value) = (int32_t) false ; + #endif + break ; + + case GxB_PRINT_1BASED : + + (*value) = (int32_t) GB_Global_print_one_based_get ( ) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_get_FP64: get global options (double scalars or arrays) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_get_FP64 // gets the current global option +( + GxB_Option_Field field, // option to query + double *value // return value of the global option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_get_FP64 (field, &value)") ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_HYPER_SWITCH : + + (*value) = (double) GB_Global_hyper_switch_get ( ) ; + break ; + + case GxB_BITMAP_SWITCH : + + for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) + { + value [k] = (double) GB_Global_bitmap_switch_get (k) ; + } + break ; + + case GxB_GLOBAL_CHUNK : // same as GxB_CHUNK + + (*value) = GB_Global_chunk_get ( ) ; + break ; + + case GxB_GLOBAL_GPU_CHUNK : // same as GxB_GPU_CHUNK + + (*value) = GB_Global_gpu_chunk_get ( ) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_get_INT64: get global options (int64_t scalars or arrays) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_get_INT64 // gets the current global option +( + GxB_Option_Field field, // option to query + int64_t *value // return value of the global option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_get_INT64 (field, &value)") ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_MEMORY_POOL : + + for (int k = 0 ; k < 64 ; k++) + { + value [k] = GB_Global_free_pool_limit_get (k) ; + } + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_get_CHAR: get global options (const char strings) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_get_CHAR // gets the current global option +( + GxB_Option_Field field, // option to query + char **value // return value of the global option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_get_CHAR (field, &value)") ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_LIBRARY_NAME : + + (*value) = GxB_IMPLEMENTATION_NAME ; + break ; + + case GxB_LIBRARY_DATE : + + (*value) = GxB_IMPLEMENTATION_DATE ; + break ; + + case GxB_LIBRARY_ABOUT : + + (*value) = GxB_IMPLEMENTATION_ABOUT ; + break ; + + case GxB_LIBRARY_LICENSE : + + (*value) = GxB_IMPLEMENTATION_LICENSE ; + break ; + + case GxB_LIBRARY_COMPILE_DATE : + + (*value) = __DATE__ ; + break ; + + case GxB_LIBRARY_COMPILE_TIME : + + (*value) = __TIME__ ; + break ; + + case GxB_LIBRARY_URL : + + (*value) = "http://faculty.cse.tamu.edu/davis/GraphBLAS" ; + break ; + + case GxB_API_DATE : + + (*value) = GxB_SPEC_DATE ; + break ; + + case GxB_API_ABOUT : + + (*value) = GxB_SPEC_ABOUT ; + break ; + + case GxB_API_URL : + + (*value) = "http://graphblas.org" ; + break ; + + case GxB_COMPILER_NAME : + + (*value) = GB_COMPILER_NAME ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_get_FUNCTION: get global options (function pointers) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_get_FUNCTION // gets the current global option +( + GxB_Option_Field field, // option to query + void **value // return value of the global option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_get_FUNCTION (field, &value)") ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_PRINTF : + + (*value) = (void *) GB_Global_printf_get ( ) ; + break ; + + case GxB_FLUSH : + + (*value) = (void *) GB_Global_flush_get ( ) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_get: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Global_Option_get // gets the current global option ( GxB_Option_Field field, // option to query @@ -219,6 +560,21 @@ GrB_Info GxB_Global_Option_get // gets the current global option } break ; + case GxB_LIBRARY_OPENMP : + + { + va_start (ap, field) ; + bool *have_openmp = va_arg (ap, bool *) ; + va_end (ap) ; + GB_RETURN_IF_NULL (have_openmp) ; + #ifdef _OPENMP + (*have_openmp) = true ; + #else + (*have_openmp) = false ; + #endif + } + break ; + case GxB_LIBRARY_URL : { diff --git a/deps/GraphBLAS/Source/GxB_Global_Option_set.c b/deps/GraphBLAS/Source/GxB_Global_Option_set.c index d2f5a40987..ebc714c279 100644 --- a/deps/GraphBLAS/Source/GxB_Global_Option_set.c +++ b/deps/GraphBLAS/Source/GxB_Global_Option_set.c @@ -7,8 +7,267 @@ //------------------------------------------------------------------------------ +// GxB_Global_Option_set is a single va_arg-based method for any global option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Global_Option_set_INT32 int32_t scalars +// GxB_Global_Option_set_FP64 double scalars +// GxB_Global_Option_set_FP64_ARRAY double arrays +// GxB_Global_Option_set_INT64_ARRAY int64_t arrays +// GxB_Global_Option_set_FUNCTION function pointers (as void *) + #include "GB.h" +//------------------------------------------------------------------------------ +// GxB_Global_Option_set_INT32: set a global option (int32_t) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_set_INT32 // set a global default option +( + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_set_INT32 (field, value)") ; + + //-------------------------------------------------------------------------- + // set the global option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_FORMAT : + + if (! (value == GxB_BY_ROW || value == GxB_BY_COL)) + { + return (GrB_INVALID_VALUE) ; + } + GB_Global_is_csc_set (value != (int) GxB_BY_ROW) ; + break ; + + case GxB_GLOBAL_NTHREADS : // same as GxB_NTHREADS + + // if < 1, then treat it as if nthreads_max = 1 + value = GB_IMAX (1, value) ; + GB_Global_nthreads_max_set (value) ; + break ; + + case GxB_BURBLE : + + GB_Global_burble_set ((bool) value) ; + break ; + + case GxB_PRINT_1BASED : + + GB_Global_print_one_based_set ((bool) value) ; + break ; + + case GxB_GLOBAL_GPU_CONTROL : // same as GxB_GPU_CONTROL + + GB_Global_gpu_control_set ((GrB_Desc_Value) value) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_set_FP64: set a global option (double) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_set_FP64 // set a global default option +( + GxB_Option_Field field, // option to change + double value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_set_FP64 (field, value)") ; + + //-------------------------------------------------------------------------- + // set the global option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_HYPER_SWITCH : + + GB_Global_hyper_switch_set ((float) value) ; + break ; + + case GxB_GLOBAL_CHUNK : // same as GxB_CHUNK + + GB_Global_chunk_set (value) ; + break ; + + case GxB_GLOBAL_GPU_CHUNK : // same as GxB_GPU_CHUNK + + GB_Global_gpu_chunk_set (value) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_set_FP64_ARRAY: set a global option (double array) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_set_FP64_ARRAY // set a global default option +( + GxB_Option_Field field, // option to change + double *value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_set_FP64_ARRAY (field, value)") ; + + //-------------------------------------------------------------------------- + // set the global option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_BITMAP_SWITCH : + + if (value == NULL) + { + // set all switches to their default + GB_Global_bitmap_switch_default ( ) ; + } + else + { + for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) + { + GB_Global_bitmap_switch_set (k, (float) (value [k])) ; + } + } + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_set_INT64_ARRAY: set a global option (int64_t array) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_set_INT64_ARRAY // set a global default option +( + GxB_Option_Field field, // option to change + int64_t *value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_set_INT64_ARRAY (field, value)") ; + + //-------------------------------------------------------------------------- + // set the global option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_MEMORY_POOL : + + if (value == NULL) + { + // set all limits to their default + GB_Global_free_pool_init (false) ; + } + else + { + GB_Global_free_pool_limit_set (value) ; + } + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_set_FUNCTION: set a global option (function pointer) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Global_Option_set_FUNCTION // set a global default option +( + GxB_Option_Field field, // option to change + void *value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Global_Option_set_FUNCTION (field, value)") ; + + //-------------------------------------------------------------------------- + // set the global option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_PRINTF : + + GB_Global_printf_set ((GB_printf_function_t) value) ; + break ; + + case GxB_FLUSH : + + GB_Global_flush_set ((GB_flush_function_t) value) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Global_Option_set: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Global_Option_set // set a global default option ( GxB_Option_Field field, // option to change @@ -124,10 +383,7 @@ GrB_Info GxB_Global_Option_set // set a global default option } else { - for (int k = 3 ; k < 64 ; k++) - { - GB_Global_free_pool_limit_set (k, free_pool_limit [k]) ; - } + GB_Global_free_pool_limit_set (free_pool_limit) ; } } break ; diff --git a/deps/GraphBLAS/Source/GxB_Matrix_Option_get.c b/deps/GraphBLAS/Source/GxB_Matrix_Option_get.c index 44e4ca9736..7f0cd65a85 100644 --- a/deps/GraphBLAS/Source/GxB_Matrix_Option_get.c +++ b/deps/GraphBLAS/Source/GxB_Matrix_Option_get.c @@ -7,8 +7,118 @@ //------------------------------------------------------------------------------ +// GxB_Matrix_Option_get is a single va_arg-based method for any matrix option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Matrix_Option_get_INT32 int32_t scalars +// GxB_Matrix_Option_get_FP64 double scalars + #include "GB.h" +//------------------------------------------------------------------------------ +// GxB_Matrix_Option_get_INT32: get matrix options (int32_t scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Matrix_Option_get_INT32 // gets the current option of a matrix +( + GrB_Matrix A, // matrix to query + GxB_Option_Field field, // option to query + int32_t *value // return value of the matrix option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Matrix_Option_get_INT32 (A, field, &value)") ; + GB_RETURN_IF_NULL_OR_FAULTY (A) ; + ASSERT_MATRIX_OK (A, "A to get option", GB0) ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_SPARSITY_CONTROL : + + (*value) = A->sparsity_control ; + break ; + + case GxB_SPARSITY_STATUS : + + (*value) = GB_sparsity (A) ; + break ; + + case GxB_FORMAT : + + (*value) = (int32_t) ((A->is_csc) ? GxB_BY_COL : GxB_BY_ROW) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Matrix_Option_get_FP64: get matrix options (double scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Matrix_Option_get_FP64 // gets the current option of a matrix +( + GrB_Matrix A, // matrix to query + GxB_Option_Field field, // option to query + double *value // return value of the matrix option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Matrix_Option_get_FP64 (A, field, &value)") ; + GB_RETURN_IF_NULL_OR_FAULTY (A) ; + ASSERT_MATRIX_OK (A, "A to get option", GB0) ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_HYPER_SWITCH : + + (*value) = (double) A->hyper_switch ; + break ; + + case GxB_BITMAP_SWITCH : + + (*value) = (double) A->bitmap_switch ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Matrix_Option_get: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Matrix_Option_get // gets the current option of a matrix ( GrB_Matrix A, // matrix to query diff --git a/deps/GraphBLAS/Source/GxB_Matrix_Option_set.c b/deps/GraphBLAS/Source/GxB_Matrix_Option_set.c index 2d19f64a87..34cc5671f3 100644 --- a/deps/GraphBLAS/Source/GxB_Matrix_Option_set.c +++ b/deps/GraphBLAS/Source/GxB_Matrix_Option_set.c @@ -11,9 +11,147 @@ #define GB_FREE_ALL ; +//------------------------------------------------------------------------------ + +// GxB_Matrix_Option_set is a single va_arg-based method for any matrix option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Matrix_Option_set_INT32 int32_t scalars +// GxB_Matrix_Option_set_FP64 double scalars + +//------------------------------------------------------------------------------ +// GxB_Matrix_Option_set_INT32: set matrix options (int32_t scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Matrix_Option_set_INT32 // set an option in a matrix +( + GrB_Matrix A, // matrix to modify + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GrB_Info info ; + GB_WHERE (A, "GxB_Matrix_Option_set_INT32 (A, field, value)") ; + GB_BURBLE_START ("GxB_set") ; + GB_RETURN_IF_NULL_OR_FAULTY (A) ; + ASSERT_MATRIX_OK (A, "A to set option", GB0) ; + + //-------------------------------------------------------------------------- + // set the matrix option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_SPARSITY_CONTROL : + + A->sparsity_control = GB_sparsity_control (value, (int64_t) (-1)) ; + break ; + + case GxB_FORMAT : + + if (! (value == GxB_BY_ROW || value == GxB_BY_COL)) + { + return (GrB_INVALID_VALUE) ; + } + // the value is normally GxB_BY_ROW (0) or GxB_BY_COL (1), but + // any nonzero value results in GxB_BY_COL. + bool new_csc = (value != GxB_BY_ROW) ; + // conform the matrix to the new by-row/by-col format + if (A->is_csc != new_csc) + { + // A = A', done in-place, and change to the new format. + GB_BURBLE_N (GB_nnz (A), "(transpose) ") ; + GB_OK (GB_transpose_in_place (A, new_csc, Context)) ; + ASSERT (A->is_csc == new_csc) ; + ASSERT (GB_JUMBLED_OK (A)) ; + } + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + //-------------------------------------------------------------------------- + // conform the matrix to its new desired sparsity structure + //-------------------------------------------------------------------------- + + ASSERT_MATRIX_OK (A, "A set before conform", GB0) ; + GB_OK (GB_conform (A, Context)) ; + GB_BURBLE_END ; + ASSERT_MATRIX_OK (A, "A set after conform", GB0) ; + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Matrix_Option_set_FP64: set matrix options (double scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Matrix_Option_set_FP64 // set an option in a matrix +( + GrB_Matrix A, // matrix to modify + GxB_Option_Field field, // option to change + double value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GrB_Info info ; + GB_WHERE (A, "GxB_Matrix_Option_set_FP64 (A, field, value)") ; + GB_BURBLE_START ("GxB_set") ; + GB_RETURN_IF_NULL_OR_FAULTY (A) ; + ASSERT_MATRIX_OK (A, "A to set option", GB0) ; + + //-------------------------------------------------------------------------- + // set the matrix option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_HYPER_SWITCH : + + A->hyper_switch = (float) value ; + break ; + + case GxB_BITMAP_SWITCH : + + A->bitmap_switch = (float) value ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + //-------------------------------------------------------------------------- + // conform the matrix to its new desired sparsity structure + //-------------------------------------------------------------------------- + + ASSERT_MATRIX_OK (A, "A set before conform", GB0) ; + GB_OK (GB_conform (A, Context)) ; + GB_BURBLE_END ; + ASSERT_MATRIX_OK (A, "A set after conform", GB0) ; + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Matrix_Option_set: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Matrix_Option_set // set an option in a matrix ( - GrB_Matrix A, // descriptor to modify + GrB_Matrix A, // matrix to modify GxB_Option_Field field, // option to change ... // value to change it to ) diff --git a/deps/GraphBLAS/Source/GxB_Matrix_memoryUsage.c b/deps/GraphBLAS/Source/GxB_Matrix_memoryUsage.c index e154e4e1c2..c6b54a24f9 100644 --- a/deps/GraphBLAS/Source/GxB_Matrix_memoryUsage.c +++ b/deps/GraphBLAS/Source/GxB_Matrix_memoryUsage.c @@ -30,7 +30,7 @@ GrB_Info GxB_Matrix_memoryUsage // return # of bytes used for a matrix int64_t nallocs ; size_t mem_shallow ; - GB_memoryUsage (&nallocs, size, &mem_shallow, A) ; + GB_memoryUsage (&nallocs, size, &mem_shallow, A, true) ; return (GrB_SUCCESS) ; } diff --git a/deps/GraphBLAS/Source/GxB_Matrix_subassign_scalar.c b/deps/GraphBLAS/Source/GxB_Matrix_subassign_scalar.c index 46a2ce9d3b..9299aed8d3 100644 --- a/deps/GraphBLAS/Source/GxB_Matrix_subassign_scalar.c +++ b/deps/GraphBLAS/Source/GxB_Matrix_subassign_scalar.c @@ -78,7 +78,6 @@ GB_ASSIGN_SCALAR (void * , UDT , ) #define GB_FREE_ALL GB_Matrix_free (&S) ; #include "GB_static_header.h" -GB_PUBLIC GrB_Info GxB_Matrix_subassign_Scalar // C(I,J) = accum (C(I,J),s) ( GrB_Matrix C, // input/output matrix for results diff --git a/deps/GraphBLAS/Source/GxB_Scalar_memoryUsage.c b/deps/GraphBLAS/Source/GxB_Scalar_memoryUsage.c index a8638462f5..1af5120954 100644 --- a/deps/GraphBLAS/Source/GxB_Scalar_memoryUsage.c +++ b/deps/GraphBLAS/Source/GxB_Scalar_memoryUsage.c @@ -30,7 +30,7 @@ GrB_Info GxB_Scalar_memoryUsage // return # of bytes used for a scalar int64_t nallocs ; size_t mem_shallow ; - GB_memoryUsage (&nallocs, size, &mem_shallow, (GrB_Matrix) s) ; + GB_memoryUsage (&nallocs, size, &mem_shallow, (GrB_Matrix) s, false) ; return (GrB_SUCCESS) ; } diff --git a/deps/GraphBLAS/Source/GxB_Type_new.c b/deps/GraphBLAS/Source/GxB_Type_new.c index c70d47f278..8f394ccd4c 100644 --- a/deps/GraphBLAS/Source/GxB_Type_new.c +++ b/deps/GraphBLAS/Source/GxB_Type_new.c @@ -122,8 +122,8 @@ GrB_Info GxB_Type_new else { // no type name, so give it a generic name, with the typesize only - snprintf (t->name, GxB_MAX_NAME_LEN-1, "user_type_of_size_%lu", - sizeof_ctype) ; + snprintf (t->name, GxB_MAX_NAME_LEN-1, "user_type_of_size_" GBu, + (uint64_t) sizeof_ctype) ; } // ensure t->name is null-terminated diff --git a/deps/GraphBLAS/Source/GxB_Vector_Option_get.c b/deps/GraphBLAS/Source/GxB_Vector_Option_get.c index a9b18f95b2..7bebd02407 100644 --- a/deps/GraphBLAS/Source/GxB_Vector_Option_get.c +++ b/deps/GraphBLAS/Source/GxB_Vector_Option_get.c @@ -9,6 +9,116 @@ #include "GB.h" +//------------------------------------------------------------------------------ + +// GxB_Vector_Option_get is a single va_arg-based method for any vector option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Vector_Option_get_INT32 int32_t scalars +// GxB_Vector_Option_get_FP64 double scalars + +//------------------------------------------------------------------------------ +// GxB_Vector_Option_get_INT32: get vector options (int32_t scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Vector_Option_get_INT32 // gets the current option of a vector +( + GrB_Vector v, // vector to query + GxB_Option_Field field, // option to query + int32_t *value // return value of the vector option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Vector_Option_get_INT32 (v, field, &value)") ; + GB_RETURN_IF_NULL_OR_FAULTY (v) ; + ASSERT_VECTOR_OK (v, "v to get option", GB0) ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_SPARSITY_CONTROL : + + (*value) = v->sparsity_control ; + break ; + + case GxB_SPARSITY_STATUS : + + (*value) = GB_sparsity ((GrB_Matrix) v) ; + break ; + + case GxB_FORMAT : + + // a GrB_Vector is always stored by-column + (*value) = (int32_t) GxB_BY_COL ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Vector_Option_get_FP64: get vector options (double scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Vector_Option_get_FP64 // gets the current option of a vector +( + GrB_Vector v, // vector to query + GxB_Option_Field field, // option to query + double *value // return value of the vector option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GB_WHERE1 ("GxB_Vector_Option_get_FP64 (v, field, &value)") ; + GB_RETURN_IF_NULL_OR_FAULTY (v) ; + ASSERT_VECTOR_OK (v, "v to get option", GB0) ; + GB_RETURN_IF_NULL (value) ; + + //-------------------------------------------------------------------------- + // get the option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_BITMAP_SWITCH : + + (*value) = (double) v->bitmap_switch ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + + } + + #pragma omp flush + return (GrB_SUCCESS) ; +} + +//------------------------------------------------------------------------------ +// GxB_Vector_Option_get: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Vector_Option_get // gets the current option of a vector ( GrB_Vector v, // vector to query diff --git a/deps/GraphBLAS/Source/GxB_Vector_Option_set.c b/deps/GraphBLAS/Source/GxB_Vector_Option_set.c index e1597e5fcd..55e6d2f8a1 100644 --- a/deps/GraphBLAS/Source/GxB_Vector_Option_set.c +++ b/deps/GraphBLAS/Source/GxB_Vector_Option_set.c @@ -11,9 +11,120 @@ #define GB_FREE_ALL ; +//------------------------------------------------------------------------------ + +// GxB_Vector_Option_set is a single va_arg-based method for any vector option, +// of any type. The following functions are alternative methods that do not +// use va_arg (useful for compilers and interfaces that do not support va_arg): +// +// GxB_Vector_Option_set_INT32 int32_t scalars +// GxB_Vector_Option_set_FP64 double scalars + +//------------------------------------------------------------------------------ +// GxB_Vector_Option_set_INT32: set vector options (int32_t scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Vector_Option_set_INT32 // set an option in a vector +( + GrB_Vector v, // vector to modify + GxB_Option_Field field, // option to change + int32_t value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GrB_Info info = GrB_SUCCESS ; + GB_WHERE (v, "GxB_Vector_Option_set_INT32 (v, field, value)") ; + GB_BURBLE_START ("GxB_set (vector option)") ; + GB_RETURN_IF_NULL_OR_FAULTY (v) ; + ASSERT_VECTOR_OK (v, "v to set option", GB0) ; + + //-------------------------------------------------------------------------- + // set the vector option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_SPARSITY_CONTROL : + + v->sparsity_control = GB_sparsity_control (value, (int64_t) (-1)) ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + //-------------------------------------------------------------------------- + // conform the vector to its new desired sparsity structure + //-------------------------------------------------------------------------- + + GB_OK (GB_conform ((GrB_Matrix) v, Context)) ; + GB_BURBLE_END ; + ASSERT_VECTOR_OK (v, "v set", GB0) ; + return (info) ; +} + +//------------------------------------------------------------------------------ +// GxB_Vector_Option_set_FP64: set vector options (double scalars) +//------------------------------------------------------------------------------ + +GrB_Info GxB_Vector_Option_set_FP64 // set an option in a vector +( + GrB_Vector v, // vector to modify + GxB_Option_Field field, // option to change + double value // value to change it to +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + GrB_Info info = GrB_SUCCESS ; + GB_WHERE (v, "GxB_Vector_Option_set_FP64 (v, field, value)") ; + GB_BURBLE_START ("GxB_set (vector option)") ; + GB_RETURN_IF_NULL_OR_FAULTY (v) ; + ASSERT_VECTOR_OK (v, "v to set option", GB0) ; + + //-------------------------------------------------------------------------- + // set the vector option + //-------------------------------------------------------------------------- + + switch (field) + { + + case GxB_BITMAP_SWITCH : + + v->bitmap_switch = (float) value ; + break ; + + default : + + return (GrB_INVALID_VALUE) ; + } + + //-------------------------------------------------------------------------- + // conform the vector to its new desired sparsity structure + //-------------------------------------------------------------------------- + + GB_OK (GB_conform ((GrB_Matrix) v, Context)) ; + GB_BURBLE_END ; + ASSERT_VECTOR_OK (v, "v set", GB0) ; + return (info) ; +} + +//------------------------------------------------------------------------------ +// GxB_Vector_Option_set: based on va_arg +//------------------------------------------------------------------------------ + GrB_Info GxB_Vector_Option_set // set an option in a vector ( - GrB_Vector v, // descriptor to modify + GrB_Vector v, // vector to modify GxB_Option_Field field, // option to change ... // value to change it to ) diff --git a/deps/GraphBLAS/Source/GxB_Vector_memoryUsage.c b/deps/GraphBLAS/Source/GxB_Vector_memoryUsage.c index fd56cfa8d3..c7a9e02d2c 100644 --- a/deps/GraphBLAS/Source/GxB_Vector_memoryUsage.c +++ b/deps/GraphBLAS/Source/GxB_Vector_memoryUsage.c @@ -31,7 +31,7 @@ GrB_Info GxB_Vector_memoryUsage // return # of bytes used for a vector int64_t nallocs ; size_t mem_shallow ; - GB_memoryUsage (&nallocs, size, &mem_shallow, (GrB_Matrix) v) ; + GB_memoryUsage (&nallocs, size, &mem_shallow, (GrB_Matrix) v, false) ; return (GrB_SUCCESS) ; } diff --git a/deps/GraphBLAS/Source/GxB_Vector_subassign_scalar.c b/deps/GraphBLAS/Source/GxB_Vector_subassign_scalar.c index 8e75579c4f..6364e60e07 100644 --- a/deps/GraphBLAS/Source/GxB_Vector_subassign_scalar.c +++ b/deps/GraphBLAS/Source/GxB_Vector_subassign_scalar.c @@ -75,7 +75,6 @@ GB_ASSIGN_SCALAR (void * , UDT , ) #define GB_FREE_ALL GB_Matrix_free (&S) ; #include "GB_static_header.h" -GB_PUBLIC GrB_Info GxB_Vector_subassign_Scalar // w(I) = accum (w(I),s) ( GrB_Vector w, // input/output matrix for results diff --git a/deps/GraphBLAS/Source/GxB_deserialize_type_name.c b/deps/GraphBLAS/Source/GxB_deserialize_type_name.c index 0b1a809b99..9aa21c9090 100644 --- a/deps/GraphBLAS/Source/GxB_deserialize_type_name.c +++ b/deps/GraphBLAS/Source/GxB_deserialize_type_name.c @@ -48,10 +48,10 @@ GrB_Info GxB_deserialize_type_name // return the type name of a blob //-------------------------------------------------------------------------- size_t s = 0 ; - GB_BLOB_READ (blob_size2, size_t) ; + GB_BLOB_READ (blob_size2, uint64_t) ; GB_BLOB_READ (typecode, int32_t) ; - if (blob_size2 != (size_t) blob_size) + if (blob_size2 != blob_size) { // blob is invalid return (GrB_INVALID_OBJECT) ; diff --git a/deps/GraphBLAS/Source/GxB_unpack_HyperHash.c b/deps/GraphBLAS/Source/GxB_unpack_HyperHash.c index 7aa351c0d4..a1066baa17 100644 --- a/deps/GraphBLAS/Source/GxB_unpack_HyperHash.c +++ b/deps/GraphBLAS/Source/GxB_unpack_HyperHash.c @@ -51,7 +51,6 @@ #include "GB_export.h" #define GB_FREE_ALL ; -GB_PUBLIC GrB_Info GxB_unpack_HyperHash // move A->Y into Y ( GrB_Matrix A, // matrix to modify diff --git a/deps/GraphBLAS/Source/Template/GB_ops_template.h b/deps/GraphBLAS/Source/Template/GB_ops_template.h index 96049930fa..039ed74447 100644 --- a/deps/GraphBLAS/Source/Template/GB_ops_template.h +++ b/deps/GraphBLAS/Source/Template/GB_ops_template.h @@ -11,13 +11,13 @@ // binary functions. #define GB_UNOP_STRUCT(op,xtype) \ - GB_PUBLIC struct GB_UnaryOp_opaque GB_OPAQUE (GB_EVAL3 (op, _, xtype)) + GB_GLOBAL struct GB_UnaryOp_opaque GB_OPAQUE (GB_EVAL3 (op, _, xtype)) #define GB_BINOP_STRUCT(op,xtype) \ - GB_PUBLIC struct GB_BinaryOp_opaque GB_OPAQUE (GB_EVAL3 (op, _, xtype)) + GB_GLOBAL struct GB_BinaryOp_opaque GB_OPAQUE (GB_EVAL3 (op, _, xtype)) #define GB_IDXOP_STRUCT(op,xtype) \ - GB_PUBLIC struct GB_IndexUnaryOp_opaque \ + GB_GLOBAL struct GB_IndexUnaryOp_opaque \ GB_OPAQUE (GB_EVAL3 (op, _, xtype)) //------------------------------------------------------------------------------ diff --git a/deps/GraphBLAS/Source/Template/GB_sparse_add_template.c b/deps/GraphBLAS/Source/Template/GB_sparse_add_template.c index 04a76c6e1f..5c2f00a9da 100644 --- a/deps/GraphBLAS/Source/Template/GB_sparse_add_template.c +++ b/deps/GraphBLAS/Source/Template/GB_sparse_add_template.c @@ -395,6 +395,14 @@ { // C (i,j) = alpha + B(i,j) GB_LOAD_B (bij, Bx, pB+p, B_iso) ; + // GB_COMPILER_MSC_2019 workaround: the following + // line of code triggers a bug in the MSC 19.2x + // compiler in Visual Studio 2019, only for the + // FIRST_FC32 and SECOND_FC32 operators. As a + // workaround, this template is not used for + // those operators when compiling GraphBLAS with + // this compiler. Note the bug may also appear + // in VS2022, but this has not yet been tested. GB_BINOP (GB_CX (pC+p), alpha_scalar, bij, i, j) ; } #else diff --git a/deps/GraphBLAS/Source/codegen_binop_method.m b/deps/GraphBLAS/Source/codegen_binop_method.m index c53779b5a7..f20e4eabef 100644 --- a/deps/GraphBLAS/Source/codegen_binop_method.m +++ b/deps/GraphBLAS/Source/codegen_binop_method.m @@ -224,6 +224,12 @@ function codegen_binop_method (binop, op, xtype) disable = sprintf ('GxB_NO_%s', upper (binop)) ; disable = [disable (sprintf (' || GxB_NO_%s', upper (fname)))] ; disable = [disable (sprintf (' || GxB_NO_%s_%s', upper (binop), upper (fname)))] ; +if (isequal (ytype, 'GxB_FC32_t') && ... + (isequal (binop, 'first') || isequal (binop, 'second'))) + % disable the FIRST_FC32 and SECOND_FC32 binary operators for + % MS Visual Studio 2019. These files trigger a bug in the compiler. + disable = [disable ' || GB_COMPILER_MSC_2019_OR_NEWER'] ; +end fprintf (f, 'define(`GB_disable'', `(%s)'')\n', disable) ; % ff = fopen ('temp.h', 'a') ; diff --git a/deps/GraphBLAS/Tcov/log_Dec22.txt b/deps/GraphBLAS/Tcov/log_Dec22.txt new file mode 100644 index 0000000000..67714d4edf --- /dev/null +++ b/deps/GraphBLAS/Tcov/log_Dec22.txt @@ -0,0 +1,142 @@ + +---------------------------------------------- [malloc] [cover] +22-Dec 22:26:26 test247 0.5 sec 217: 20251 of 20468 1.1% 465.45/s +22-Dec 22:26:35 test246 9.0 sec 157: 20094 of 20468 1.8% 17.45/s +22-Dec 22:26:36 test01 1.1 sec 2089: 18005 of 20468 12.0% 1829.57/s +22-Dec 22:26:37 test245 0.2 sec 47: 17958 of 20468 12.3% 284.68/s +22-Dec 22:26:37 test199 0.0 sec 17: 17941 of 20468 12.3% 2063.36/s +22-Dec 22:26:37 test83 0.1 sec 21: 17920 of 20468 12.4% 262.31/s +22-Dec 22:26:37 test210 0.0 sec 7: 17913 of 20468 12.5% 2356.90/s +22-Dec 22:26:37 test165 0.0 sec 12: 17901 of 20468 12.5% 1083.52/s +22-Dec 22:26:37 test219 0.1 sec 11: 17890 of 20468 12.6% 153.52/s +22-Dec 22:26:37 test241 0.3 sec 16: 17874 of 20468 12.7% 53.15/s +22-Dec 22:26:37 test220 0.1 sec 66: 17808 of 20468 13.0% 504.36/s +22-Dec 22:26:37 test211 0.1 sec 26: 17782 of 20468 13.1% 374.59/s +22-Dec 22:26:37 test202 0.1 sec 33: 17749 of 20468 13.3% 232.50/s +22-Dec 22:26:39 test152 1.4 sec 1127: 16622 of 20468 18.8% 815.99/s +22-Dec 22:26:39 test222 0.1 sec 6: 16616 of 20468 18.8% 80.07/s +22-Dec 22:26:39 test240 0.4 sec 42: 16574 of 20468 19.0% 118.42/s +22-Dec 22:26:40 test186 0.5 sec 67: 16507 of 20468 19.4% 132.69/s +22-Dec 22:26:40 test186(0) 0.4 sec 4: 16503 of 20468 19.4% 10.68/s +22-Dec 22:26:41 test186 0.4 sec 3: 16500 of 20468 19.4% 6.87/s +22-Dec 22:26:41 test150 0.2 sec 63: 16437 of 20468 19.7% 345.18/s +22-Dec 22:26:41 test239 0.1 sec 14: 16423 of 20468 19.8% 124.03/s +22-Dec 22:26:41 test235 0.0 sec 12: 16411 of 20468 19.8% 302.89/s +22-Dec 22:26:41 test226 0.0 sec 8: 16403 of 20468 19.9% 631.16/s +22-Dec 22:26:41 test223 0.0 sec 2: 16401 of 20468 19.9% 69.39/s +22-Dec 22:26:41 test204 0.1 sec 21: 16380 of 20468 20.0% 156.34/s +22-Dec 22:26:41 test203 0.1 sec 11: 16369 of 20468 20.0% 98.48/s +22-Dec 22:26:41 test183 0.0 sec 12: 16357 of 20468 20.1% 312.01/s +22-Dec 22:26:41 test179 0.1 sec 26: 16331 of 20468 20.2% 177.89/s +22-Dec 22:26:41 test174 0.1 sec 10: 16321 of 20468 20.3% 173.07/s +22-Dec 22:26:42 test155 0.2 sec 48: 16273 of 20468 20.5% 287.36/s +22-Dec 22:26:42 test156 0.7 sec 258: 16015 of 20468 21.8% 357.34/s +22-Dec 22:26:43 test136 0.2 sec 58: 15957 of 20468 22.0% 309.93/s +22-Dec 22:26:43 test02 0.4 sec 181: 15776 of 20468 22.9% 498.04/s +22-Dec 22:26:43 test109 0.1 sec 12: 15764 of 20468 23.0% 123.37/s +22-Dec 22:26:43 test109 0.0 sec 1: 15763 of 20468 23.0% 312.21/s +22-Dec 22:26:43 test04 0.1 sec 21: 15742 of 20468 23.1% 208.04/s +22-Dec 22:26:43 test207 0.0 sec 1: 15741 of 20468 23.1% 261.10/s +22-Dec 22:26:43 test221 0.0 sec 2: 15739 of 20468 23.1% 259.03/s +22-Dec 22:26:43 test162 0.1 sec 5: 15734 of 20468 23.1% 68.32/s +22-Dec 22:26:45 test159 1.5 sec 135: 15599 of 20468 23.8% 92.25/s +22-Dec 22:26:45 test09 0.0 sec 5: 15594 of 20468 23.8% 493.39/s +22-Dec 22:26:45 test132 0.1 sec 8: 15586 of 20468 23.9% 85.26/s +22-Dec 22:26:50 test141 5.3 sec 543: 15043 of 20468 26.5% 102.54/s +22-Dec 22:26:51 testc2(1,1) 0.4 sec 46: 14997 of 20468 26.7% 115.02/s +22-Dec 22:26:51 test214 0.0 sec 3: 14994 of 20468 26.7% 238.42/s +22-Dec 22:26:51 test213 0.0 sec 4: 14990 of 20468 26.8% 383.99/s +22-Dec 22:26:53 test206 2.7 sec 265: 14725 of 20468 28.1% 99.72/s +22-Dec 22:26:53 test212 0.1 sec 10: 14715 of 20468 28.1% 115.71/s +22-Dec 22:26:54 test128 0.4 sec 53: 14662 of 20468 28.4% 132.25/s +22-Dec 22:26:54 test82 0.1 sec 18: 14644 of 20468 28.5% 169.71/s +22-Dec 22:26:55 test229 1.0 sec 7: 14637 of 20468 28.5% 7.30/s +22-Dec 22:26:55 test144 0.6 sec 2: 14635 of 20468 28.5% 3.32/s +22-Dec 22:27:16 test14 20.7 sec 724: 13911 of 20468 32.0% 35.03/s +22-Dec 22:27:26 test180 9.7 sec 133: 13778 of 20468 32.7% 13.70/s +22-Dec 22:27:30 test236 3.7 sec 73: 13705 of 20468 33.0% 19.47/s +22-Dec 22:27:32 test232 2.8 sec 22: 13683 of 20468 33.1% 7.95/s +22-Dec 22:27:50 test228 17.8 sec 37: 13646 of 20468 33.3% 2.08/s +22-Dec 22:29:52 test154 121.9 sec 1503: 12143 of 20468 40.7% 12.33/s +22-Dec 22:30:07 test238 14.9 sec 70: 12073 of 20468 41.0% 4.70/s +22-Dec 22:30:52 test151b 45.3 sec 144: 11929 of 20468 41.7% 3.18/s +22-Dec 22:30:55 test184 3.1 sec 39: 11890 of 20468 41.9% 12.73/s +22-Dec 22:31:08 test191 13.0 sec 20: 11870 of 20468 42.0% 1.54/s +22-Dec 22:32:00 test188 51.7 sec 194: 11676 of 20468 43.0% 3.75/s +22-Dec 22:32:01 test237 0.7 sec 16: 11660 of 20468 43.0% 21.79/s +22-Dec 22:32:06 test224 5.1 sec 24: 11636 of 20468 43.2% 4.71/s +22-Dec 22:32:08 test196 2.5 sec 11: 11625 of 20468 43.2% 4.40/s +22-Dec 22:32:14 test209 5.7 sec 20: 11605 of 20468 43.3% 3.49/s +22-Dec 22:32:33 test104 18.8 sec 40: 11565 of 20468 43.5% 2.13/s +22-Dec 22:32:41 test189 7.8 sec 1: 11564 of 20468 43.5% 0.13/s +22-Dec 22:33:53 test194 71.9 sec 8: 11556 of 20468 43.5% 0.11/s +22-Dec 22:34:08 test76 15.8 sec 18: 11538 of 20468 43.6% 1.14/s +22-Dec 22:34:47 test244 38.3 sec 17: 11521 of 20468 43.7% 0.44/s +[malloc debugging turned off] +22-Dec 22:34:47 test201 0.0 sec 5: 11516 of 20468 43.7% 712.86/s +22-Dec 22:34:47 test225 0.1 sec 5: 11511 of 20468 43.8% 35.87/s +22-Dec 22:34:47 test170 0.1 sec 1: 11510 of 20468 43.8% 14.12/s +22-Dec 22:34:47 test176 0.1 sec 5: 11505 of 20468 43.8% 60.79/s +22-Dec 22:34:47 test208 0.0 sec 5: 11500 of 20468 43.8% 304.75/s +22-Dec 22:34:47 test216 0.1 sec 3: 11497 of 20468 43.8% 37.77/s +22-Dec 22:34:54 test142 7.2 sec 630: 10867 of 20468 46.9% 87.59/s +22-Dec 22:34:54 test137 0.1 sec 5: 10862 of 20468 46.9% 36.62/s +22-Dec 22:34:55 test139 0.3 sec 2: 10860 of 20468 46.9% 5.89/s +22-Dec 22:34:55 test145 0.2 sec 10: 10850 of 20468 47.0% 64.13/s +22-Dec 22:34:55 test172 0.1 sec 3: 10847 of 20468 47.0% 32.79/s +22-Dec 22:34:55 test148 0.4 sec 6: 10841 of 20468 47.0% 14.83/s +22-Dec 22:34:56 test157 0.7 sec 13: 10828 of 20468 47.1% 19.28/s +22-Dec 22:34:57 test182 1.0 sec 9: 10819 of 20468 47.1% 9.18/s +22-Dec 22:34:58 test108 0.4 sec 1: 10818 of 20468 47.1% 2.47/s +22-Dec 22:34:59 test130 1.0 sec 26: 10792 of 20468 47.3% 26.60/s +22-Dec 22:34:59 test124 0.2 sec 3: 10789 of 20468 47.3% 16.55/s +22-Dec 22:34:59 test138 0.1 sec 1: 10788 of 20468 47.3% 19.65/s +22-Dec 22:35:04 test227 5.0 sec 27: 10761 of 20468 47.4% 5.44/s +22-Dec 22:35:35 test125 31.3 sec 627: 10134 of 20468 50.5% 20.04/s +22-Dec 22:36:51 test234 75.5 sec 69: 10065 of 20468 50.8% 0.91/s +22-Dec 22:37:42 test242 51.6 sec 77: 9988 of 20468 51.2% 1.49/s +22-Dec 22:37:43 test173 1.3 sec 11: 9977 of 20468 51.3% 8.68/s +22-Dec 22:37:47 test200 3.3 sec 10: 9967 of 20468 51.3% 2.99/s +22-Dec 22:37:47 test197 0.1 sec 1: 9966 of 20468 51.3% 7.55/s +22-Dec 22:37:48 test84 1.4 sec 18: 9948 of 20468 51.4% 13.03/s +22-Dec 22:38:02 test19b 13.3 sec 57: 9891 of 20468 51.7% 4.29/s +22-Dec 22:38:10 test19b 8.8 sec 5: 9886 of 20468 51.7% 0.57/s +22-Dec 22:38:11 test133 0.4 sec 2: 9884 of 20468 51.7% 5.29/s +22-Dec 22:38:15 test80 3.9 sec 12: 9872 of 20468 51.8% 3.08/s +22-Dec 22:38:35 test151 20.3 sec 73: 9799 of 20468 52.1% 3.59/s +22-Dec 22:38:53 test23 18.1 sec 88: 9711 of 20468 52.6% 4.86/s +22-Dec 22:38:55 test135 1.9 sec 7: 9704 of 20468 52.6% 3.66/s +22-Dec 22:39:25 test160 30.3 sec 24: 9680 of 20468 52.7% 0.79/s +22-Dec 22:39:31 test54 5.7 sec 20: 9660 of 20468 52.8% 3.51/s +22-Dec 22:39:32 test129 1.2 sec 7: 9653 of 20468 52.8% 5.67/s +22-Dec 22:39:34 test69 2.1 sec 3: 9650 of 20468 52.9% 1.44/s +22-Dec 22:41:09 test230 94.6 sec 104: 9546 of 20468 53.4% 1.10/s +22-Dec 22:51:44 test74 635.4 sec 5796: 3750 of 20468 81.7% 9.12/s +22-Dec 22:55:50 test127 245.7 sec 1606: 2144 of 20468 89.5% 6.54/s +22-Dec 22:55:53 test19 3.4 sec 12: 2132 of 20468 89.6% 3.51/s +22-Dec 22:55:57 test11 3.6 sec 3: 2129 of 20468 89.6% 0.83/s +22-Dec 22:56:27 test160 30.2 sec 4: 2125 of 20468 89.6% 0.13/s +22-Dec 22:56:30 test215 2.9 sec 1: 2124 of 20468 89.6% 0.34/s +22-Dec 22:56:48 test193 17.8 sec 5: 2119 of 20468 89.6% 0.28/s +22-Dec 22:58:09 test195 80.7 sec 36: 2083 of 20468 89.8% 0.45/s +22-Dec 22:58:16 test233 7.8 sec 1: 2082 of 20468 89.8% 0.13/s +22-Dec 22:58:43 test243 26.2 sec 7: 2075 of 20468 89.9% 0.27/s +22-Dec 22:58:51 test29 8.7 sec 2: 2073 of 20468 89.9% 0.23/s +22-Dec 22:58:53 testc2(0,0) 1.2 sec 9: 2064 of 20468 89.9% 7.26/s +22-Dec 22:58:53 testc4(0) 0.6 sec 4: 2060 of 20468 89.9% 6.98/s +22-Dec 22:59:11 testc7(0) 17.7 sec 3: 2057 of 20468 90.0% 0.17/s +22-Dec 22:59:17 testcc(1) 5.8 sec 1: 2056 of 20468 90.0% 0.17/s +22-Dec 22:59:25 test187 8.5 sec 3: 2053 of 20468 90.0% 0.35/s +22-Dec 22:59:31 test192 5.8 sec 1: 2052 of 20468 90.0% 0.17/s +22-Dec 22:59:51 test181 19.9 sec 13: 2039 of 20468 90.0% 0.65/s +22-Dec 23:01:27 test185 95.7 sec 11: 2028 of 20468 90.1% 0.11/s +22-Dec 23:01:42 test53 15.5 sec 4: 2024 of 20468 90.1% 0.26/s +22-Dec 23:02:33 test17 51.1 sec 28: 1996 of 20468 90.2% 0.55/s +22-Dec 23:10:08 test231 455.2 sec 295: 1701 of 20468 91.7% 0.65/s +22-Dec 23:23:01 test10 772.3 sec 793: 908 of 20468 95.6% 1.03/s +22-Dec 23:33:01 test75b 600.7 sec 860: 48 of 20468 99.8% 1.43/s +22-Dec 23:34:33 test21b 92.0 sec 26: 22 of 20468 99.9% 0.28/s +22-Dec 23:35:41 testca(1) 67.7 sec 5: 17 of 20468 99.9% 0.07/s +22-Dec 23:37:36 test81 115.1 sec 1: 16 of 20468 99.9% 0.01/s +22-Dec 23:44:42 test18 425.5 sec 16: all 20468 full 100% 0.04/s +[malloc debugging turned back on] diff --git a/deps/GraphBLAS/Tcov/log_Dec8.txt b/deps/GraphBLAS/Tcov/log_Dec8.txt new file mode 100644 index 0000000000..5c0425b38f --- /dev/null +++ b/deps/GraphBLAS/Tcov/log_Dec8.txt @@ -0,0 +1,142 @@ + +---------------------------------------------- [malloc] [cover] +08-Dec 16:07:21 test247 0.5 sec 217: 20139 of 20356 1.1% 445.61/s +08-Dec 16:07:32 test246 10.9 sec 157: 19982 of 20356 1.8% 14.45/s +08-Dec 16:07:33 test01 1.4 sec 1976: 18006 of 20356 11.5% 1446.61/s +08-Dec 16:07:33 test245 0.2 sec 47: 17959 of 20356 11.8% 276.85/s +08-Dec 16:07:33 test199 0.0 sec 17: 17942 of 20356 11.9% 1993.90/s +08-Dec 16:07:33 test83 0.1 sec 21: 17921 of 20356 12.0% 223.61/s +08-Dec 16:07:33 test210 0.0 sec 7: 17914 of 20356 12.0% 1443.89/s +08-Dec 16:07:33 test165 0.0 sec 12: 17902 of 20356 12.1% 581.93/s +08-Dec 16:07:33 test219 0.1 sec 11: 17891 of 20356 12.1% 81.05/s +08-Dec 16:07:34 test241 0.3 sec 16: 17875 of 20356 12.2% 47.84/s +08-Dec 16:07:34 test220 0.1 sec 66: 17809 of 20356 12.5% 494.76/s +08-Dec 16:07:34 test211 0.1 sec 26: 17783 of 20356 12.6% 474.77/s +08-Dec 16:07:34 test202 0.2 sec 33: 17750 of 20356 12.8% 219.82/s +08-Dec 16:07:36 test152 1.5 sec 1127: 16623 of 20356 18.3% 753.67/s +08-Dec 16:07:36 test222 0.1 sec 6: 16617 of 20356 18.4% 48.73/s +08-Dec 16:07:36 test240 0.5 sec 42: 16575 of 20356 18.6% 77.65/s +08-Dec 16:07:37 test186 0.5 sec 67: 16508 of 20356 18.9% 131.38/s +08-Dec 16:07:37 test186(0) 0.6 sec 4: 16504 of 20356 18.9% 6.35/s +08-Dec 16:07:38 test186 0.5 sec 3: 16501 of 20356 18.9% 6.60/s +08-Dec 16:07:38 test150 0.4 sec 63: 16438 of 20356 19.2% 160.70/s +08-Dec 16:07:38 test239 0.1 sec 14: 16424 of 20356 19.3% 113.42/s +08-Dec 16:07:38 test235 0.0 sec 12: 16412 of 20356 19.4% 297.70/s +08-Dec 16:07:38 test226 0.0 sec 8: 16404 of 20356 19.4% 612.14/s +08-Dec 16:07:38 test223 0.0 sec 2: 16402 of 20356 19.4% 69.53/s +08-Dec 16:07:39 test204 0.1 sec 21: 16381 of 20356 19.5% 148.67/s +08-Dec 16:07:39 test203 0.1 sec 11: 16370 of 20356 19.6% 131.67/s +08-Dec 16:07:39 test183 0.0 sec 12: 16358 of 20356 19.6% 313.68/s +08-Dec 16:07:39 test179 0.2 sec 26: 16332 of 20356 19.8% 172.26/s +08-Dec 16:07:39 test174 0.1 sec 10: 16322 of 20356 19.8% 170.29/s +08-Dec 16:07:39 test155 0.2 sec 48: 16274 of 20356 20.1% 284.70/s +08-Dec 16:07:40 test156 0.9 sec 258: 16016 of 20356 21.3% 273.24/s +08-Dec 16:07:40 test136 0.2 sec 58: 15958 of 20356 21.6% 297.04/s +08-Dec 16:07:41 test02 0.5 sec 181: 15777 of 20356 22.5% 387.16/s +08-Dec 16:07:41 test109 0.1 sec 12: 15765 of 20356 22.6% 115.44/s +08-Dec 16:07:41 test109 0.0 sec 1: 15764 of 20356 22.6% 308.74/s +08-Dec 16:07:41 test04 0.1 sec 21: 15743 of 20356 22.7% 202.05/s +08-Dec 16:07:41 test207 0.0 sec 1: 15742 of 20356 22.7% 230.52/s +08-Dec 16:07:41 test221 0.0 sec 2: 15740 of 20356 22.7% 256.57/s +08-Dec 16:07:41 test162 0.1 sec 5: 15735 of 20356 22.7% 75.31/s +08-Dec 16:07:43 test159 2.0 sec 135: 15600 of 20356 23.4% 66.19/s +08-Dec 16:07:43 test09 0.0 sec 5: 15595 of 20356 23.4% 212.63/s +08-Dec 16:07:43 test132 0.1 sec 8: 15587 of 20356 23.4% 75.07/s +08-Dec 16:07:50 test141 6.7 sec 543: 15044 of 20356 26.1% 81.02/s +08-Dec 16:07:51 testc2(1,1) 0.5 sec 46: 14998 of 20356 26.3% 85.39/s +08-Dec 16:07:51 test214 0.0 sec 3: 14995 of 20356 26.3% 217.14/s +08-Dec 16:07:51 test213 0.0 sec 4: 14991 of 20356 26.4% 377.86/s +08-Dec 16:07:54 test206 3.2 sec 265: 14726 of 20356 27.7% 83.87/s +08-Dec 16:07:54 test212 0.1 sec 10: 14716 of 20356 27.7% 112.58/s +08-Dec 16:07:55 test128 0.8 sec 53: 14663 of 20356 28.0% 64.43/s +08-Dec 16:07:55 test82 0.1 sec 18: 14645 of 20356 28.1% 145.20/s +08-Dec 16:07:56 test229 1.0 sec 7: 14638 of 20356 28.1% 7.09/s +08-Dec 16:07:56 test144 0.7 sec 2: 14636 of 20356 28.1% 2.90/s +08-Dec 16:08:22 test14 25.8 sec 724: 13912 of 20356 31.7% 28.06/s +08-Dec 16:08:33 test180 10.8 sec 133: 13779 of 20356 32.3% 12.36/s +08-Dec 16:08:38 test236 4.5 sec 73: 13706 of 20356 32.7% 16.15/s +08-Dec 16:08:41 test232 3.3 sec 22: 13684 of 20356 32.8% 6.59/s +08-Dec 16:09:02 test228 21.4 sec 37: 13647 of 20356 33.0% 1.73/s +08-Dec 16:11:37 test154 154.2 sec 1503: 12144 of 20356 40.3% 9.75/s +08-Dec 16:11:55 test238 18.3 sec 70: 12074 of 20356 40.7% 3.82/s +08-Dec 16:12:53 test151b 58.0 sec 144: 11930 of 20356 41.4% 2.48/s +08-Dec 16:12:56 test184 3.1 sec 39: 11891 of 20356 41.6% 12.38/s +08-Dec 16:13:09 test191 13.2 sec 20: 11871 of 20356 41.7% 1.51/s +08-Dec 16:14:02 test188 52.9 sec 194: 11677 of 20356 42.6% 3.67/s +08-Dec 16:14:03 test237 0.8 sec 16: 11661 of 20356 42.7% 20.38/s +08-Dec 16:14:08 test224 5.2 sec 24: 11637 of 20356 42.8% 4.59/s +08-Dec 16:14:11 test196 2.4 sec 11: 11626 of 20356 42.9% 4.56/s +08-Dec 16:14:17 test209 5.9 sec 20: 11606 of 20356 43.0% 3.42/s +08-Dec 16:14:35 test104 18.8 sec 40: 11566 of 20356 43.2% 2.13/s +08-Dec 16:14:43 test189 7.8 sec 1: 11565 of 20356 43.2% 0.13/s +08-Dec 16:15:56 test194 72.7 sec 8: 11557 of 20356 43.2% 0.11/s +08-Dec 16:16:12 test76 16.3 sec 18: 11539 of 20356 43.3% 1.10/s +08-Dec 16:16:51 test244 38.8 sec 17: 11522 of 20356 43.4% 0.44/s +[malloc debugging turned off] +08-Dec 16:16:51 test201 0.0 sec 5: 11517 of 20356 43.4% 712.05/s +08-Dec 16:16:51 test225 0.1 sec 5: 11512 of 20356 43.4% 33.91/s +08-Dec 16:16:51 test170 0.1 sec 1: 11511 of 20356 43.5% 13.69/s +08-Dec 16:16:51 test176 0.1 sec 5: 11506 of 20356 43.5% 60.98/s +08-Dec 16:16:51 test208 0.0 sec 5: 11501 of 20356 43.5% 266.85/s +08-Dec 16:16:51 test216 0.1 sec 3: 11498 of 20356 43.5% 36.67/s +08-Dec 16:16:59 test142 7.4 sec 630: 10868 of 20356 46.6% 85.57/s +08-Dec 16:16:59 test137 0.1 sec 5: 10863 of 20356 46.6% 33.78/s +08-Dec 16:16:59 test139 0.4 sec 2: 10861 of 20356 46.6% 5.63/s +08-Dec 16:16:59 test145 0.2 sec 10: 10851 of 20356 46.7% 60.90/s +08-Dec 16:16:59 test172 0.1 sec 3: 10848 of 20356 46.7% 38.48/s +08-Dec 16:17:00 test148 0.4 sec 6: 10842 of 20356 46.7% 14.69/s +08-Dec 16:17:01 test157 0.7 sec 13: 10829 of 20356 46.8% 19.73/s +08-Dec 16:17:02 test182 1.0 sec 9: 10820 of 20356 46.8% 9.02/s +08-Dec 16:17:02 test108 0.4 sec 1: 10819 of 20356 46.9% 2.48/s +08-Dec 16:17:03 test130 0.9 sec 26: 10793 of 20356 47.0% 27.59/s +08-Dec 16:17:03 test124 0.2 sec 3: 10790 of 20356 47.0% 16.49/s +08-Dec 16:17:03 test138 0.0 sec 1: 10789 of 20356 47.0% 20.43/s +08-Dec 16:17:08 test227 4.9 sec 27: 10762 of 20356 47.1% 5.49/s +08-Dec 16:17:41 test125 32.6 sec 627: 10135 of 20356 50.2% 19.22/s +08-Dec 16:18:57 test234 76.3 sec 69: 10066 of 20356 50.6% 0.90/s +08-Dec 16:19:49 test242 52.1 sec 77: 9989 of 20356 50.9% 1.48/s +08-Dec 16:19:50 test173 1.2 sec 11: 9978 of 20356 51.0% 8.81/s +08-Dec 16:19:54 test200 3.5 sec 10: 9968 of 20356 51.0% 2.89/s +08-Dec 16:19:54 test197 0.1 sec 1: 9967 of 20356 51.0% 7.43/s +08-Dec 16:19:55 test84 1.4 sec 18: 9949 of 20356 51.1% 12.45/s +08-Dec 16:20:09 test19b 13.4 sec 57: 9892 of 20356 51.4% 4.26/s +08-Dec 16:20:18 test19b 9.3 sec 5: 9887 of 20356 51.4% 0.54/s +08-Dec 16:20:18 test133 0.5 sec 2: 9885 of 20356 51.4% 4.41/s +08-Dec 16:20:23 test80 4.2 sec 12: 9873 of 20356 51.5% 2.85/s +08-Dec 16:20:44 test151 21.1 sec 73: 9800 of 20356 51.9% 3.46/s +08-Dec 16:21:03 test23 18.8 sec 88: 9712 of 20356 52.3% 4.67/s +08-Dec 16:21:05 test135 2.0 sec 7: 9705 of 20356 52.3% 3.50/s +08-Dec 16:21:37 test160 32.4 sec 25: 9680 of 20356 52.4% 0.77/s +08-Dec 16:21:43 test54 5.8 sec 20: 9660 of 20356 52.5% 3.44/s +08-Dec 16:21:44 test129 1.2 sec 7: 9653 of 20356 52.6% 5.66/s +08-Dec 16:21:46 test69 2.1 sec 3: 9650 of 20356 52.6% 1.44/s +08-Dec 16:23:23 test230 96.5 sec 104: 9546 of 20356 53.1% 1.08/s +08-Dec 16:34:12 test74 649.8 sec 5796: 3750 of 20356 81.6% 8.92/s +08-Dec 16:38:26 test127 253.4 sec 1606: 2144 of 20356 89.5% 6.34/s +08-Dec 16:38:29 test19 3.5 sec 12: 2132 of 20356 89.5% 3.39/s +08-Dec 16:38:33 test11 3.6 sec 3: 2129 of 20356 89.5% 0.83/s +08-Dec 16:39:05 test160 32.3 sec 4: 2125 of 20356 89.6% 0.12/s +08-Dec 16:39:08 test215 3.0 sec 1: 2124 of 20356 89.6% 0.33/s +08-Dec 16:39:27 test193 18.3 sec 5: 2119 of 20356 89.6% 0.27/s +08-Dec 16:40:53 test195 86.7 sec 36: 2083 of 20356 89.8% 0.42/s +08-Dec 16:41:01 test233 8.0 sec 1: 2082 of 20356 89.8% 0.12/s +08-Dec 16:41:28 test243 27.1 sec 7: 2075 of 20356 89.8% 0.26/s +08-Dec 16:41:37 test29 8.9 sec 2: 2073 of 20356 89.8% 0.22/s +08-Dec 16:41:39 testc2(0,0) 1.3 sec 9: 2064 of 20356 89.9% 6.96/s +08-Dec 16:41:39 testc4(0) 0.6 sec 4: 2060 of 20356 89.9% 6.88/s +08-Dec 16:41:58 testc7(0) 18.7 sec 3: 2057 of 20356 89.9% 0.16/s +08-Dec 16:42:04 testcc(1) 5.8 sec 1: 2056 of 20356 89.9% 0.17/s +08-Dec 16:42:12 test187 8.6 sec 3: 2053 of 20356 89.9% 0.35/s +08-Dec 16:42:18 test192 5.9 sec 1: 2052 of 20356 89.9% 0.17/s +08-Dec 16:42:39 test181 20.7 sec 13: 2039 of 20356 90.0% 0.63/s +08-Dec 16:44:19 test185 100.2 sec 11: 2028 of 20356 90.0% 0.11/s +08-Dec 16:44:35 test53 16.0 sec 4: 2024 of 20356 90.1% 0.25/s +08-Dec 16:45:26 test17 51.2 sec 28: 1996 of 20356 90.2% 0.55/s +08-Dec 16:53:08 test231 461.6 sec 295: 1701 of 20356 91.6% 0.64/s +08-Dec 17:06:07 test10 778.6 sec 793: 908 of 20356 95.5% 1.02/s +08-Dec 17:16:13 test75b 605.8 sec 860: 48 of 20356 99.8% 1.42/s +08-Dec 17:17:45 test21b 92.8 sec 26: 22 of 20356 99.9% 0.28/s +08-Dec 17:18:54 testca(1) 68.9 sec 5: 17 of 20356 99.9% 0.07/s +08-Dec 17:20:48 test81 113.9 sec 1: 16 of 20356 99.9% 0.01/s +08-Dec 17:28:00 test18 432.4 sec 16: all 20356 full 100% 0.04/s +[malloc debugging turned back on] diff --git a/deps/GraphBLAS/Tcov/log_Oct13.txt b/deps/GraphBLAS/Tcov/log_Oct13.txt deleted file mode 100644 index 97220e2a76..0000000000 --- a/deps/GraphBLAS/Tcov/log_Oct13.txt +++ /dev/null @@ -1,141 +0,0 @@ - ----------------------------------------------- [malloc] [cover] -13-Oct 19:31:32 test246 9.1 sec 374: 19981 of 20355 1.8% 40.94/s -13-Oct 19:31:33 test01 0.9 sec 1975: 18006 of 20355 11.5% 2166.50/s -13-Oct 19:31:34 test245 0.2 sec 47: 17959 of 20355 11.8% 268.90/s -13-Oct 19:31:34 test199 0.0 sec 17: 17942 of 20355 11.9% 1542.09/s -13-Oct 19:31:34 test83 0.1 sec 21: 17921 of 20355 12.0% 258.12/s -13-Oct 19:31:34 test210 0.0 sec 7: 17914 of 20355 12.0% 1508.62/s -13-Oct 19:31:34 test165 0.0 sec 12: 17902 of 20355 12.1% 1099.20/s -13-Oct 19:31:34 test219 0.1 sec 11: 17891 of 20355 12.1% 150.11/s -13-Oct 19:31:34 test241 0.3 sec 16: 17875 of 20355 12.2% 46.23/s -13-Oct 19:31:34 test220 0.1 sec 66: 17809 of 20355 12.5% 501.33/s -13-Oct 19:31:34 test211 0.1 sec 26: 17783 of 20355 12.6% 476.16/s -13-Oct 19:31:34 test202 0.1 sec 33: 17750 of 20355 12.8% 222.10/s -13-Oct 19:31:36 test152 1.4 sec 1127: 16623 of 20355 18.3% 809.75/s -13-Oct 19:31:36 test222 0.1 sec 6: 16617 of 20355 18.4% 77.45/s -13-Oct 19:31:36 test240 0.4 sec 42: 16575 of 20355 18.6% 117.50/s -13-Oct 19:31:37 test186 0.5 sec 67: 16508 of 20355 18.9% 129.58/s -13-Oct 19:31:37 test186(0) 0.4 sec 4: 16504 of 20355 18.9% 9.00/s -13-Oct 19:31:38 test186 0.5 sec 3: 16501 of 20355 18.9% 6.57/s -13-Oct 19:31:38 test150 0.2 sec 63: 16438 of 20355 19.2% 316.49/s -13-Oct 19:31:38 test239 0.1 sec 14: 16424 of 20355 19.3% 120.74/s -13-Oct 19:31:38 test235 0.0 sec 12: 16412 of 20355 19.4% 306.81/s -13-Oct 19:31:38 test226 0.0 sec 8: 16404 of 20355 19.4% 639.08/s -13-Oct 19:31:38 test223 0.0 sec 2: 16402 of 20355 19.4% 63.90/s -13-Oct 19:31:38 test204 0.1 sec 21: 16381 of 20355 19.5% 151.52/s -13-Oct 19:31:38 test203 0.1 sec 11: 16370 of 20355 19.6% 135.08/s -13-Oct 19:31:38 test183 0.0 sec 12: 16358 of 20355 19.6% 319.30/s -13-Oct 19:31:39 test179 0.1 sec 26: 16332 of 20355 19.8% 177.37/s -13-Oct 19:31:39 test174 0.1 sec 10: 16322 of 20355 19.8% 177.79/s -13-Oct 19:31:39 test155 0.2 sec 48: 16274 of 20355 20.0% 282.53/s -13-Oct 19:31:40 test156 0.7 sec 258: 16016 of 20355 21.3% 359.18/s -13-Oct 19:31:40 test136 0.2 sec 58: 15958 of 20355 21.6% 298.87/s -13-Oct 19:31:40 test02 0.4 sec 181: 15777 of 20355 22.5% 494.60/s -13-Oct 19:31:40 test109 0.1 sec 12: 15765 of 20355 22.5% 100.04/s -13-Oct 19:31:40 test109 0.0 sec 1: 15764 of 20355 22.6% 297.35/s -13-Oct 19:31:40 test04 0.1 sec 21: 15743 of 20355 22.7% 201.56/s -13-Oct 19:31:40 test207 0.0 sec 1: 15742 of 20355 22.7% 255.62/s -13-Oct 19:31:40 test221 0.0 sec 2: 15740 of 20355 22.7% 259.00/s -13-Oct 19:31:40 test162 0.1 sec 5: 15735 of 20355 22.7% 75.45/s -13-Oct 19:31:42 test159 1.5 sec 135: 15600 of 20355 23.4% 90.37/s -13-Oct 19:31:42 test09 0.0 sec 5: 15595 of 20355 23.4% 494.02/s -13-Oct 19:31:42 test132 0.1 sec 8: 15587 of 20355 23.4% 84.66/s -13-Oct 19:31:48 test141 5.6 sec 543: 15044 of 20355 26.1% 97.00/s -13-Oct 19:31:48 testc2(1,1) 0.4 sec 45: 14999 of 20355 26.3% 110.21/s -13-Oct 19:31:48 test214 0.0 sec 3: 14996 of 20355 26.3% 227.26/s -13-Oct 19:31:48 test213 0.0 sec 4: 14992 of 20355 26.3% 391.58/s -13-Oct 19:31:51 test206 2.7 sec 265: 14727 of 20355 27.6% 99.67/s -13-Oct 19:31:51 test212 0.1 sec 10: 14717 of 20355 27.7% 113.83/s -13-Oct 19:31:51 test128 0.3 sec 53: 14664 of 20355 28.0% 151.52/s -13-Oct 19:31:51 test82 0.1 sec 18: 14646 of 20355 28.0% 199.79/s -13-Oct 19:31:52 test229 1.0 sec 7: 14639 of 20355 28.1% 7.16/s -13-Oct 19:31:53 test144 0.6 sec 2: 14637 of 20355 28.1% 3.35/s -13-Oct 19:32:15 test14 22.1 sec 725: 13912 of 20355 31.7% 32.82/s -13-Oct 19:32:25 test180 9.8 sec 133: 13779 of 20355 32.3% 13.63/s -13-Oct 19:32:28 test236 3.6 sec 73: 13706 of 20355 32.7% 20.35/s -13-Oct 19:32:31 test232 2.8 sec 22: 13684 of 20355 32.8% 7.99/s -13-Oct 19:32:49 test228 17.5 sec 37: 13647 of 20355 33.0% 2.11/s -13-Oct 19:34:48 test154 119.8 sec 1503: 12144 of 20355 40.3% 12.55/s -13-Oct 19:35:04 test238 15.3 sec 70: 12074 of 20355 40.7% 4.56/s -13-Oct 19:35:52 test151b 47.8 sec 144: 11930 of 20355 41.4% 3.01/s -13-Oct 19:35:55 test184 3.1 sec 39: 11891 of 20355 41.6% 12.48/s -13-Oct 19:36:08 test191 13.0 sec 20: 11871 of 20355 41.7% 1.54/s -13-Oct 19:36:59 test188 51.8 sec 194: 11677 of 20355 42.6% 3.74/s -13-Oct 19:37:00 test237 0.7 sec 16: 11661 of 20355 42.7% 21.98/s -13-Oct 19:37:05 test224 5.2 sec 24: 11637 of 20355 42.8% 4.58/s -13-Oct 19:37:08 test196 2.5 sec 11: 11626 of 20355 42.9% 4.44/s -13-Oct 19:37:14 test209 5.7 sec 20: 11606 of 20355 43.0% 3.48/s -13-Oct 19:37:32 test104 18.6 sec 40: 11566 of 20355 43.2% 2.15/s -13-Oct 19:37:40 test189 7.7 sec 1: 11565 of 20355 43.2% 0.13/s -13-Oct 19:38:52 test194 71.9 sec 8: 11557 of 20355 43.2% 0.11/s -13-Oct 19:39:08 test76 15.9 sec 18: 11539 of 20355 43.3% 1.13/s -13-Oct 19:39:46 test244 38.4 sec 17: 11522 of 20355 43.4% 0.44/s -[malloc debugging turned off] -13-Oct 19:39:46 test201 0.0 sec 5: 11517 of 20355 43.4% 688.33/s -13-Oct 19:39:46 test225 0.1 sec 5: 11512 of 20355 43.4% 34.82/s -13-Oct 19:39:46 test170 0.1 sec 1: 11511 of 20355 43.4% 13.06/s -13-Oct 19:39:47 test176 0.1 sec 5: 11506 of 20355 43.5% 58.50/s -13-Oct 19:39:47 test208 0.0 sec 5: 11501 of 20355 43.5% 295.25/s -13-Oct 19:39:47 test216 0.1 sec 3: 11498 of 20355 43.5% 35.58/s -13-Oct 19:39:54 test142 7.3 sec 630: 10868 of 20355 46.6% 86.80/s -13-Oct 19:39:54 test137 0.1 sec 5: 10863 of 20355 46.6% 34.16/s -13-Oct 19:39:54 test139 0.4 sec 2: 10861 of 20355 46.6% 5.48/s -13-Oct 19:39:55 test145 0.2 sec 10: 10851 of 20355 46.7% 60.08/s -13-Oct 19:39:55 test172 0.1 sec 3: 10848 of 20355 46.7% 39.22/s -13-Oct 19:39:55 test148 0.5 sec 6: 10842 of 20355 46.7% 13.11/s -13-Oct 19:39:56 test157 0.6 sec 13: 10829 of 20355 46.8% 20.31/s -13-Oct 19:39:57 test182 1.0 sec 9: 10820 of 20355 46.8% 9.07/s -13-Oct 19:39:57 test108 0.5 sec 1: 10819 of 20355 46.8% 2.20/s -13-Oct 19:39:58 test130 0.9 sec 26: 10793 of 20355 47.0% 27.42/s -13-Oct 19:39:58 test124 0.2 sec 3: 10790 of 20355 47.0% 16.67/s -13-Oct 19:39:58 test138 0.0 sec 1: 10789 of 20355 47.0% 20.03/s -13-Oct 19:40:03 test227 4.9 sec 27: 10762 of 20355 47.1% 5.55/s -13-Oct 19:40:35 test125 32.2 sec 627: 10135 of 20355 50.2% 19.50/s -13-Oct 19:41:51 test234 76.0 sec 69: 10066 of 20355 50.5% 0.91/s -13-Oct 19:42:44 test242 52.0 sec 77: 9989 of 20355 50.9% 1.48/s -13-Oct 19:42:45 test173 1.3 sec 11: 9978 of 20355 51.0% 8.41/s -13-Oct 19:42:48 test200 3.3 sec 10: 9968 of 20355 51.0% 3.00/s -13-Oct 19:42:48 test197 0.1 sec 1: 9967 of 20355 51.0% 7.68/s -13-Oct 19:42:50 test84 1.4 sec 18: 9949 of 20355 51.1% 12.73/s -13-Oct 19:43:04 test19b 13.8 sec 57: 9892 of 20355 51.4% 4.14/s -13-Oct 19:43:13 test19b 9.2 sec 5: 9887 of 20355 51.4% 0.54/s -13-Oct 19:43:13 test133 0.4 sec 2: 9885 of 20355 51.4% 5.24/s -13-Oct 19:43:17 test80 3.8 sec 12: 9873 of 20355 51.5% 3.14/s -13-Oct 19:43:38 test151 20.8 sec 73: 9800 of 20355 51.9% 3.50/s -13-Oct 19:43:56 test23 18.6 sec 88: 9712 of 20355 52.3% 4.73/s -13-Oct 19:43:58 test135 1.9 sec 7: 9705 of 20355 52.3% 3.71/s -13-Oct 19:44:28 test160 29.3 sec 25: 9680 of 20355 52.4% 0.85/s -13-Oct 19:44:33 test54 5.9 sec 20: 9660 of 20355 52.5% 3.41/s -13-Oct 19:44:35 test129 1.2 sec 7: 9653 of 20355 52.6% 5.63/s -13-Oct 19:44:37 test69 2.2 sec 3: 9650 of 20355 52.6% 1.34/s -13-Oct 19:46:12 test230 94.9 sec 104: 9546 of 20355 53.1% 1.10/s -13-Oct 19:56:55 test74 643.5 sec 5796: 3750 of 20355 81.6% 9.01/s -13-Oct 20:01:06 test127 250.4 sec 1606: 2144 of 20355 89.5% 6.41/s -13-Oct 20:01:09 test19 3.6 sec 12: 2132 of 20355 89.5% 3.35/s -13-Oct 20:01:13 test11 3.7 sec 3: 2129 of 20355 89.5% 0.81/s -13-Oct 20:01:42 test160 29.3 sec 4: 2125 of 20355 89.6% 0.14/s -13-Oct 20:01:45 test215 2.8 sec 1: 2124 of 20355 89.6% 0.35/s -13-Oct 20:02:03 test193 17.8 sec 5: 2119 of 20355 89.6% 0.28/s -13-Oct 20:03:23 test195 80.1 sec 36: 2083 of 20355 89.8% 0.45/s -13-Oct 20:03:31 test233 7.8 sec 1: 2082 of 20355 89.8% 0.13/s -13-Oct 20:03:57 test243 26.4 sec 7: 2075 of 20355 89.8% 0.27/s -13-Oct 20:04:07 test29 9.5 sec 2: 2073 of 20355 89.8% 0.21/s -13-Oct 20:04:08 testc2(0,0) 1.3 sec 9: 2064 of 20355 89.9% 7.06/s -13-Oct 20:04:09 testc4(0) 0.6 sec 4: 2060 of 20355 89.9% 6.86/s -13-Oct 20:04:27 testc7(0) 18.4 sec 3: 2057 of 20355 89.9% 0.16/s -13-Oct 20:04:33 testcc(1) 5.8 sec 1: 2056 of 20355 89.9% 0.17/s -13-Oct 20:04:41 test187 8.3 sec 3: 2053 of 20355 89.9% 0.36/s -13-Oct 20:04:47 test192 5.7 sec 1: 2052 of 20355 89.9% 0.17/s -13-Oct 20:05:07 test181 20.0 sec 13: 2039 of 20355 90.0% 0.65/s -13-Oct 20:06:42 test185 95.5 sec 11: 2028 of 20355 90.0% 0.12/s -13-Oct 20:06:58 test53 16.0 sec 4: 2024 of 20355 90.1% 0.25/s -13-Oct 20:07:48 test17 50.1 sec 28: 1996 of 20355 90.2% 0.56/s -13-Oct 20:15:23 test231 454.6 sec 295: 1701 of 20355 91.6% 0.65/s -13-Oct 20:28:18 test10 774.8 sec 793: 908 of 20355 95.5% 1.02/s -13-Oct 20:38:26 test75b 608.0 sec 860: 48 of 20355 99.8% 1.41/s -13-Oct 20:39:58 test21b 92.2 sec 26: 22 of 20355 99.9% 0.28/s -13-Oct 20:41:10 testca(1) 72.2 sec 5: 17 of 20355 99.9% 0.07/s -13-Oct 20:43:04 test81 113.4 sec 1: 16 of 20355 99.9% 0.01/s -13-Oct 20:50:15 test18 431.1 sec 16: all 20355 full 100% 0.04/s -[malloc debugging turned back on] diff --git a/deps/GraphBLAS/Test/GB_mex_about.c b/deps/GraphBLAS/Test/GB_mex_about.c index 5096048b13..f13efdfd64 100644 --- a/deps/GraphBLAS/Test/GB_mex_about.c +++ b/deps/GraphBLAS/Test/GB_mex_about.c @@ -207,6 +207,7 @@ void mexFunction GrB_Descriptor Duh ; GrB_Desc_Value val ; + int v2 ; GrB_Descriptor_new (&Duh) ; GB_Descriptor_check (Duh, "\n---------------------------------- Duh:", @@ -221,6 +222,12 @@ void mexFunction GxB_COMPLETE, stdout) ; GxB_Desc_get (Duh, GxB_SORT, &val) ; printf ("got sort %d\n", val) ; CHECK (val == true) ; + GxB_Desc_set (Duh, GxB_SORT, false) ; + GxB_Desc_set_INT32 (Duh, GxB_SORT, true) ; + GB_Descriptor_check (Duh, "\n------------------------------- Duh set sort:", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GxB_SORT, &v2) ; printf ("got sort %d\n", v2) ; CHECK (v2 == true) ; + GxB_Desc_set (Duh, GrB_INP0, GrB_TRAN) ; GB_Descriptor_check (Duh, "\n------------------------------- Duh set:", GxB_COMPLETE, stdout) ; @@ -229,6 +236,15 @@ void mexFunction GxB_Desc_get (Duh, GrB_INP0, &val) ; printf ("got inp0 %d\n", val) ; CHECK (val == GrB_TRAN) ; GxB_Desc_get (Duh, GrB_INP1, &val) ; printf ("got inp1 %d\n", val) ; CHECK (val == GxB_DEFAULT) ; + GxB_Desc_set (Duh, GrB_INP0, GxB_DEFAULT) ; + GxB_Desc_set_INT32 (Duh, GrB_INP0, GrB_TRAN) ; + GB_Descriptor_check (Duh, "\n------------------------------- Duh set:", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GrB_OUTP, &v2) ; printf ("got outp %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_get_INT32 (Duh, GrB_MASK, &v2) ; printf ("got mask %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_get_INT32 (Duh, GrB_INP0, &v2) ; printf ("got inp0 %d\n", v2) ; CHECK (v2 == GrB_TRAN) ; + GxB_Desc_get_INT32 (Duh, GrB_INP1, &v2) ; printf ("got inp1 %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_set (Duh, GrB_MASK, GrB_COMP) ; GB_Descriptor_check (Duh, "\n-----Duh set mask", GxB_COMPLETE, stdout) ; @@ -237,6 +253,15 @@ void mexFunction GxB_Desc_get (Duh, GrB_INP0, &val) ; printf ("got inp0 %d\n", val) ; CHECK (val == GrB_TRAN) ; GxB_Desc_get (Duh, GrB_INP1, &val) ; printf ("got inp1 %d\n", val) ; CHECK (val == GxB_DEFAULT) ; + GxB_Desc_set (Duh, GrB_MASK, GxB_DEFAULT) ; + GxB_Desc_set_INT32 (Duh, GrB_MASK, GrB_COMP) ; + GB_Descriptor_check (Duh, "\n-----Duh set mask", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GrB_OUTP, &v2) ; printf ("got outp %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_get_INT32 (Duh, GrB_MASK, &v2) ; printf ("got mask %d\n", v2) ; CHECK (v2 == GrB_COMP) ; + GxB_Desc_get_INT32 (Duh, GrB_INP0, &v2) ; printf ("got inp0 %d\n", v2) ; CHECK (v2 == GrB_TRAN) ; + GxB_Desc_get_INT32 (Duh, GrB_INP1, &v2) ; printf ("got inp1 %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_set (Duh, GrB_OUTP, GrB_REPLACE) ; GB_Descriptor_check (Duh, "\n-----Duh set out", GxB_COMPLETE, stdout) ; @@ -245,6 +270,15 @@ void mexFunction GxB_Desc_get (Duh, GrB_INP0, &val) ; printf ("got inp0 %d\n", val) ; CHECK (val == GrB_TRAN) ; GxB_Desc_get (Duh, GrB_INP1, &val) ; printf ("got inp1 %d\n", val) ; CHECK (val == GxB_DEFAULT) ; + GxB_Desc_set (Duh, GrB_OUTP, GxB_DEFAULT) ; + GxB_Desc_set_INT32 (Duh, GrB_OUTP, GrB_REPLACE) ; + GB_Descriptor_check (Duh, "\n-----Duh set out", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GrB_OUTP, &v2) ; printf ("got outp %d\n", v2) ; CHECK (v2 == GrB_REPLACE) ; + GxB_Desc_get_INT32 (Duh, GrB_MASK, &v2) ; printf ("got mask %d\n", v2) ; CHECK (v2 == GrB_COMP) ; + GxB_Desc_get_INT32 (Duh, GrB_INP0, &v2) ; printf ("got inp0 %d\n", v2) ; CHECK (v2 == GrB_TRAN) ; + GxB_Desc_get_INT32 (Duh, GrB_INP1, &v2) ; printf ("got inp1 %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GrB_Descriptor_set (Duh, GrB_MASK, GrB_STRUCTURE) ; GB_Descriptor_check (Duh, "\n-----Duh set mask structural", GxB_COMPLETE, stdout) ; @@ -253,6 +287,16 @@ void mexFunction GxB_Desc_get (Duh, GrB_INP0, &val) ; printf ("got inp0 %d\n", val) ; CHECK (val == GrB_TRAN) ; GxB_Desc_get (Duh, GrB_INP1, &val) ; printf ("got inp1 %d\n", val) ; CHECK (val == GxB_DEFAULT) ; + GrB_Descriptor_set (Duh, GrB_MASK, GxB_DEFAULT) ; + GxB_Desc_set_INT32 (Duh, GrB_MASK, GrB_STRUCTURE) ; + GxB_Desc_set_INT32 (Duh, GrB_MASK, GrB_COMP) ; + GB_Descriptor_check (Duh, "\n-----Duh set mask structural", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GrB_OUTP, &v2) ; printf ("got outp %d\n", v2) ; CHECK (v2 == GrB_REPLACE) ; + GxB_Desc_get_INT32 (Duh, GrB_MASK, &v2) ; printf ("got mask %d\n", v2) ; CHECK (v2 == GrB_COMP + GrB_STRUCTURE) ; + GxB_Desc_get_INT32 (Duh, GrB_INP0, &v2) ; printf ("got inp0 %d\n", v2) ; CHECK (v2 == GrB_TRAN) ; + GxB_Desc_get_INT32 (Duh, GrB_INP1, &v2) ; printf ("got inp1 %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GrB_Descriptor_set (Duh, GrB_MASK, GxB_DEFAULT) ; GB_Descriptor_check (Duh, "\n-----Duh set mask back", GxB_COMPLETE, stdout) ; @@ -261,6 +305,15 @@ void mexFunction GxB_Desc_get (Duh, GrB_INP0, &val) ; printf ("got inp0 %d\n", val) ; CHECK (val == GrB_TRAN) ; GxB_Desc_get (Duh, GrB_INP1, &val) ; printf ("got inp1 %d\n", val) ; CHECK (val == GxB_DEFAULT) ; + GrB_Descriptor_set (Duh, GrB_MASK, GrB_STRUCTURE) ; + GxB_Desc_set_INT32 (Duh, GrB_MASK, GxB_DEFAULT) ; + GB_Descriptor_check (Duh, "\n-----Duh set mask back", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GrB_OUTP, &v2) ; printf ("got outp %d\n", v2) ; CHECK (v2 == GrB_REPLACE) ; + GxB_Desc_get_INT32 (Duh, GrB_MASK, &v2) ; printf ("got mask %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_get_INT32 (Duh, GrB_INP0, &v2) ; printf ("got inp0 %d\n", v2) ; CHECK (v2 == GrB_TRAN) ; + GxB_Desc_get_INT32 (Duh, GrB_INP1, &v2) ; printf ("got inp1 %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + info = GxB_Desc_set (Duh, GrB_INP1, GrB_REPLACE) ; OK (GrB_Descriptor_wait_(Duh, GrB_MATERIALIZE)) ; GrB_Descriptor_error_(&err, Duh) ; @@ -272,6 +325,18 @@ void mexFunction GxB_Desc_get (Duh, GrB_INP0, &val) ; printf ("got inp0 %d\n", val) ; CHECK (val == GrB_TRAN) ; GxB_Desc_get (Duh, GrB_INP1, &val) ; printf ("got inp1 %d\n", val) ; CHECK (val == GxB_DEFAULT) ; + info = GxB_Desc_set (Duh, GrB_INP1, GxB_DEFAULT) ; + info = GxB_Desc_set_INT32 (Duh, GrB_INP1, GrB_REPLACE) ; + OK (GrB_Descriptor_wait_(Duh, GrB_MATERIALIZE)) ; + GrB_Descriptor_error_(&err, Duh) ; + printf ("%s\n", err) ; + GB_Descriptor_check (Duh, "\n-----Duh set in1", + GxB_COMPLETE, stdout) ; + GxB_Desc_get_INT32 (Duh, GrB_OUTP, &v2) ; printf ("got outp %d\n", v2) ; CHECK (v2 == GrB_REPLACE) ; + GxB_Desc_get_INT32 (Duh, GrB_MASK, &v2) ; printf ("got mask %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GxB_Desc_get_INT32 (Duh, GrB_INP0, &v2) ; printf ("got inp0 %d\n", v2) ; CHECK (v2 == GrB_TRAN) ; + GxB_Desc_get_INT32 (Duh, GrB_INP1, &v2) ; printf ("got inp1 %d\n", v2) ; CHECK (v2 == GxB_DEFAULT) ; + GrB_Descriptor_free_(&Duh) ; //-------------------------------------------------------------------------- @@ -312,13 +377,23 @@ void mexFunction CHECK (strcmp (about, GxB_SPEC_ABOUT) == 0) ; printf ("About the spec:\n%s\n", about) ; + char *str ; + OK (GxB_Global_Option_get_CHAR (GxB_API_ABOUT, &str)) ; + CHECK (strcmp (str, GxB_SPEC_ABOUT) == 0) ; + OK (GxB_Global_Option_get_(GxB_API_DATE, &date)) ; CHECK (strcmp (date, GxB_SPEC_DATE) == 0) ; printf ("date: %s\n", date) ; + OK (GxB_Global_Option_get_CHAR (GxB_API_DATE, &str)) ; + CHECK (strcmp (str, GxB_SPEC_DATE) == 0) ; + OK (GxB_Global_Option_get_(GxB_API_URL, &url)) ; printf ("URL: %s\n", url) ; + OK (GxB_Global_Option_get_CHAR (GxB_API_URL, &str)) ; + CHECK (strcmp (str, url) == 0) ; + OK (GxB_Global_Option_get_(GxB_API_VERSION, all_version)) ; CHECK (all_version [0] == GxB_SPEC_MAJOR) ; CHECK (all_version [1] == GxB_SPEC_MINOR) ; @@ -326,6 +401,12 @@ void mexFunction printf ("Spec Version (%d.%d.%d)\n", all_version [0], all_version [1], all_version [2]) ; + int32_t all_version2 [3] = { -1, -1, -2 } ; + OK (GxB_Global_Option_get_INT32 (GxB_API_VERSION, all_version2)) ; + CHECK (all_version2 [0] == GxB_SPEC_MAJOR) ; + CHECK (all_version2 [1] == GxB_SPEC_MINOR) ; + CHECK (all_version2 [2] == GxB_SPEC_SUB) ; + //-------------------------------------------------------------------------- // about the library //-------------------------------------------------------------------------- @@ -337,18 +418,30 @@ void mexFunction CHECK (strcmp (name, GxB_IMPLEMENTATION_NAME) == 0) ; printf ("name: %s\n", name) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_NAME, &str)) ; + CHECK (strcmp (str, GxB_IMPLEMENTATION_NAME) == 0) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_DATE, &date)) ; if (date != NULL) printf ("date: %s\n", date) ; CHECK (strcmp (date, GxB_IMPLEMENTATION_DATE) == 0) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_DATE, &str)) ; + CHECK (strcmp (str, GxB_IMPLEMENTATION_DATE) == 0) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_ABOUT, &about)) ; CHECK (strcmp (about, GxB_IMPLEMENTATION_ABOUT) == 0) ; printf ("about:\n%s\n", about) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_ABOUT, &str)) ; + CHECK (strcmp (str, GxB_IMPLEMENTATION_ABOUT) == 0) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_LICENSE, &license)) ; CHECK (strcmp (license, GxB_IMPLEMENTATION_LICENSE) == 0) ; printf ("license:\n%s\n", license) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_LICENSE, &str)) ; + CHECK (strcmp (str, GxB_IMPLEMENTATION_LICENSE) == 0) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_VERSION, all_version)) ; CHECK (all_version [0] == GxB_IMPLEMENTATION_MAJOR) ; CHECK (all_version [1] == GxB_IMPLEMENTATION_MINOR) ; @@ -357,15 +450,37 @@ void mexFunction all_version [0], all_version [1], all_version [2]) ; printf ("Implementation: ("GBu")\n", GxB_IMPLEMENTATION) ; + OK (GxB_Global_Option_get_INT32 (GxB_LIBRARY_VERSION, all_version2)) ; + CHECK (all_version2 [0] == GxB_IMPLEMENTATION_MAJOR) ; + CHECK (all_version2 [1] == GxB_IMPLEMENTATION_MINOR) ; + CHECK (all_version2 [2] == GxB_IMPLEMENTATION_SUB) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_COMPILE_DATE, &compile_date)) ; printf ("compile date: %s\n", compile_date) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_COMPILE_DATE, &str)) ; + CHECK (strcmp (str, compile_date) == 0) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_COMPILE_TIME, &compile_time)) ; printf ("compile time: %s\n", compile_time) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_COMPILE_TIME, &str)) ; + CHECK (strcmp (str, compile_time) == 0) ; + + bool have_openmp = false ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_OPENMP, &have_openmp)) ; + printf ("with OpenMP: %d\n", have_openmp) ; + + int32_t have_openmp2 = 33 ; + OK (GxB_Global_Option_get_INT32 (GxB_LIBRARY_OPENMP, &have_openmp2)) ; + CHECK ((have_openmp ? 1 : 0) == have_openmp2) ; + OK (GxB_Global_Option_get_(GxB_LIBRARY_URL, &url)) ; printf ("URL: %s\n", url) ; + OK (GxB_Global_Option_get_CHAR (GxB_LIBRARY_URL, &str)) ; + CHECK (strcmp (str, url) == 0) ; + #if GxB_SPEC_VERSION >= GxB_VERSION(1,0,0) printf ("The spec is >= version 1.0.0\n") ; #else @@ -397,14 +512,30 @@ void mexFunction OK (GxB_Global_Option_get_(GxB_GLOBAL_GPU_CONTROL, &gpu_control)) ; printf ("gpu control: %d\n", gpu_control) ; + int32_t gpu_control2 = -88 ; + OK (GxB_Global_Option_get_INT32 (GxB_GLOBAL_GPU_CONTROL, &gpu_control2)) ; + CHECK ((int) gpu_control == gpu_control2) ; + + GB_Global_gpu_control_set (12) ; OK (GxB_Global_Option_set_(GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER)) ; OK (GxB_Global_Option_get_(GxB_GLOBAL_GPU_CONTROL, &gpu_control)) ; CHECK (gpu_control == GxB_GPU_NEVER) ; + GB_Global_gpu_control_set (13) ; + OK (GxB_Global_Option_set_INT32 (GxB_GLOBAL_GPU_CONTROL, GxB_GPU_NEVER)) ; + OK (GxB_Global_Option_get_INT32 (GxB_GLOBAL_GPU_CONTROL, &gpu_control2)) ; + CHECK (gpu_control2 == (int32_t) GxB_GPU_NEVER) ; + + OK (GxB_Global_Option_get_INT32 (GxB_GLOBAL_GPU_CONTROL, &gpu_control2)) ; + CHECK (gpu_control2 == (int) GxB_GPU_NEVER) ; + OK (GxB_Global_Option_set_(GxB_GLOBAL_GPU_CONTROL, GxB_GPU_ALWAYS)) ; OK (GxB_Global_Option_get_(GxB_GLOBAL_GPU_CONTROL, &gpu_control)) ; CHECK (gpu_control == (gpu_count > 0) ? GxB_GPU_ALWAYS : GxB_GPU_NEVER) ; + OK (GxB_Global_Option_get_INT32 (GxB_GLOBAL_GPU_CONTROL, &gpu_control2)) ; + CHECK (gpu_control2 == (gpu_count > 0) ? GxB_GPU_ALWAYS : GxB_GPU_NEVER) ; + OK (GxB_Global_Option_set_(GxB_GLOBAL_GPU_CONTROL, GxB_DEFAULT)) ; OK (GxB_Global_Option_get_(GxB_GLOBAL_GPU_CONTROL, &gpu_control)) ; CHECK (gpu_control == (gpu_count > 0) ? GxB_DEFAULT : GxB_GPU_NEVER) ; @@ -413,11 +544,23 @@ void mexFunction OK (GxB_Global_Option_get_(GxB_GLOBAL_GPU_CHUNK, &gpu_chunk)) ; printf ("gpu chunk: %g\n", gpu_chunk) ; + double gpu_chunk2 = -1 ; + OK (GxB_Global_Option_get_FP64 (GxB_GLOBAL_GPU_CHUNK, &gpu_chunk2)) ; + CHECK (gpu_chunk == gpu_chunk2) ; + double gpu_chunk_42 = 42e6 ; OK (GxB_Global_Option_set_(GxB_GLOBAL_GPU_CHUNK, gpu_chunk_42)) ; OK (GxB_Global_Option_get_(GxB_GLOBAL_GPU_CHUNK, &gpu_chunk)) ; CHECK (gpu_chunk == 42e6) ; + OK (GxB_Global_Option_get_FP64 (GxB_GLOBAL_GPU_CHUNK, &gpu_chunk2)) ; + CHECK (gpu_chunk2 == 42e6) ; + + double gpu_chunk_43 = 43e6 ; + OK (GxB_Global_Option_set_FP64 (GxB_GLOBAL_GPU_CHUNK, gpu_chunk_43)) ; + OK (GxB_Global_Option_get_FP64 (GxB_GLOBAL_GPU_CHUNK, &gpu_chunk)) ; + CHECK (gpu_chunk == 43e6) ; + //-------------------------------------------------------------------------- // types //-------------------------------------------------------------------------- @@ -490,28 +633,45 @@ void mexFunction // global get/set //-------------------------------------------------------------------------- - double h, bswitch [GxB_NBITMAP_SWITCH] ; + double h = 1, h2 = 3, bswitch [GxB_NBITMAP_SWITCH] ; + double bswitch2 [GxB_NBITMAP_SWITCH] ; GxB_Format_Value ff ; + int32_t ff2 ; GxB_Global_Option_get_(GxB_HYPER_SWITCH, &h) ; + GxB_Global_Option_get_FP64 (GxB_HYPER_SWITCH, &h2) ; + CHECK (h == h2) ; + GxB_Global_Option_get_(GxB_BITMAP_SWITCH, bswitch) ; + GxB_Global_Option_get_FP64 (GxB_BITMAP_SWITCH, bswitch2) ; GxB_Global_Option_get_(GxB_FORMAT, &ff) ; + GxB_Global_Option_get_INT32 (GxB_FORMAT, &ff2) ; printf ("hyper_switch %g csc %d\n", h, (ff == GxB_BY_COL)) ; + CHECK ((int32_t) ff == ff2) ; for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) { printf ("bitmap_switch [%d]: %g\n", k, bswitch [k]) ; + CHECK (bswitch [k] == bswitch2 [k]) ; } - GrB_Mode mode ; + GrB_Mode mode = GrB_BLOCKING ; GxB_Global_Option_get_(GxB_MODE, &mode) ; printf ("mode: %d\n", mode) ; - int nthreads ; + int32_t mode2 = 55 ; + GxB_Global_Option_get_INT32 (GxB_MODE, &mode2) ; + CHECK ((int32_t) mode == mode2) ; + + int nthreads = 1, nthreads2 = 2 ; GxB_Global_Option_get_(GxB_NTHREADS, &nthreads) ; + GxB_Global_Option_get_INT32 (GxB_NTHREADS, &nthreads2) ; printf ("# threads: %d\n", nthreads) ; + CHECK (nthreads == nthreads2) ; - double chunk ; + double chunk = 45, chunk2 = 99 ; GxB_Global_Option_get_(GxB_CHUNK, &chunk) ; + GxB_Global_Option_get_FP64 (GxB_CHUNK, &chunk2) ; printf ("chunk: %g\n", chunk) ; + CHECK (chunk == chunk2) ; //-------------------------------------------------------------------------- // check A and B aliased @@ -549,6 +709,12 @@ void mexFunction OK (GxB_Descriptor_fprint_(desc, GxB_COMPLETE, NULL)) ; CHECK (chunk == 12345) ; CHECK (nthreads == 42) ; + + chunk = -1 ; + nthreads = 0 ; + OK (GxB_Desc_get_FP64 (desc, GxB_CHUNK, &chunk)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_NTHREADS, &nthreads)) ; + GrB_Descriptor_free_(&desc) ; //-------------------------------------------------------------------------- @@ -788,31 +954,60 @@ void mexFunction // GxB_get //-------------------------------------------------------------------------- - int sparsity ; + int sparsity = 88 ; OK (GxB_Matrix_Option_get_(A, GxB_SPARSITY_CONTROL, &sparsity)) ; CHECK (sparsity == GxB_AUTO_SPARSITY) ; + + sparsity = 88 ; + OK (GxB_Matrix_Option_get_INT32 (A, GxB_SPARSITY_CONTROL, &sparsity)) ; + CHECK (sparsity == GxB_AUTO_SPARSITY) ; + + sparsity = 88 ; OK (GxB_Vector_Option_get_(victor, GxB_SPARSITY_CONTROL, &sparsity)) ; CHECK (sparsity == GxB_AUTO_SPARSITY) ; + + sparsity = 88 ; + OK (GxB_Vector_Option_get_INT32 (victor, GxB_SPARSITY_CONTROL, &sparsity)) ; + CHECK (sparsity == GxB_AUTO_SPARSITY) ; + + sparsity = 88 ; OK (GxB_Vector_Option_get_(victor, GxB_SPARSITY_STATUS, &sparsity)) ; CHECK (sparsity == GxB_SPARSE) ; + + sparsity = 88 ; + OK (GxB_Vector_Option_get_INT32 (victor, GxB_SPARSITY_STATUS, &sparsity)) ; + CHECK (sparsity == GxB_SPARSE) ; + GxB_Format_Value fmt ; OK (GxB_Vector_Option_get_(victor, GxB_FORMAT, &fmt)) ; CHECK (fmt == GxB_BY_COL) ; + + int f2 = 44 ; + OK (GxB_Vector_Option_get_INT32 (victor, GxB_FORMAT, &f2)) ; + CHECK (f2 == GxB_BY_COL) ; + bool is_hyper ; OK (GxB_Vector_Option_get_(victor, GxB_IS_HYPER, &is_hyper)) ; CHECK (!is_hyper) ; + expected = GrB_INVALID_VALUE ; ERR (GxB_Vector_Option_get_(victor, -999, &is_hyper)) ; + ERR (GxB_Vector_Option_get_INT32 (victor, -999, &f2)) ; //-------------------------------------------------------------------------- // GxB_set //-------------------------------------------------------------------------- ERR (GxB_Vector_Option_set_(victor, -999, &is_hyper)) ; + OK (GxB_Vector_Option_set_(victor, GxB_SPARSITY_CONTROL, 9999)) ; OK (GxB_Vector_Option_get_(victor, GxB_SPARSITY_CONTROL, &sparsity)) ; CHECK (sparsity == GxB_AUTO_SPARSITY) ; + OK (GxB_Vector_Option_set_INT32 (victor, GxB_SPARSITY_CONTROL, 9999)) ; + OK (GxB_Vector_Option_get_INT32 (victor, GxB_SPARSITY_CONTROL, &sparsity)) ; + CHECK (sparsity == GxB_AUTO_SPARSITY) ; + //-------------------------------------------------------------------------- // removeElement errors //-------------------------------------------------------------------------- @@ -884,10 +1079,26 @@ void mexFunction OK (GxB_Global_Option_set (GxB_PRINT_1BASED, true)) ; OK (GxB_Global_Option_get (GxB_PRINT_1BASED, &onebased)) ; CHECK (onebased) ; + + int32_t onebased2 ; + OK (GxB_Global_Option_get_INT32 (GxB_PRINT_1BASED, &onebased2)) ; + CHECK (onebased2) ; + + OK (GxB_Global_Option_set_INT32 (GxB_PRINT_1BASED, false)) ; + OK (GxB_Global_Option_get_INT32 (GxB_PRINT_1BASED, &onebased2)) ; + CHECK (!onebased2) ; + OK (GxB_Matrix_fprint_(C, GxB_COMPLETE_VERBOSE, NULL)) ; - OK (GxB_Global_Option_set (GxB_PRINT_1BASED, false)) ; + OK (GxB_Global_Option_set (GxB_PRINT_1BASED, true)) ; OK (GxB_Global_Option_get (GxB_PRINT_1BASED, &onebased)) ; - CHECK (!onebased) ; + CHECK (onebased) ; + + OK (GxB_Global_Option_get_INT32 (GxB_PRINT_1BASED, &onebased2)) ; + CHECK (onebased2) ; + + OK (GxB_Global_Option_set_INT32 (GxB_PRINT_1BASED, true)) ; + OK (GxB_Global_Option_get_INT32 (GxB_PRINT_1BASED, &onebased2)) ; + CHECK (onebased2) ; expected = GrB_NULL_POINTER ; ERR1 (C, GxB_Matrix_select_(C, NULL, NULL, selectop, A, NULL, NULL)) ; @@ -1068,6 +1279,10 @@ void mexFunction OK (GxB_Global_Option_get_(GxB_BURBLE, &burble)) ; printf ("burble: %d\n", burble) ; + int32_t burble2 = 33 ; + OK (GxB_Global_Option_get_INT32 (GxB_BURBLE, &burble2)) ; + CHECK ((int32_t) burble == burble2) ; + //-------------------------------------------------------------------------- // select ops //-------------------------------------------------------------------------- diff --git a/deps/GraphBLAS/Test/GB_mex_about10.c b/deps/GraphBLAS/Test/GB_mex_about10.c new file mode 100644 index 0000000000..b5d8d1df1f --- /dev/null +++ b/deps/GraphBLAS/Test/GB_mex_about10.c @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// GB_mex_about9: still more basic tests +//------------------------------------------------------------------------------ + +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//------------------------------------------------------------------------------ + +#include "GB_mex.h" +#include "GB_mex_errors.h" + +#define USAGE "GB_mex_about10" + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + + GrB_Info info, expected ; + GrB_Matrix A = NULL ; + GrB_Vector v = NULL ; + int64_t pool1 [64], pool2 [64] ; + + //-------------------------------------------------------------------------- + // startup GraphBLAS + //-------------------------------------------------------------------------- + + GrB_Descriptor desc = NULL ; + bool malloc_debug = GB_mx_get_global (true) ; + + //-------------------------------------------------------------------------- + // get/set tests + //-------------------------------------------------------------------------- + + double chunk = 0 ; + expected = GrB_INVALID_VALUE ; + ERR (GxB_Desc_set_INT32 (GrB_DESC_ST0, GrB_OUTP, GrB_REPLACE)) ; + ERR (GxB_Desc_set_FP64 (GrB_DESC_ST0, GxB_DESCRIPTOR_CHUNK, 1e6)) ; + ERR (GxB_Global_Option_set_FP64 (-1, 0)) ; + ERR (GxB_Global_Option_set_FP64_ARRAY (-1, NULL)) ; + ERR (GxB_Global_Option_set_INT64_ARRAY (-1, NULL)) ; + ERR (GxB_Global_Option_set_FUNCTION (-1, NULL)) ; + ERR (GxB_Desc_get_FP64 (NULL, -1, &chunk)) ; + + int value = -1 ; + OK (GrB_Descriptor_new (&desc)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_IMPORT, &value)) ; + CHECK (value == GxB_DEFAULT) ; + OK (GxB_Desc_set_INT32 (desc, GxB_IMPORT, GxB_SECURE_IMPORT)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_IMPORT, &value)) ; + CHECK (value == GxB_SECURE_IMPORT) ; + + OK (GxB_Desc_set_FP64 (desc, GxB_DESCRIPTOR_CHUNK, 1e6)) ; + OK (GxB_Desc_get_FP64 (desc, GxB_DESCRIPTOR_CHUNK, &chunk)) ; + CHECK (chunk = 1e6) ; + + OK (GxB_Global_Option_set_FP64 (GxB_GLOBAL_CHUNK, 2e6)) ; + OK (GxB_Global_Option_get_FP64 (GxB_GLOBAL_CHUNK, &chunk)) ; + CHECK (chunk = 2e6) ; + + int32_t ver [3] ; + char *compiler ; + OK (GxB_Global_Option_get_INT32 (GxB_COMPILER_VERSION, ver)) ; + OK (GxB_Global_Option_get_CHAR (GxB_COMPILER_NAME, &compiler)) ; + printf ("compiler: %s %d.%d.%d\n", compiler, ver [0], ver [1], ver [2]) ; + + OK (GxB_Global_Option_set_INT32 (GxB_BURBLE, 1)) ; + OK (GrB_Matrix_new (&A, GrB_FP64, 10, 10)) ; + OK (GrB_transpose (A, NULL, NULL, A, desc)) ; + OK (GxB_Global_Option_set_INT32 (GxB_BURBLE, 0)) ; + OK (GrB_transpose (A, NULL, NULL, A, desc)) ; + + OK (GxB_Matrix_Option_get_INT32 (A, GxB_SPARSITY_STATUS, &value)) ; + CHECK (value == GxB_HYPERSPARSE) ; + + double bswitch1 = 0.5, bswitch2 = 1.0 ; + OK (GxB_Matrix_Option_set (A, GxB_BITMAP_SWITCH, bswitch1)) ; + OK (GxB_Matrix_Option_get (A, GxB_BITMAP_SWITCH, &bswitch2)) ; + CHECK (bswitch1 == bswitch2) ; + + for (int k = 0 ; k < 64 ; k++) + { + pool1 [k] = (k < 3) ? 0 : k ; + } + OK (GxB_Global_Option_set_INT64_ARRAY (GxB_MEMORY_POOL, pool1)) ; + OK (GxB_Global_Option_get_INT64 (GxB_MEMORY_POOL, pool2)) ; + for (int k = 0 ; k < 64 ; k++) + { + CHECK (pool1 [k] == pool2 [k]) ; + } + + ERR (GxB_Matrix_Option_set_FP64 (A, -1, 0)) ; + + OK (GrB_Vector_new (&v, GrB_FP64, 10)) ; + ERR (GxB_Vector_Option_set_FP64 (v, -1, 0)) ; + ERR (GxB_Vector_Option_set_FP64 (v, -1, 0)) ; + ERR (GxB_Vector_Option_get_FP64 (v, -1, &chunk)) ; + ERR (GxB_Vector_Option_set_INT32 (v, -1, 0)) ; + + OK (GrB_Descriptor_free (&desc)) ; + OK (GrB_Matrix_free (&A)) ; + OK (GrB_Vector_free (&v)) ; + + //-------------------------------------------------------------------------- + // wrapup + //-------------------------------------------------------------------------- + + GB_mx_put_global (true) ; + printf ("\nGB_mex_about10: all tests passed\n\n") ; +} + diff --git a/deps/GraphBLAS/Test/GB_mex_about2.c b/deps/GraphBLAS/Test/GB_mex_about2.c index a795061109..b92ab29c51 100644 --- a/deps/GraphBLAS/Test/GB_mex_about2.c +++ b/deps/GraphBLAS/Test/GB_mex_about2.c @@ -114,7 +114,7 @@ void mexFunction int n = 10 ; OK (GrB_Matrix_new (&A, GxB_FC32, n, n)) ; - OK (GxB_Matrix_Option_set_(A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; OK (GrB_Matrix_new (&C, GxB_FC32, n, n)) ; OK (GrB_Scalar_new (&scalar, GxB_FC32)) ; @@ -148,9 +148,12 @@ void mexFunction double bswitch = 1 ; OK (GrB_Matrix_new (&A, GrB_INT32, n, n)) ; - OK (GxB_Matrix_Option_set_(A, GxB_BITMAP_SWITCH, 0.125)) ; + OK (GxB_Matrix_Option_set_FP64 (A, GxB_BITMAP_SWITCH, 0.125)) ; OK (GxB_Matrix_Option_get_(A, GxB_BITMAP_SWITCH, &bswitch)) ; CHECK (fabs (bswitch - 0.125) < 1e-5) ; + bswitch = 1 ; + OK (GxB_Matrix_Option_get_FP64 (A, GxB_BITMAP_SWITCH, &bswitch)) ; + CHECK (fabs (bswitch - 0.125) < 1e-5) ; OK (GxB_Matrix_Option_set_(A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; OK (GrB_Matrix_assign_INT32 (A, NULL, NULL, 3, GrB_ALL, n, GrB_ALL, n, @@ -296,11 +299,19 @@ void mexFunction OK (GxB_Desc_get (NULL, GxB_AxB_METHOD, &method)) ; CHECK (method == GxB_DEFAULT) ; + method = -1 ; + OK (GxB_Desc_get_INT32 (NULL, GxB_AxB_METHOD, &method)) ; + CHECK (method == GxB_DEFAULT) ; OK (GxB_Desc_set (desc, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; OK (GxB_Descriptor_fprint (desc, "descriptor", GxB_COMPLETE, NULL)) ; OK (GxB_Desc_get (desc, GxB_AxB_METHOD, &method)) ; CHECK (method == GxB_AxB_GUSTAVSON) ; + OK (GxB_Desc_set_INT32 (desc, GxB_AxB_METHOD, GxB_AxB_SAXPY)) ; + OK (GxB_Descriptor_fprint (desc, "descriptor", GxB_COMPLETE, NULL)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_AxB_METHOD, &method)) ; + CHECK (method == GxB_AxB_SAXPY) ; + desc->mask = GrB_REPLACE ; expected = GrB_INVALID_OBJECT ; ERR (GxB_Descriptor_fprint (desc, "invalid", GxB_COMPLETE, NULL)) ; @@ -332,6 +343,10 @@ void mexFunction OK (GxB_Vector_Option_get_(victor, GxB_BITMAP_SWITCH, &bswitch)) ; printf ("vector bitmap switch: %g\n\n", bswitch) ; + double b2 = 0 ; + OK (GxB_Vector_Option_get_FP64 (victor, GxB_BITMAP_SWITCH, &b2)) ; + CHECK (bswitch == b2) ; + expected = GrB_NOT_IMPLEMENTED ; ERR (GrB_Matrix_reduce_BinaryOp (victor, NULL, NULL, GxB_FIRSTI_INT32, A, NULL)) ; @@ -431,6 +446,12 @@ void mexFunction double bitmap_switch = 8 ; OK (GxB_Vector_Option_get (victor, GxB_BITMAP_SWITCH, &bitmap_switch)) ; CHECK (bitmap_switch == 4.5) ; + + OK (GxB_Vector_Option_set_FP64 (victor, GxB_BITMAP_SWITCH, (double) 5.25)) ; + bitmap_switch = 8 ; + OK (GxB_Vector_Option_get_FP64 (victor, GxB_BITMAP_SWITCH, &bitmap_switch)) ; + CHECK (bitmap_switch == 5.25) ; + GrB_Vector_free (&victor) ; //-------------------------------------------------------------------------- diff --git a/deps/GraphBLAS/Test/GB_mex_about3.c b/deps/GraphBLAS/Test/GB_mex_about3.c index 6fb43a44f9..06c151e11a 100644 --- a/deps/GraphBLAS/Test/GB_mex_about3.c +++ b/deps/GraphBLAS/Test/GB_mex_about3.c @@ -86,13 +86,17 @@ void mexFunction OK (GxB_Global_Option_set (GxB_PRINTF, myprintf)) ; OK (GxB_Global_Option_set (GxB_FLUSH, myflush)) ; - printf_func_t mypr ; + printf_func_t mypr, mypr2 ; OK (GxB_Global_Option_get (GxB_PRINTF, &mypr)) ; + OK (GxB_Global_Option_get_FUNCTION (GxB_PRINTF, (void **) &mypr2)) ; CHECK (mypr == myprintf) ; + CHECK (mypr2 == myprintf) ; - flush_func_t myfl ; + flush_func_t myfl, myfl2 ; OK (GxB_Global_Option_get (GxB_FLUSH, &myfl)) ; + OK (GxB_Global_Option_get_FUNCTION (GxB_FLUSH, (void **) &myfl2)) ; CHECK (myfl == myflush) ; + CHECK (myfl2 == myflush) ; printf ("\nBurble with myprintf/myflush:\n") ; OK (GrB_Matrix_nvals (&nvals, C)) ; @@ -102,44 +106,79 @@ void mexFunction OK (GxB_Global_Option_set (GxB_PRINTF, printf)) ; OK (GxB_Global_Option_set (GxB_FLUSH, NULL)) ; + OK (GxB_Global_Option_set_FUNCTION (GxB_PRINTF, myprintf)) ; + OK (GxB_Global_Option_set_FUNCTION (GxB_FLUSH, myflush)) ; + + OK (GxB_Global_Option_get_FUNCTION (GxB_PRINTF, (void **) &mypr2)) ; + OK (GxB_Global_Option_get_FUNCTION (GxB_FLUSH, (void **) &myfl2)) ; + CHECK (mypr2 == myprintf) ; + CHECK (myfl2 == myflush) ; + + OK (GxB_Global_Option_set (GxB_PRINTF, printf)) ; + OK (GxB_Global_Option_set (GxB_FLUSH, NULL)) ; + //-------------------------------------------------------------------------- // test GxB_set/get for free_pool_limit //-------------------------------------------------------------------------- - int64_t free_pool_limit [64] ; + int64_t free_pool_limit [64], free_pool_limit2 [64] ; + int64_t free_pool_defaults [64] ; + for (int k = 0 ; k < 64 ; k++) + { + free_pool_limit [k] = k+1 ; + free_pool_limit2 [k] = 3*k + 4 ; + } + OK (GxB_Global_Option_set (GxB_MEMORY_POOL, NULL)) ; - OK (GxB_Global_Option_get (GxB_MEMORY_POOL, free_pool_limit)) ; + OK (GxB_Global_Option_get (GxB_MEMORY_POOL, free_pool_defaults)) ; + OK (GxB_Global_Option_get_INT64 (GxB_MEMORY_POOL, free_pool_limit2)) ; printf ("\ndefault memory pool limits:\n") ; for (int k = 0 ; k < 64 ; k++) { - if (free_pool_limit [k] > 0) + if (free_pool_defaults [k] > 0) { - printf ("pool %2d: limit %ld\n", k, free_pool_limit [k]) ; + printf ("pool %2d: limit %ld\n", k, free_pool_defaults [k]) ; } + CHECK (free_pool_defaults [k] == free_pool_limit2 [k]) ; } + for (int k = 0 ; k < 64 ; k++) { free_pool_limit [k] = k ; } OK (GxB_Global_Option_set (GxB_MEMORY_POOL, free_pool_limit)) ; OK (GxB_Global_Option_get (GxB_MEMORY_POOL, free_pool_limit)) ; + OK (GxB_Global_Option_get_INT64 (GxB_MEMORY_POOL, free_pool_limit2)) ; for (int k = 0 ; k < 3 ; k++) { CHECK (free_pool_limit [k] == 0) ; + CHECK (free_pool_limit2 [k] == 0) ; } for (int k = 3 ; k < 64 ; k++) { CHECK (free_pool_limit [k] == k) ; + CHECK (free_pool_limit2 [k] == k) ; } for (int k = 0 ; k < 64 ; k++) { free_pool_limit [k] = 0 ; + free_pool_limit2 [k] = 0 ; } + OK (GxB_Global_Option_set (GxB_MEMORY_POOL, free_pool_limit)) ; OK (GxB_Global_Option_get (GxB_MEMORY_POOL, free_pool_limit)) ; + OK (GxB_Global_Option_get_INT64 (GxB_MEMORY_POOL, free_pool_limit2)) ; for (int k = 0 ; k < 64 ; k++) { CHECK (free_pool_limit [k] == 0) ; + CHECK (free_pool_limit2 [k] == 0) ; + } + + OK (GxB_Global_Option_set_INT64_ARRAY (GxB_MEMORY_POOL, NULL)) ; + OK (GxB_Global_Option_get_INT64 (GxB_MEMORY_POOL, free_pool_limit2)) ; + for (int k = 0 ; k < 64 ; k++) + { + CHECK (free_pool_defaults [k] == free_pool_limit2 [k]) ; } //-------------------------------------------------------------------------- @@ -739,7 +778,7 @@ void mexFunction int64_t nallocs ; size_t mem_deep, mem_shallow ; - GB_memoryUsage (&nallocs, &mem_deep, &mem_shallow, NULL) ; + GB_memoryUsage (&nallocs, &mem_deep, &mem_shallow, NULL, false) ; CHECK (nallocs == 0) ; CHECK (mem_deep == 0) ; CHECK (mem_shallow == 0) ; diff --git a/deps/GraphBLAS/Test/GB_mex_about5.c b/deps/GraphBLAS/Test/GB_mex_about5.c index fdb17ae642..944a7fcf70 100644 --- a/deps/GraphBLAS/Test/GB_mex_about5.c +++ b/deps/GraphBLAS/Test/GB_mex_about5.c @@ -925,6 +925,10 @@ void mexFunction OK (GxB_Desc_set (desc, GxB_IMPORT, GxB_SECURE_IMPORT)) ; OK (GxB_Descriptor_fprint (desc, "desc with secure import", 3, NULL)) ; + OK (GxB_Desc_set_INT32 (desc, GxB_IMPORT, GxB_DEFAULT)) ; + OK (GxB_Desc_set_INT32 (desc, GxB_IMPORT, GxB_SECURE_IMPORT)) ; + OK (GxB_Descriptor_fprint (desc, "desc with secure import", 3, NULL)) ; + int method = -999 ; OK (GxB_Desc_get (desc, GxB_IMPORT, &method)) ; CHECK (method == GxB_SECURE_IMPORT) ; @@ -933,6 +937,10 @@ void mexFunction OK (GxB_Desc_get (desc, GxB_COMPRESSION, &method)) ; CHECK (method == GxB_COMPRESSION_LZ4HC + 4) + OK (GxB_Desc_set_INT32 (desc, GxB_COMPRESSION, GxB_COMPRESSION_LZ4HC + 5)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_COMPRESSION, &method)) ; + CHECK (method == GxB_COMPRESSION_LZ4HC + 5) + OK (GxB_Descriptor_fprint (desc, "desc with secure & lz4hc+4", 3, NULL)) ; OK (GrB_Descriptor_free_ (&desc)) ; #endif @@ -953,31 +961,69 @@ void mexFunction OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_COO_FORMAT) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_CSR_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_COO_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_CSR_FORMAT) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_BITMAP)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_CSR_FORMAT) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_FULL)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_CSR_FORMAT) ; -// CHECK (fmt == GrB_DENSE_ROW_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_BITMAP)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_CSR_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_FULL)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_CSR_FORMAT) ; OK (GxB_Matrix_Option_set (A, GxB_FORMAT, GxB_BY_COL)) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_COO_FORMAT) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_CSC_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_COO_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_CSC_FORMAT) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_BITMAP)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_CSC_FORMAT) ; + OK (GxB_Matrix_Option_set (A, GxB_SPARSITY_CONTROL, GxB_FULL)) ; OK (GrB_Matrix_exportHint (&fmt, A)) ; CHECK (fmt == GrB_CSC_FORMAT) ; + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_BITMAP)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_CSC_FORMAT) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_FULL)) ; + OK (GrB_Matrix_exportHint (&fmt, A)) ; + CHECK (fmt == GrB_CSC_FORMAT) ; + expected = GrB_NULL_POINTER ; ERR (GrB_Matrix_exportHint (NULL, A)) ; ERR (GrB_Matrix_exportHint (&fmt, NULL)) ; diff --git a/deps/GraphBLAS/Test/GB_mex_about7.c b/deps/GraphBLAS/Test/GB_mex_about7.c index ee70b546a4..5935d4eccc 100644 --- a/deps/GraphBLAS/Test/GB_mex_about7.c +++ b/deps/GraphBLAS/Test/GB_mex_about7.c @@ -70,6 +70,7 @@ void mexFunction OK (GrB_Matrix_free (&(A->Y))) ; A->Y = Y_mangled ; ERR (GxB_Matrix_fprint (A, "A with invalid A->Y (wrong type)", 3, NULL)) ; + A->Y = NULL ; OK (GrB_Matrix_free (&A)) ; @@ -81,6 +82,7 @@ void mexFunction A->Y = Y_mangled ; ERR (GxB_Matrix_fprint (A, "A with invalid A->Y (not hyper)", 3, NULL)) ; + A->Y = NULL ; OK (GrB_Matrix_free (&Y_mangled)) ; OK (GrB_Matrix_free (&A)) ; diff --git a/deps/GraphBLAS/Test/GB_mex_errors.c b/deps/GraphBLAS/Test/GB_mex_errors.c index 15708d17c1..c4ddff24d7 100644 --- a/deps/GraphBLAS/Test/GB_mex_errors.c +++ b/deps/GraphBLAS/Test/GB_mex_errors.c @@ -1794,6 +1794,12 @@ void mexFunction ERRD (dnull, GxB_Desc_set (dnull, 0, 0)) ; ERR (GxB_Desc_get (dnull, 0, NULL)) ; + ERRD (dnull, GxB_Desc_set_INT32 (dnull, 0, 0)) ; + ERR (GxB_Desc_get_INT32 (dnull, 0, NULL)) ; + + ERRD (dnull, GxB_Desc_set_FP64 (dnull, 0, 0)) ; + ERR (GxB_Desc_get_FP64 (dnull, 0, NULL)) ; + ERRD (dnull, GrB_Descriptor_set (dnull, 0, 0)) ; ERR (GxB_Descriptor_get (NULL, dnull, 0)) ; @@ -1802,12 +1808,23 @@ void mexFunction ERRD (dcrud, GxB_Desc_set (dcrud, 0, 0)) ; ERR (GxB_Desc_get (dcrud, 0, &dval)) ; + int32_t dval2 ; + ERRD (dcrud, GxB_Desc_set_INT32 (dcrud, 0, 0)) ; + ERR (GxB_Desc_get_INT32 (dcrud, 0, &dval2)) ; + + double dval3 ; + ERRD (dcrud, GxB_Desc_set_FP64 (dcrud, 0, 0)) ; + ERR (GxB_Desc_get_FP64 (dcrud, 0, &dval3)) ; + ERRD (dcrud, GrB_Descriptor_set (dcrud, 0, 0)) ; ERR (GxB_Descriptor_get (&dval, dcrud, 0)) ; OK (GxB_Desc_get (dnull, 0, &dval)) ; CHECK (dval == GxB_DEFAULT) ; + OK (GxB_Desc_get_INT32 (dnull, 0, &dval2)) ; + CHECK (dval2 == GxB_DEFAULT) ; + OK (GxB_Descriptor_get (&dval, dnull, 0)) ; CHECK (dval == GxB_DEFAULT) ; @@ -1816,7 +1833,10 @@ void mexFunction expected = GrB_INVALID_VALUE ; ERR (GxB_Desc_get (desc, -1, &dval)) ; + ERR (GxB_Desc_get_INT32 (desc, -1, &dval2)) ; ERRD (desc, GxB_Desc_set (desc, -1, 0)) ; + ERRD (desc, GxB_Desc_set_INT32 (desc, -1, 0)) ; + ERRD (desc, GxB_Desc_set_FP64 (desc, -1, 0)) ; ERR (GxB_Descriptor_get (&dval, desc, -1)) ; ERRD (desc, GrB_Descriptor_set (desc, -1, 0)) ; @@ -1837,6 +1857,24 @@ void mexFunction GrB_Descriptor_error_(&err, desc) ; CHECK (err != NULL) ; printf ("%s\n", err) ; + + ERRD (desc, GxB_Desc_set_INT32 (desc, GrB_OUTP, -1)) ; + GrB_Descriptor_error_(&err, desc) ; + CHECK (err != NULL) ; + printf ("%s\n", err) ; + ERRD (desc, GxB_Desc_set_INT32 (desc, GrB_MASK, -1)) ; + GrB_Descriptor_error_(&err, desc) ; + CHECK (err != NULL) ; + printf ("%s\n", err) ; + ERRD (desc, GxB_Desc_set_INT32 (desc, GrB_INP0, -1)) ; + GrB_Descriptor_error_(&err, desc) ; + CHECK (err != NULL) ; + printf ("%s\n", err) ; + ERRD (desc, GxB_Desc_set_INT32 (desc, GrB_INP1, -1)) ; + GrB_Descriptor_error_(&err, desc) ; + CHECK (err != NULL) ; + printf ("%s\n", err) ; + ERRD (desc, GrB_Descriptor_set (desc, GxB_AxB_METHOD, -1)) ; GrB_Descriptor_error_(&err, desc) ; CHECK (err != NULL) ; @@ -1863,15 +1901,32 @@ void mexFunction CHECK (err != NULL) ; printf ("%s\n", err) ; + dval = -1 ; OK (GxB_Desc_get (desc, GrB_OUTP, &dval)) ; CHECK (dval == GxB_DEFAULT) ; + dval = -1 ; OK (GxB_Desc_get (desc, GrB_MASK, &dval)) ; CHECK (dval == GxB_DEFAULT) ; + dval = -1 ; OK (GxB_Desc_get (desc, GrB_INP0, &dval)) ; CHECK (dval == GxB_DEFAULT) ; + dval = -1 ; OK (GxB_Desc_get (desc, GrB_INP1, &dval)) ; CHECK (dval == GxB_DEFAULT) ; + dval2 = -1 ; + OK (GxB_Desc_get_INT32 (desc, GrB_OUTP, &dval2)) ; + CHECK (dval2 == GxB_DEFAULT) ; + dval2 = -1 ; + OK (GxB_Desc_get_INT32 (desc, GrB_MASK, &dval2)) ; + CHECK (dval2 == GxB_DEFAULT) ; + dval2 = -1 ; + OK (GxB_Desc_get_INT32 (desc, GrB_INP0, &dval2)) ; + CHECK (dval2 == GxB_DEFAULT) ; + dval2 = -1 ; + OK (GxB_Desc_get_INT32 (desc, GrB_INP1, &dval2)) ; + CHECK (dval2 == GxB_DEFAULT) ; + OK (GxB_Descriptor_get (&dval, desc, GrB_OUTP)) ; CHECK (dval == GxB_DEFAULT) ; OK (GxB_Descriptor_get (&dval, desc, GrB_MASK)) ; @@ -1916,6 +1971,25 @@ void mexFunction OK (GB_Descriptor_check (d7, "new descriptor (still Gustavson)", G3, NULL)); OK (GxB_Descriptor_fprint (d7, "d7", G3, ff)) ; + OK (GxB_Desc_set_INT32 (d7, GxB_AxB_METHOD, GxB_DEFAULT)) ; + OK (GB_Descriptor_check (d7, "new descriptor (default)", G3, NULL)) ; + OK (GxB_Descriptor_fprint (d7, "d7", G3, ff)) ; + + OK (GxB_Desc_set_INT32 (d7, GxB_AxB_METHOD, GxB_AxB_DOT)) ; + OK (GB_Descriptor_check (d7, "new descriptor (dot)", G3, NULL)) ; + OK (GxB_Descriptor_fprint (d7, "d7", G3, ff)) ; + OK (GxB_Descriptor_get (&dval, d7, GxB_AxB_METHOD)) ; + CHECK (dval == GxB_AxB_DOT) ; + + OK (GxB_Desc_set_INT32 (d7, GxB_AxB_METHOD, GxB_AxB_GUSTAVSON)) ; + OK (GB_Descriptor_check (d7, "new descriptor (Gustavson)", G3, NULL)) ; + OK (GxB_Descriptor_fprint (d7, "d7", G3, ff)) ; + + expected = GrB_INVALID_VALUE ; + ERRD (d7, GxB_Desc_set_INT32 (d7, GxB_AxB_METHOD, 911911)) ; + OK (GB_Descriptor_check (d7, "new descriptor (still Gustavson)", G3, NULL)); + OK (GxB_Descriptor_fprint (d7, "d7", G3, ff)) ; + expected = GrB_INVALID_OBJECT ; d7->axb = 99 ; @@ -4402,12 +4476,26 @@ void mexFunction OK (GB_Matrix_check (A, "A now hyper", G3, NULL)) ; CHECK (A->h != NULL) ; + CHECK (GB_IS_HYPERSPARSE (A)) ; + OK (GxB_Matrix_Option_set_INT32 (A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; + CHECK (GB_IS_SPARSE (A)) ; + OK (GB_Matrix_check (A, "A now sparse", G3, NULL)) ; + CHECK (A->h == NULL) ; + + CHECK (GB_IS_SPARSE (A)) ; + OK (GxB_Matrix_Option_set_(A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE)) ; + CHECK (GB_IS_HYPERSPARSE (A)) ; + OK (GB_Matrix_check (A, "A now hyper", G3, NULL)) ; + CHECK (A->h != NULL) ; + OK (GxB_Matrix_Option_set_(A, GxB_HYPER_SWITCH, GxB_NEVER_HYPER)) ; OK (GxB_Matrix_Option_set_(A, GxB_SPARSITY_CONTROL, GxB_SPARSE)) ; CHECK (A->h == NULL) ; bool A_is_hyper ; OK (GxB_Matrix_Option_get_(A, GxB_IS_HYPER, &A_is_hyper)) ; // historical CHECK (!A_is_hyper) ; + int32_t A_is_hyperw ; + OK (GxB_Matrix_Option_get_(A, GxB_IS_HYPER, &A_is_hyper)) ; // historical OK (GxB_Matrix_Option_set_(A, GxB_HYPER_SWITCH, GxB_ALWAYS_HYPER)) ; OK (GxB_Matrix_Option_set_(A, GxB_SPARSITY_CONTROL, GxB_HYPERSPARSE)) ; @@ -4441,6 +4529,14 @@ void mexFunction OK (GxB_Matrix_Option_get_(A, GxB_HYPER_SWITCH, &hratio2)) ; CHECK (hratio == hratio2) ; + hratio = 0.75 ; + OK (GxB_Matrix_Option_set_FP64 (A, GxB_HYPER_SWITCH, hratio)) ; + + hratio2 = 0 ; + OK (GxB_Matrix_Option_get_FP64 (A, GxB_HYPER_SWITCH, &hratio2)) ; + printf ("hratio: %g %g %g\n", hratio, hratio2, hratio-hratio2) ; + CHECK (hratio == hratio2) ; + double bswitch [GxB_NBITMAP_SWITCH] ; for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) { @@ -4455,6 +4551,21 @@ void mexFunction CHECK (fabs (bswitch [k] - bswitch2 [k]) < 1e-5) ; } + OK (GxB_Global_Option_set_FP64_ARRAY (GxB_BITMAP_SWITCH, NULL)) ; + OK (GxB_Global_Option_set_FP64_ARRAY (GxB_BITMAP_SWITCH, bswitch)) ; + OK (GxB_Global_Option_get_(GxB_BITMAP_SWITCH, bswitch2)) ; + for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) + { + CHECK (fabs (bswitch [k] - bswitch2 [k]) < 1e-5) ; + } + + double bswitch3 [GxB_NBITMAP_SWITCH] ; + OK (GxB_Global_Option_get_FP64 (GxB_BITMAP_SWITCH, bswitch3)) ; + for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) + { + CHECK (bswitch2 [k] == bswitch3 [k]) ; + } + OK (GxB_Global_Option_set_(GxB_BITMAP_SWITCH, NULL)) ; OK (GxB_Global_Option_get_(GxB_BITMAP_SWITCH, bswitch)) ; for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) @@ -4462,6 +4573,22 @@ void mexFunction printf ("default bswitch [%d] = %g\n", k, bswitch [k]) ; } + OK (GxB_Global_Option_set_FP64_ARRAY (GxB_BITMAP_SWITCH, NULL)) ; + OK (GxB_Global_Option_get_ (GxB_BITMAP_SWITCH, bswitch2)) ; + OK (GxB_Global_Option_get_FP64 (GxB_BITMAP_SWITCH, bswitch3)) ; + for (int k = 0 ; k < GxB_NBITMAP_SWITCH ; k++) + { + CHECK (bswitch2 [k] == bswitch3 [k]) ; + } + + OK (GxB_Matrix_Option_set_(A, GxB_FORMAT, GxB_BY_COL)) ; + CHECK (GB_IS_HYPERSPARSE (A)) ; + CHECK (A->is_csc) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_FORMAT, GxB_BY_ROW)) ; + CHECK (GB_IS_HYPERSPARSE (A)) ; + CHECK (!A->is_csc) ; + OK (GxB_Matrix_Option_set_(A, GxB_FORMAT, GxB_BY_COL)) ; CHECK (GB_IS_HYPERSPARSE (A)) ; CHECK (A->is_csc) ; @@ -4470,78 +4597,184 @@ void mexFunction OK (GxB_Matrix_Option_get_(A, GxB_FORMAT, &format)) ; CHECK (format == GxB_BY_COL) ; + int f2 = 99 ; + OK (GxB_Matrix_Option_get_INT32 (A, GxB_FORMAT, &f2)) ; + CHECK (f2 == GxB_BY_COL) ; + OK (GxB_Matrix_Option_set_(A, GxB_FORMAT, GxB_BY_ROW)) ; CHECK (!A->is_csc) ; + OK (GxB_Matrix_Option_set_INT32 (A, GxB_FORMAT, GxB_BY_COL)) ; + CHECK (A->is_csc) ; + + OK (GxB_Matrix_Option_set_INT32 (A, GxB_FORMAT, GxB_BY_ROW)) ; + CHECK (!A->is_csc) ; + OK (GxB_Matrix_Option_get_(A, GxB_FORMAT, &format)) ; CHECK (format == GxB_BY_ROW) ; + OK (GxB_Matrix_Option_get_INT32 (A, GxB_FORMAT, &f2)) ; + CHECK (f2 == GxB_BY_ROW) ; + OK (GxB_Matrix_Option_set_(A, GxB_FORMAT, GxB_BY_COL)) ; CHECK (A->is_csc) ; + OK (GxB_Matrix_Option_set_INT32(A, GxB_FORMAT, GxB_BY_ROW)) ; + CHECK (!A->is_csc) ; + + OK (GxB_Matrix_Option_set_INT32(A, GxB_FORMAT, GxB_BY_COL)) ; + CHECK (A->is_csc) ; + OK (GxB_Global_Option_set_(GxB_FORMAT, GxB_BY_ROW)) ; format = 99 ; OK (GxB_Global_Option_get_(GxB_FORMAT, &format)) ; CHECK (format == 0) ; + int32_t format2 = 999 ; + OK (GxB_Global_Option_get_INT32 (GxB_FORMAT, &format2)) ; + CHECK (format2 == 0) ; + + OK (GxB_Global_Option_set_INT32 (GxB_FORMAT, GxB_BY_COL)) ; + OK (GxB_Global_Option_get_INT32 (GxB_FORMAT, &format2)) ; + CHECK (format2 == 1) ; + + OK (GxB_Global_Option_set_INT32 (GxB_FORMAT, GxB_BY_ROW)) ; + OK (GxB_Global_Option_get_INT32 (GxB_FORMAT, &format2)) ; + CHECK (format2 == 0) ; OK (GxB_Global_Option_set_(GxB_HYPER_SWITCH, 77.33f)) ; OK (GxB_Global_Option_get_(GxB_HYPER_SWITCH, &hratio)) ; printf ("%g\n", hratio) ; CHECK (hratio == 77.33f) ; + hratio2 = 88 ; + OK (GxB_Global_Option_get_FP64 (GxB_HYPER_SWITCH, &hratio2)) ; + CHECK (hratio == hratio2) ; + + OK (GxB_Global_Option_set_FP64 (GxB_HYPER_SWITCH, 88.22f)) ; + OK (GxB_Global_Option_get_FP64 (GxB_HYPER_SWITCH, &hratio)) ; + CHECK (hratio == 88.22f) ; OK (GxB_Global_Option_set_(GxB_HYPER_SWITCH, GxB_HYPER_DEFAULT)) ; OK (GxB_Global_Option_get_(GxB_HYPER_SWITCH, &hratio)) ; CHECK (hratio == GxB_HYPER_DEFAULT) ; + OK (GxB_Global_Option_set_(GxB_HYPER_SWITCH, 12.34f)) ; + OK (GxB_Global_Option_set_FP64 (GxB_HYPER_SWITCH, GxB_HYPER_DEFAULT)) ; + OK (GxB_Global_Option_get_FP64 (GxB_HYPER_SWITCH, &hratio)) ; + CHECK (hratio == GxB_HYPER_DEFAULT) ; + + hratio2 = 22 ; + OK (GxB_Global_Option_get_FP64 (GxB_HYPER_SWITCH, &hratio2)) ; + CHECK (hratio == hratio2) ; + expected = GrB_NULL_POINTER ; GrB_Matrix O_NULL = NULL ; ERR1 (O_NULL, GxB_Matrix_Option_set_(O_NULL, GxB_FORMAT, GxB_BY_COL)) ; + ERR1 (O_NULL, GxB_Matrix_Option_set_INT32 (O_NULL, GxB_FORMAT, GxB_BY_COL)) ; expected = GrB_NULL_POINTER ; ERR (GxB_Global_Option_get_(GxB_FORMAT, NULL)) ; + ERR (GxB_Global_Option_get_INT32 (GxB_FORMAT, NULL)) ; expected = GrB_NULL_POINTER ; ERR (GxB_Matrix_Option_get_(A, GxB_FORMAT, NULL)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected (A format null):%s\n", err) ; + ERR (GxB_Matrix_Option_get_INT32 (A, GxB_FORMAT, NULL)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected (A format null):%s\n", err) ; + expected = GrB_NULL_POINTER ; ERR (GxB_Matrix_Option_get_(A, GxB_HYPER_SWITCH, NULL)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected:%s\n", err) ; + ERR (GxB_Matrix_Option_get_FP64 (A, GxB_HYPER_SWITCH, NULL)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected:%s\n", err) ; + ERR (GxB_Matrix_Option_get_(A, GxB_BITMAP_SWITCH, NULL)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected:%s\n", err) ; + ERR (GxB_Matrix_Option_get_FP64 (A, GxB_BITMAP_SWITCH, NULL)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected:%s\n", err) ; + expected = GrB_NULL_POINTER ; ERR (GxB_Global_Option_get_(GxB_HYPER_SWITCH, NULL)) ; ERR (GxB_Global_Option_get_(GxB_BITMAP_SWITCH, NULL)) ; + ERR (GxB_Global_Option_get_FP64 (GxB_HYPER_SWITCH, NULL)) ; + ERR (GxB_Global_Option_get_FP64 (GxB_BITMAP_SWITCH, NULL)) ; expected = GrB_INVALID_VALUE ; ERR (GxB_Global_Option_get_(-1, NULL)) ; + int32_t ignore2 = 999 ; + ERR (GxB_Global_Option_get_INT32 (-1, &ignore2)) ; + CHECK (ignore2 == 999) ; + + int64_t ignore3 = 999 ; + ERR (GxB_Global_Option_get_INT64 (-1, &ignore3)) ; + CHECK (ignore3 == 999) ; + + double ignore4 = 999 ; + ERR (GxB_Global_Option_get_FP64 (-1, &ignore4)) ; + CHECK (ignore4 == 999) ; + + void *ignore5 = NULL ; + ERR (GxB_Global_Option_get_FUNCTION (-1, &ignore5)) ; + CHECK (ignore5 == NULL) ; + + char *ignore6 = NULL ; + ERR (GxB_Global_Option_get_CHAR (-1, &ignore6)) ; + CHECK (ignore6 == NULL) ; + ERR (GxB_Matrix_Option_get_(A, 999, NULL)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected (bad field):%s\n", err) ; + int ii ; + ERR (GxB_Matrix_Option_get_INT32 (A, 999, &ii)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected (bad field):%s\n", err) ; + + double xx ; + ERR (GxB_Matrix_Option_get_FP64 (A, 999, &xx)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected (bad field):%s\n", err) ; + ERR1 (A, GxB_Matrix_Option_set_(A, 999, GxB_BY_ROW)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected:%s\n", err) ; + ERR1 (A, GxB_Matrix_Option_set_INT32 (A, 999, GxB_BY_ROW)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected:%s\n", err) ; + ERR (GxB_Global_Option_set_(999, GxB_BY_ROW)) ; + ERR (GxB_Global_Option_set_INT32 (999, GxB_BY_ROW)) ; expected = GrB_INVALID_VALUE ; ERR (GxB_Global_Option_set_(GxB_FORMAT, 9999)) ; + ERR (GxB_Global_Option_set_INT32 (GxB_FORMAT, 9999)) ; ERR1 (A, GxB_Matrix_Option_set_(A, 999, GxB_BY_ROW)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected:%s\n", err) ; + ERR1 (A, GxB_Matrix_Option_set_INT32 (A, 999, GxB_BY_ROW)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected:%s\n", err) ; + ERR1 (A, GxB_Matrix_Option_set_(A, GxB_FORMAT, 909090)) ; GrB_Matrix_error_(&err, A) ; printf ("error expected:%s\n", err) ; + ERR1 (A, GxB_Matrix_Option_set_INT32 (A, GxB_FORMAT, 909090)) ; + GrB_Matrix_error_(&err, A) ; + printf ("error expected:%s\n", err) ; + CHECK (A != NULL) ; CHECK (A->is_csc) ; @@ -5189,6 +5422,14 @@ void mexFunction OK (GxB_Global_Option_get_(GxB_NTHREADS, &nthreads)) ; CHECK (nthreads == 42) ; + OK (GxB_Global_Option_set_INT32 (GxB_NTHREADS, 44)) ; + OK (GxB_Global_Option_get_INT32 (GxB_NTHREADS, &nthreads)) ; + CHECK (nthreads == 44) ; + + int32_t nthreads2 = 11 ; + OK (GxB_Global_Option_get_(GxB_NTHREADS, &nthreads2)) ; + CHECK (nthreads == nthreads2) ; + OK (GxB_Desc_set (desc, GxB_NTHREADS, 43)) ; OK (GxB_Desc_get (desc, GxB_NTHREADS, &nthreads)) ; CHECK (nthreads == 43) ; @@ -5197,6 +5438,14 @@ void mexFunction OK (GxB_Desc_get (desc, GxB_DESCRIPTOR_NTHREADS, &nthreads)) ; CHECK (nthreads == 44) ; + OK (GxB_Desc_set_INT32 (desc, GxB_NTHREADS, 40)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_NTHREADS, &nthreads)) ; + CHECK (nthreads == 40) ; + + OK (GxB_Desc_set_INT32 (desc, GxB_DESCRIPTOR_NTHREADS, 41)) ; + OK (GxB_Desc_get_INT32 (desc, GxB_DESCRIPTOR_NTHREADS, &nthreads)) ; + CHECK (nthreads == 41) ; + //-------------------------------------------------------------------------- // import/export //-------------------------------------------------------------------------- diff --git a/deps/GraphBLAS/Test/GB_mex_select_idxunop.c b/deps/GraphBLAS/Test/GB_mex_select_idxunop.c index 744cde3042..db162d70ed 100644 --- a/deps/GraphBLAS/Test/GB_mex_select_idxunop.c +++ b/deps/GraphBLAS/Test/GB_mex_select_idxunop.c @@ -271,6 +271,15 @@ void mexFunction FREE_ALL ; mexErrMsgTxt ("scalar failed") ; } + + int f2 = 99 ; + GxB_Matrix_Option_get_INT32 (S, GxB_FORMAT, &f2) ; + if (fmt != GxB_BY_COL) + { + FREE_ALL ; + mexErrMsgTxt ("scalar failed") ; + } + scalar = (GrB_Scalar) S ; GrB_Info info = GxB_Scalar_fprint (scalar, "scalar", GxB_SILENT, NULL) ; if (info != GrB_SUCCESS) diff --git a/deps/GraphBLAS/Test/GB_mx_usercomplex.h b/deps/GraphBLAS/Test/GB_mx_usercomplex.h index de0a1c6f7a..ae9ad9806c 100644 --- a/deps/GraphBLAS/Test/GB_mx_usercomplex.h +++ b/deps/GraphBLAS/Test/GB_mx_usercomplex.h @@ -14,7 +14,7 @@ // 10 binary functions, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_first , Complex_second , Complex_min , Complex_max , Complex_plus , Complex_minus , Complex_times , Complex_div , Complex_rdiv , @@ -24,7 +24,7 @@ GrB_BinaryOp Complex_first , Complex_second , Complex_min , // 6 binary comparators, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_iseq , Complex_isne , Complex_isgt , Complex_islt , Complex_isge , Complex_isle ; @@ -33,14 +33,14 @@ GrB_BinaryOp Complex_iseq , Complex_isne , // 3 binary boolean functions, z=f(x,y), where CxC -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_or , Complex_and , Complex_xor ; //------------------------------------------------------------------------------ // 6 binary comparators, z=f(x,y), where CxC -> bool //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_BinaryOp Complex_eq , Complex_ne , Complex_gt , Complex_lt , Complex_ge , Complex_le ; @@ -49,13 +49,13 @@ GrB_BinaryOp Complex_eq , Complex_ne , // 1 binary function, z=f(x,y), where double x double -> C //------------------------------------------------------------------------------ -GB_PUBLIC GrB_BinaryOp Complex_complex ; +extern GrB_BinaryOp Complex_complex ; //------------------------------------------------------------------------------ // 5 unary functions, z=f(x) where C -> C //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_UnaryOp Complex_identity , Complex_ainv , Complex_minv , Complex_not , Complex_conj, Complex_one , Complex_abs ; @@ -64,7 +64,7 @@ GrB_UnaryOp Complex_identity , Complex_ainv , Complex_minv , // 4 unary functions, z=f(x) where C -> double //------------------------------------------------------------------------------ -GB_PUBLIC +extern GrB_UnaryOp Complex_real, Complex_imag, Complex_cabs, Complex_angle ; @@ -72,17 +72,17 @@ GrB_UnaryOp Complex_real, Complex_imag, // 2 unary functions, z=f(x) where double -> C //------------------------------------------------------------------------------ -GB_PUBLIC GrB_UnaryOp Complex_complex_real, Complex_complex_imag ; +extern GrB_UnaryOp Complex_complex_real, Complex_complex_imag ; //------------------------------------------------------------------------------ // Complex type, scalars, monoids, and semiring //------------------------------------------------------------------------------ -GB_PUBLIC GrB_Type Complex ; -GB_PUBLIC GrB_Monoid Complex_plus_monoid, Complex_times_monoid ; -GB_PUBLIC GrB_Semiring Complex_plus_times ; -GB_PUBLIC GrB_Info Complex_init (bool builtin_complex) ; -GB_PUBLIC GrB_Info Complex_finalize (void) ; +extern GrB_Type Complex ; +extern GrB_Monoid Complex_plus_monoid, Complex_times_monoid ; +extern GrB_Semiring Complex_plus_times ; +GrB_Info Complex_init (bool builtin_complex) ; +GrB_Info Complex_finalize (void) ; //------------------------------------------------------------------------------ // C++ compatibility @@ -171,48 +171,48 @@ GB_PUBLIC GrB_Info Complex_finalize (void) ; #define Y *y #define Z *z -GB_PUBLIC void complex_first (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_second (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_pair (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_plus (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_minus (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_rminus (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_times (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_div (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_rdiv (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_iseq (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_isne (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_eq (bool Z, const C X, const C Y) ; -GB_PUBLIC void complex_ne (bool Z, const C X, const C Y) ; -GB_PUBLIC void complex_complex (C Z, const double X, const double Y) ; -GB_PUBLIC void complex_one (C Z, const C X) ; -GB_PUBLIC void complex_identity (C Z, const C X) ; -GB_PUBLIC void complex_ainv (C Z, const C X) ; -GB_PUBLIC void complex_minv (C Z, const C X) ; -GB_PUBLIC void complex_conj (C Z, const C X) ; -GB_PUBLIC void complex_real (double Z, const C X) ; -GB_PUBLIC void complex_imag (double Z, const C X) ; -GB_PUBLIC void complex_cabs (double Z, const C X) ; -GB_PUBLIC void complex_angle (double Z, const C X) ; - -GB_PUBLIC void complex_min (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_max (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_isgt (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_islt (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_isge (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_isle (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_or (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_and (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_xor (C Z, const C X, const C Y) ; -GB_PUBLIC void complex_gt (bool Z, const C X, const C Y) ; -GB_PUBLIC void complex_lt (bool Z, const C X, const C Y) ; -GB_PUBLIC void complex_ge (bool Z, const C X, const C Y) ; -GB_PUBLIC void complex_le (bool Z, const C X, const C Y) ; -GB_PUBLIC void complex_abs (C Z, const C X) ; -GB_PUBLIC void complex_not (C Z, const C X) ; - -GB_PUBLIC void complex_complex_real (C Z, const double X) ; -GB_PUBLIC void complex_complex_imag (C Z, const double X) ; +void complex_first (C Z, const C X, const C Y) ; +void complex_second (C Z, const C X, const C Y) ; +void complex_pair (C Z, const C X, const C Y) ; +void complex_plus (C Z, const C X, const C Y) ; +void complex_minus (C Z, const C X, const C Y) ; +void complex_rminus (C Z, const C X, const C Y) ; +void complex_times (C Z, const C X, const C Y) ; +void complex_div (C Z, const C X, const C Y) ; +void complex_rdiv (C Z, const C X, const C Y) ; +void complex_iseq (C Z, const C X, const C Y) ; +void complex_isne (C Z, const C X, const C Y) ; +void complex_eq (bool Z, const C X, const C Y) ; +void complex_ne (bool Z, const C X, const C Y) ; +void complex_complex (C Z, const double X, const double Y) ; +void complex_one (C Z, const C X) ; +void complex_identity (C Z, const C X) ; +void complex_ainv (C Z, const C X) ; +void complex_minv (C Z, const C X) ; +void complex_conj (C Z, const C X) ; +void complex_real (double Z, const C X) ; +void complex_imag (double Z, const C X) ; +void complex_cabs (double Z, const C X) ; +void complex_angle (double Z, const C X) ; + +void complex_min (C Z, const C X, const C Y) ; +void complex_max (C Z, const C X, const C Y) ; +void complex_isgt (C Z, const C X, const C Y) ; +void complex_islt (C Z, const C X, const C Y) ; +void complex_isge (C Z, const C X, const C Y) ; +void complex_isle (C Z, const C X, const C Y) ; +void complex_or (C Z, const C X, const C Y) ; +void complex_and (C Z, const C X, const C Y) ; +void complex_xor (C Z, const C X, const C Y) ; +void complex_gt (bool Z, const C X, const C Y) ; +void complex_lt (bool Z, const C X, const C Y) ; +void complex_ge (bool Z, const C X, const C Y) ; +void complex_le (bool Z, const C X, const C Y) ; +void complex_abs (C Z, const C X) ; +void complex_not (C Z, const C X) ; + +void complex_complex_real (C Z, const double X) ; +void complex_complex_imag (C Z, const double X) ; #undef C #undef X diff --git a/deps/GraphBLAS/Test/test01.m b/deps/GraphBLAS/Test/test01.m index 819107ddfb..9a5f1254b7 100644 --- a/deps/GraphBLAS/Test/test01.m +++ b/deps/GraphBLAS/Test/test01.m @@ -13,6 +13,7 @@ GB_mex_about6 ; GB_mex_about7 ; GB_mex_about8 ; +GB_mex_about10 ; if (~ispc) GB_mex_about9 ; end diff --git a/deps/GraphBLAS/Test/test128.m b/deps/GraphBLAS/Test/test128.m index 2bd79b2855..8d6fc014cb 100644 --- a/deps/GraphBLAS/Test/test128.m +++ b/deps/GraphBLAS/Test/test128.m @@ -43,6 +43,30 @@ S = sparse (m,n) ; X = sparse (rand (m,n)) ; +% test the workaround for the GB_COMPILER_MSC_2019 bug in the +% Microsoft C compiler +A.class = 'single complex' ; +B.class = 'single complex' ; +T.matrix = sparse (m,n) ; +T.class = 'single complex' ; +GrB.burble (1) ; +for B_hyper = 0:1 + for A_hyper = 0:1 + A.is_hyper = A_hyper ; + B.is_hyper = B_hyper ; + C1 = GB_spec_Matrix_eWiseUnion(T, [ ], [ ], 'first', A, 1, B, 2, [ ]) ; + C4 = GB_mex_Matrix_eWiseUnion (T, [ ], [ ], 'first', A, 1, B, 2, [ ]) ; + GB_spec_compare (C1, C4) ; + C1 = GB_spec_Matrix_eWiseUnion(T, [ ], [ ], 'second', A, 1, B, 2, [ ]) ; + C4 = GB_mex_Matrix_eWiseUnion (T, [ ], [ ], 'second', A, 1, B, 2, [ ]) ; + GB_spec_compare (C1, C4) ; + end +end +GrB.burble (0) ; + +A.class = 'double' ; +B.class = 'double' ; + for B_hyper = 0:1 for A_hyper = 0:1 A.is_hyper = A_hyper ; diff --git a/deps/GraphBLAS/Test/test247.m b/deps/GraphBLAS/Test/test247.m new file mode 100644 index 0000000000..69ac3b154c --- /dev/null +++ b/deps/GraphBLAS/Test/test247.m @@ -0,0 +1,35 @@ +function test247 +%TEST247: test saxpy3 fine-hash method + +% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. +% SPDX-License-Identifier: Apache-2.0 + +rng ('default') ; + +n = 1000000 ; +A.matrix = sparse (n, n) ; +B.matrix = sprand (n, 1, 0.01) ; +A.matrix (1:100, 1:100) = sprand (100, 100, 0.4) ; +S = sparse (n, 1) ; + +semiring.multiply = 'times' ; +semiring.add = 'plus' ; +semiring.class = 'double' ; + +[nth chk] = nthreads_get ; + +desc.axb = 'hash' ; +nthreads_set (16, 1) ; +GrB.burble (1) ; +C1 = GB_mex_mxm (S, [ ], [ ], semiring, A, B, desc) ; +GrB.burble (0) ; + +C2 = A.matrix * B.matrix ; +err = norm (C1.matrix - C2, 1) ; +fprintf ('err: %g\n', err) ; +assert (err < 1e-12) ; + +nthreads_set (nth, chk) ; + +fprintf ('\ntest247: all tests passed\n') ; + diff --git a/deps/GraphBLAS/Test/testall.m b/deps/GraphBLAS/Test/testall.m index b083c0578b..55aac0f52c 100644 --- a/deps/GraphBLAS/Test/testall.m +++ b/deps/GraphBLAS/Test/testall.m @@ -75,6 +75,7 @@ function testall (threads,longtests) % tests with high rates (over 100/sec) %---------------------------------------- +logstat ('test247',t) ; % GrB_mxm: fine Hash method logstat ('test246',t) ; % GrB_mxm parallelism (changes slice_balanced) logstat ('test01' ,t) ; % error handling logstat ('test245',t) ; % test complex row/col scale diff --git a/deps/GraphBLAS/alternative/Makefile b/deps/GraphBLAS/alternative/Makefile index 7b39ddd8f3..25059303cd 100644 --- a/deps/GraphBLAS/alternative/Makefile +++ b/deps/GraphBLAS/alternative/Makefile @@ -18,10 +18,9 @@ default: library -# This version info must match ../CMakeLists.txt VER1 = 7 -VER2 = 3 -VER3 = 0 +VER2 = 4 +VER3 = 4 # pick your compiler: CC = gcc @@ -142,7 +141,7 @@ DOBJ = $(DSRC2:.c=.o) DEMO_PRG = $(notdir $(wildcard ../Demo/Program/*_demo.c)) DEMO = $(DEMO_PRG:.c=) -demo: $(DEMO) +demos: $(DEMO) ./altdemo clean: diff --git a/deps/GraphBLAS/alternative/README.txt b/deps/GraphBLAS/alternative/README.txt index 5000677f35..b6d09dfd98 100644 --- a/deps/GraphBLAS/alternative/README.txt +++ b/deps/GraphBLAS/alternative/README.txt @@ -35,5 +35,5 @@ to compile the static library: make static to compile in parallel with 4 cores: make -j4 to install in /usr/local/*: sudo make install to cleanup: make distclean -to compile and run the demos: make demo +to compile and run the demos: make demos diff --git a/deps/GraphBLAS/cmake_modules/FindGraphBLAS.cmake b/deps/GraphBLAS/cmake_modules/FindGraphBLAS.cmake new file mode 100644 index 0000000000..247b31f813 --- /dev/null +++ b/deps/GraphBLAS/cmake_modules/FindGraphBLAS.cmake @@ -0,0 +1,169 @@ +#[=======================================================================[.rst: +FindGraphBLAS +-------- + +The following copyright and license applies to just this file only, not to +the GraphBLAS library itself: +LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved. +SPDX-License-Identifier: BSD-2-Clause +See additional acknowledgments in the LICENSE file, +or contact permission@sei.cmu.edu for the full terms. + +Find the native GRAPHBLAS includes and library. + +IMPORTED Targets +^^^^^^^^^^^^^^^^ + +This module defines :prop_tgt:`IMPORTED` target ``GRAPHBLAS::GRAPHBLAS``, if +GRAPHBLAS has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +:: + + GRAPHBLAS_INCLUDE_DIR - where to find GraphBLAS.h, etc. + GRAPHBLAS_LIBRARY - dynamic GraphBLAS library + GRAPHBLAS_STATIC - static GraphBLAS library + GRAPHBLAS_LIBRARIES - List of libraries when using GraphBLAS. + GRAPHBLAS_FOUND - True if GraphBLAS found. + +:: + +Hints +^^^^^ + +A user may set ``GRAPHBLAS_ROOT`` or ``GraphBLAS_ROOT`` to a GraphBLAS +installation root to tell this module where to look. + +Otherwise, the first place searched is in ../GraphBLAS, relative to the LAGraph +source directory. That is, if GraphBLAS and LAGraph reside in the same parent +folder, side-by-side, and if it contains GraphBLAS/Include/GraphBLAS.h file and +GraphBLAS/build/libgraphblas.so (or dylib, etc), then that version is used. +This takes precedence over the system-wide installation of GraphBLAS, which +might be an older version. This method gives the user the ability to compile +LAGraph with their own copy of GraphBLAS, ignoring the system-wide version. + +If SuiteSparse:GraphBLAS is the GraphBLAS library being utilized, +all the Find*.cmake files in SuiteSparse are installed by 'make install' into +/usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the +${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands +in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: + + set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) + +#]=======================================================================] + +# NB: this is built around assumptions about one particular GraphBLAS +# installation (SuiteSparse:GraphBLAS). As other installations become available +# changes to this will likely be required. + +#------------------------------------------------------------------------------- + +# "Include" for SuiteSparse:GraphBLAS +find_path ( GRAPHBLAS_INCLUDE_DIR + NAMES GraphBLAS.h + HINTS ${GRAPHBLAS_ROOT} + HINTS ENV GRAPHBLAS_ROOT + HINTS ${CMAKE_SOURCE_DIR}/.. + HINTS ${CMAKE_SOURCE_DIR}/../GraphBLAS + HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/GraphBLAS + PATH_SUFFIXES include Include + ) + +# dynamic SuiteSparse:GraphBLAS library (or static if no dynamic library was built) +find_library ( GRAPHBLAS_LIBRARY + NAMES graphblas graphblas_static + HINTS ${GRAPHBLAS_ROOT} + HINTS ENV GRAPHBLAS_ROOT + HINTS ${CMAKE_SOURCE_DIR}/.. + HINTS ${CMAKE_SOURCE_DIR}/../GraphBLAS + HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/GraphBLAS + PATH_SUFFIXES lib build build/Release build/Debug alternative + ) + +if ( MSVC ) + set ( STATIC_NAME graphblas_static ) +else ( ) + set ( STATIC_NAME graphblas ) + set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) + set ( CMAKE_FIND_LIBRARY_SUFFIXES + ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +endif ( ) + +# static SuiteSparse:GraphBLAS library +find_library ( GRAPHBLAS_STATIC + NAMES ${STATIC_NAME} + HINTS ${GRAPHBLAS_ROOT} + HINTS ENV GRAPHBLAS_ROOT + HINTS ${CMAKE_SOURCE_DIR}/.. + HINTS ${CMAKE_SOURCE_DIR}/../GraphBLAS + HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/GraphBLAS + PATH_SUFFIXES lib build build/Release build/Debug alternative + ) + +if ( NOT MSVC ) + # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable + set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) +endif ( ) + +# get version of the library from the dynamic library name +get_filename_component ( GRAPHBLAS_LIBRARY ${GRAPHBLAS_LIBRARY} REALPATH ) +get_filename_component ( GRAPHBLAS_FILENAME ${GRAPHBLAS_LIBRARY} NAME ) +string ( + REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" + GRAPHBLAS_VERSION + ${GRAPHBLAS_FILENAME} + ) + +# set ( GRAPHBLAS_VERSION "" ) +if ( EXISTS "${GRAPHBLAS_INCLUDE_DIR}" AND NOT GRAPHBLAS_VERSION ) + # if the version does not appear in the filename, read the include file + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h GRAPHBLAS_MAJOR_STR + REGEX "define GxB_IMPLEMENTATION_MAJOR" ) + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h GRAPHBLAS_MINOR_STR + REGEX "define GxB_IMPLEMENTATION_MINOR" ) + file ( STRINGS ${GRAPHBLAS_INCLUDE_DIR}/GraphBLAS.h GRAPHBLAS_PATCH_STR + REGEX "define GxB_IMPLEMENTATION_SUB" ) + message ( STATUS "major: ${GRAPHBLAS_MAJOR_STR}" ) + message ( STATUS "minor: ${GRAPHBLAS_MINOR_STR}" ) + message ( STATUS "patch: ${GRAPHBLAS_PATCH_STR}" ) + string ( REGEX MATCH "[0-9]+" GRAPHBLAS_MAJOR ${GRAPHBLAS_MAJOR_STR} ) + string ( REGEX MATCH "[0-9]+" GRAPHBLAS_MINOR ${GRAPHBLAS_MINOR_STR} ) + string ( REGEX MATCH "[0-9]+" GRAPHBLAS_PATCH ${GRAPHBLAS_PATCH_STR} ) + set (GRAPHBLAS_VERSION "${GRAPHBLAS_MAJOR}.${GRAPHBLAS_MINOR}.${GRAPHBLAS_PATCH}") +endif ( ) + +set ( GRAPHBLAS_LIBRARIES ${GRAPHBLAS_LIBRARY} ) + +include ( FindPackageHandleStandardArgs ) + +find_package_handle_standard_args( + GraphBLAS + REQUIRED_VARS GRAPHBLAS_LIBRARY GRAPHBLAS_INCLUDE_DIR + VERSION_VAR GRAPHBLAS_VERSION + ) + +mark_as_advanced( + GRAPHBLAS_INCLUDE_DIR + GRAPHBLAS_LIBRARY + GRAPHBLAS_STATIC + GRAPHBLAS_LIBRARIES + ) + +if ( GRAPHBLAS_FOUND ) + message ( STATUS "GraphBLAS version: ${GRAPHBLAS_VERSION}" ) + message ( STATUS "GraphBLAS include: ${GRAPHBLAS_INCLUDE_DIR}" ) + message ( STATUS "GraphBLAS library: ${GRAPHBLAS_LIBRARY}" ) + message ( STATUS "GraphBLAS static: ${GRAPHBLAS_STATIC}" ) +else ( ) + message ( STATUS "GraphBLAS not found" ) + set ( GRAPHBLAS_INCLUDE_DIR "" ) + set ( GRAPHBLAS_LIBRARIES "" ) + set ( GRAPHBLAS_LIBRARY "" ) + set ( GRAPHBLAS_STATIC "" ) +endif ( ) + diff --git a/deps/GraphBLAS/cmake_modules/GraphBLAS_version.cmake b/deps/GraphBLAS/cmake_modules/GraphBLAS_version.cmake new file mode 100644 index 0000000000..b8d9fcb01c --- /dev/null +++ b/deps/GraphBLAS/cmake_modules/GraphBLAS_version.cmake @@ -0,0 +1,13 @@ +#------------------------------------------------------------------------------- +# GraphBLAS/cmake_modules/GraphBLAS_version.cmake: define the GraphBLAS version +#------------------------------------------------------------------------------- + +# SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2023, All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +# version of SuiteSparse:GraphBLAS +set ( GraphBLAS_DATE "Mar 25, 2023" ) +set ( GraphBLAS_VERSION_MAJOR 7 ) +set ( GraphBLAS_VERSION_MINOR 4 ) +set ( GraphBLAS_VERSION_SUB 4 ) + diff --git a/deps/GraphBLAS/cmake_modules/SuiteSparseAtomic.cmake b/deps/GraphBLAS/cmake_modules/SuiteSparseAtomic.cmake new file mode 100644 index 0000000000..18e8af2eb4 --- /dev/null +++ b/deps/GraphBLAS/cmake_modules/SuiteSparseAtomic.cmake @@ -0,0 +1,62 @@ +#------------------------------------------------------------------------------- +# GraphBLAS/cmake_modules/SuiteSparseAtomic.cmake +#------------------------------------------------------------------------------- + +# Copyright (c) 2017-2023, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +#------------------------------------------------------------------------------- + +# determine if -latomic must be linked + +include ( CheckCSourceCompiles ) + +set ( atomic_source +" +#if defined ( _MSC_VER ) && \ + !(defined ( __INTEL_CLANG_COMPILER ) || defined ( __INTEL_COMPILER ) || \ + defined ( __clang__ ) || defined ( __GNUC__ )) + // MS Visual Studio compiler. No need to check for atomics; GraphBLAS + // uses MSC-specific methods. (See Source/GB_atomics.h) + int main (void) { return (0) ; } +#else + // gcc, clang, icx, xlc, etc: see if -latomic is required + #include + #include + int main (void) + { + _Atomic uint8_t t8 = 0 ; + uint8_t e8 = 0, d8 = 0 ; + atomic_compare_exchange_weak (&t8, &e8, d8) ; + _Atomic uint16_t t16 = 0 ; + uint16_t e16 = 0, d16 = 0 ; + atomic_compare_exchange_weak (&t16, &e16, d16) ; + _Atomic uint32_t t32 = 0 ; + uint32_t e32 = 0, d32 = 0 ; + atomic_compare_exchange_weak (&t32, &e32, d32) ; + _Atomic uint64_t t64 = 0 ; + uint64_t e64 = 0, d64 = 0 ; + atomic_compare_exchange_weak (&t64, &e64, d64) ; + return (0) ; + } +#endif +" ) + +check_c_source_compiles ( "${atomic_source}" TEST_FOR_STDATOMIC ) + +if ( NOT TEST_FOR_STDATOMIC ) + # try with -latomic + set ( CMAKE_REQUIRED_LIBRARIES "atomic" ) + check_c_source_compiles ( "${atomic_source}" TEST_FOR_STDATOMIC_WITH_LIBATOMIC ) + if ( NOT TEST_FOR_STDATOMIC_WITH_LIBATOMIC ) + # fails with -latomic + message ( FATAL_ERROR "ANSI C11 atomics: failed" ) + endif ( ) + # source compiles but -latomic is required + set ( LIBATOMIC_REQUIRED true ) + message ( STATUS "ANSI C11 atomics: OK, but -latomic required" ) +else ( ) + set ( LIBATOMIC_REQUIRED false ) + message ( STATUS "ANSI C11 atomics: OK. -latomic not needed" ) +endif ( ) + diff --git a/deps/GraphBLAS/cmake_modules/SuiteSparsePolicy.cmake b/deps/GraphBLAS/cmake_modules/SuiteSparsePolicy.cmake index e1de3b1877..57727207dd 100644 --- a/deps/GraphBLAS/cmake_modules/SuiteSparsePolicy.cmake +++ b/deps/GraphBLAS/cmake_modules/SuiteSparsePolicy.cmake @@ -2,7 +2,7 @@ # SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake #------------------------------------------------------------------------------- -# Copyright (c) 2022, Timothy A. Davis. All Rights Reserved. +# Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. # SPDX-License-Identifier: BSD-3-clause #------------------------------------------------------------------------------- @@ -15,9 +15,61 @@ # set ( CMAKE_BUILD_TYPE Debug ) # # ENABLE_CUDA: if set to true, CUDA is enabled for the project. +# Default: true for CHOLMOD and SPQR, false for GraphBLAS +# (for which CUDA is in progress and not ready for +# production use). # -# To select a specific BLAS library, edit this file and uncomment one of: -# set ( BLA_VENDOR ... ) +# LOCAL_INSTALL: if true, "cmake --install" will install +# into SuiteSparse/lib and SuiteSparse/include. +# if false, "cmake --install" will install into the +# default prefix (or the one configured with +# CMAKE_INSTALL_PREFIX). +# Default: false +# +# NSTATIC: if true, static libraries are not built. +# Default: false, except for GraphBLAS, which +# takes a long time to compile so the default for +# GraphBLAS is true. For Mongoose, the NSTATIC setting +# is treated as if it always false, since the mongoose +# program is built with the static library. +# +# SUITESPARSE_CUDA_ARCHITECTURES: a string, such as "all" or +# "35;50;75;80" that lists the CUDA architectures to use +# when compiling CUDA kernels with nvcc. The "all" +# option requires cmake 3.23 or later. +# Default: "52;75;80". +# +# BLA_VENDOR and BLA_SIZEOF_INTEGER: By default, SuiteSparse searches for +# the BLAS library in a specific order. If you wish to +# use a specific BLAS library, set both of these with +# (for example): +# -DBLA_VENDOR=Intel10_64lp -DBLA_SIZEOF_INTEGER=4 +# Both settings must appear, or neither. +# Default: neither are defined. +# +# BLA_STATIC: if true, use static linkage for BLAS and LAPACK. +# Default: false +# +# ALLOW_64BIT_BLAS if true, SuiteSparse will search for both 32-bit and +# 64-bit BLAS. If false, only 32-bit BLAS will be +# searched for. Ignored if BLA_VENDOR and +# BLA_SIZEOF_INTEGER are defined. +# +# SUITESPARSE_C_TO_FORTRAN: a string that defines how C calls Fortran. +# Defaults to "(name,NAME) name" for Windows (lower case, +# no underscore appended to the name), which is the +# system that is most likely not to have a Fortran +# compiler. Defaults to "(name,NAME) name##_" otherwise. +# This setting is only used if no Fortran compiler is +# found. +# +# NFORTRAN: if true, no Fortan files are compiled, and the Fortran +# language is not enabled in any cmake scripts. The +# built-in cmake script FortranCInterface is skipped. +# This will require SUITESPARSE_C_TO_FORTRAN to be defined +# explicitly, if the defaults are not appropriate for your +# system. +# Default: false cmake_minimum_required ( VERSION 3.19 ) @@ -27,54 +79,102 @@ message ( STATUS "Build: ${CMAKE_BINARY_DIR} ") cmake_policy ( SET CMP0042 NEW ) # enable MACOSX_RPATH by default cmake_policy ( SET CMP0048 NEW ) # VERSION variable policy cmake_policy ( SET CMP0054 NEW ) # if ( expression ) handling policy +cmake_policy ( SET CMP0104 NEW ) # initialize CUDA architectures + +if ( WIN32 ) + set ( CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS true ) + add_compile_definitions ( _CRT_SECURE_NO_WARNINGS ) +endif ( ) set ( CMAKE_MACOSX_RPATH TRUE ) enable_language ( C ) include ( GNUInstallDirs ) +# add the cmake_modules folder for this package to the module path +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/cmake_modules ) + +# NSTATIC option +if ( NSTATIC_DEFAULT_ON ) + option ( NSTATIC "ON (default): do not build static libraries. OFF: build static libraries" on ) +else ( ) + option ( NSTATIC "ON: do not build static libraries. OFF (default): build static libraries" off ) +endif ( ) + +# installation options +option ( LOCAL_INSTALL "Install in SuiteSparse/lib" off ) + +if ( SUITESPARSE_SECOND_LEVEL ) + # some packages in SuiteSparse are in SuiteSparse/Package/Package + set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/../../lib/cmake ) +else ( ) + # most packages in SuiteSparse are located in SuiteSparse/Package + set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/../lib/cmake ) +endif ( ) + # add the ./build folder to the runpath so other SuiteSparse packages can # find this one without "make install" set ( CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} ${CMAKE_BINARY_DIR} ) -# determine if this package is inside the top-level SuiteSparse folder -# (if ../lib and ../include exist, relative to the source directory) +# determine if this Package is inside the SuiteSparse folder +set ( INSIDE_SUITESPARSE false ) +if ( LOCAL_INSTALL ) + # if you do not want to install local copies of SuiteSparse + # packages in SuiteSparse/lib and SuiteSparse/, set + # LOCAL_INSTALL to false in your CMake options. + if ( SUITESPARSE_SECOND_LEVEL ) + # the package is normally located at the 2nd level inside SuiteSparse + # (SuiteSparse/GraphBLAS/GraphBLAS/ for example) + if ( EXISTS ${CMAKE_SOURCE_DIR}/../../SuiteSparse_config ) + set ( INSIDE_SUITESPARSE true ) + endif ( ) + else ( ) + # typical case, the package is at the 1st level inside SuiteSparse + # (SuiteSparse/AMD for example) + if ( EXISTS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config ) + set ( INSIDE_SUITESPARSE true ) + endif ( ) + endif ( ) + + if ( NOT INSIDE_SUITESPARSE ) + message ( FATAL_ERROR "Unsupported layout for local installation. Correct the directory layout or unset LOCAL_INSTALL." ) + endif ( ) -if ( SUITESPARSE_SECOND_LEVEL ) - # the package is normally located at the 2nd level inside SuiteSparse - # (SuiteSparse/GraphBLAS/GraphBLAS/ for example) - set ( INSIDE_SUITESPARSE - ( ( EXISTS ${CMAKE_SOURCE_DIR}/../../lib ) AND - ( EXISTS ${CMAKE_SOURCE_DIR}/../../include ) ) ) -else ( ) - # typical case, the package is at the 1st level inside SuiteSparse - # (SuiteSparse/AMD for example) - set ( INSIDE_SUITESPARSE - ( ( EXISTS ${CMAKE_SOURCE_DIR}/../lib ) AND - ( EXISTS ${CMAKE_SOURCE_DIR}/../include ) ) ) endif ( ) if ( INSIDE_SUITESPARSE ) # ../lib and ../include exist: the package is inside SuiteSparse. # find ( REAL_PATH ...) requires cmake 3.19. if ( SUITESPARSE_SECOND_LEVEL ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../../lib SUITESPARSE_LIBDIR ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../../include SUITESPARSE_INCLUDEDIR ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../../bin SUITESPARSE_BINDIR ) + file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../.. SUITESPARSE_LOCAL_PREFIX ) else ( ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../lib SUITESPARSE_LIBDIR ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../include SUITESPARSE_INCLUDEDIR ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../bin SUITESPARSE_BINDIR ) + file ( REAL_PATH ${CMAKE_SOURCE_DIR}/.. SUITESPARSE_LOCAL_PREFIX ) endif ( ) - message ( STATUS "Local install: ${SUITESPARSE_LIBDIR} ") - message ( STATUS "Local include: ${SUITESPARSE_INCLUDEDIR} ") - message ( STATUS "Local bin: ${SUITESPARSE_BINDIR} ") - # append ../lib to the install and build runpaths +endif ( ) + +if ( LOCAL_INSTALL ) + set ( SUITESPARSE_LIBDIR ${SUITESPARSE_LOCAL_PREFIX}/lib ) + set ( SUITESPARSE_INCLUDEDIR ${SUITESPARSE_LOCAL_PREFIX}/include ) + set ( SUITESPARSE_BINDIR ${SUITESPARSE_LOCAL_PREFIX}/bin ) +else ( ) + set ( SUITESPARSE_LIBDIR ${CMAKE_INSTALL_LIBDIR} ) + set ( SUITESPARSE_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR} ) + set ( SUITESPARSE_BINDIR ${CMAKE_INSTALL_BINDIR} ) +endif ( ) + +if ( INSIDE_SUITESPARSE ) + # append ../lib to the install and build runpaths set ( CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} ${SUITESPARSE_LIBDIR} ) set ( CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} ${SUITESPARSE_LIBDIR} ) endif ( ) -message ( STATUS "Install rpath: ${CMAKE_INSTALL_RPATH} ") -message ( STATUS "Build rpath: ${CMAKE_BUILD_RPATH} ") +message ( STATUS "Install lib: ${SUITESPARSE_LIBDIR}" ) +message ( STATUS "Install include: ${SUITESPARSE_INCLUDEDIR}" ) +message ( STATUS "Install bin: ${SUITESPARSE_BINDIR}" ) +message ( STATUS "Install rpath: ${CMAKE_INSTALL_RPATH}" ) +message ( STATUS "Build rpath: ${CMAKE_BUILD_RPATH}" ) if ( NOT CMAKE_BUILD_TYPE ) set ( CMAKE_BUILD_TYPE Release ) @@ -85,21 +185,35 @@ message ( STATUS "Build type: ${CMAKE_BUILD_TYPE} ") set ( CMAKE_INCLUDE_CURRENT_DIR ON ) #------------------------------------------------------------------------------- -# BLAS library +# check if Fortran is available and enabled #------------------------------------------------------------------------------- -# Uncomment one of the lines below to select OpenBLAS or the Intel MKL. -# Be sure to use a parallel BLAS library for best results in UMFPACK, -# CHOLMOD, SPQR, and ParU. All SuiteSparse packages should use the same -# BLAS and the same OpenMP library. - -# set ( BLA_VENDOR OpenBLAS ) # OpenBLAS with 32-bit integers -# set ( BLA_VENDOR Intel10_64ilp ) # MKL BLAS with 64-bit integers -# set ( BLA_VENDOR Intel10_64lp ) # MKL BLAS with 32-bit integers +include ( CheckLanguage ) +option ( NFORTRAN "ON: do not try to use Fortran. OFF (default): try Fortran" off ) +if ( NFORTRAN ) + message ( STATUS "Fortran: not enabled" ) +else ( ) + check_language ( Fortran ) + if ( CMAKE_Fortran_COMPILER ) + enable_language ( Fortran ) + message ( STATUS "Fortran: ${CMAKE_Fortran_COMPILER}" ) + else ( ) + # Fortran not available: + set ( NFORTRAN true ) + message ( STATUS "Fortran: not available" ) + endif ( ) +endif ( ) -# The Intel MKL BLAS is recommended. It is free to download (but be sure to -# check their license to make sure you accept it). See: -# https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl.htm +# default C-to-Fortran name mangling if Fortran compiler not found +if ( MSVC ) + # MS Visual Studio Fortran compiler does not mangle the Fortran name + set ( SUITESPARSE_C_TO_FORTRAN "(name,NAME) name" + CACHE STRING "C to Fortan name mangling" ) +else ( ) + # Other systems (Linux, Mac) typically append an underscore + set ( SUITESPARSE_C_TO_FORTRAN "(name,NAME) name##_" + CACHE STRING "C to Fortan name mangling" ) +endif ( ) #------------------------------------------------------------------------------- # find CUDA @@ -108,7 +222,6 @@ set ( CMAKE_INCLUDE_CURRENT_DIR ON ) if ( ENABLE_CUDA ) # try finding CUDA - include ( CheckLanguage ) check_language ( CUDA ) message ( STATUS "Looking for CUDA" ) if ( CMAKE_CUDA_COMPILER ) @@ -144,6 +257,9 @@ endif ( ) if ( SUITESPARSE_CUDA ) message ( STATUS "CUDA: enabled" ) + add_compile_definitions ( SUITESPARSE_CUDA ) + set ( SUITESPARSE_CUDA_ARCHITECTURES "52;75;80" CACHE STRING "CUDA architectures" ) + set ( CMAKE_CUDA_ARCHITECTURES ${SUITESPARSE_CUDA_ARCHITECTURES} ) else ( ) message ( STATUS "CUDA: not enabled" ) endif ( ) diff --git a/deps/GraphBLAS/cmake_modules/SuiteSparseReport.cmake b/deps/GraphBLAS/cmake_modules/SuiteSparseReport.cmake index c656f73b82..9271c4a920 100644 --- a/deps/GraphBLAS/cmake_modules/SuiteSparseReport.cmake +++ b/deps/GraphBLAS/cmake_modules/SuiteSparseReport.cmake @@ -2,24 +2,54 @@ # SuiteSparse/SuiteSparse_config/SuiteSparseReport.cmake #------------------------------------------------------------------------------- -# Copyright (c) 2022, Timothy A. Davis. All Rights Reserved. +# Copyright (c) 2012-2023, Timothy A. Davis. All Rights Reserved. # SPDX-License-Identifier: BSD-3-clause #------------------------------------------------------------------------------- # report status and compile flags #------------------------------------------------------------------------------- -message ( STATUS "CMAKE C flags: ${CMAKE_C_FLAGS}" ) -message ( STATUS "CMAKE C++ flags: ${CMAKE_CXX_FLAGS}" ) -message ( STATUS "CMAKE build type: ${CMAKE_BUILD_TYPE}" ) +message ( STATUS "------------------------------------------------------------------------" ) +message ( STATUS "SuiteSparse CMAKE report for: ${CMAKE_PROJECT_NAME}" ) +message ( STATUS "------------------------------------------------------------------------" ) +message ( STATUS "inside common SuiteSparse root: ${INSIDE_SUITESPARSE}" ) +message ( STATUS "install in SuiteSparse/lib and SuiteSparse/include: ${LOCAL_INSTALL}" ) +message ( STATUS "build type: ${CMAKE_BUILD_TYPE}" ) +if ( NSTATIC ) + message ( STATUS "NSTATIC: true (do not build static library)" ) +else ( ) + message ( STATUS "NSTATIC: false (build static library)" ) +endif ( ) +if ( OPENMP_FOUND ) + message ( STATUS "use OpenMP: yes ") +else ( ) + message ( STATUS "use OpenMP: no ") +endif ( ) +message ( STATUS "C compiler: ${CMAKE_C_COMPILER} ") +message ( STATUS "C flags: ${CMAKE_C_FLAGS}" ) +message ( STATUS "C++ compiler: ${CMAKE_CXX_COMPILER}" ) +message ( STATUS "C++ flags: ${CMAKE_CXX_FLAGS}" ) if ( ${CMAKE_BUILD_TYPE} STREQUAL "Debug" ) - message ( STATUS "CMAKE C Flags debug: ${CMAKE_C_FLAGS_DEBUG} ") - message ( STATUS "CMAKE C++ Flags debug: ${CMAKE_CXX_FLAGS_DEBUG} ") + message ( STATUS "C Flags debug: ${CMAKE_C_FLAGS_DEBUG} ") + message ( STATUS "C++ Flags debug: ${CMAKE_CXX_FLAGS_DEBUG} ") else ( ) - message ( STATUS "CMAKE C Flags release: ${CMAKE_C_FLAGS_RELEASE} ") - message ( STATUS "CMAKE C++ Flags release: ${CMAKE_CXX_FLAGS_RELEASE} ") + message ( STATUS "C Flags release: ${CMAKE_C_FLAGS_RELEASE} ") + message ( STATUS "C++ Flags release: ${CMAKE_CXX_FLAGS_RELEASE} ") endif ( ) -message ( STATUS "CMAKE C compiler: ${CMAKE_C_COMPILER_ID} ") -message ( STATUS "CMAKE C++ compiler: ${CMAKE_CXX_COMPILER_ID}" ) -message ( STATUS "CMAKE have OpenMP: ${OPENMP_FOUND} ") - +if ( NFORTRAN ) + message ( STATUS "Fortran compiler: none" ) +else ( ) + message ( STATUS "Fortran compiler: ${CMAKE_Fortran_COMPILER} " ) +endif ( ) +get_property ( CDEFN DIRECTORY PROPERTY COMPILE_DEFINITIONS ) +message ( STATUS "compile definitions: ${CDEFN}") +if ( DEFINED SuiteSparse_BLAS_integer ) + message ( STATUS "BLAS integer: ${SuiteSparse_BLAS_integer}" ) +endif ( ) +if ( DEFINED CMAKE_CUDA_ARCHITECTURES ) + message ( STATUS "CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}" ) +endif ( ) +if ( NPARTITION ) + message ( STATUS "NPARTITION: do not use METIS" ) +endif ( ) +message ( STATUS "------------------------------------------------------------------------" ) diff --git a/deps/GraphBLAS/rmm_wrap/CMakeLists.txt b/deps/GraphBLAS/rmm_wrap/CMakeLists.txt index 3fc0ade50e..2eb5ed3d18 100644 --- a/deps/GraphBLAS/rmm_wrap/CMakeLists.txt +++ b/deps/GraphBLAS/rmm_wrap/CMakeLists.txt @@ -41,9 +41,9 @@ endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}/external_includes/rmm/include) -add_library(rmm_wrap rmm_wrap.cpp rmm_wrap.hpp rmm_wrap.h) +add_library(rmm_wrap STATIC rmm_wrap.cpp rmm_wrap.hpp rmm_wrap.h) -SET_TARGET_PROPERTIES (rmm_wrap PROPERTIES +set_target_properties (rmm_wrap PROPERTIES VERSION ${GraphBLAS_VERSION_MAJOR}.${GraphBLAS_VERSION_MINOR}.${GraphBLAS_VERSION_SUB} SOVERSION ${GraphBLAS_VERSION_MAJOR} C_STANDARD_REQUIRED 11 @@ -66,29 +66,11 @@ target_include_directories(rmm_wrap_test PUBLIC "${RMM_WRAP_INCLUDES}") # installation location #------------------------------------------------------------------------------- -# use "cmake -DSUITESPARSE_LOCAL=1" to install only in ../lib and -# ../include. - -if ( NOT SUITESPARSE_LOCAL ) - # install in /usr/local/lib and /usr/local/include. - # requires "sudo make install" - message ( STATUS "Installation will be system-wide (requires 'sudo make install')" ) - install ( TARGETS rmm_wrap - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -endif ( ) - -if ( INSIDE_SUITESPARSE ) - # also install in SuiteSparse/lib and SuiteSparse/include; - # does not require "sudo make install", just "make install" - message ( STATUS "Installation in ../../lib and ../../include," ) - message ( STATUS " with 'make local ; make install'. No 'sudo' required." ) - install ( TARGETS rmm_wrap - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) -endif ( ) +install ( TARGETS rmm_wrap + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) # install (TARGETS rmm_wrap # PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/deps/libcypher-parser b/deps/libcypher-parser index 70c940d004..10ba12b2dc 160000 --- a/deps/libcypher-parser +++ b/deps/libcypher-parser @@ -1 +1 @@ -Subproject commit 70c940d00450b60c53ad8c071bd668fd91587669 +Subproject commit 10ba12b2dcd45110fcaa6cdf37728ff71a20f4fa diff --git a/deps/readies b/deps/readies index 5a462c26bc..0f682ae82f 160000 --- a/deps/readies +++ b/deps/readies @@ -1 +1 @@ -Subproject commit 5a462c26bc8b5533e822c885458b5b01109bf81e +Subproject commit 0f682ae82f0ace820d323bca394b0de1549d8fe8 diff --git a/docs/commands/graph.query.md b/docs/commands/graph.query.md index d1b873632b..ba9c0d14a4 100644 --- a/docs/commands/graph.query.md +++ b/docs/commands/graph.query.md @@ -54,6 +54,7 @@ The syntax is based on [Cypher](http://www.opencypher.org/). [Most](https://redi * [UNION](#union) * [UNWIND](#unwind) * [FOREACH](#foreach) +* [CALL {}](/docs/commands/graph.query.md#call-) #### MATCH @@ -788,6 +789,24 @@ GRAPH.QUERY DEMO_GRAPH "MATCH (u:User) WITH u AS nonrecent ORDER BY u.lastVisit LIMIT 3 SET nonrecent.should_contact = true" ``` +#### UNION +The UNION clause is used to combine the result of multiple queries. + +UNION combines the results of two or more queries into a single result set that includes all the rows that belong to all queries in the union. + +The number and the names of the columns must be identical in all queries combined by using UNION. + +To keep all the result rows, use UNION ALL. + +Using just UNION will combine and remove duplicates from the result set. + +```sh +GRAPH.QUERY DEMO_GRAPH +"MATCH (n:Actor) RETURN n.name AS name +UNION ALL +MATCH (n:Movie) RETURN n.title AS name" +``` + #### UNWIND The UNWIND clause breaks down a given list into a sequence of records; each contains a single element in the list. @@ -804,6 +823,9 @@ GRAPH.QUERY DEMO_GRAPH ``` #### FOREACH + +(Since RedisGraph v2.12) + The `FOREACH` clause feeds the components of a list to a sub-query comprised of **updating clauses only** (`CREATE`, `MERGE`, `SET`, `REMOVE`, `DELETE` and `FOREACH`), while passing on the records it receives without change. The clauses within the sub-query recognize the bound variables defined prior to the `FOREACH` clause, but are local in the sense that later clauses are not aware of the variables defined inside them. In other words, `FOREACH` uses the current context, and does not affect it. @@ -835,23 +857,147 @@ GRAPH.QUERY DEMO_GRAPH FOREACH(do_perform IN CASE WHEN b = NULL THEN [1] ELSE [] END | MERGE (h)-[b2:BUYS_FROM]->(s:SUPPLIER {supplies_bread: true}) SET b2.direct = false)" ``` -#### UNION -The UNION clause is used to combine the result of multiple queries. +#### CALL \{\} -UNION combines the results of two or more queries into a single result set that includes all the rows that belong to all queries in the union. +(Since RedisGraph v2.12) -The number and the names of the columns must be identical in all queries combined by using UNION. +The CALL {} (subquery) clause allows local execution of subqueries, which opens the door for many comfortable and efficient actions on a graph. -To keep all the result rows, use UNION ALL. +The subquery is executed once for each record in the input stream. -Using just UNION will combine and remove duplicates from the result set. +The subquery may be a returning or non-returning subquery. A returning subquery may change the amount of records, while a non-returning subquery will not. + +The variables in the scope before the CALL {} clause are available after the clause, together with the variables returned by the subquery (in the case of a returning subquery). + +Variables may be imported from the outer scope **only** in an opening `WITH` clause, via simple projections (e.g. `WITH n, m`), or via `WITH *` (which imports all bound variables). The variables returned from a subquery may not override existing variables in the outer scope. + +The CALL {} clause may be used for numerous purposes, such as: Post-`UNION` processing, local environment for aggregations and actions on every input row, efficient operations using a limited namespace (via imports) and performing side-effects using non-returning subqueries. Let's see some examples. + +* Post-`UNION` processing. + +We can easily get the cheapest and most expensive items in a store and set their `of_interest` property to `true` (to keep monitoring the 'interesting' items) using post-`UNION` processing: + + ```sh + GRAPH.QUERY DEMO_GRAPH + CALL { + MATCH (s:Store {name: 'Walmart'})-[:SELLS]->(i:Item) + RETURN i AS item + ORDER BY price ASC + LIMIT 1 + UNION + MATCH (s:Store {name: 'Walmart'})-[:SELLS]->(i:Item) + RETURN i AS item + ORDER BY price DESC + LIMIT 1 + } + SET item.of_interest = true + RETURN item.name AS name, item.price AS price + ``` + +We can utilize post-`UNION` processing to perform aggregations over differently-matched entities. For example, we can count the number of customers and vendors that a store interacts with: + + ```sh + GRAPH.QUERY DEMO_GRAPH + CALL { + MATCH (s:Store {name: 'Walmart'})-[:SELLS_TO]->(c:Customer) + RETURN c AS interface + UNION + MATCH (s:Store {name: 'Walmart'})-[:BUYS_FROM]->(v:Vendor) + RETURN v AS interface + } + RETURN count(interface) AS interfaces + ``` + +* Local environment for aggregations and actions on every input row. + +Another key feature of the CALL {} clause is the ability to perform isolated aggregations on every input row. For example, let's check if there is any correlation between the amount of sales per-product and the advertisement-intensity implemented for it in a particular month. + + ```sh + GRAPH.QUERY DEMO_GRAPH + MATCH (item:Item) + CALL { + WITH item + MATCH (item)-[s:SOLD_TO {advertisement_intensity: 10}]->(c:Customer) + WHERE s.date > '01-01-2023' AND s.date < '01-02-2023' + RETURN count(s) AS item_sales_ads_high + } + CALL { + WITH item + MATCH (item)-[s:SOLD_TO {advertisement_intensity: 5}]->(c:Customer) + WHERE s.date > '01-01-2023' AND s.date < '01-02-2023' + RETURN count(s) AS item_sales_ads_low + } + RETURN item.name AS name, item_sales_ads_high as high_ads_sales, item_sales_ads_low as low_ads_sales + ``` + + + + + + +* Side-effects. + +We can comfortably perform side-effects using non-returning subqueries. For example, we can mark a sub-group of nodes in the graph withholding some shared property. Let's mark all the items in a Walmart store that were sold more than 100 times as popular items, and return **all** items in the store: + + ```sh + GRAPH.QUERY DEMO_GRAPH + MATCH (item:Item) + CALL { + WITH item + MATCH (item)-[s:SOLD_TO]->(c:Customer) + WITH item, count(s) AS item_sales + WHERE item_sales > 100 + SET item.popular = true + } + RETURN item + ``` ### Functions @@ -921,11 +1067,11 @@ This section contains information on all supported functions from the Cypher que | head(_expr_) | Returns the first element of a list
Returns null when _expr_ evaluates to null or an empty list | | keys(_expr_) | Returns a list of strings: all key names for given map or all property names for a given node or edge
Returns null when _expr_ evaluates to null | | last(_expr_) | Returns the last element of a list
Returns null when _expr_ evaluates to null or an empty list -| list.dedup(_list_) * | Given a list, returns a similar list after removing duplicate elements
Order is preserved, duplicates are removed from the end of the list
Returns null when _list_ evaluates to null
Emit an error when _list_ does not evaluate to a list or to null | -| list.insert(_list_, _idx_, _val_[, _dups_ = TRUE]) * | Given a list, returns a list after inserting a given value at a given index
_idx_ is 0-based when non-negative, or from the end of the list when negative
Returns null when _list_ evaluates to null
Returns _list_ when _val_ evaluates to null
Returns _list_ when _idx_ evaluates to an integer not in [-NumItems-1 .. NumItems]
When _dups_ evaluats to FALSE: returns _list_ when _val_ evaluates to a value that is already an element of _list_
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _idx_ does not evaluate to an integer
Emit an error when _dups_, if specified, does not evaluate to a Boolean | -| list.insertListElements(_list_, _list2_, _idx_[, _dups_ = TRUE]) * | Given a list, returns a list after inserting the elements of a second list at a given index
_idx_ is 0-based when non-negative, or from the end of the list when negative
Returns null when _list_ evaluates to null
Returns _list_ when _list2_ evaluates to null
Returns _list_ when _idx_ evaluates to an integer not in [-NumItems-1 .. NumItems]
When _dups_ evaluates to FALSE: If an element of _list2_ evaluates to an element of _list_ it would be skipped; If multiple elements of _list2_ evaluate to the same value - this value would be inserted at most once to _list_
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _list2_ does not evaluate to a list or to null
Emit an error when _idx_ does not evaluate to an integer
Emit an error when _dups_, if specified, does not evaluate to a Boolean | -| list.remove(_list_, _idx_[, _count_ = 1]) * | Given a list, returns a list after removing a given number of consecutive elements (or less, if the end of the list has been reached). starting at a given index.
_idx_ is 0-based when non-negative, or from the end of the list when negative
Returns _null_ when _list_ evaluates to null
Returns _list_ when _idx_ evaluates to an integer not in [-NumItems .. NumItems-1]
Returns _list_ when _count_ evaluates to a non-positive integer
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _idx_ does not evaluate to an integer
Emit an error when _count_, if specified, does not evaluate to an integer | -| list.sort(_list_[, _ascending_ = TRUE]) * | Given a list, returns a list with similar elements, but sorted (taking into account type ordering) (inversely-sorted if _ascending_ is evaluated to FALSE)
Returns null when _list_ evaluates to null
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _ascending_, if specified, does not evaluate to a Boolean | +| list.dedup(_list_) * | (Since RedisGraph v2.12)
Given a list, returns a similar list after removing duplicate elements
Order is preserved, duplicates are removed from the end of the list
Returns null when _list_ evaluates to null
Emit an error when _list_ does not evaluate to a list or to null | +| list.insert(_list_, _idx_, _val_[, _dups_ = TRUE]) * | (Since RedisGraph v2.12)
Given a list, returns a list after inserting a given value at a given index
_idx_ is 0-based when non-negative, or from the end of the list when negative
Returns null when _list_ evaluates to null
Returns _list_ when _val_ evaluates to null
Returns _list_ when _idx_ evaluates to an integer not in [-NumItems-1 .. NumItems]
When _dups_ evaluats to FALSE: returns _list_ when _val_ evaluates to a value that is already an element of _list_
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _idx_ does not evaluate to an integer
Emit an error when _dups_, if specified, does not evaluate to a Boolean | +| list.insertListElements(_list_, _list2_, _idx_[, _dups_ = TRUE]) * | (Since RedisGraph v2.12)
Given a list, returns a list after inserting the elements of a second list at a given index
_idx_ is 0-based when non-negative, or from the end of the list when negative
Returns null when _list_ evaluates to null
Returns _list_ when _list2_ evaluates to null
Returns _list_ when _idx_ evaluates to an integer not in [-NumItems-1 .. NumItems]
When _dups_ evaluates to FALSE: If an element of _list2_ evaluates to an element of _list_ it would be skipped; If multiple elements of _list2_ evaluate to the same value - this value would be inserted at most once to _list_
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _list2_ does not evaluate to a list or to null
Emit an error when _idx_ does not evaluate to an integer
Emit an error when _dups_, if specified, does not evaluate to a Boolean | +| list.remove(_list_, _idx_[, _count_ = 1]) * | (Since RedisGraph v2.12)
Given a list, returns a list after removing a given number of consecutive elements (or less, if the end of the list has been reached). starting at a given index.
_idx_ is 0-based when non-negative, or from the end of the list when negative
Returns _null_ when _list_ evaluates to null
Returns _list_ when _idx_ evaluates to an integer not in [-NumItems .. NumItems-1]
Returns _list_ when _count_ evaluates to a non-positive integer
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _idx_ does not evaluate to an integer
Emit an error when _count_, if specified, does not evaluate to an integer | +| list.sort(_list_[, _ascending_ = TRUE]) * | (Since RedisGraph v2.12)
Given a list, returns a list with similar elements, but sorted (inversely-sorted if _ascending_ is evaluated to FALSE)
Returns null when _list_ evaluates to null
Emit an error when _list_ does not evaluate to a list or to null
Emit an error when _ascending_, if specified, does not evaluate to a Boolean | | range(_first_, _last_[, _step_ = 1]) | Returns a list of integers in the range of [start, end]. _step_, an optional integer argument, is the increment between consequtive elements | | size(_expr_) | Returns the number of elements in a list
Returns null with _expr_ evaluates to null | | tail(_expr_) | Returns a sublist of a list, which contains all its elements except the first
Returns an empty list when _expr_ containst less than 2 elements.
Returns null when _expr_ evaluates to null | @@ -1027,7 +1173,7 @@ This section contains information on all supported functions from the Cypher que | toInteger(_expr_) * | Returns an integer when _expr_ evaluates to an integer
Converts a floating point to integer
Converts a string to an integer or null
Converts a Boolean to an integer (false to 0, true to 1) (Since RedisGraph v2.10.8)
Returns null when _expr_ evaluates to null
Emit an error on other types | | toIntegerList(_exprList_) * | Converts a list to a list of integer values. Each element in the list is converted using toIntegerOrNull() | | toIntegerOrNull(_expr_) * | Returns an integer when _expr_ evaluates to an integer
Converts a floating point to integer
Converts a string to an integer or null
Converts a Boolean to an integer (false to 0, true to 1) (Since RedisGraph v2.10.8)
Returns null when _expr_ evaluates to null
Returns null for other types | -| toString(_expr_) | Returns a string when _expr_ evaluates to a string
Converts an integer, float, Boolean, string, or point to a string representation
Returns null when _expr_ evaluates to null
Emit an error on other types | +| toString(_expr_) | Returns a string when _expr_ evaluates to a string
Converts an integer, float, Boolean, string, list, map, or point to a string representation
Returns null when _expr_ evaluates to null
Emit an error on other types | | toStringList(_exprList_) | Converts a list to a list of strings. Each element in the list is converted using toStringOrNull() | | toStringOrNull(_expr_) | Returns a string when _expr_ evaluates to a string
Converts an integer, float, Boolean, string, or point to a string representation
Returns null when _expr_ evaluates to null
Returns null for other types | @@ -1224,7 +1370,7 @@ YIELD modifiers are only required if explicitly specified; by default the value ### Algorithms #### BFS -The breadth-first-search algorithm accepts 4 arguments: +The breadth-first-search algorithm accepts 3 arguments: `source-node (node)` - The root of the search. diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index 56ff58bfec..00df1b9e6b 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -64,6 +64,7 @@ The following table summarizes which configuration parameters can be set at modu | [RESULTSET_SIZE](#resultset_size) | :white_check_mark: | :white_check_mark: | | [QUERY_MEM_CAPACITY](#query_mem_capacity) | :white_check_mark: | :white_check_mark: | | [VKEY_MAX_ENTITY_COUNT](#vkey_max_entity_count) | :white_check_mark: | :white_check_mark: | +| [EFFECTS_THRESHOLD](#effects_threshold) | :white_check_mark: | :white_check_mark: | --- @@ -285,6 +286,26 @@ This configuration can be set when the module loads or at runtime. `VKEY_MAX_ENTITY_COUNT` is 100,000. +### CMD_INFO + +An on/off toggle for the `GRAPH.INFO` command. Disabling this command may increase performance and lower the memory usage and these are the main reasons for it to be disabled. + +It's valid values are 'yes' and 'no' (i.e., on and off). + +#### Default + +`CMD_INFO` is `yes`. + +### MAX_INFO_QUERIES + +A limit for the number of previously executed queries stored in the telemetry stream. + +A number within the range [0, 1000] + +#### Default + +`MAX_INFO_QUERIES` is 10000. + --- ## Query Configurations @@ -306,3 +327,22 @@ Retrieve all paths in a graph with a timeout of 500 milliseconds. ``` GRAPH.QUERY wikipedia "MATCH p=()-[*]->() RETURN p" TIMEOUT 500 ``` + +--- + +### EFFECTS_THRESHOLD + +Replicate modification via effect when average modification time > `EFFECTS_THRESHOLD` + +#### Default + +`EFFECTS_THRESHOLD` is 300 μs. + +#### Example + +Assume `MATCH (n) WHERE n.id < 100 SET n.v = n.v + 1` updated 5 nodes +and the query total execution time is 5ms, the average modification time is: +total execution time / number of changes: 5ms / 5 = 1ms. +if the average modification time is greater then `EFFECTS_THRESHOLD` the query +will be replicated to both replicas and AOF as a graph effect otherwise the original +query will be replicated. diff --git a/licenses/AGPLv3.txt b/licenses/AGPLv3.txt new file mode 100644 index 0000000000..c5f57ac3ca --- /dev/null +++ b/licenses/AGPLv3.txt @@ -0,0 +1,661 @@ +GNU AFFERO GENERAL PUBLIC LICENSE, Version 3, 19 Nov 2007 +======================================================== + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/licenses/SSPLv1.txt b/licenses/SSPLv1.txt index 5851192fd8..ea3921393f 100644 --- a/licenses/SSPLv1.txt +++ b/licenses/SSPLv1.txt @@ -555,101 +555,3 @@ return for a fee. END OF TERMS AND CONDITIONS - - - - - -Elastic License 2.0 - -URL: https://www.elastic.co/licensing/elastic-license - -## Acceptance - -By using the software, you agree to all of the terms and conditions below. - -## Copyright License - -The licensor grants you a non-exclusive, royalty-free, worldwide, -non-sublicensable, non-transferable license to use, copy, distribute, make -available, and prepare derivative works of the software, in each case subject to -the limitations and conditions below. - -## Limitations - -You may not provide the software to third parties as a hosted or managed -service, where the service provides users with access to any substantial set of -the features or functionality of the software. - -You may not move, change, disable, or circumvent the license key functionality -in the software, and you may not remove or obscure any functionality in the -software that is protected by the license key. - -You may not alter, remove, or obscure any licensing, copyright, or other notices -of the licensor in the software. Any use of the licensor’s trademarks is subject -to applicable law. - -## Patents - -The licensor grants you a license, under any patent claims the licensor can -license, or becomes able to license, to make, have made, use, sell, offer for -sale, import and have imported the software, in each case subject to the -limitations and conditions in this license. This license does not cover any -patent claims that you cause to be infringed by modifications or additions to -the software. If you or your company make any written claim that the software -infringes or contributes to infringement of any patent, your patent license for -the software granted under these terms ends immediately. If your company makes -such a claim, your patent license ends immediately for work on behalf of your -company. - -## Notices - -You must ensure that anyone who gets a copy of any part of the software from you -also gets a copy of these terms. - -If you modify the software, you must include in any modified copies of the -software prominent notices stating that you have modified the software. - -## No Other Rights - -These terms do not imply any licenses other than those expressly granted in -these terms. - -## Termination - -If you use the software in violation of these terms, such use is not licensed, -and your licenses will automatically terminate. If the licensor provides you -with a notice of your violation, and you cease all violation of this license no -later than 30 days after you receive that notice, your licenses will be -reinstated retroactively. However, if you violate these terms after such -reinstatement, any additional violation of these terms will cause your licenses -to terminate automatically and permanently. - -## No Liability - -*As far as the law allows, the software comes as is, without any warranty or -condition, and the licensor will not be liable to you for any damages arising -out of these terms or the use or nature of the software, under any kind of -legal claim.* - -## Definitions - -The **licensor** is the entity offering these terms, and the **software** is the -software the licensor makes available under these terms, including any portion -of it. - -**you** refers to the individual or entity agreeing to these terms. - -**your company** is any legal entity, sole proprietorship, or other kind of -organization that you work for, plus all organizations that have control over, -are under the control of, or are under common control with that -organization. **control** means ownership of substantially all the assets of an -entity, or the power to direct its management and policies by vote, contract, or -otherwise. Control can be direct or indirect. - -**your licenses** are all the licenses granted to you for the software under -these terms. - -**use** means anything you do with the software requiring one of your licenses. - -**trademark** means trademarks, service marks, and similar rights. diff --git a/ramp.yml b/ramp.yml index 054eebb587..df559be276 100644 --- a/ramp.yml +++ b/ramp.yml @@ -5,7 +5,7 @@ description: A graph database module for Redis homepage: http://redisgraph.io license: Redis Source Available License 2.0 (RSALv2) or the Server Side Public License v1 (SSPLv1) command_line_args: "" -min_redis_version: "6.0" +min_redis_version: "6.2" min_redis_pack_version: "6.2.8" config_command: "GRAPH.CONFIG SET" capabilities: diff --git a/sbin/system-setup.py b/sbin/system-setup.py index 50765934a0..95a21bac95 100755 --- a/sbin/system-setup.py +++ b/sbin/system-setup.py @@ -20,16 +20,16 @@ def __init__(self, args): def common_first(self): self.install_downloaders() - self.run("%s/bin/enable-utf8" % READIES, sudo=self.os != 'macos') + self.run(f"{READIES}/bin/enable-utf8", sudo=self.os != 'macos') self.install("git automake libtool autoconf") def debian_compat(self): self.install("locales") - self.run("%s/bin/getgcc --modern" % READIES) + self.run(f"{READIES}/bin/getgcc --modern") self.install("peg") if self.platform.is_arm(): self.install("python3-dev") - self.run("{READIES}/bin/getjava".format(READIES=READIES)) # for grammarinator/ANTLR + self.run(f"{READIES}/bin/getjava") # for grammarinator/ANTLR self.pip_install("-r tests/fuzz/requirements.txt --use-pep517") def redhat_compat(self): @@ -39,18 +39,18 @@ def redhat_compat(self): self.install_linux_gnu_tar() if self.osnick == 'ol8': self.install("which") # for automake - self.run("%s/bin/getepel" % READIES, sudo=True) - self.run("%s/bin/getgcc --modern" % READIES) + self.run(f"{READIES}/bin/getepel", sudo=True) + self.run(f"{READIES}/bin/getgcc --modern") self.install("m4 libgomp") self.install_peg() def fedora(self): - self.run("%s/bin/getgcc" % READIES) + self.run(f"{READIES}/bin/getgcc") self.install_peg() def macos(self): self.install_gnu_utils() - # self.run("%s/bin/getgcc --modern" % READIES) + # self.run(f"{READIES}/bin/getgcc --modern") self.run("brew install libomp") self.install("redis") self.install_peg() @@ -58,24 +58,23 @@ def macos(self): def alpine(self): self.install("automake make autoconf libtool m4") - self.run("%s/bin/getgcc" % READIES) + self.run(f"{READIES}/bin/getgcc") self.install_peg() def linux_last(self): self.install("valgrind") def common_last(self): - self.run("%s/bin/getaws" % READIES) + self.run(f"{READIES}/bin/getaws") self.install("astyle", _try=True) # fails for centos7 - self.run("{PYTHON} {READIES}/bin/getcmake --usr".format(PYTHON=self.python, READIES=READIES), - sudo=self.os != 'macos') + self.run(f"{self.python} {READIES}/bin/getcmake --usr", sudo=self.os != 'macos') if self.dist != "arch": self.install("lcov") else: self.install("lcov-git", aur=True) if not self.no_rmpytools: - self.run("{PYTHON} {READIES}/bin/getrmpytools --reinstall --modern --redispy-version a246f40".format(PYTHON=self.python, READIES=READIES)) + self.run(f"{self.python} {READIES}/bin/getrmpytools --reinstall") self.pip_install("-r tests/requirements.txt") def install_peg(self): diff --git a/src/RG.h b/src/RG.h index 1338a953a1..9b67df37ef 100644 --- a/src/RG.h +++ b/src/RG.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -12,6 +15,22 @@ #include #include "redismodule.h" +//------------------------------------------------------------------------------ +// common bitwise operations +//------------------------------------------------------------------------------ + +// Mask with most significant bit on 10000... +#define MSB_MASK (1UL << (sizeof(uint64_t) * 8 - 1)) + +// Mask complement 01111... +#define MSB_MASK_CMP ~MSB_MASK + +// Set X's most significant bit on. +#define SET_MSB(x) (x) | MSB_MASK + +// Clear X's most significant bit. +#define CLEAR_MSB(x) (x) & MSB_MASK_CMP + //------------------------------------------------------------------------------ // code development settings //------------------------------------------------------------------------------ @@ -96,3 +115,25 @@ free(str); \ } while(0) + +// write string to stream +#define fwrite_string(str, stream) \ +{ \ + size_t l = strlen(str) + 1; \ + fwrite_assert(&l, sizeof(size_t), stream); \ + fwrite_assert(str, l, stream); \ +} + +#define fwrite_assert(input, size, stream) \ +{ \ + int write = fwrite(input, size, 1, stream); \ + ASSERT(write == 1); \ +} + +#define fread_assert(output, size, stream) \ +{ \ + int read = fread((void*)(output), size, 1, stream); \ + /* short read! */ \ + ASSERT("short read" && read == 1); \ +} + diff --git a/src/algorithms/LAGraph/LAGraph_bfs.h b/src/algorithms/LAGraph/LAGraph_bfs.h index ec23fe0a09..b1925e3806 100644 --- a/src/algorithms/LAGraph/LAGraph_bfs.h +++ b/src/algorithms/LAGraph/LAGraph_bfs.h @@ -1,8 +1,11 @@ -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. -// SPDX-License-Identifier: BSD-2-Clause -// -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/LAGraph/LG_BreadthFirstSearch_SSGrB.c b/src/algorithms/LAGraph/LG_BreadthFirstSearch_SSGrB.c index ab44e8f7fb..93b308ef68 100644 --- a/src/algorithms/LAGraph/LG_BreadthFirstSearch_SSGrB.c +++ b/src/algorithms/LAGraph/LG_BreadthFirstSearch_SSGrB.c @@ -1,12 +1,11 @@ -//------------------------------------------------------------------------------ -// LG_BreadthFirstSearch_SSGrB: BFS using Suitesparse extensions -//------------------------------------------------------------------------------ - -// LAGraph, (c) 2021 by The LAGraph Contributors, All Rights Reserved. -// SPDX-License-Identifier: BSD-2-Clause -// -// See additional acknowledgments in the LICENSE file, -// or contact permission@sei.cmu.edu for the full terms. +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ //------------------------------------------------------------------------------ diff --git a/src/algorithms/algorithms.h b/src/algorithms/algorithms.h index 084bf0c74e..ae2e3466f0 100644 --- a/src/algorithms/algorithms.h +++ b/src/algorithms/algorithms.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/all_neighbors.c b/src/algorithms/all_neighbors.c index f786c801bd..13e26b585e 100644 --- a/src/algorithms/all_neighbors.c +++ b/src/algorithms/all_neighbors.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "all_neighbors.h" @@ -24,20 +27,6 @@ static void _AllNeighborsCtx_CollectNeighbors } } -static bool _AllNeighborsCtx_Visited -( - AllNeighborsCtx *ctx, - EntityID id -) { - uint count = ctx->current_level; - - for(uint i = 0; i < count; i++) { - if(ctx->visited[i] == id) return true; - } - - return false; -} - void AllNeighborsCtx_Reset ( AllNeighborsCtx *ctx, // all neighbors context to reset @@ -46,27 +35,27 @@ void AllNeighborsCtx_Reset uint minLen, // minimum traversal depth uint maxLen // maximum traversal depth ) { - ASSERT(M != NULL); - ASSERT(src != INVALID_ENTITY_ID); - ASSERT(ctx != NULL); - ASSERT(ctx->levels != NULL); - ASSERT(ctx->visited != NULL); - - ctx->M = M; - ctx->src = src; - ctx->minLen = minLen; - ctx->maxLen = maxLen; - ctx->first_pull = true; - ctx->current_level = 0; + ASSERT(M != NULL); + ASSERT(src != INVALID_ENTITY_ID); + ASSERT(ctx != NULL); + ASSERT(ctx->levels != NULL); + ASSERT(ctx->visited != NULL); + + ctx->M = M; + ctx->src = src; + ctx->minLen = minLen; + ctx->maxLen = maxLen; + ctx->first_pull = true; + ctx->current_level = 0; - uint count = array_len(ctx->levels); - for (uint i = 0; i < count; i++) { - RG_MatrixTupleIter_detach(ctx->levels + i); - } array_clear(ctx->levels); array_clear(ctx->visited); - // Dummy iterator at level 0 + // reset visited nodes + HashTableRelease(ctx->visited_nodes); + ctx->visited_nodes = HashTableCreate(&def_dt); + + // dummy iterator at level 0 array_append(ctx->levels, (RG_MatrixTupleIter) {0}); } @@ -82,14 +71,15 @@ AllNeighborsCtx *AllNeighborsCtx_New AllNeighborsCtx *ctx = rm_calloc(1, sizeof(AllNeighborsCtx)); - ctx->M = M; - ctx->src = src; - ctx->minLen = minLen; - ctx->maxLen = maxLen; - ctx->levels = array_new(RG_MatrixTupleIter, 1); - ctx->visited = array_new(EntityID, 1); - ctx->first_pull = true; - ctx->current_level = 0; + ctx->M = M; + ctx->src = src; + ctx->minLen = minLen; + ctx->maxLen = maxLen; + ctx->levels = array_new(RG_MatrixTupleIter, 1); + ctx->visited = array_new(EntityID, 1); + ctx->first_pull = true; + ctx->current_level = 0; + ctx->visited_nodes = HashTableCreate(&def_dt); // Dummy iterator at level 0 array_append(ctx->levels, (RG_MatrixTupleIter) {0}); @@ -101,14 +91,15 @@ EntityID AllNeighborsCtx_NextNeighbor ( AllNeighborsCtx *ctx ) { - if(!ctx) return INVALID_ENTITY_ID; + if(unlikely(ctx == NULL)) return INVALID_ENTITY_ID; - if(ctx->first_pull) { + if(unlikely(ctx->first_pull)) { ASSERT(ctx->current_level == 0); ctx->first_pull = false; // update visited path, replace frontier with current node array_append(ctx->visited, ctx->src); + HashTableAdd(ctx->visited_nodes, (void*)(ctx->src), NULL); // current_level >= ctx->minLen // see if we should expand further? @@ -132,14 +123,18 @@ EntityID AllNeighborsCtx_NextNeighbor if(info == GxB_EXHAUSTED) { // backtrack ctx->current_level--; - array_pop(ctx->visited); + dest_id = array_pop(ctx->visited); + int res = HashTableDelete(ctx->visited_nodes, (void*)(dest_id)); + ASSERT(res == DICT_OK); continue; } // update visited path, replace frontier with current node - array_append(ctx->visited, dest_id); + bool visited = + HashTableAdd(ctx->visited_nodes, (void*)(dest_id), NULL) != DICT_OK; - if(ctx->current_level < ctx->minLen) { + if(ctx->current_level < ctx->minLen && !visited) { + array_append(ctx->visited, dest_id); // continue traversing _AllNeighborsCtx_CollectNeighbors(ctx, dest_id); continue; @@ -147,8 +142,8 @@ EntityID AllNeighborsCtx_NextNeighbor // current_level >= ctx->minLen // see if we should expand further? - if(ctx->current_level < ctx->maxLen && - !_AllNeighborsCtx_Visited(ctx, dest_id)) { + if(ctx->current_level < ctx->maxLen && !visited) { + array_append(ctx->visited, dest_id); // we can expand further _AllNeighborsCtx_CollectNeighbors(ctx, dest_id); } @@ -173,6 +168,8 @@ void AllNeighborsCtx_Free array_free(ctx->levels); array_free(ctx->visited); + HashTableRelease(ctx->visited_nodes); + rm_free(ctx); } diff --git a/src/algorithms/all_neighbors.h b/src/algorithms/all_neighbors.h index 1bd8f5a207..cc94b5353c 100644 --- a/src/algorithms/all_neighbors.h +++ b/src/algorithms/all_neighbors.h @@ -1,12 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "../../deps/GraphBLAS/Include/GraphBLAS.h" +#include "../util/dict.h" #include "../graph/rg_matrix/rg_matrix.h" #include "../graph/rg_matrix/rg_matrix_iter.h" #include "../graph/entities/node.h" @@ -29,6 +33,7 @@ typedef struct { bool first_pull; // first call to Next EntityID *visited; // visited nodes RG_MatrixTupleIter *levels; // array of neighbors iterator + dict *visited_nodes; // visited nodes } AllNeighborsCtx; void AllNeighborsCtx_Reset diff --git a/src/algorithms/all_paths.c b/src/algorithms/all_paths.c index fb15e62507..45c029d5fc 100644 --- a/src/algorithms/all_paths.c +++ b/src/algorithms/all_paths.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "all_paths.h" diff --git a/src/algorithms/all_paths.h b/src/algorithms/all_paths.h index 4f8daad8bc..4cdd1a0a6c 100644 --- a/src/algorithms/all_paths.h +++ b/src/algorithms/all_paths.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ /* * Finds all paths starting at given source node diff --git a/src/algorithms/all_shortest_paths.c b/src/algorithms/all_shortest_paths.c index ad1589b38b..ca08875aa8 100644 --- a/src/algorithms/all_shortest_paths.c +++ b/src/algorithms/all_shortest_paths.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "all_shortest_paths.h" diff --git a/src/algorithms/all_shortest_paths.h b/src/algorithms/all_shortest_paths.h index 474ea91d62..8c89993f78 100644 --- a/src/algorithms/all_shortest_paths.h +++ b/src/algorithms/all_shortest_paths.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/bfs.c b/src/algorithms/bfs.c index 042b9948aa..fd22ff22d8 100644 --- a/src/algorithms/bfs.c +++ b/src/algorithms/bfs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./bfs.h" #include "../util/arr.h" diff --git a/src/algorithms/bfs.h b/src/algorithms/bfs.h index 67b2b4d957..33f71eec5a 100644 --- a/src/algorithms/bfs.h +++ b/src/algorithms/bfs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/detect_cycle.c b/src/algorithms/detect_cycle.c index 76abeddb66..454fa98d9c 100644 --- a/src/algorithms/detect_cycle.c +++ b/src/algorithms/detect_cycle.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./detect_cycle.h" #include "rax.h" diff --git a/src/algorithms/detect_cycle.h b/src/algorithms/detect_cycle.h index 18a70f3a6c..090768df7b 100644 --- a/src/algorithms/detect_cycle.h +++ b/src/algorithms/detect_cycle.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/dfs.c b/src/algorithms/dfs.c index 1a63b87a84..9407857b59 100644 --- a/src/algorithms/dfs.c +++ b/src/algorithms/dfs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./bfs.h" #include "../util/arr.h" diff --git a/src/algorithms/dfs.h b/src/algorithms/dfs.h index cad9e081ef..4f8b1a6594 100644 --- a/src/algorithms/dfs.h +++ b/src/algorithms/dfs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/longest_path.c b/src/algorithms/longest_path.c index de5252a0aa..0c7dfd3aaf 100644 --- a/src/algorithms/longest_path.c +++ b/src/algorithms/longest_path.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./longest_path.h" #include "./bfs.h" diff --git a/src/algorithms/longest_path.h b/src/algorithms/longest_path.h index c6353953ef..f60a98b5df 100644 --- a/src/algorithms/longest_path.h +++ b/src/algorithms/longest_path.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/algorithms/pagerank.c b/src/algorithms/pagerank.c index 64d6d37eea..b28449b687 100644 --- a/src/algorithms/pagerank.c +++ b/src/algorithms/pagerank.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + //------------------------------------------------------------------------------ // LAGraph_pagerank: pagerank using a real semiring //------------------------------------------------------------------------------ diff --git a/src/algorithms/pagerank.h b/src/algorithms/pagerank.h index fd2031a43a..9ff9b6d45d 100644 --- a/src/algorithms/pagerank.h +++ b/src/algorithms/pagerank.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* LAGraph: graph algorithms based on GraphBLAS Copyright 2019 LAGraph Contributors. diff --git a/src/arithmetic/aggregate_funcs/agg_avg.c b/src/arithmetic/aggregate_funcs/agg_avg.c index 9e7e6818cc..0a717093fe 100644 --- a/src/arithmetic/aggregate_funcs/agg_avg.c +++ b/src/arithmetic/aggregate_funcs/agg_avg.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_collect.c b/src/arithmetic/aggregate_funcs/agg_collect.c index 88d3e442c5..1d0110607d 100644 --- a/src/arithmetic/aggregate_funcs/agg_collect.c +++ b/src/arithmetic/aggregate_funcs/agg_collect.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_count.c b/src/arithmetic/aggregate_funcs/agg_count.c index 46c0193be2..b62c17c768 100644 --- a/src/arithmetic/aggregate_funcs/agg_count.c +++ b/src/arithmetic/aggregate_funcs/agg_count.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_funcs.c b/src/arithmetic/aggregate_funcs/agg_funcs.c index 282602e322..e2136b0d50 100644 --- a/src/arithmetic/aggregate_funcs/agg_funcs.c +++ b/src/arithmetic/aggregate_funcs/agg_funcs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_funcs.h b/src/arithmetic/aggregate_funcs/agg_funcs.h index 7424e40b77..753f345ed5 100644 --- a/src/arithmetic/aggregate_funcs/agg_funcs.h +++ b/src/arithmetic/aggregate_funcs/agg_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/aggregate_funcs/agg_max.c b/src/arithmetic/aggregate_funcs/agg_max.c index dfdc1f8027..61ece84abe 100644 --- a/src/arithmetic/aggregate_funcs/agg_max.c +++ b/src/arithmetic/aggregate_funcs/agg_max.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_min.c b/src/arithmetic/aggregate_funcs/agg_min.c index 20dd7f8a40..5dd1e784f4 100644 --- a/src/arithmetic/aggregate_funcs/agg_min.c +++ b/src/arithmetic/aggregate_funcs/agg_min.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_precentile.c b/src/arithmetic/aggregate_funcs/agg_precentile.c index eaab42b8b1..4c0ef7f482 100644 --- a/src/arithmetic/aggregate_funcs/agg_precentile.c +++ b/src/arithmetic/aggregate_funcs/agg_precentile.c @@ -1,14 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" +#include "../../errors/errors.h" #include #include @@ -40,8 +43,7 @@ AggregateResult AGG_PERC(SIValue *argv, int argc, void *private_data) { // need to apply on the first function invocation SIValue_ToDouble(&argv[1], &perc_ctx->percentile); if(perc_ctx->percentile < 0 || perc_ctx->percentile > 1) { - ErrorCtx_SetError("Invalid input - '%f' is not a valid argument, must be a number in the range 0.0 to 1.0", - perc_ctx->percentile); + ErrorCtx_SetError(EMSG_PREC_INPUT_RANGE, perc_ctx->percentile); } perc_ctx->values = array_new(double, 1024); } diff --git a/src/arithmetic/aggregate_funcs/agg_std.c b/src/arithmetic/aggregate_funcs/agg_std.c index 771be59c1e..87f58d2a54 100644 --- a/src/arithmetic/aggregate_funcs/agg_std.c +++ b/src/arithmetic/aggregate_funcs/agg_std.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/aggregate_funcs/agg_sum.c b/src/arithmetic/aggregate_funcs/agg_sum.c index a3e3f615d4..079f05eea1 100644 --- a/src/arithmetic/aggregate_funcs/agg_sum.c +++ b/src/arithmetic/aggregate_funcs/agg_sum.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "agg_funcs.h" diff --git a/src/arithmetic/algebraic_expression.h b/src/arithmetic/algebraic_expression.h index 1fd4deeaa8..a56fea7b75 100644 --- a/src/arithmetic/algebraic_expression.h +++ b/src/arithmetic/algebraic_expression.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/algebraic_expression/algebraic_expression.c b/src/arithmetic/algebraic_expression/algebraic_expression.c index 977dfa11a8..bd21d74ec9 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "utils.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_add.c b/src/arithmetic/algebraic_expression/algebraic_expression_add.c index 1d0068ec48..007b7a3408 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_add.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_add.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "utils.h" #include "../../query_ctx.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_construction.c b/src/arithmetic/algebraic_expression/algebraic_expression_construction.c index 341b97a669..43433e36c4 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_construction.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_construction.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../algebraic_expression.h" @@ -415,20 +418,23 @@ static AlgebraicExpression *_AlgebraicExpression_OperandFromEdge return root; } -/* In case edges `a` and `b` share a node: +/* In case edges `e0` and `e1` share a node: * (a)-[E0]->(b)<-[E1]-(c) * than the shared entity is returned * if edges are disjoint, NULL is returned. */ static QGNode *_SharedNode ( - const QGEdge *a, - const QGEdge *b + const QGEdge *e0, + const QGEdge *e1 ) { - ASSERT(a && b); - if(a->dest == b->src) return a->dest; // (a)-[E0]->(b)-[E1]->(c) - if(a->src == b->dest) return a->src; // (a)<-[E0]-(b)<-[E1]-(c) - if(a->src == b->src) return a->src; // (a)<-[E0]-(b)-[E1]->(c) - if(a->dest == b->dest) return a->dest; // (a)-[E0]->(b)<-[E1]-(c) + ASSERT(e0 != NULL); + ASSERT(e1 != NULL); + + if(e0->dest == e1->src) return e0->dest; // (a)-[E0]->(b)-[E1]->(c) + if(e0->dest == e1->dest) return e0->dest; // (a)-[E0]->(b)<-[E1]-(c) + if(e0->src == e1->dest) return e0->src; // (a)<-[E0]-(b)<-[E1]-(c) + if(e0->src == e1->src) return e0->src; // (a)<-[E0]-(b)-[E1]->(c) + return NULL; } diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_debug.c b/src/arithmetic/algebraic_expression/algebraic_expression_debug.c index 93c308faa1..794a1f9de6 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_debug.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_debug.c @@ -1,8 +1,12 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #include "../algebraic_expression.h" #include "utils.h" #include "../../RG.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_eval.c b/src/arithmetic/algebraic_expression/algebraic_expression_eval.c index 12476bcc8b..e46c98756d 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_eval.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_eval.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "utils.h" #include "../../query_ctx.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_mul.c b/src/arithmetic/algebraic_expression/algebraic_expression_mul.c index 6de8e6fb37..85251cc15a 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_mul.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_mul.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "utils.h" #include "../../query_ctx.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_operand.c b/src/arithmetic/algebraic_expression/algebraic_expression_operand.c index 9dfb2f9e4f..3a3884045d 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_operand.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_operand.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "utils.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_optimization.c b/src/arithmetic/algebraic_expression/algebraic_expression_optimization.c index 1f988a4fd2..f10fee2bab 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_optimization.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_optimization.c @@ -1,8 +1,12 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #include "utils.h" #include "../../util/arr.h" #include "../../query_ctx.h" diff --git a/src/arithmetic/algebraic_expression/algebraic_expression_transpose.c b/src/arithmetic/algebraic_expression/algebraic_expression_transpose.c index 619a8131c3..e61eaf3634 100644 --- a/src/arithmetic/algebraic_expression/algebraic_expression_transpose.c +++ b/src/arithmetic/algebraic_expression/algebraic_expression_transpose.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../algebraic_expression.h" #include "utils.h" diff --git a/src/arithmetic/algebraic_expression/utils.c b/src/arithmetic/algebraic_expression/utils.c index 7e19cc9ec4..b610fea55c 100644 --- a/src/arithmetic/algebraic_expression/utils.c +++ b/src/arithmetic/algebraic_expression/utils.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "utils.h" #include "../../util/arr.h" diff --git a/src/arithmetic/algebraic_expression/utils.h b/src/arithmetic/algebraic_expression/utils.h index c60412a3ab..a8a3dfea33 100644 --- a/src/arithmetic/algebraic_expression/utils.h +++ b/src/arithmetic/algebraic_expression/utils.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/arithmetic_expression.c b/src/arithmetic/arithmetic_expression.c index 7d4de2ccba..28a7dea22f 100644 --- a/src/arithmetic/arithmetic_expression.c +++ b/src/arithmetic/arithmetic_expression.c @@ -1,19 +1,22 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./arithmetic_expression.h" #include "../RG.h" #include "funcs.h" #include "rax.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../graph/graph.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../graph/graphcontext.h" #include "../datatypes/temporal_value.h" #include "../datatypes/array.h" @@ -173,11 +176,11 @@ static void _AR_EXP_ValidateArgsCount // Make sure number of arguments is as expected. if(fdesc->min_argc > argc) { // Set the query-level error. - ErrorCtx_SetError("Received %d arguments to function '%s', expected at least %d", argc, + ErrorCtx_SetError(EMSG_FUNCTION_MIN_ARGS, argc, fdesc->name, fdesc->min_argc); } else if(fdesc->max_argc < argc) { // Set the query-level error. - ErrorCtx_SetError("Received %d arguments to function '%s', expected at most %d", argc, + ErrorCtx_SetError(EMSG_FUNCTION_MAX_ARGS, argc, fdesc->name, fdesc->max_argc); } } @@ -456,7 +459,7 @@ static AR_EXP_Result _AR_EXP_EvaluateFunctionCall ) { AR_EXP_Result res = EVAL_OK; - int child_count = node->op.child_count; + int child_count = NODE_CHILD_COUNT(node); // evaluate each child before evaluating current node SIValue *sub_trees = NULL; @@ -469,7 +472,7 @@ static AR_EXP_Result _AR_EXP_EvaluateFunctionCall sub_trees = sub_trees_on_stack; } bool param_found = false; - for(int child_idx = 0; child_idx < NODE_CHILD_COUNT(node); child_idx++) { + for(int child_idx = 0; child_idx < child_count; child_idx++) { SIValue v; AR_ExpNode *child = NODE_CHILD(node, child_idx); res = _AR_EXP_Evaluate(child, r, &v); @@ -517,15 +520,13 @@ static AR_EXP_Result _AR_EXP_EvaluateFunctionCall static bool _AR_EXP_UpdateEntityIdx(AR_OperandNode *node, const Record r) { if(!r) { // Set the query-level error. - ErrorCtx_SetError("_AR_EXP_UpdateEntityIdx: No record was given to locate a value with alias %s", - node->variadic.entity_alias); + ErrorCtx_SetError(EMSG_MISSING_RECORD, node->variadic.entity_alias); return false; } int entry_alias_idx = Record_GetEntryIdx(r, node->variadic.entity_alias); if(entry_alias_idx == INVALID_INDEX) { // Set the query-level error. - ErrorCtx_SetError("_AR_EXP_UpdateEntityIdx: Unable to locate a value with alias %s within the record", - node->variadic.entity_alias); + ErrorCtx_SetError(EMSG_MISSING_VALUE, node->variadic.entity_alias); return false; } else { node->variadic.entity_alias_idx = entry_alias_idx; @@ -563,7 +564,7 @@ static AR_EXP_Result _AR_EXP_EvaluateParam if(params == NULL || param == raxNotFound) { // set the query-level error - ErrorCtx_SetError("Missing parameters"); + ErrorCtx_SetError(EMSG_MISSING_PARAMETERS); return EVAL_ERR; } diff --git a/src/arithmetic/arithmetic_expression.h b/src/arithmetic/arithmetic_expression.h index 905003607a..7d2f9f70b5 100644 --- a/src/arithmetic/arithmetic_expression.h +++ b/src/arithmetic/arithmetic_expression.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/arithmetic_expression_construct.c b/src/arithmetic/arithmetic_expression_construct.c index 226c795a53..d2bf11a703 100644 --- a/src/arithmetic/arithmetic_expression_construct.c +++ b/src/arithmetic/arithmetic_expression_construct.c @@ -1,15 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "arithmetic_expression_construct.h" #include "RG.h" #include "funcs.h" -#include "../errors.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../datatypes/array.h" #include "../configuration/config.h" #include "../ast/ast_build_filter_tree.h" @@ -81,7 +84,7 @@ static AR_ExpNode *_AR_EXP_FromApplyExpression(const cypher_astnode_t *expr) { } if(op->op.f->internal) { - ErrorCtx_SetError("Attempted to access variable before it has been defined"); + ErrorCtx_SetError(EMSG_ACCESS_VAR); return AR_EXP_NewConstOperandNode(SI_NullVal()); } @@ -131,7 +134,7 @@ static AR_ExpNode *_AR_EXP_FromIdentifier(const cypher_astnode_t *expr) { /* Attempted to access the AST before it has been constructed. * This can occur in scenarios like parameter evaluation: * CYPHER param=[a] MATCH (a) RETURN a */ - ErrorCtx_SetError("Attempted to access variable before it has been defined"); + ErrorCtx_SetError(EMSG_ACCESS_VAR); return AR_EXP_NewConstOperandNode(SI_NullVal()); } @@ -171,14 +174,15 @@ static AR_ExpNode *_AR_EXP_FromPropertyExpression(const cypher_astnode_t *expr) static SIValue _AR_EXP_FromIntegerString(const char *value_str) { char *endptr = NULL; + errno = 0; int64_t l = strtol(value_str, &endptr, 0); if(endptr[0] != 0) { // Failed to convert integer value; set compile-time error to be raised later. - ErrorCtx_SetError("Invalid numeric value '%s'", value_str); + ErrorCtx_SetError(EMSG_INVALID_NUMERIC, value_str); return SI_NullVal(); } if(errno == ERANGE) { - ErrorCtx_SetError("Integer overflow '%s'", value_str); + ErrorCtx_SetError(EMSG_INTEGER_OVERFLOW, value_str); return SI_NullVal(); } SIValue converted = SI_LongVal(l); @@ -197,11 +201,11 @@ static AR_ExpNode *_AR_EXP_FromFloatExpression(const cypher_astnode_t *expr) { double d = strtod(value_str, &endptr); if(endptr[0] != 0) { // Failed to convert integer value; set compile-time error to be raised later. - ErrorCtx_SetError("Invalid numeric value '%s'", value_str); + ErrorCtx_SetError(EMSG_INVALID_NUMERIC, value_str); return AR_EXP_NewConstOperandNode(SI_NullVal()); } if(errno == ERANGE) { - ErrorCtx_SetError("Float overflow '%s'", value_str); + ErrorCtx_SetError(EMSG_FLOAT_OVERFLOW, value_str); return AR_EXP_NewConstOperandNode(SI_NullVal()); } SIValue converted = SI_DoubleVal(d); @@ -390,7 +394,7 @@ static AR_ExpNode *_AR_ExpFromMapProjection(const cypher_astnode_t *expr) { // Return an error if the identifier is not a string literal, like 5 in: // RETURN 5 {v: 'b'} if(cypher_astnode_type(identifier) != CYPHER_AST_IDENTIFIER) { - ErrorCtx_SetError("Encountered unhandled type when trying to read map projection identifier"); + ErrorCtx_SetError(EMSG_UNHANDLED_TYPE_MAP_PROJECTION); return AR_EXP_NewConstOperandNode(SI_NullVal()); } const char *entity_name = cypher_ast_identifier_get_name(identifier); @@ -524,7 +528,7 @@ static AR_ExpNode *_AR_ExpFromShortestPath uint path_len = cypher_ast_pattern_path_nelements(path); if(path_len != 3) { - ErrorCtx_SetError("shortestPath requires a path containing a single relationship"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_SINGLE_RELATIONSHIP); return AR_EXP_NewConstOperandNode(SI_NullVal()); } @@ -541,7 +545,7 @@ static AR_ExpNode *_AR_ExpFromShortestPath // If specified, the edge's minimum hop value must be 0 or 1 start = AST_ParseIntegerNode(range_start); if(start > 1) { - ErrorCtx_SetError("shortestPath does not support a minimal length different from 0 or 1"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_MINIMAL_LENGTH); return AR_EXP_NewConstOperandNode(SI_NullVal()); } } @@ -549,25 +553,25 @@ static AR_ExpNode *_AR_ExpFromShortestPath if(range_end) end = AST_ParseIntegerNode(range_end); if(end != EDGE_LENGTH_INF && end < start) { - ErrorCtx_SetError("Maximum number of hops must be greater than or equal to minimum number of hops"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_MAX_HOPS); return AR_EXP_NewConstOperandNode(SI_NullVal()); } } enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(edge); if(dir == CYPHER_REL_BIDIRECTIONAL) { - ErrorCtx_SetError("RedisGraph does not currently support undirected shortestPath traversals"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_UNDIRECTED); return AR_EXP_NewConstOperandNode(SI_NullVal()); } if(cypher_ast_rel_pattern_get_properties(edge)) { - ErrorCtx_SetError("RedisGraph does not currently support filters on relationships in shortestPath"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_RELATIONSHIP_FILTERS); return AR_EXP_NewConstOperandNode(SI_NullVal()); } if(cypher_ast_node_pattern_get_properties(cypher_ast_pattern_path_get_element(path, 0)) || cypher_ast_node_pattern_get_properties(cypher_ast_pattern_path_get_element(path, 2))) { - ErrorCtx_SetError("Node filters may not be introduced in shortestPath"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_NODE_FILTERS); return AR_EXP_NewConstOperandNode(SI_NullVal()); } @@ -667,7 +671,7 @@ static AR_ExpNode *_AR_ExpNodeFromComprehensionFunction AST_ConvertFilters(&ctx->ft, predicate_node); } else if(type != CYPHER_AST_LIST_COMPREHENSION) { // Functions like any() and all() must have a predicate node. - ErrorCtx_SetError("'%s' function requires a WHERE predicate", func_name); + ErrorCtx_SetError(EMSG_FUNCTION_REQUIER_PREDICATE, func_name); rm_free(ctx); return AR_EXP_NewConstOperandNode(SI_NullVal()); } @@ -881,7 +885,7 @@ AR_ExpNode *AR_EXP_FromASTNode(const cypher_astnode_t *expr) { * count(max(n.v)) */ if(_AR_EXP_ContainsNestedAgg(root)) { // Set error (compile-time), this error will be raised later on. - ErrorCtx_SetError("Can't use aggregate functions inside of aggregate functions."); + ErrorCtx_SetError(EMSG_NESTED_AGGREGATION); } return root; diff --git a/src/arithmetic/arithmetic_expression_construct.h b/src/arithmetic/arithmetic_expression_construct.h index 3b68704e09..ba34fea3c4 100644 --- a/src/arithmetic/arithmetic_expression_construct.h +++ b/src/arithmetic/arithmetic_expression_construct.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/arithmetic_op.c b/src/arithmetic/arithmetic_op.c index 28764c47e1..d4c39aec2f 100644 --- a/src/arithmetic/arithmetic_op.c +++ b/src/arithmetic/arithmetic_op.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "arithmetic_op.h" diff --git a/src/arithmetic/arithmetic_op.h b/src/arithmetic/arithmetic_op.h index edef04df61..15c10d8e85 100644 --- a/src/arithmetic/arithmetic_op.h +++ b/src/arithmetic/arithmetic_op.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "../ast/ast_shared.h" diff --git a/src/arithmetic/boolean_funcs/boolean_funcs.c b/src/arithmetic/boolean_funcs/boolean_funcs.c index 0fc6556ea9..bd2433e729 100644 --- a/src/arithmetic/boolean_funcs/boolean_funcs.c +++ b/src/arithmetic/boolean_funcs/boolean_funcs.c @@ -1,14 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "boolean_funcs.h" -#include "../../errors.h" #include "../func_desc.h" #include "../../util/arr.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" #include "../../datatypes/map.h" #include "../../datatypes/array.h" diff --git a/src/arithmetic/boolean_funcs/boolean_funcs.h b/src/arithmetic/boolean_funcs/boolean_funcs.h index 39133f5f6c..6da9940c21 100644 --- a/src/arithmetic/boolean_funcs/boolean_funcs.h +++ b/src/arithmetic/boolean_funcs/boolean_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/comprehension_funcs/comprehension_funcs.c b/src/arithmetic/comprehension_funcs/comprehension_funcs.c index 9832ee2266..f3f7a8a72e 100644 --- a/src/arithmetic/comprehension_funcs/comprehension_funcs.c +++ b/src/arithmetic/comprehension_funcs/comprehension_funcs.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "comprehension_funcs.h" #include "RG.h" #include "../../value.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" #include "../../datatypes/array.h" #include "../../util/rax_extensions.h" #include "../../execution_plan/record.h" diff --git a/src/arithmetic/comprehension_funcs/comprehension_funcs.h b/src/arithmetic/comprehension_funcs/comprehension_funcs.h index f701409f9a..089f51f0e2 100644 --- a/src/arithmetic/comprehension_funcs/comprehension_funcs.h +++ b/src/arithmetic/comprehension_funcs/comprehension_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/conditional_funcs/conditional_funcs.c b/src/arithmetic/conditional_funcs/conditional_funcs.c index b753721463..df937e5205 100644 --- a/src/arithmetic/conditional_funcs/conditional_funcs.c +++ b/src/arithmetic/conditional_funcs/conditional_funcs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "conditional_funcs.h" #include "../func_desc.h" diff --git a/src/arithmetic/conditional_funcs/conditional_funcs.h b/src/arithmetic/conditional_funcs/conditional_funcs.h index a8427fce78..b8155052d4 100644 --- a/src/arithmetic/conditional_funcs/conditional_funcs.h +++ b/src/arithmetic/conditional_funcs/conditional_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/entity_funcs/entity_funcs.c b/src/arithmetic/entity_funcs/entity_funcs.c index 9e1ff09502..ad59bae8e4 100644 --- a/src/arithmetic/entity_funcs/entity_funcs.c +++ b/src/arithmetic/entity_funcs/entity_funcs.c @@ -1,15 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "entity_funcs.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../query_ctx.h" #include "../../datatypes/map.h" +#include "../../errors/errors.h" #include "../../datatypes/array.h" #include "../../graph/graphcontext.h" #include "../../datatypes/datatypes.h" @@ -93,7 +96,7 @@ SIValue AR_TYPE(SIValue *argv, int argc, void *private_data) { char *type = ""; Edge *e = argv[0].ptrval; GraphContext *gc = QueryCtx_GetGraphCtx(); - int id = Graph_GetEdgeRelation(gc->g, e); + int id = Edge_GetRelationID(e); if(id != GRAPH_NO_RELATION) type = gc->relation_schemas[id]->name; return SI_ConstStringVal(type); } @@ -171,7 +174,7 @@ static SIValue _AR_NodeDegree } } else if (SI_TYPE(argv[1]) == T_ARRAY) { if(argc > 2) { - ErrorCtx_SetError("Received %d arguments, expected at most 2 because second argument is List", argc); + ErrorCtx_SetError(EMSG_NODE_DEGREE_ARGUMENTS, argc); } // validate signature function(NODE, ARRAY_OF_STRINGS) uint len = SIArray_Length(argv[1]); diff --git a/src/arithmetic/entity_funcs/entity_funcs.h b/src/arithmetic/entity_funcs/entity_funcs.h index 52ee3e3c9b..cd16892a65 100644 --- a/src/arithmetic/entity_funcs/entity_funcs.h +++ b/src/arithmetic/entity_funcs/entity_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/func_desc.c b/src/arithmetic/func_desc.c index 99412565e1..f6a2575105 100644 --- a/src/arithmetic/func_desc.c +++ b/src/arithmetic/func_desc.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "func_desc.h" #include "../RG.h" diff --git a/src/arithmetic/func_desc.h b/src/arithmetic/func_desc.h index 83fc05e023..e686acb1df 100644 --- a/src/arithmetic/func_desc.h +++ b/src/arithmetic/func_desc.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/funcs.c b/src/arithmetic/funcs.c index a90d66ed5c..69bc82ec66 100644 --- a/src/arithmetic/funcs.c +++ b/src/arithmetic/funcs.c @@ -1,9 +1,11 @@ - /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "funcs.h" #include "../RG.h" diff --git a/src/arithmetic/funcs.h b/src/arithmetic/funcs.h index a7114699af..bae21c8979 100644 --- a/src/arithmetic/funcs.h +++ b/src/arithmetic/funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/list_funcs/list_funcs.c b/src/arithmetic/list_funcs/list_funcs.c index 48c8b440a2..ae1a391429 100644 --- a/src/arithmetic/list_funcs/list_funcs.c +++ b/src/arithmetic/list_funcs/list_funcs.c @@ -1,17 +1,20 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "list_funcs.h" #include "RG.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../query_ctx.h" #include "../../util/dict.h" #include "../../util/strutil.h" +#include "../../errors/errors.h" #include "../../datatypes/array.h" #include "../../util/rax_extensions.h" #include "../string_funcs/string_funcs.h" @@ -557,25 +560,12 @@ SIValue AR_INSERT(SIValue *argv, int argc, void *private_data) { return array; } -// fake hash function -// hash of key is simply key -static uint64_t nop_hash -( - const void *key -) { - return ((uint64_t)key); -} - -// hashtable callbacks -static dictType dt = { nop_hash, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL}; - static dict *_list2dict ( SIValue list ) { uint32_t n = SIArray_Length(list); - dict *values = HashTableCreate(&dt); + dict *values = HashTableCreate(&def_dt); for(uint i = 0; i < n; i++) { SIValue val = SIArray_Get(list, i); XXH64_state_t state; @@ -681,7 +671,7 @@ SIValue AR_DEDUP(SIValue *argv, int argc, void *private_data) { uint32_t n = SIArray_Length(list); SIValue dedup_list = SI_Array(n); - dict *values = HashTableCreate(&dt); + dict *values = HashTableCreate(&def_dt); // check if value already exists in list for(uint i = 0; i < n; i++) { SIValue val = SIArray_Get(list, i); diff --git a/src/arithmetic/list_funcs/list_funcs.h b/src/arithmetic/list_funcs/list_funcs.h index cdd9d3df02..bf16b72e75 100644 --- a/src/arithmetic/list_funcs/list_funcs.h +++ b/src/arithmetic/list_funcs/list_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/map_funcs/map_funcs.c b/src/arithmetic/map_funcs/map_funcs.c index 8b158b2db4..d7ca30124d 100644 --- a/src/arithmetic/map_funcs/map_funcs.c +++ b/src/arithmetic/map_funcs/map_funcs.c @@ -1,15 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "map_funcs.h" #include "RG.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../datatypes/map.h" +#include "../../errors/errors.h" #include "../../datatypes/array.h" #include "../../graph/entities/graph_entity.h" @@ -67,7 +70,7 @@ SIValue AR_PROPERTIES(SIValue *argv, int argc, void *private_data) { case T_EDGE: return GraphEntity_Properties(argv[0].ptrval); case T_MAP: - return argv[0]; + return SI_CloneValue(argv[0]); // clone the map default: ASSERT(false); } diff --git a/src/arithmetic/map_funcs/map_funcs.h b/src/arithmetic/map_funcs/map_funcs.h index 56f531c7e8..10c3f6e3f4 100644 --- a/src/arithmetic/map_funcs/map_funcs.h +++ b/src/arithmetic/map_funcs/map_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/numeric_funcs/numeric_funcs.c b/src/arithmetic/numeric_funcs/numeric_funcs.c index 4c83a074b2..da19b83b72 100644 --- a/src/arithmetic/numeric_funcs/numeric_funcs.c +++ b/src/arithmetic/numeric_funcs/numeric_funcs.c @@ -1,12 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "numeric_funcs.h" #include "RG.h" -#include "../../errors.h" +#include "../../errors/errors.h" #include "../func_desc.h" #include "../../util/arr.h" #include "../../util/rmalloc.h" diff --git a/src/arithmetic/numeric_funcs/numeric_funcs.h b/src/arithmetic/numeric_funcs/numeric_funcs.h index c85a888277..35b45a10a3 100644 --- a/src/arithmetic/numeric_funcs/numeric_funcs.h +++ b/src/arithmetic/numeric_funcs/numeric_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/path_funcs/path_funcs.c b/src/arithmetic/path_funcs/path_funcs.c index 5bff06c8c8..2d0a8c68d0 100644 --- a/src/arithmetic/path_funcs/path_funcs.c +++ b/src/arithmetic/path_funcs/path_funcs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "path_funcs.h" #include "../func_desc.h" @@ -248,7 +251,7 @@ SIValue AR_SHORTEST_PATH(SIValue *argv, int argc, void *private_data) { SIPathBuilder_AppendEdge(p, SI_Edge(&edges[0]), false); // Append the reached node to the path. - id = edges[0].srcNodeID; + id = Edge_GetSrcNodeID(&edges[0]); Node n = GE_NEW_NODE(); Graph_GetNode(gc->g, id, &n); SIPathBuilder_AppendNode(p, SI_Node(&n)); diff --git a/src/arithmetic/path_funcs/path_funcs.h b/src/arithmetic/path_funcs/path_funcs.h index 83243c4941..e916e41ada 100644 --- a/src/arithmetic/path_funcs/path_funcs.h +++ b/src/arithmetic/path_funcs/path_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "../../value.h" diff --git a/src/arithmetic/placeholder_funcs/placeholder_funcs.c b/src/arithmetic/placeholder_funcs/placeholder_funcs.c index f7e781e6c4..7b7f7b1420 100644 --- a/src/arithmetic/placeholder_funcs/placeholder_funcs.c +++ b/src/arithmetic/placeholder_funcs/placeholder_funcs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "placeholder_funcs.h" #include "../func_desc.h" diff --git a/src/arithmetic/placeholder_funcs/placeholder_funcs.h b/src/arithmetic/placeholder_funcs/placeholder_funcs.h index 53b5593a11..da1a8d3a57 100644 --- a/src/arithmetic/placeholder_funcs/placeholder_funcs.h +++ b/src/arithmetic/placeholder_funcs/placeholder_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/point_funcs/point_funcs.c b/src/arithmetic/point_funcs/point_funcs.c index 8e8803ae75..87ac345a74 100644 --- a/src/arithmetic/point_funcs/point_funcs.c +++ b/src/arithmetic/point_funcs/point_funcs.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" +#include "../../errors/errors.h" #include "../../datatypes/map.h" #include diff --git a/src/arithmetic/point_funcs/point_funcs.h b/src/arithmetic/point_funcs/point_funcs.h index d94a3801b4..da81080e41 100644 --- a/src/arithmetic/point_funcs/point_funcs.h +++ b/src/arithmetic/point_funcs/point_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/string_funcs/string_funcs.c b/src/arithmetic/string_funcs/string_funcs.c index 32cc2629fe..b4986df1a1 100644 --- a/src/arithmetic/string_funcs/string_funcs.c +++ b/src/arithmetic/string_funcs/string_funcs.c @@ -1,24 +1,29 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "string_funcs.h" #include "../func_desc.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../util/uuid.h" #include "utf8proc/utf8proc.h" #include "../../util/rmalloc.h" #include "../../util/strutil.h" +#include "../../errors/errors.h" +#include "../../util/math_util.h" #include "../../datatypes/array.h" #include "../../util/json_encoder.h" #include "../deps/oniguruma/src/oniguruma.h" // toString supports only integer, float, string, boolean, point, duration, // date, time, localtime, localdatetime or datetime values -#define STRINGABLE (SI_NUMERIC | T_POINT | T_DURATION | T_DATETIME | T_STRING | T_BOOL) +// array for backward compatibility +#define STRINGABLE (SI_NUMERIC | T_ARRAY | T_POINT | T_DURATION | T_DATETIME | T_STRING | T_BOOL) // returns a string containing the specified number of leftmost characters of the original string. SIValue AR_LEFT(SIValue *argv, int argc, void *private_data) { @@ -29,7 +34,7 @@ SIValue AR_LEFT(SIValue *argv, int argc, void *private_data) { newlen = argv[1].longval; } if(newlen < 0) { - ErrorCtx_SetError("length must be a non-negative integer"); + ErrorCtx_SetError(EMSG_MUST_BE_NON_NEGATIVE, "length"); return SI_NullVal(); } @@ -75,7 +80,7 @@ SIValue AR_RIGHT(SIValue *argv, int argc, void *private_data) { newlen = argv[1].longval; } if(newlen < 0) { - ErrorCtx_SetError("length must be a non-negative integer"); + ErrorCtx_SetError(EMSG_MUST_BE_NON_NEGATIVE, "length"); return SI_NullVal(); } @@ -165,7 +170,7 @@ SIValue AR_SUBSTRING(SIValue *argv, int argc, void *private_data) { /* Make sure start doesn't overreach. */ if(start < 0) { - ErrorCtx_SetError("start must be a non-negative integer"); + ErrorCtx_SetError(EMSG_MUST_BE_NON_NEGATIVE, "start"); return SI_NullVal(); } @@ -179,7 +184,7 @@ SIValue AR_SUBSTRING(SIValue *argv, int argc, void *private_data) { } else { length = argv[2].longval; if(length < 0) { - ErrorCtx_SetError("length must be a non-negative integer"); + ErrorCtx_SetError(EMSG_MUST_BE_NON_NEGATIVE, "length"); return SI_ConstStringVal(""); } @@ -222,11 +227,24 @@ SIValue AR_JOIN(SIValue *argv, int argc, void *private_data) { delimiter = argv[1].stringval; } - uint32_t count = SIArray_Length(list); + int str_len = 0; // output string length + uint32_t n = SIArray_Length(list); // number of strings to join + size_t delimeter_len = strlen(delimiter); // length of the delimiter - size_t delimeter_len = strlen(delimiter); - uint str_len = delimeter_len * (count - 1); - for(uint i = 0; i < count; i++) { + //-------------------------------------------------------------------------- + // compute required string length + //-------------------------------------------------------------------------- + + // delimeter length is added between each string + if(n >= 2) { + if(safe_mul(delimeter_len, n - 1, &str_len)) { + ErrorCtx_SetError("String overflow"); + return SI_NullVal(); + } + } + + // acount for each string length + for(uint i = 0; i < n; i++) { SIValue str = SIArray_Get(list, i); if(SI_TYPE(str) != T_STRING) { // all elements in the list should be string. @@ -234,21 +252,43 @@ SIValue AR_JOIN(SIValue *argv, int argc, void *private_data) { return SI_NullVal(); } - str_len += strlen(str.stringval); + if(safe_add(str_len, strlen(str.stringval), &str_len)) { + ErrorCtx_SetError("String overflow"); + return SI_NullVal(); + } + } + + // acoun for null terminator + if(safe_add(str_len, 1, &str_len)) { + ErrorCtx_SetError("String overflow"); + return SI_NullVal(); } - int cur_len = 0; - char *res = rm_malloc(str_len + 1); - for(uint i = 0; i < count - 1; i++) { + //-------------------------------------------------------------------------- + // join strings + //-------------------------------------------------------------------------- + + int l = 0; // current string length + int cur_len = 0; // offset into output string + char *res = rm_malloc(str_len); // output string + + for(uint i = 0; i < n - 1; i++) { SIValue str = SIArray_Get(list, i); - memcpy(res + cur_len, str.stringval, strlen(str.stringval)); - cur_len += strlen(str.stringval); + l = strlen(str.stringval); + memcpy(res + cur_len, str.stringval, l); + cur_len += l; memcpy(res + cur_len, delimiter, delimeter_len); cur_len += delimeter_len; } - SIValue str = SIArray_Get(list, count - 1); - memcpy(res + cur_len, str.stringval, strlen(str.stringval)); - res[str_len] = '\0'; + + // write the last string + SIValue str = SIArray_Get(list, n - 1); + l = strlen(str.stringval); + memcpy(res + cur_len, str.stringval, l); + cur_len += l; + + // place null terminator + res[cur_len] = '\0'; return SI_TransferStringVal(res); } @@ -298,7 +338,7 @@ SIValue AR_MATCHREGEX(SIValue *argv, int argc, void *private_data) { if(rv != ONIG_NORMAL) { char s[ONIG_MAX_ERROR_MESSAGE_LEN]; onig_error_code_to_str((UChar* )s, rv, &einfo); - ErrorCtx_SetError("Invalid regex, err=%s", s); + ErrorCtx_SetError(EMSG_INVALID_REGEX, s); onig_free(regex); onig_region_free(region, 1); SIValue_Free(list); @@ -316,7 +356,7 @@ SIValue AR_MATCHREGEX(SIValue *argv, int argc, void *private_data) { if(rv < 0) { char s[ONIG_MAX_ERROR_MESSAGE_LEN]; onig_error_code_to_str((OnigUChar* )s, rv); - ErrorCtx_SetError("Invalid regex, err=%s", s); + ErrorCtx_SetError(EMSG_INVALID_REGEX, s); onig_free(regex); onig_region_free(region, 1); SIValue_Free(list); @@ -392,7 +432,7 @@ SIValue AR_REPLACEREGEX(SIValue *argv, int argc, void *private_data) { if(rv != ONIG_NORMAL) { char s[ONIG_MAX_ERROR_MESSAGE_LEN]; onig_error_code_to_str((UChar* )s, rv, &einfo); - ErrorCtx_SetError("Invalid regex, err=%s", s); + ErrorCtx_SetError(EMSG_INVALID_REGEX, s); onig_free(regex); onig_region_free(region, 1); return SI_NullVal(); @@ -413,7 +453,7 @@ SIValue AR_REPLACEREGEX(SIValue *argv, int argc, void *private_data) { if(rv < 0) { char s[ONIG_MAX_ERROR_MESSAGE_LEN]; onig_error_code_to_str((OnigUChar* )s, rv); - ErrorCtx_SetError("Invalid regex, err=%s", s); + ErrorCtx_SetError(EMSG_INVALID_REGEX, s); onig_free(regex); onig_region_free(region, 1); return SI_NullVal(); @@ -455,8 +495,7 @@ SIValue AR_TOSTRING(SIValue *argv, int argc, void *private_data) { size_t bytesWritten = 0; SIValue_ToString(argv[0], &str, &len, &bytesWritten); return SI_TransferStringVal(str); - } - else { + } else { return SI_NullVal(); } } diff --git a/src/arithmetic/string_funcs/string_funcs.h b/src/arithmetic/string_funcs/string_funcs.h index f44aac43ba..9a525d4484 100644 --- a/src/arithmetic/string_funcs/string_funcs.h +++ b/src/arithmetic/string_funcs/string_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/arithmetic/time_funcs/time_funcs.c b/src/arithmetic/time_funcs/time_funcs.c index 3cb27988cf..68684e2750 100644 --- a/src/arithmetic/time_funcs/time_funcs.c +++ b/src/arithmetic/time_funcs/time_funcs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "time_funcs.h" #include "../func_desc.h" diff --git a/src/arithmetic/time_funcs/time_funcs.h b/src/arithmetic/time_funcs/time_funcs.h index ecacd63c5d..1e4c3eecdc 100644 --- a/src/arithmetic/time_funcs/time_funcs.h +++ b/src/arithmetic/time_funcs/time_funcs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast.c b/src/ast/ast.c index 2b343c6fd7..c253f58d1b 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast.h" #include @@ -14,6 +17,7 @@ #include "query_ctx.h" #include "procedures/procedure.h" #include "ast_rewrite_same_clauses.h" +#include "ast_rewrite_call_subquery.h" #include "ast_rewrite_star_projections.h" #include "arithmetic/arithmetic_expression.h" #include "arithmetic/arithmetic_expression_construct.h" @@ -185,6 +189,55 @@ bool AST_ReadOnly return true; } +// returns true if the given ast-node will result in an eager operation +static bool _clause_is_eager +( + const cypher_astnode_t *clause +) { + // ------------------------------------------------------------------------- + // check if clause type is one of: CREATE, DELETE, MERGE, SET or REMOVE + // ------------------------------------------------------------------------- + cypher_astnode_type_t type = cypher_astnode_type(clause); + if(type == CYPHER_AST_CREATE || + type == CYPHER_AST_DELETE || + type == CYPHER_AST_MERGE || + type == CYPHER_AST_SET || + type == CYPHER_AST_REMOVE || + type == CYPHER_AST_FOREACH) { + return true; + } + + if(type == CYPHER_AST_CALL_SUBQUERY) { + return AST_IsEager(cypher_ast_call_subquery_get_query(clause)); + } + + // ------------------------------------------------------------------------- + // check if clause is a WITH or RETURN clause with an aggregation + // ------------------------------------------------------------------------- + if(type == CYPHER_AST_RETURN || type == CYPHER_AST_WITH) { + return AST_ClauseContainsAggregation(clause); + } + + return false; +} + +// checks if a query contains an ast-node corresponding to an eager operation +bool AST_IsEager +( + const cypher_astnode_t *root +) { + ASSERT(cypher_astnode_type(root) == CYPHER_AST_QUERY); + uint n_clauses = cypher_ast_query_nclauses(root); + + for(uint i = 0; i < n_clauses; i++) { + if(_clause_is_eager(cypher_ast_query_get_clause(root, i))) { + return true; + } + } + + return false; +} + inline bool AST_ContainsClause ( const AST *ast, @@ -672,7 +725,7 @@ cypher_parse_result_t *parse_query // check that the parser parsed the entire query if(!cypher_parse_result_eof(result)) { - ErrorCtx_SetError("Error: query with more than one statement is not supported."); + ErrorCtx_SetError(EMSG_QUERY_WITH_MULTIPLE_STATEMENTS); parse_result_free(result); return NULL; } @@ -699,17 +752,25 @@ cypher_parse_result_t *parse_query return NULL; } - // rewrite '*' projections - // e.g. MATCH (a), (b) RETURN * - // will be rewritten as: - // MATCH (a), (b) RETURN a, b - bool rerun_validation = AST_RewriteStarProjections(root); - // compress clauses // e.g. MATCH (a:N) MATCH (b:N) RETURN a,b // will be rewritten as: // MATCH (a:N), (b:N) RETURN a,b - rerun_validation |= AST_RewriteSameClauses(root); + bool rerun_validation = AST_RewriteSameClauses(root); + + // rewrite eager & resulting Call {} clauses + // e.g. MATCH (m) CALL { CREATE (n:N) RETURN n } RETURN n, m + // will be rewritten as: + // MATCH (m) CALL { WITH m AS @m CREATE (n:N) RETURN n, @m AS m } RETURN n, m + // note: we rewrite the ast for sure here, so we need to re-validate it + rerun_validation |= AST_RewriteCallSubquery(root); + + // rewrite '*' projections + // e.g. MATCH (a), (b) RETURN * + // will be rewritten as: + // MATCH (a), (b) RETURN a, b + rerun_validation |= AST_RewriteStarProjections( + cypher_ast_statement_get_body(root)); // only perform validations again if there's been a rewrite if(rerun_validation && AST_Validate_Query(root) != AST_VALID) { diff --git a/src/ast/ast.h b/src/ast/ast.h index ea4774b0e3..7185d19316 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -67,6 +70,12 @@ bool AST_ReadOnly const cypher_astnode_t *root ); +// checks if a query contains an ast-node corresponding to an eager operation +bool AST_IsEager +( + const cypher_astnode_t *root +); + // checks to see if AST contains specified clause bool AST_ContainsClause ( diff --git a/src/ast/ast_annotations_ctx_collection.c b/src/ast/ast_annotations_ctx_collection.c index 1f0c511041..d9f763f317 100644 --- a/src/ast/ast_annotations_ctx_collection.c +++ b/src/ast/ast_annotations_ctx_collection.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast_annotations_ctx_collection.h" #include "../util/rmalloc.h" diff --git a/src/ast/ast_annotations_ctx_collection.h b/src/ast/ast_annotations_ctx_collection.h index 6ccca69bb8..6c0d49bfc4 100644 --- a/src/ast/ast_annotations_ctx_collection.h +++ b/src/ast/ast_annotations_ctx_collection.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "cypher-parser.h" diff --git a/src/ast/ast_build_filter_tree.c b/src/ast/ast_build_filter_tree.c index 2b5b3774db..f75240a901 100644 --- a/src/ast/ast_build_filter_tree.c +++ b/src/ast/ast_build_filter_tree.c @@ -1,14 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" #include "ast_build_filter_tree.h" #include "ast_shared.h" -#include "../RG.h" -#include "../errors.h" #include "../util/arr.h" +#include "../errors/errors.h" #include "../arithmetic/arithmetic_expression_construct.h" // Forward declaration @@ -105,7 +108,7 @@ static FT_FilterNode *_convertBinaryOperator(const cypher_astnode_t *op_node) { rhs = cypher_ast_binary_operator_get_argument2(op_node); return _CreateFilterSubtree(op, lhs, rhs); case OP_NOT: - ErrorCtx_SetError("Invalid usage of 'NOT' filter with expressions on left and right sides."); + ErrorCtx_SetError(EMSG_INVALIDE_NOT_USAGE); return NULL; default: return FilterTree_CreateExpressionFilter(AR_EXP_FromASTNode(op_node)); diff --git a/src/ast/ast_build_filter_tree.h b/src/ast/ast_build_filter_tree.h index 78f60ab32d..f675216bbe 100644 --- a/src/ast/ast_build_filter_tree.h +++ b/src/ast/ast_build_filter_tree.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast_build_op_contexts.c b/src/ast/ast_build_op_contexts.c index 8f691118fd..d73cb439c5 100644 --- a/src/ast/ast_build_op_contexts.c +++ b/src/ast/ast_build_op_contexts.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast_build_op_contexts.h" -#include "../errors.h" #include "ast_shared.h" #include "../util/arr.h" +#include "../errors/errors.h" #include "../util/rax_extensions.h" #include "../arithmetic/arithmetic_expression_construct.h" #include "../query_ctx.h" diff --git a/src/ast/ast_build_op_contexts.h b/src/ast/ast_build_op_contexts.h index 6ad2bc3090..ca3fa02e31 100644 --- a/src/ast/ast_build_op_contexts.h +++ b/src/ast/ast_build_op_contexts.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast_build_reference_map.c b/src/ast/ast_build_reference_map.c index 3327204c62..ac3b9f15ed 100644 --- a/src/ast/ast_build_reference_map.c +++ b/src/ast/ast_build_reference_map.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast.h" #include "RG.h" @@ -347,6 +350,22 @@ static void _AST_MapForeachClauseReferences } } +// maps entities in a CALL {} clause +static void _AST_MapCallSubqueryReferences +( + AST *ast, // AST + const cypher_astnode_t *callsubquery_clause // clause +) { + const cypher_astnode_t *query = cypher_ast_call_subquery_get_query( + callsubquery_clause); + uint n_clauses = cypher_ast_query_nclauses(query); + for(uint i = 0; i < n_clauses; i++) { + const cypher_astnode_t *clause = + cypher_ast_query_get_clause(query, i); + _ASTClause_BuildReferenceMap(ast, clause); + } +} + // maps entities in DELETE clause static void _AST_MapDeleteClauseReferences ( @@ -472,6 +491,9 @@ static void _ASTClause_BuildReferenceMap(AST *ast, const cypher_astnode_t *claus } else if(type == CYPHER_AST_FOREACH) { // add referenced aliases for a FOREACH clause _AST_MapForeachClauseReferences(ast, clause); + } else if(type == CYPHER_AST_CALL_SUBQUERY) { + // add referenced aliases for a CALL {} clause + _AST_MapCallSubqueryReferences(ast, clause); } } diff --git a/src/ast/ast_enrich.c b/src/ast/ast_enrich.c index aee60ffa5a..b603e8202b 100644 --- a/src/ast/ast_enrich.c +++ b/src/ast/ast_enrich.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "enrichment/annotate_projected_named_paths.h" diff --git a/src/ast/ast_mock.c b/src/ast/ast_mock.c index 6a89b9435e..568631b59b 100644 --- a/src/ast/ast_mock.c +++ b/src/ast/ast_mock.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast_mock.h" #include "../query_ctx.h" diff --git a/src/ast/ast_mock.h b/src/ast/ast_mock.h index 68c6814df2..c69733230a 100644 --- a/src/ast/ast_mock.h +++ b/src/ast/ast_mock.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast_rewrite_call_subquery.c b/src/ast/ast_rewrite_call_subquery.c new file mode 100644 index 0000000000..caa178e944 --- /dev/null +++ b/src/ast/ast_rewrite_call_subquery.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "ast_shared.h" +#include "../util/arr.h" +#include "../util/rmalloc.h" +#include "ast_rewrite_call_subquery.h" + +// fill `names` and `inner_names` with the bound vars and their internal +// representation, respectively +static void _get_vars_inner_rep +( + rax *outer_mapping, // rax containing bound vars + char ***names, // [OUTPUT] bound vars + char ***inter_names // [OUTPUT] internal representation of vars +) { + ASSERT(outer_mapping != NULL); + + raxIterator it; + raxStart(&it, outer_mapping); + raxSeek(&it, "^", NULL, 0); + while(raxNext(&it)) { + // avoid multiple internal representations of the same alias + if(it.key[0] == '@') { + continue; + } + + char *curr = rm_strndup((const char *)it.key, it.key_len); + char *internal_rep = rm_malloc(it.key_len + 2); + sprintf(internal_rep, "@%.*s", (int)it.key_len, it.key); + + // append original name + array_append(*names, curr); + // append internal (temporary) name + array_append(*inter_names, internal_rep); + } +} + +// adds projections from `names` to `inter_names` into `projections` array +static uint _add_names_projections +( + cypher_astnode_t *projections[], // array of projections + uint proj_idx, // index to start adding projections + char **names, // bound vars + char **inter_names, // internal representation of bound vars + bool hide // hide or reveal vars +) { + uint n_names = hide ? array_len(names) : array_len(inter_names); + + for(uint i = 0; i < n_names; i++) { + // create a projection for the bound var + struct cypher_input_range range = {0}; + cypher_astnode_t *exp = cypher_ast_identifier(names[i], + strlen(names[i]), range); + cypher_astnode_t *alias = cypher_ast_identifier(inter_names[i], + strlen(inter_names[i]), range); + cypher_astnode_t *children[2]; + children[0] = exp; + children[1] = alias; + + projections[proj_idx++] = cypher_ast_projection(exp, alias, children, + 2, range); + } + + return proj_idx; +} + +// add projections to projections array, corresponding to the bound vars (names) +// and their internal representation (inter_names) +// if `direction` is 0 (false), projections from `names` to `inter_names` are added. +// if `directions` is 1, projections from `inter_names` to `names` are added. +// if `directions` is 2, projections from `inter_names` to `inter_names` are +// added. +// returns the new value of `proj_idx` +static uint _add_projections +( + cypher_astnode_t *projections[], // array of projections + uint proj_idx, // index to start adding projections + char **names, // bound vars + char **inter_names, // internal representation of bound vars + bool hide // hide or reveal vars +) { + uint n_names = array_len(names); + uint n_inter_names = array_len(inter_names); + uint n_outer_names = n_inter_names - n_names; + + if(hide) { + proj_idx = _add_names_projections(projections, proj_idx, names, + inter_names + n_outer_names, hide); + } else { + proj_idx = _add_names_projections(projections, proj_idx, + inter_names + n_outer_names, names, hide); + } + + // ------------------------------------------------------------------------- + // create projections for bound vars from outer context + // ------------------------------------------------------------------------- + for(uint i = 0; i < n_outer_names; i++) { + // create a projection for the bound var + struct cypher_input_range range = {0}; + cypher_astnode_t *exp = cypher_ast_identifier(inter_names[i], + strlen(inter_names[i]), range); + cypher_astnode_t *alias = cypher_ast_identifier(inter_names[i], + strlen(inter_names[i]), range); + cypher_astnode_t *children[2]; + children[0] = exp; + children[1] = alias; + + projections[proj_idx++] = cypher_ast_projection(exp, alias, children, + 2, range); + } + + return proj_idx; +} + +// replaces a `WITH` clause, placed in clause_idx within `callsubquery`, with a +// new `WITH` clause containing projections of `names` to `inter_names` +static void _replace_with_clause +( + cypher_astnode_t *callsubquery, // call subquery ast-node + uint clause_idx, // index of clause to replace + char **names, // original bound vars + char **inter_names // internal representation of bound vars +) { + cypher_astnode_t *query = + cypher_ast_call_subquery_get_query(callsubquery); + const cypher_astnode_t *clause = cypher_ast_query_get_clause(query, + clause_idx); + + uint existing_projections_count = cypher_ast_with_nprojections(clause); + uint n_projections = array_len(inter_names) + existing_projections_count; + uint proj_idx = 0; + cypher_astnode_t *projections[n_projections]; + + //-------------------------------------------------------------------------- + // create projections for bound vars + //-------------------------------------------------------------------------- + + proj_idx = _add_projections(projections, proj_idx, names, inter_names, + true); + + //-------------------------------------------------------------------------- + // introduce explicit projections + //-------------------------------------------------------------------------- + + // clone explicit projections into projections array + for(uint i = 0; i < existing_projections_count; i++) { + const cypher_astnode_t *projection = + cypher_ast_with_get_projection(clause, i); + projections[proj_idx++] = cypher_ast_clone(projection); + } + + // copy projections to the children array + cypher_astnode_t *children[n_projections + 4]; + for(uint i = 0; i < n_projections; i++) { + children[i] = projections[i]; + } + + //-------------------------------------------------------------------------- + // prepare additional arguments + //-------------------------------------------------------------------------- + + bool distinct = false; + const cypher_astnode_t *skip = NULL; + const cypher_astnode_t *limit = NULL; + const cypher_astnode_t *order_by = NULL; + const cypher_astnode_t *pred = NULL; + + skip = cypher_ast_with_get_skip(clause); + limit = cypher_ast_with_get_limit(clause); + distinct = cypher_ast_with_is_distinct(clause); + order_by = cypher_ast_with_get_order_by(clause); + pred = cypher_ast_with_get_predicate(clause); + + // clone any ORDER BY, SKIP, LIMIT, and WHERE modifiers to + // add to the children array and populate the new clause + uint nchildren = n_projections; + if(skip) skip = children[nchildren++] = cypher_ast_clone(skip); + if(pred) pred = children[nchildren++] = cypher_ast_clone(pred); + if(limit) limit = children[nchildren++] = cypher_ast_clone(limit); + if(order_by) order_by = children[nchildren++] = cypher_ast_clone(order_by); + + bool include_existing = cypher_ast_with_has_include_existing(clause); + struct cypher_input_range range = cypher_astnode_range(clause); + + // build the replacement clause + cypher_astnode_t *new_clause; + new_clause = cypher_ast_with(distinct, include_existing, projections, + n_projections, order_by, skip, limit, pred, children, nchildren, range); + + // replace original clause with fully populated one + cypher_ast_query_replace_clauses(query, new_clause, clause_idx, + clause_idx); +} + +// adds a leading WITH clause to the query, projecting all bound vars (names) to +// their internal representation (inter_names) +static void _add_first_clause +( + cypher_astnode_t *callsubquery, // call subquery ast-node + uint callsubquery_ind, // index of the call subquery node + uint first_ind, // the index in which to plant the clause + char **names, // original bound vars + char **inter_names // internal representation of bound vars +) { + uint n_names = array_len(names); + uint n_inter_names = array_len(inter_names); + + uint n_projections = n_inter_names; + uint proj_idx = 0; + cypher_astnode_t *projections[n_projections]; + + // ------------------------------------------------------------------------- + // create projections for bound vars + // ------------------------------------------------------------------------- + proj_idx = _add_projections(projections, proj_idx, names, inter_names, + true); + + // ------------------------------------------------------------------------- + // prepare additional arguments + //-------------------------------------------------------------------------- + + struct cypher_input_range range = {0}; + + // build the replacement clause + cypher_astnode_t *new_clause; + new_clause = cypher_ast_with(false, false, projections, n_projections, + NULL, NULL, NULL, NULL, projections, n_projections, range); + + // ------------------------------------------------------------------------- + // replace original clause with fully populated one + // ------------------------------------------------------------------------- + + cypher_astnode_t *query = cypher_ast_call_subquery_get_query(callsubquery); + + uint n_clauses = cypher_ast_query_nclauses(query); + cypher_astnode_t *clauses[n_clauses + 1]; + for(uint i = 0; i < first_ind; i++) { + clauses[i] = cypher_ast_clone(cypher_ast_query_get_clause(query, i)); + } + + clauses[first_ind] = new_clause; + + for(uint i = first_ind; i < n_clauses; i++) { + clauses[i + 1] = cypher_ast_clone(cypher_ast_query_get_clause(query, i)); + } + + cypher_astnode_t *q = cypher_ast_query(NULL, 0, clauses, n_clauses + 1, + clauses, n_clauses + 1, range); + + cypher_ast_call_subquery_replace_query(callsubquery, q); +} + +// replace all intermediate WITH clauses in the query with new WITH clauses, +// containing projections from the internal representation of bound vars to +// themselves (inter_names) +static void _replace_intermediate_with_clauses +( + cypher_astnode_t *callsubquery, // call subquery ast-node + uint first_ind, // index of first relevant clause + uint last_ind, // index of last relevant clause + char **inter_names // internal representation of bound vars +) { + cypher_astnode_t *query = cypher_ast_call_subquery_get_query(callsubquery); + for(uint i = first_ind + 1; i < last_ind; i++) { + const cypher_astnode_t *clause = cypher_ast_query_get_clause(query, i); + if(cypher_astnode_type(clause) == CYPHER_AST_WITH) { + _replace_with_clause(callsubquery, i, inter_names, inter_names); + } + } +} + +// replaces the RETURN clause in query to a new one, containing projections of +// inter_names to names +static void _replace_return_clause +( + cypher_astnode_t *callsubquery, // call subquery ast-node + uint last_ind, // index of last relevant clause + char **names, // original bound vars + char **inter_names // internal representation of bound vars +) { + cypher_astnode_t *query = cypher_ast_call_subquery_get_query( + callsubquery); + // we know that the last clause in query is a RETURN clause, which we want + // to replace + cypher_astnode_t *clause = (cypher_astnode_t *)cypher_ast_query_get_clause( + query, last_ind-1); + + uint n_names = array_len(names); + uint n_inter_names = array_len(inter_names); + + uint existing_projections_count = cypher_ast_return_nprojections(clause); + uint n_projections = n_inter_names + existing_projections_count; + uint proj_idx = 0; + cypher_astnode_t *projections[n_projections]; + + // ------------------------------------------------------------------------- + // create projections for bound vars + // ------------------------------------------------------------------------- + proj_idx = _add_projections(projections, proj_idx, names, inter_names, + false); + + // ------------------------------------------------------------------------- + // introduce explicit projections + //-------------------------------------------------------------------------- + // clone explicit projections into projections array + for(uint i = 0; i < existing_projections_count; i++) { + const cypher_astnode_t *projection = + cypher_ast_return_get_projection(clause, i); + projections[proj_idx++] = cypher_ast_clone(projection); + } + + ASSERT(proj_idx == n_projections); + + // copy projections to the children array + cypher_astnode_t *children[n_projections + 3]; + for(uint i = 0; i < n_projections; i++) { + children[i] = projections[i]; + } + + // ------------------------------------------------------------------------- + // prepare additional arguments + //-------------------------------------------------------------------------- + bool distinct = false; + const cypher_astnode_t *skip = NULL; + const cypher_astnode_t *limit = NULL; + const cypher_astnode_t *order_by = NULL; + + skip = cypher_ast_return_get_skip(clause); + limit = cypher_ast_return_get_limit(clause); + distinct = cypher_ast_return_is_distinct(clause); + order_by = cypher_ast_return_get_order_by(clause); + + // clone any ORDER BY, SKIP, LIMIT, and WHERE modifiers to + // add to the children array and populate the new clause + uint nchildren = n_projections; + if(skip) skip = children[nchildren++] = cypher_ast_clone(skip); + if(limit) limit = children[nchildren++] = cypher_ast_clone(limit); + if(order_by) order_by = children[nchildren++] = cypher_ast_clone(order_by); + + bool include_existing = cypher_ast_return_has_include_existing(clause); + struct cypher_input_range range = cypher_astnode_range(clause); + + // build the replacement clause + cypher_astnode_t *new_clause; + new_clause = cypher_ast_return(distinct, + include_existing, + projections, + n_projections, + order_by, + skip, + limit, + children, + nchildren, + range); + + // replace original clause with fully populated one + cypher_ast_query_replace_clauses(query, new_clause, last_ind - 1, + last_ind - 1); +} + +// rewrites the projections of a Call {} clause, such that bound vars will +// remain in the record when passed to the CallSubquery op +static void _rewrite_projections +( + cypher_astnode_t *wrapping_clause, // outer-context clause (query/call {}) + uint clause_ind, // index of call {} clause in query + uint start, // start ind of outer-scope bound vars + char ***inter_names // internal representation of bound vars +) { + //-------------------------------------------------------------------------- + // collect outer scope bound vars + //-------------------------------------------------------------------------- + + rax *outer_mapping = raxNew(); + if(start != clause_ind) { + collect_aliases_in_scope(wrapping_clause, start, clause_ind, + outer_mapping); + } + + uint mapping_size = raxSize(outer_mapping); + if(mapping_size == 0 && array_len(*inter_names) == 0) { + raxFree(outer_mapping); + return; + } + + // create an array for the outer scope bound vars + char **names = array_new(char *, mapping_size); + + _get_vars_inner_rep(outer_mapping, &names, inter_names); + raxFree(outer_mapping); + + //-------------------------------------------------------------------------- + // transform relevant clauses + //-------------------------------------------------------------------------- + + // if there is a UNION clause in the subquery, each branch must be handled + cypher_astnode_t *clause = (cypher_astnode_t *) + cypher_ast_query_get_clause(wrapping_clause, clause_ind); + cypher_astnode_t *subquery = cypher_ast_call_subquery_get_query(clause); + AST ast = {0}; + ast.root = subquery; + uint *union_indices = AST_GetClauseIndices(&ast, CYPHER_AST_UNION); + uint clause_count = cypher_ast_query_nclauses(subquery); + array_append(union_indices, clause_count); + uint n_union_branches = array_len(union_indices); + + uint first_ind = 0; + for(uint i = 0; i < n_union_branches; i++) { + uint last_ind = union_indices[i]; + + // check if first clause is a WITH clause + const cypher_astnode_t *first_clause = + cypher_ast_query_get_clause(subquery, first_ind); + if(cypher_astnode_type(first_clause) == CYPHER_AST_WITH) { + // replace first clause (WITH) with a WITH clause containing + // "n->@n" projections for all bound vars in outer-scope context + _replace_with_clause(clause, first_ind, names, *inter_names); + } else { + // add a leading WITH clause containing "n->@n" projections + // for all bound vars (in outer-scope context) + _add_first_clause(clause, clause_ind, first_ind, names, + *inter_names); + + // update union indeces + for(uint j = i; j < n_union_branches; j++) { + union_indices[j]++; + } + last_ind++; + } + + // for every intermediate WITH clause (all but first one), + // replace it with a clause that contains "@n->@n" projections for + // all bound vars in outer-scope context + _replace_intermediate_with_clauses(clause, first_ind, last_ind, + *inter_names); + + // replace the RETURN clause (last) with a clause containing the + // projections "@n->n" for all bound vars in outer-scope context + _replace_return_clause(clause, last_ind, names, *inter_names); + first_ind = union_indices[i] + 1; + } + + array_free(union_indices); + + // free the names and inter_names, and corresponding arrays + array_free_cb(names, rm_free); +} + +// rewrites the subquery to contain the projections needed in case of an +// eager and returning execution-plan such that bound vars will +// remain in the record when passed to the CallSubquery op +// returns true if the subquery was rewritten +static bool _rewrite_call_subquery_clause +( + cypher_astnode_t *wrapping_clause, // outer-context clause (query/call {}) + uint clause_idx, // index of the call {} clause in query + uint start, // start ind from which to collect bound vars + char ***inter_names // internal representation of bound vars +) { + ASSERT(cypher_astnode_type(wrapping_clause) == CYPHER_AST_QUERY); + + cypher_astnode_t *clause = (cypher_astnode_t *) + cypher_ast_query_get_clause(wrapping_clause, clause_idx); + ASSERT(cypher_astnode_type(clause) == CYPHER_AST_CALL_SUBQUERY); + + cypher_astnode_t *subquery = cypher_ast_call_subquery_get_query(clause); + uint subclauses_count = cypher_ast_query_nclauses(subquery); + + // check if the subquery will result in an eager and returning + // execution-plan + const cypher_astnode_t *last_clause = + cypher_ast_query_get_clause(subquery, subclauses_count - 1); + bool is_returning = cypher_astnode_type(last_clause) == CYPHER_AST_RETURN; + + bool is_eager = AST_IsEager(subquery); + + if(is_eager && is_returning) { + _rewrite_projections(wrapping_clause, clause_idx, start, inter_names); + return true; + } + + return false; +} + +// restores `outer_names` to its original size by freeing the added components +static void _restore_outer_internal_names +( + char ***outer_names, // expanded context + int orig_size // original context size +) { + // free added names + int n_added_names = array_len(*outer_names) - orig_size; + for(int i = 0; i < n_added_names; i++) { + char *name = array_pop(*outer_names); + rm_free(name); + } +} + +// rewrites the subquery to contain the projections needed in case of an +// eager and returning execution-plan such that bound vars will +// remain in the record when passed to the CallSubquery op +// returns true if a rewrite was performed +static bool _rewrite_call_subquery_clauses +( + cypher_astnode_t *wrapping_clause, // clause (query/call {}) + char ***outer_inter_names // internal names of bound vars in outer-scope ('@n', '@m', etc.) +) { + ASSERT(cypher_astnode_type(wrapping_clause) == CYPHER_AST_QUERY); + + bool rewritten = false; + uint nclauses = cypher_ast_query_nclauses(wrapping_clause); + + // go over clauses. Upon finding a Call {} clause, rewrite it recursively + uint start_scope = 0; + int orig_len = array_len(*outer_inter_names); + + for(uint i = 0; i < nclauses; i++) { + cypher_astnode_t *clause = (cypher_astnode_t *) + cypher_ast_query_get_clause(wrapping_clause, i); + cypher_astnode_type_t type = cypher_astnode_type(clause); + if(type == CYPHER_AST_CALL_SUBQUERY) { + // if the subquery is returning & eager, rewrite its projections + rewritten |= _rewrite_call_subquery_clause(wrapping_clause, + i, start_scope, outer_inter_names); + + // `outer_inter_names` now contains the internal representation of + // the current context as well + + // recursively rewrite embedded Call {} clauses, taking the + // potentially updated query + rewritten |= _rewrite_call_subquery_clauses( + cypher_ast_call_subquery_get_query(clause), outer_inter_names); + + // restore `outer_inter_names` to its original state + _restore_outer_internal_names(outer_inter_names, orig_len); + } + + // update start_scope if needed + if(type == CYPHER_AST_WITH || type == CYPHER_AST_RETURN) { + start_scope = i; + } + } + + return rewritten; +} + +static void _add_star_projection +( + cypher_astnode_t *node, // node to add the projection to + uint idx // index in which to plant the projection +) { + cypher_astnode_type_t type = cypher_astnode_type(node); + + cypher_astnode_t *query; + if(type == CYPHER_AST_STATEMENT) { + query = (cypher_astnode_t *)cypher_ast_statement_get_body(node); + } else { + // node is a call {} clause + ASSERT(type == CYPHER_AST_CALL_SUBQUERY); + + query = cypher_ast_call_subquery_get_query(node); + } + + uint nclauses = cypher_ast_query_nclauses(query); + + // create a star projection + struct cypher_input_range range = {0}; + cypher_astnode_t *star_projection = cypher_ast_with(false, true, NULL, 0, + NULL, NULL, NULL, NULL, NULL, 0, range); + + cypher_astnode_t *clauses[nclauses + 1]; + for(uint i = 0; i < idx; i++) { + clauses[i] = cypher_ast_clone(cypher_ast_query_get_clause(query, i)); + } + clauses[idx] = star_projection; + for(uint i = idx; i < nclauses; i++) { + clauses[i + 1] = cypher_ast_clone(cypher_ast_query_get_clause(query, i)); + } + + cypher_astnode_t *new_query = cypher_ast_query(NULL, 0, clauses, + nclauses + 1, clauses, nclauses + 1, range); + + if(type == CYPHER_AST_STATEMENT) { + cypher_ast_statement_replace_body(node, new_query); + } else { + cypher_ast_call_subquery_replace_query(node, new_query); + } +} + +static bool _add_star_projections +( + cypher_astnode_t *node // node to add the projections to +) { + cypher_astnode_type_t type = cypher_astnode_type(node); + + cypher_astnode_t *query; + if(type == CYPHER_AST_STATEMENT) { + query = (cypher_astnode_t *)cypher_ast_statement_get_body(node); + } else { + // node is a call {} clause + ASSERT(type == CYPHER_AST_CALL_SUBQUERY); + + query = cypher_ast_call_subquery_get_query(node); + } + + bool rewritten = false; + uint nclauses = cypher_ast_query_nclauses(query); + for(uint i = 1; i < nclauses; i++) { + cypher_astnode_t *clause = (cypher_astnode_t *) + cypher_ast_query_get_clause(query, i); + if(cypher_astnode_type(clause) == CYPHER_AST_CALL_SUBQUERY) { + _add_star_projection(node, i); + rewritten = true; + + // update `query` and `nclauses` to reflect the new query + query = type == CYPHER_AST_STATEMENT ? + (cypher_astnode_t *)cypher_ast_statement_get_body(node) : + cypher_ast_call_subquery_get_query(node); + i++; + nclauses++; + clause = (cypher_astnode_t *)cypher_ast_query_get_clause(query, i); + + _add_star_projections(clause); + } + } + + return rewritten; +} + +// if the subquery will result in an eager and returning execution-plan +// rewrites it to contain the projections needed: +// 1. "n" -> "@n" in the initial WITH clause if exists. Otherwise, creates it. +// 2. "@n" -> "@n" in the intermediate WITH clauses. +// 3. "@n" -> "n" in the final RETURN clause. +// if the subquery will not result in an eager & returning execution-plan, does +// nothing +bool AST_RewriteCallSubquery +( + const cypher_astnode_t *root // root of AST +) { + if(cypher_astnode_type(root) != CYPHER_AST_STATEMENT) { + return false; + } + + // retrieve the root's body + cypher_astnode_t *query = + (cypher_astnode_t *)cypher_ast_statement_get_body(root); + + if(cypher_astnode_type(query) != CYPHER_AST_QUERY) { + return false; + } + + char **inter_names = array_new(char *, 0); + bool rewritten = _rewrite_call_subquery_clauses(query, &inter_names); + uint n_inter_names = array_len(inter_names); + array_free_cb(inter_names, rm_free); + + // add a `WITH *` clause before every call {} clause + // this is an optimization that decreases the mapping size of the plan up to + // the CallSubquery operation + rewritten |= _add_star_projections((cypher_astnode_t *)root); + + return rewritten; +} diff --git a/src/ast/ast_rewrite_call_subquery.h b/src/ast/ast_rewrite_call_subquery.h new file mode 100644 index 0000000000..db57698418 --- /dev/null +++ b/src/ast/ast_rewrite_call_subquery.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "ast.h" + +// if the subquery will result in an eager and returning execution-plan +// rewrites it to contain the projections needed: +// 1. "n" -> "@n" in the initial WITH clause if exists. Otherwise, creates it. +// 2. "@n" -> "@n" in the intermediate WITH clauses. +// 3. "@n" -> "n" in the final RETURN clause. +// if the subquery will not result in an eager & returning execution-plan, does +// nothing +bool AST_RewriteCallSubquery +( + const cypher_astnode_t *root // root of AST +); diff --git a/src/ast/ast_rewrite_same_clauses.c b/src/ast/ast_rewrite_same_clauses.c index 87e3970315..5684f01e5e 100644 --- a/src/ast/ast_rewrite_same_clauses.c +++ b/src/ast/ast_rewrite_same_clauses.c @@ -1,19 +1,23 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/qsort.h" #include "../util/sds/sds.h" +#include "../errors/errors.h" #include "../procedures/procedure.h" // forward declarations -static inline bool is_compressible(const cypher_astnode_t *clause); +static inline bool is_compressible(const cypher_astnode_t *clause, + cypher_astnode_type_t type); static bool _compress_clauses(const cypher_astnode_t *node); typedef void (*replace_func)(cypher_astnode_t *, cypher_astnode_t *, unsigned int, unsigned int); @@ -146,6 +150,9 @@ static void _replace_delete_clause if(raxTryInsert(identifiers, (unsigned char *)identifier, strlen(identifier), NULL, NULL)) { array_append(exps, cypher_ast_clone(exp)); } + } else { + // "MATCH p1=(n:N), p2=(m:M) DELETE nodes(p1)[0] DELETE nodes(p2)[0]" + array_append(exps, cypher_ast_clone(exp)); } } } @@ -236,34 +243,42 @@ static bool _compress_clauses ) { bool rewritten = false; + cypher_astnode_type_t type = cypher_astnode_type(node); + + ASSERT(type == CYPHER_AST_QUERY || type == CYPHER_AST_FOREACH); + cypher_astnode_t **clauses = array_new(cypher_astnode_t *, 0); // is the node representing a FOREACH clause uint clause_count = 0; replace_func replace_func = NULL; get_clause_func get_clause = NULL; // use appropriate function to get a positioned clause - if(cypher_astnode_type(node) == CYPHER_AST_FOREACH) { + if(type == CYPHER_AST_FOREACH) { get_clause = cypher_ast_foreach_get_clause; clause_count = cypher_ast_foreach_nclauses(node); replace_func = cypher_ast_foreach_replace_clauses; } else { get_clause = cypher_ast_query_get_clause; - clause_count = cypher_ast_query_nclauses(node); replace_func = cypher_ast_query_replace_clauses; + clause_count = cypher_ast_query_nclauses(node); } for(uint i = 0; i < clause_count; i++) { const cypher_astnode_t *clause = get_clause(node, i); cypher_astnode_type_t t = cypher_astnode_type(clause); - // try compressing the inner-clauses of a foreach clause + // try compressing the inner-clauses of foreach clause and call subquery if(t == CYPHER_AST_FOREACH) { - rewritten = _compress_clauses(get_clause(node, i)); + rewritten |= _compress_clauses(clause); + continue; + } else if(t == CYPHER_AST_CALL_SUBQUERY) { + rewritten |= + _compress_clauses(cypher_ast_call_subquery_get_query(clause)); continue; } // check compressibility, move on if not compressible - if(!is_compressible(clause)) { + if(!is_compressible(clause, t)) { continue; } @@ -274,7 +289,7 @@ static bool _compress_clauses for (uint j = i; j < clause_count; j++) { clause = get_clause(node, j); cypher_astnode_type_t t2 = cypher_astnode_type(clause); - if(t2 != t || !is_compressible(clause)) { + if(t2 != t || !is_compressible(clause, t2)) { break; } array_append(clauses, (cypher_astnode_t *)clause); @@ -314,11 +329,11 @@ static bool _compress_clauses return rewritten; } - // returns true if AST clause type is compressible static inline bool is_compressible ( - const cypher_astnode_t *clause + const cypher_astnode_t *clause, // clause to check + cypher_astnode_type_t type // type of clause ) { // compressible clauses: // 1. Non-OPTIONAL MATCH @@ -326,13 +341,12 @@ static inline bool is_compressible // 3. SET // 4. DELETE // 5. REMOVE - cypher_astnode_type_t t = cypher_astnode_type(clause); - return ( (t == CYPHER_AST_MATCH && + return ((type == CYPHER_AST_MATCH && !cypher_ast_match_is_optional(clause)) || - t == CYPHER_AST_CREATE || - t == CYPHER_AST_SET || - t == CYPHER_AST_DELETE || - t == CYPHER_AST_REMOVE); + type == CYPHER_AST_CREATE || + type == CYPHER_AST_SET || + type == CYPHER_AST_DELETE || + type == CYPHER_AST_REMOVE); } // rewrite result by compressing consecutive clauses of the same type diff --git a/src/ast/ast_rewrite_same_clauses.h b/src/ast/ast_rewrite_same_clauses.h index 6c2e75df6b..f6e4b44f20 100644 --- a/src/ast/ast_rewrite_same_clauses.h +++ b/src/ast/ast_rewrite_same_clauses.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast_rewrite_star_projections.c b/src/ast/ast_rewrite_star_projections.c index 99a7b408d0..f449d0ea52 100644 --- a/src/ast/ast_rewrite_star_projections.c +++ b/src/ast/ast_rewrite_star_projections.c @@ -1,183 +1,43 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast.h" -#include "../query_ctx.h" -#include "../errors.h" +#include "ast_shared.h" #include "../util/arr.h" +#include "../query_ctx.h" #include "../util/sds/sds.h" +#include "../errors/errors.h" +#include "../util/rax_extensions.h" #include "../procedures/procedure.h" -//------------------------------------------------------------------------------ -// Annotation context - WITH/RETURN * projections -//------------------------------------------------------------------------------ -static void _collect_aliases_in_path -( - const cypher_astnode_t *path, - rax *identifiers -) { - uint path_len = cypher_ast_pattern_path_nelements(path); - // every even offset corresponds to a node - for(uint i = 0; i < path_len; i += 2) { - const cypher_astnode_t *ast_node = - cypher_ast_pattern_path_get_element(path, i); - const cypher_astnode_t *ast_alias = - cypher_ast_node_pattern_get_identifier(ast_node); - - if(ast_alias == NULL) continue; // unaliased node, do nothing - - // add node alias to projection rax - const char *identifier = cypher_ast_identifier_get_name(ast_alias); - raxTryInsert(identifiers, (unsigned char *)identifier, - strlen(identifier), (void *)ast_alias, NULL); - } - - // every odd offset corresponds to an edge - for(uint i = 1; i < path_len; i += 2) { - const cypher_astnode_t *ast_edge = - cypher_ast_pattern_path_get_element(path, i); - const cypher_astnode_t *ast_alias = - cypher_ast_rel_pattern_get_identifier(ast_edge); - - if(ast_alias == NULL) continue; // unaliased edge, do nothing - - // add edge alias to projection rax - const char *identifier = cypher_ast_identifier_get_name(ast_alias); - raxTryInsert(identifiers, (unsigned char *)identifier, - strlen(identifier), (void *)ast_alias, NULL); - } -} - -static void _collect_aliases_in_pattern -( - const cypher_astnode_t *pattern, - rax *identifiers -) { - uint path_count = cypher_ast_pattern_npaths(pattern); - for(uint i = 0; i < path_count; i ++) { - _collect_aliases_in_path(cypher_ast_pattern_get_path(pattern, i), - identifiers); - } -} - -static void _collect_with_projections -( - const cypher_astnode_t *with_clause, - rax *identifiers -) { - uint projection_count = cypher_ast_with_nprojections(with_clause); - for(uint i = 0; i < projection_count; i ++) { - const cypher_astnode_t *projection = - cypher_ast_with_get_projection(with_clause, i); - const cypher_astnode_t *identifier_node = - cypher_ast_projection_get_alias(projection); - if(identifier_node == NULL) { - // the projection was not aliased - // so the projection itself must be an identifier - identifier_node = cypher_ast_projection_get_expression(projection); - ASSERT(cypher_astnode_type(identifier_node) == CYPHER_AST_IDENTIFIER); - } else { - // do not include empty projections, which may have been made to - // handle the MATCH () WITH * case - if(!strcmp(cypher_ast_identifier_get_name(identifier_node), "")) continue; - } - const char *identifier = cypher_ast_identifier_get_name(identifier_node); - raxTryInsert(identifiers, (unsigned char *)identifier, - strlen(identifier), (void *)identifier_node, NULL); - } -} - -static void _collect_call_projections( - const cypher_astnode_t *call_clause, - rax *identifiers -) { - uint yield_count = cypher_ast_call_nprojections(call_clause); - - if(yield_count == 0) { - // error if this is a RETURN clause with no aliases - // e.g. - // CALL db.indexes() RETURN * - ErrorCtx_SetError("RETURN * is not allowed when there are no variables in scope"); - return; - } - - for(uint i = 0; i < yield_count; i ++) { - const cypher_astnode_t *projection = cypher_ast_call_get_projection(call_clause, i); - const cypher_astnode_t *ast_exp = cypher_ast_projection_get_expression(projection); - - const cypher_astnode_t *alias_node = cypher_ast_projection_get_alias(projection); - if(alias_node == NULL) alias_node = ast_exp; - - const char *identifier = cypher_ast_identifier_get_name(alias_node); - raxTryInsert(identifiers, (unsigned char *)identifier, - strlen(identifier), (void *)alias_node, NULL); - } -} - -static void _collect_aliases_in_scope -( - const cypher_astnode_t *root, - uint scope_start, - uint scope_end, - rax *identifiers -) { - ASSERT(scope_start != scope_end); - ASSERT(identifiers != NULL); - - for(uint i = scope_start; i < scope_end; i ++) { - const cypher_astnode_t *clause = cypher_ast_query_get_clause(root, i); - cypher_astnode_type_t type = cypher_astnode_type(clause); - - if(type == CYPHER_AST_WITH) { - // the WITH clause contains either - // aliases or its own STAR projection - _collect_with_projections(clause, identifiers); - } else if(type == CYPHER_AST_MATCH) { - // the MATCH clause contains one pattern of N paths - const cypher_astnode_t *pattern = - cypher_ast_match_get_pattern(clause); - _collect_aliases_in_pattern(pattern, identifiers); - } else if(type == CYPHER_AST_CREATE) { - // the CREATE clause contains one pattern of N paths - const cypher_astnode_t *pattern = - cypher_ast_create_get_pattern(clause); - _collect_aliases_in_pattern(pattern, identifiers); - } else if(type == CYPHER_AST_MERGE) { - // the MERGE clause contains one path - const cypher_astnode_t *path = - cypher_ast_merge_get_pattern_path(clause); - _collect_aliases_in_path(path, identifiers); - } else if(type == CYPHER_AST_UNWIND) { - // the UNWIND clause introduces one alias - const cypher_astnode_t *unwind_alias = - cypher_ast_unwind_get_alias(clause); - const char *identifier = - cypher_ast_identifier_get_name(unwind_alias); - raxTryInsert(identifiers, (unsigned char *)identifier, - strlen(identifier), (void *)unwind_alias, NULL); - } else if(type == CYPHER_AST_CALL) { - _collect_call_projections(clause, identifiers); - } - } -} +bool AST_RewriteStarProjections(const cypher_astnode_t *root); +// replaces a `WITH` clause containing a star projection with explicit +// projections. +// if `identifiers` is NULL, it will be populated with all identifiers in scope static void replace_clause ( cypher_astnode_t *root, // ast root cypher_astnode_t *clause, // clause being replaced int scope_start, // beginning of scope - int scope_end // ending of scope + int scope_end, // ending of scope + rax *identifiers // bound vars ) { cypher_astnode_type_t t = cypher_astnode_type(clause); //-------------------------------------------------------------------------- // collect identifiers //-------------------------------------------------------------------------- - rax *identifiers = raxNew(); - _collect_aliases_in_scope(root, scope_start, scope_end, identifiers); + if(identifiers == NULL) { + identifiers = raxNew(); + collect_aliases_in_scope(root, scope_start, scope_end, identifiers); + } //-------------------------------------------------------------------------- // determine number of projections @@ -251,7 +111,7 @@ static void replace_clause // error if this is a RETURN clause with no aliases // e.g. // MATCH () RETURN * - ErrorCtx_SetError("RETURN * is not allowed when there are no variables in scope"); + ErrorCtx_SetError(EMSG_RETURN_STAR_NO_VARIABLES); raxFree(identifiers); return; } else { @@ -267,7 +127,6 @@ static void replace_clause children[1] = identifier; projections[proj_idx++] = cypher_ast_projection(expression, identifier, children, 2, range); - nprojections = 1; } } @@ -289,7 +148,6 @@ static void replace_clause // maintain expression projections[proj_idx++] = cypher_ast_clone(projection); - nprojections++; } // update `nprojections` to actual number of projections @@ -365,24 +223,103 @@ static void replace_clause cypher_ast_query_set_clause(root, new_clause, scope_end); } +// rewrites star projections in a CALL {} clause +static bool _rewrite_call_subquery_star_projections +( + const cypher_astnode_t *wrapping_clause, // wrapping clause + uint scope_start, // start scope in wrapping clause + uint idx // index of the call subquery +) { + bool rewritten = false; + + // get the call subquery clause + cypher_astnode_t *call_subquery = (cypher_astnode_t *) + cypher_ast_query_get_clause(wrapping_clause, idx); + // get the query node + cypher_astnode_t *query = (cypher_astnode_t *) + cypher_ast_call_subquery_get_query(call_subquery); + + uint n_clauses = cypher_ast_query_nclauses(query); + + uint first_in_scope = 0; + // initialize `last_is_union` to true to rewrite the first importing `WITH` + bool last_is_union = true; + for(uint i = 0; i < n_clauses; i++) { + cypher_astnode_t *clause = (cypher_astnode_t *) + cypher_ast_query_get_clause(query, i); + cypher_astnode_type_t t = cypher_astnode_type(clause); + + if(t == CYPHER_AST_CALL_SUBQUERY) { + cypher_astnode_t *inner_query = + cypher_ast_call_subquery_get_query(call_subquery); + rewritten |= AST_RewriteStarProjections(inner_query); + last_is_union = false; + } else if(t == CYPHER_AST_WITH || t == CYPHER_AST_RETURN) { + // check whether the clause contains a star projection + bool has_star = (t == CYPHER_AST_WITH) ? + cypher_ast_with_has_include_existing(clause) : + cypher_ast_return_has_include_existing(clause); + + // if so, rewrite the clause in a way corresponding to its type and + // position. If this is an importing `WITH` clause, collect the + // aliases in the wrapping clause to be imported. Otherwise, just + // rewrite the clause regularly. + if(has_star) { + if(last_is_union && t == CYPHER_AST_WITH) { + // importing `WITH` clause, import vars from wrapping clause + rax *identifiers = raxNew(); + if(scope_start != idx) { + collect_aliases_in_scope(wrapping_clause, + scope_start, idx, identifiers); + } + replace_clause(query, clause, first_in_scope, i, + identifiers); + } else { + // intermediate `WITH` or `RETURN` clause + replace_clause(query, clause, first_in_scope, i, NULL); + } + rewritten = true; + } + first_in_scope = i; + last_is_union = false; + } else if(t == CYPHER_AST_UNION) { + first_in_scope = i + 1; + last_is_union = true; + } else { + last_is_union = false; + } + } + + return rewritten; +} + bool AST_RewriteStarProjections ( const cypher_astnode_t *root // root for which to rewrite star projections ) { bool rewritten = false; - // retrieve the root query node from the statement - root = cypher_ast_statement_get_body(root); - if(cypher_astnode_type(root) != CYPHER_AST_QUERY) return rewritten; + if(cypher_astnode_type(root) != CYPHER_AST_QUERY) { + return false; + } // rewrite all WITH * / RETURN * clauses to include all aliases - uint scope_start = 0; - uint clause_count = cypher_ast_query_nclauses(root); + uint scope_start = 0; + uint clause_count = cypher_ast_query_nclauses(root); for(uint i = 0; i < clause_count; i ++) { const cypher_astnode_t *clause = cypher_ast_query_get_clause(root, i); cypher_astnode_type_t t = cypher_astnode_type(clause); - if(t != CYPHER_AST_WITH && t != CYPHER_AST_RETURN) continue; + + if(t == CYPHER_AST_CALL_SUBQUERY) { + rewritten |= + _rewrite_call_subquery_star_projections(root, scope_start, i); + continue; + } + + if(t != CYPHER_AST_WITH && t != CYPHER_AST_RETURN) { + continue; + } bool has_include_existing = (t == CYPHER_AST_WITH) ? cypher_ast_with_has_include_existing(clause) : @@ -391,7 +328,7 @@ bool AST_RewriteStarProjections if(has_include_existing) { // clause contains a star projection, replace it replace_clause((cypher_astnode_t *)root, (cypher_astnode_t *)clause, - scope_start, i); + scope_start, i, NULL); rewritten = true; } diff --git a/src/ast/ast_rewrite_star_projections.h b/src/ast/ast_rewrite_star_projections.h index 80f8ec5298..d708f70535 100644 --- a/src/ast/ast_rewrite_star_projections.h +++ b/src/ast/ast_rewrite_star_projections.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast_shared.c b/src/ast/ast_shared.c index a2baf5f95f..d007ac2bd5 100644 --- a/src/ast/ast_shared.c +++ b/src/ast/ast_shared.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ast_shared.h" #include "../RG.h" @@ -230,3 +233,211 @@ void UpdateCtx_Free rm_free(ctx); } + +static void _collect_aliases_in_path +( + const cypher_astnode_t *path, + rax *identifiers +) { + // collect path name if, if exists + if(cypher_astnode_type(path) == CYPHER_AST_NAMED_PATH) { + const cypher_astnode_t *ast_alias = + cypher_ast_named_path_get_identifier(path); + if(ast_alias != NULL) { + const char *identifier = cypher_ast_identifier_get_name(ast_alias); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)ast_alias, NULL); + } + } + + uint path_len = cypher_ast_pattern_path_nelements(path); + // every even offset corresponds to a node + for(uint i = 0; i < path_len; i += 2) { + const cypher_astnode_t *ast_node = + cypher_ast_pattern_path_get_element(path, i); + const cypher_astnode_t *ast_alias = + cypher_ast_node_pattern_get_identifier(ast_node); + + if(ast_alias == NULL) continue; // unaliased node, do nothing + + // add node alias to projection rax + const char *identifier = cypher_ast_identifier_get_name(ast_alias); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)ast_alias, NULL); + } + + // every odd offset corresponds to an edge + for(uint i = 1; i < path_len; i += 2) { + const cypher_astnode_t *ast_edge = + cypher_ast_pattern_path_get_element(path, i); + const cypher_astnode_t *ast_alias = + cypher_ast_rel_pattern_get_identifier(ast_edge); + + if(ast_alias == NULL) continue; // unaliased edge, do nothing + + // add edge alias to projection rax + const char *identifier = cypher_ast_identifier_get_name(ast_alias); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)ast_alias, NULL); + } +} + +static void _collect_aliases_in_pattern +( + const cypher_astnode_t *pattern, + rax *identifiers +) { + uint path_count = cypher_ast_pattern_npaths(pattern); + for(uint i = 0; i < path_count; i ++) { + _collect_aliases_in_path(cypher_ast_pattern_get_path(pattern, i), + identifiers); + } +} + +static void _collect_with_projections +( + const cypher_astnode_t *with_clause, + rax *identifiers +) { + uint projection_count = cypher_ast_with_nprojections(with_clause); + for(uint i = 0; i < projection_count; i ++) { + const cypher_astnode_t *projection = + cypher_ast_with_get_projection(with_clause, i); + const cypher_astnode_t *identifier_node = + cypher_ast_projection_get_alias(projection); + if(identifier_node == NULL) { + // the projection was not aliased + // so the projection itself must be an identifier + identifier_node = cypher_ast_projection_get_expression(projection); + ASSERT(cypher_astnode_type(identifier_node) == CYPHER_AST_IDENTIFIER); + } else { + // do not include empty projections, which may have been made to + // handle the MATCH () WITH * case + if(!strcmp(cypher_ast_identifier_get_name(identifier_node), "")) continue; + } + const char *identifier = cypher_ast_identifier_get_name(identifier_node); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)identifier_node, NULL); + } +} + +static void _collect_call_projections( + const cypher_astnode_t *call_clause, + rax *identifiers +) { + uint yield_count = cypher_ast_call_nprojections(call_clause); + + if(yield_count == 0) { + // error if this is a RETURN clause with no aliases + // e.g. + // CALL db.indexes() RETURN * + ErrorCtx_SetError(EMSG_RETURN_STAR_NO_VARIABLES); + return; + } + + for(uint i = 0; i < yield_count; i ++) { + const cypher_astnode_t *projection = cypher_ast_call_get_projection(call_clause, i); + const cypher_astnode_t *ast_exp = cypher_ast_projection_get_expression(projection); + + const cypher_astnode_t *alias_node = cypher_ast_projection_get_alias(projection); + if(alias_node == NULL) alias_node = ast_exp; + + const char *identifier = cypher_ast_identifier_get_name(alias_node); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)alias_node, NULL); + } +} + +// collect aliases from a CALL {} clause +static void _collect_call_subquery_projections +( + const cypher_astnode_t *clause, + rax *identifiers +) { + // collect returned aliases from the subquery, if there are any + const cypher_astnode_t *query = + cypher_ast_call_subquery_get_query(clause); + uint nclauses = cypher_ast_query_nclauses(query); + const cypher_astnode_t *last_clause = + cypher_ast_query_get_clause(query, nclauses - 1); + bool is_returning = (cypher_astnode_type(last_clause) == CYPHER_AST_RETURN); + if(!is_returning) { + return; + } + + // collect aliases from the RETURN clause + uint projection_count = cypher_ast_return_nprojections(last_clause); + for(uint i = 0; i < projection_count; i ++) { + const cypher_astnode_t *projection = + cypher_ast_return_get_projection(last_clause, i); + const cypher_astnode_t *identifier_node = + cypher_ast_projection_get_alias(projection); + if(identifier_node == NULL) { + // the projection was not aliased + // so the projection itself must be an identifier + identifier_node = cypher_ast_projection_get_expression(projection); + ASSERT(cypher_astnode_type(identifier_node) == CYPHER_AST_IDENTIFIER); + } else { + // do not include empty projections, which may have been made to + // handle the MATCH () WITH * case + if(!strcmp(cypher_ast_identifier_get_name(identifier_node), "")) continue; + } + const char *identifier = cypher_ast_identifier_get_name(identifier_node); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)identifier_node, NULL); + } +} + +// collect aliases defined in a scope bounded by scope_start and scope_end +void collect_aliases_in_scope +( + const cypher_astnode_t *root, // the query root + uint scope_start, // start index of scope + uint scope_end, // end index of scope + rax *identifiers // rax to populate with identifiers +) { + ASSERT(scope_start != scope_end); + ASSERT(identifiers != NULL); + + for(uint i = scope_start; i < scope_end; i ++) { + const cypher_astnode_t *clause = cypher_astnode_type(root) == + CYPHER_AST_QUERY ? + cypher_ast_query_get_clause(root, i) : + cypher_ast_query_get_clause( + cypher_ast_call_subquery_get_query(root), i); + cypher_astnode_type_t type = cypher_astnode_type(clause); + + if(type == CYPHER_AST_WITH) { + // the WITH clause contains either + // aliases or its own STAR projection + _collect_with_projections(clause, identifiers); + } else if(type == CYPHER_AST_MATCH) { + // the MATCH clause contains one pattern of N paths + const cypher_astnode_t *pattern = + cypher_ast_match_get_pattern(clause); + _collect_aliases_in_pattern(pattern, identifiers); + } else if(type == CYPHER_AST_CREATE) { + // the CREATE clause contains one pattern of N paths + const cypher_astnode_t *pattern = + cypher_ast_create_get_pattern(clause); + _collect_aliases_in_pattern(pattern, identifiers); + } else if(type == CYPHER_AST_MERGE) { + // the MERGE clause contains one path + const cypher_astnode_t *path = + cypher_ast_merge_get_pattern_path(clause); + _collect_aliases_in_path(path, identifiers); + } else if(type == CYPHER_AST_UNWIND) { + // the UNWIND clause introduces one alias + const cypher_astnode_t *unwind_alias = + cypher_ast_unwind_get_alias(clause); + const char *identifier = + cypher_ast_identifier_get_name(unwind_alias); + raxTryInsert(identifiers, (unsigned char *)identifier, + strlen(identifier), (void *)unwind_alias, NULL); + } else if(type == CYPHER_AST_CALL) { + _collect_call_projections(clause, identifiers); + } else if(type == CYPHER_AST_CALL_SUBQUERY) { + _collect_call_subquery_projections(clause, identifiers); + } + } +} diff --git a/src/ast/ast_shared.h b/src/ast/ast_shared.h index 28fde7bfea..5faa7d208b 100644 --- a/src/ast/ast_shared.h +++ b/src/ast/ast_shared.h @@ -1,13 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once -#include "../arithmetic/arithmetic_expression.h" #include "ast.h" +#include "../errors/errors.h" +#include "../arithmetic/arithmetic_expression.h" struct AR_ExpNode; @@ -83,13 +87,13 @@ typedef struct { PropertyMap *properties; // edge properties set } EdgeCreateCtx; -// Context describing a relationship in a CREATE or MERGE clause +// context describing a relationship in a CREATE or MERGE clause typedef struct { - int node_idx; // node record index - int *labelsId; // array of node labels id - const char *alias; // node alias - const char **labels; // node labels - PropertyMap *properties; // node properties set + int node_idx; // node record index + int *labelsId; // array of node labels id + const char *alias; // node alias + const char **labels; // node labels + PropertyMap *properties; // node properties set } NodeCreateCtx; AST_Operator AST_ConvertOperatorNode(const cypher_operator_t *op); @@ -113,3 +117,11 @@ EntityUpdateEvalCtx *UpdateCtx_Clone(const EntityUpdateEvalCtx *ctx); void UpdateCtx_Clear(EntityUpdateEvalCtx *ctx); void UpdateCtx_Free(EntityUpdateEvalCtx *ctx); +// collect aliases defined in a scope bounded by scope_start and scope_end +void collect_aliases_in_scope +( + const cypher_astnode_t *root, // the query root + uint scope_start, // start index of scope + uint scope_end, // end index of scope + rax *identifiers // rax to populate with identifiers +); diff --git a/src/ast/ast_validations.c b/src/ast/ast_validations.c index 74d214a853..360d20cb58 100644 --- a/src/ast/ast_validations.c +++ b/src/ast/ast_validations.c @@ -1,19 +1,23 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "ast.h" #include "util.h" #include "astnode.h" -#include "../errors.h" #include "ast_shared.h" #include "../util/arr.h" #include "ast_visitor.h" +#include "../errors/errors.h" #include "../util/rax_extensions.h" #include "../procedures/procedure.h" +#include "../execution_plan/ops/op.h" #include "../arithmetic/arithmetic_expression.h" typedef enum { @@ -26,11 +30,12 @@ typedef struct { rax *defined_identifiers; // identifiers environment cypher_astnode_type_t clause; // top-level clause type is_union_all union_all; // union type (regular or ALL) + bool ignore_identifiers; // ignore identifiers in case `RETURN *` was met in a call {} clause } validations_ctx; // ast validation visitor mappings -// number of ast-node types: _MAX_VT_OFF = sizeof(struct cypher_astnode_vts) / sizeof(struct cypher_astnode_vt *) = 114 -static visit validations_mapping[114]; +// number of ast-node types: _MAX_VT_OFF = sizeof(struct cypher_astnode_vts) / sizeof(struct cypher_astnode_vt *) = 115 +static visit validations_mapping[115]; // validate that allShortestPaths is in a supported place static bool _ValidateAllShortestPaths @@ -100,7 +105,7 @@ static bool _ValidateShortestPaths return true; } -// get aliases of a WITH clause +// introduce aliases of a WITH clause to the bound vars // return true if no errors where encountered, false otherwise static bool _AST_GetWithAliases ( @@ -127,7 +132,7 @@ static bool _AST_GetWithAliases // Retrieve "a" from "WITH a" const cypher_astnode_t *expr = cypher_ast_projection_get_expression(child); if(cypher_astnode_type(expr) != CYPHER_AST_IDENTIFIER) { - ErrorCtx_SetError("WITH clause projections must be aliased"); + ErrorCtx_SetError(EMSG_WITH_PROJ_MISSING_ALIAS); raxFree(local_env); return false; } @@ -135,11 +140,14 @@ static bool _AST_GetWithAliases } raxInsert(aliases, (unsigned char *)alias, strlen(alias), NULL, NULL); - // check for duplicate column names - if(raxTryInsert(local_env, (unsigned char *)alias, strlen(alias), NULL, NULL) == 0) { - ErrorCtx_SetError("Error: Multiple result columns with the same name are not supported."); - raxFree(local_env); - return false; + // check for duplicate column names (other than internal representation + // of outer-context variables) + if(raxTryInsert(local_env, (unsigned char *)alias, strlen(alias), NULL, + NULL) == 0 && + alias[0] != '@') { + ErrorCtx_SetError(EMSG_SAME_RESULT_COLUMN_NAME); + raxFree(local_env); + return false; } } @@ -177,7 +185,7 @@ static void _AST_GetProcCallAliases } } -// make sure multi-hop traversals are not aliased +// make sure multi-hop traversals has length greater than or equal to zero static AST_Validation _ValidateMultiHopTraversal ( const cypher_astnode_t *edge, // ast-node to validate @@ -198,25 +206,11 @@ static AST_Validation _ValidateMultiHopTraversal // Validate specified range if(start > end) { - ErrorCtx_SetError("Variable length path, maximum number of hops must be greater or equal to minimum number of hops."); + ErrorCtx_SetError(EMSG_VAR_LEN_INVALID_RANGE); return AST_INVALID; } - - if(start <= 1 && start == end) { - return AST_VALID; - } - - // Check if the relation has an alias - const cypher_astnode_t *ast_identifier = cypher_ast_rel_pattern_get_identifier(edge); - if(!ast_identifier) { - return AST_VALID; - } - const char *identifier = cypher_ast_identifier_get_name(ast_identifier); - ErrorCtx_SetError("RedisGraph does not support alias of variable-length traversal edges '%s'. \ - Instead, use a query in the style of: 'MATCH p = (a)-[*]->(b) RETURN relationships(p)'.", - identifier); - return AST_INVALID; + return AST_VALID; } // Verify that MERGE doesn't redeclare bound relations, that one reltype is specified for unbound relations, @@ -229,7 +223,7 @@ static AST_Validation _ValidateMergeRelation // Verify that this is not a variable length relationship const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(entity); if(range) { - ErrorCtx_SetError("Variable length relationships cannot be used in MERGE"); + ErrorCtx_SetError(EMSG_VAR_LEN, "MERGE"); return AST_INVALID; } @@ -239,7 +233,7 @@ static AST_Validation _ValidateMergeRelation alias = cypher_ast_identifier_get_name(identifier); // Verify that we're not redeclaring a bound variable if(raxFind(defined_aliases, (unsigned char *)alias, strlen(alias)) != raxNotFound) { - ErrorCtx_SetError("The bound variable %s' can't be redeclared in a MERGE clause", alias); + ErrorCtx_SetError(EMSG_REDECLARE, "variable", alias, "MERGE"); return AST_INVALID; } } @@ -247,7 +241,7 @@ static AST_Validation _ValidateMergeRelation // Exactly one reltype should be specified for the introduced edge uint reltype_count = cypher_ast_rel_pattern_nreltypes(entity); if(reltype_count != 1) { - ErrorCtx_SetError("Exactly one relationship type must be specified for each relation in a MERGE pattern."); + ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "MERGE"); return AST_INVALID; } @@ -281,7 +275,7 @@ static AST_Validation _ValidateMergeNode // If the entity is already bound, the MERGE pattern should not introduce labels or properties if(cypher_ast_node_pattern_nlabels(entity) || cypher_ast_node_pattern_get_properties(entity)) { - ErrorCtx_SetError("The bound node '%s' can't be redeclared in a MERGE clause", alias); + ErrorCtx_SetError(EMSG_REDECLARE, "node", alias, "MERGE"); return AST_INVALID; } @@ -298,7 +292,7 @@ static AST_Validation _ValidateCreateRelation if(identifier) { const char *alias = cypher_ast_identifier_get_name(identifier); if(raxFind(defined_aliases, (unsigned char *)alias, strlen(alias)) != raxNotFound) { - ErrorCtx_SetError("The bound variable '%s' can't be redeclared in a CREATE clause", alias); + ErrorCtx_SetError(EMSG_REDECLARE, "variable", alias, "CREATE"); return AST_INVALID; } } @@ -321,7 +315,7 @@ static AST_Validation _Validate_CREATE_Entities if(identifier) { const char *alias = cypher_ast_identifier_get_name(identifier); if(raxFind(defined_aliases, (unsigned char *)alias, strlen(alias)) != raxNotFound) { - ErrorCtx_SetError("The bound variable '%s' can't be redeclared in a CREATE clause", alias); + ErrorCtx_SetError(EMSG_REDECLARE, "variable", alias, "CREATE"); return AST_INVALID; } } @@ -338,7 +332,7 @@ static AST_Validation _Validate_referred_identifier ) { int len = strlen(identifier); if(raxFind(defined_identifiers, (unsigned char *)identifier, len) == raxNotFound) { - ErrorCtx_SetError("%.*s not defined", len, identifier); + ErrorCtx_SetError(EMSG_NOT_DEFINED_LEN, len, identifier); return AST_INVALID; } @@ -354,51 +348,51 @@ static VISITOR_STRATEGY _Validate_list_comprehension ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(start) { - const cypher_astnode_t *id = cypher_ast_list_comprehension_get_identifier(n); - const char *identifier = cypher_ast_identifier_get_name(id); - bool is_new = (raxFind(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier)) == raxNotFound); + // we enter ONLY when start=true, so no check is needed - // Introduce local identifier if it is not yet introduced - if(is_new) { - raxInsert(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL, NULL); - } + const cypher_astnode_t *id = cypher_ast_list_comprehension_get_identifier(n); + const char *identifier = cypher_ast_identifier_get_name(id); + bool is_new = (raxFind(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier)) == raxNotFound); - // Visit expression-children - // Visit expression - const cypher_astnode_t *exp = cypher_ast_list_comprehension_get_expression(n); - if(exp) { - AST_Visitor_visit(exp, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } - } + // Introduce local identifier if it is not yet introduced + if(is_new) { + raxInsert(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL, NULL); + } - // Visit predicate - const cypher_astnode_t *pred = cypher_ast_list_comprehension_get_predicate(n); - if(pred) { - AST_Visitor_visit(pred, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // Visit expression-children + // Visit expression + const cypher_astnode_t *exp = cypher_ast_list_comprehension_get_expression(n); + if(exp) { + AST_Visitor_visit(exp, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } + } - // Visit eval - const cypher_astnode_t *eval = cypher_ast_list_comprehension_get_eval(n); - if(eval) { - AST_Visitor_visit(eval, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // Visit predicate + const cypher_astnode_t *pred = cypher_ast_list_comprehension_get_predicate(n); + if(pred) { + AST_Visitor_visit(pred, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } + } - // list comprehension identifier is no longer bound, remove it from bound vars - // if it was introduced - if(is_new) { - raxRemove(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL); + // Visit eval + const cypher_astnode_t *eval = cypher_ast_list_comprehension_get_eval(n); + if(eval) { + AST_Visitor_visit(eval, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } } + // list comprehension identifier is no longer bound, remove it from bound vars + // if it was introduced + if(is_new) { + raxRemove(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL); + } + // do not traverse children return VISITOR_CONTINUE; } @@ -412,58 +406,58 @@ static VISITOR_STRATEGY _Validate_pattern_comprehension ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(start) { - const cypher_astnode_t *id = cypher_ast_pattern_comprehension_get_identifier(n); - bool is_new; - const char *identifier; - if(id) { - identifier = cypher_ast_identifier_get_name(id); - is_new = (raxFind(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier)) == raxNotFound); - } - else { - is_new = false; - } + // we enter ONLY when start=true, so no check is needed - // Introduce local identifier if it is not yet introduced - if(is_new) { - raxInsert(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL, NULL); - } + const cypher_astnode_t *id = cypher_ast_pattern_comprehension_get_identifier(n); + bool is_new; + const char *identifier; + if(id) { + identifier = cypher_ast_identifier_get_name(id); + is_new = (raxFind(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier)) == raxNotFound); + } + else { + is_new = false; + } - // Visit expression-children - // Visit pattern - const cypher_astnode_t *pattern = cypher_ast_pattern_comprehension_get_pattern(n); - if(pattern) { - AST_Visitor_visit(pattern, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } - } + // Introduce local identifier if it is not yet introduced + if(is_new) { + raxInsert(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL, NULL); + } - // Visit predicate - const cypher_astnode_t *pred = cypher_ast_pattern_comprehension_get_predicate(n); - if(pred) { - AST_Visitor_visit(pred, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // Visit expression-children + // Visit pattern + const cypher_astnode_t *pattern = cypher_ast_pattern_comprehension_get_pattern(n); + if(pattern) { + AST_Visitor_visit(pattern, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } + } - // Visit eval - const cypher_astnode_t *eval = cypher_ast_pattern_comprehension_get_eval(n); - if(eval) { - AST_Visitor_visit(eval, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // Visit predicate + const cypher_astnode_t *pred = cypher_ast_pattern_comprehension_get_predicate(n); + if(pred) { + AST_Visitor_visit(pred, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } + } - // pattern comprehension identifier is no longer bound, remove it from bound vars - // if it was introduced - if(is_new) { - raxRemove(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL); + // Visit eval + const cypher_astnode_t *eval = cypher_ast_pattern_comprehension_get_eval(n); + if(eval) { + AST_Visitor_visit(eval, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } } + // pattern comprehension identifier is no longer bound, remove it from bound vars + // if it was introduced + if(is_new) { + raxRemove(vctx->defined_identifiers, (unsigned char *)identifier, strlen(identifier), NULL); + } + // do not traverse children return VISITOR_CONTINUE; } @@ -477,7 +471,7 @@ static VISITOR_STRATEGY _Validate_identifier ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(!start) { + if(!start || vctx->ignore_identifiers) { return VISITOR_CONTINUE; } @@ -498,15 +492,15 @@ static VISITOR_STRATEGY _Validate_map ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(start) { - // traverse the entries of the map - uint nentries = cypher_ast_map_nentries(n); - for (uint i = 0; i < nentries; i++) { - const cypher_astnode_t *exp = cypher_ast_map_get_value(n, i); - AST_Visitor_visit(exp, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // we enter ONLY when start=true, so no check is needed + + // traverse the entries of the map + uint nentries = cypher_ast_map_nentries(n); + for (uint i = 0; i < nentries; i++) { + const cypher_astnode_t *exp = cypher_ast_map_get_value(n, i); + AST_Visitor_visit(exp, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } } @@ -523,12 +517,12 @@ static VISITOR_STRATEGY _Validate_projection ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(start) { - const cypher_astnode_t *exp = cypher_ast_projection_get_expression(n); - AST_Visitor_visit(exp, visitor); - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // we enter ONLY when start=true, so no check is needed + + const cypher_astnode_t *exp = cypher_ast_projection_get_expression(n); + AST_Visitor_visit(exp, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } // do not traverse children @@ -543,13 +537,13 @@ static AST_Validation _ValidateFunctionCall ) { // check existence of the function-name if(!AR_FuncExists(funcName)) { - ErrorCtx_SetError("Unknown function '%s'", funcName); + ErrorCtx_SetError(EMSG_UNKNOWN_FUNCTION, funcName); return AST_INVALID; } if(!include_aggregates && AR_FuncIsAggregate(funcName)) { // Provide a unique error for using aggregate functions from inappropriate contexts - ErrorCtx_SetError("Invalid use of aggregating function '%s'", funcName); + ErrorCtx_SetError(EMSG_INVALID_USE_OF_AGGREGATION_FUNCTION, funcName); return AST_INVALID; } @@ -574,14 +568,14 @@ static VISITOR_STRATEGY _Validate_apply_all_operator // Verify that this is a COUNT call. if(strcasecmp(func_name, "COUNT")) { - ErrorCtx_SetError("COUNT is the only function which can accept * as an argument"); + ErrorCtx_SetError(EMSG_INVALID_USAGE_OF_STAR_PARAMETER); return VISITOR_BREAK; } // Verify that DISTINCT is not specified. if(cypher_ast_apply_all_operator_get_distinct(n)) { // TODO consider opening a parser error, this construction is invalid in Neo's parser. - ErrorCtx_SetError("Cannot specify both DISTINCT and * in COUNT(DISTINCT *)"); + ErrorCtx_SetError(EMSG_INVALID_USAGE_OF_DISTINCT_STAR_PARAMETER); return VISITOR_BREAK; } @@ -645,7 +639,7 @@ static VISITOR_STRATEGY _Validate_reduce // check if the variable has already been introduced const char *var_str = cypher_ast_identifier_get_name(init_node); if(raxFind(vctx->defined_identifiers, (unsigned char *)var_str, strlen(var_str)) == raxNotFound) { - ErrorCtx_SetError("%s not defined.", var_str); + ErrorCtx_SetError(EMSG_NOT_DEFINED, var_str); return VISITOR_BREAK; } } @@ -662,7 +656,7 @@ static VISITOR_STRATEGY _Validate_reduce if(cypher_astnode_type(list_var) == CYPHER_AST_IDENTIFIER) { const char *list_var_str = cypher_ast_identifier_get_name(list_var); if(raxFind(vctx->defined_identifiers, (unsigned char *) list_var_str, strlen(list_var_str)) == raxNotFound) { - ErrorCtx_SetError("%s not defined", list_var_str); + ErrorCtx_SetError(EMSG_NOT_DEFINED, list_var_str); return VISITOR_BREAK; } } @@ -676,7 +670,7 @@ static VISITOR_STRATEGY _Validate_reduce // make sure that the eval-expression exists const cypher_astnode_t *eval_node = cypher_ast_reduce_get_eval(n); if(!eval_node) { - ErrorCtx_SetError("No eval expression given in reduce"); + ErrorCtx_SetError(EMSG_MISSING_EVAL_EXP_IN_REDUCE); return VISITOR_BREAK; } @@ -731,7 +725,7 @@ static AST_Validation _ValidateInlinedProperties // Emit an error if the properties are not presented as a map, as in: // MATCH (p {invalid_property_construction}) RETURN p if(cypher_astnode_type(props) != CYPHER_AST_MAP) { - ErrorCtx_SetError("Encountered unhandled type in inlined properties."); + ErrorCtx_SetError(EMSG_UNHANDLED_TYPE_INLINE_PROPERTIES); return AST_INVALID; } @@ -745,7 +739,7 @@ static AST_Validation _ValidateInlinedProperties if(patterns_count > 0) { // Encountered query of the form: // MATCH (a {prop: ()-[]->()}) RETURN a - ErrorCtx_SetError("Encountered unhandled type in inlined properties."); + ErrorCtx_SetError(EMSG_UNHANDLED_TYPE_INLINE_PROPERTIES); return AST_INVALID; } } @@ -775,19 +769,19 @@ static VISITOR_STRATEGY _Validate_rel_pattern // Validate that each relation has exactly one type uint reltype_count = cypher_ast_rel_pattern_nreltypes(n); if(reltype_count != 1) { - ErrorCtx_SetError("Exactly one relationship type must be specified for CREATE"); + ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "CREATE"); return VISITOR_BREAK; } // Validate that each relation being created is directed if(cypher_ast_rel_pattern_get_direction(n) == CYPHER_REL_BIDIRECTIONAL) { - ErrorCtx_SetError("Only directed relationships are supported in CREATE"); + ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP); return VISITOR_BREAK; } // Validate that each relation being created is not variable length relationship if(range) { - ErrorCtx_SetError("Variable length relationships cannot be used in CREATE"); + ErrorCtx_SetError(EMSG_VAR_LEN, "CREATE"); return VISITOR_BREAK; } } @@ -802,29 +796,32 @@ static VISITOR_STRATEGY _Validate_rel_pattern } const cypher_astnode_t *alias_node = cypher_ast_rel_pattern_get_identifier(n); - if(!alias_node) { - return VISITOR_RECURSE; // Skip unaliased entities. - } - const char *alias = cypher_ast_identifier_get_name(alias_node); - void *alias_type = raxFind(vctx->defined_identifiers, (unsigned char *)alias, strlen(alias)); - if(alias_type == raxNotFound) { - raxInsert(vctx->defined_identifiers, (unsigned char *)alias, strlen(alias), (void *)T_EDGE, NULL); - return VISITOR_RECURSE; + if(!alias_node && !range) { + return VISITOR_RECURSE; // Skip unaliased, single-hop entities. } - if(alias_type != (void *)T_EDGE && alias_type != NULL) { - ErrorCtx_SetError("The alias '%s' was specified for both a node and a relationship.", alias); + // If this is a multi-hop traversal, validate it accordingly + if(range && _ValidateMultiHopTraversal(n, range) == AST_INVALID) { return VISITOR_BREAK; } - if(vctx->clause == CYPHER_AST_MATCH && alias_type != NULL) { - ErrorCtx_SetError("Cannot use the same relationship variable '%s' for multiple patterns.", alias); - return VISITOR_BREAK; - } + if(alias_node) { + const char *alias = cypher_ast_identifier_get_name(alias_node); + void *alias_type = raxFind(vctx->defined_identifiers, (unsigned char *)alias, strlen(alias)); + if(alias_type == raxNotFound) { + raxInsert(vctx->defined_identifiers, (unsigned char *)alias, strlen(alias), (void *)T_EDGE, NULL); + return VISITOR_RECURSE; + } + + if(alias_type != (void *)T_EDGE && alias_type != NULL) { + ErrorCtx_SetError(EMSG_SAME_ALIAS_NODE_RELATIONSHIP, alias); + return VISITOR_BREAK; + } - // If this is a multi-hop traversal, validate it accordingly - if(range && _ValidateMultiHopTraversal(n, range) == AST_VALID) { - return VISITOR_BREAK; + if(vctx->clause == CYPHER_AST_MATCH && alias_type != NULL) { + ErrorCtx_SetError(EMSG_SAME_ALIAS_MULTIPLE_PATTERNS, alias); + return VISITOR_BREAK; + } } return VISITOR_RECURSE; @@ -859,7 +856,7 @@ static VISITOR_STRATEGY _Validate_node_pattern } else { void *alias_type = raxFind(vctx->defined_identifiers, (unsigned char *)alias, strlen(alias)); if(alias_type != raxNotFound && alias_type != NULL && alias_type != (void *)T_NODE) { - ErrorCtx_SetError("The alias '%s' was specified for both a node and a relationship.", alias); + ErrorCtx_SetError(EMSG_SAME_ALIAS_NODE_RELATIONSHIP, alias); return VISITOR_BREAK; } } @@ -886,14 +883,14 @@ static VISITOR_STRATEGY _Validate_shortest_path const cypher_astnode_t *start = cypher_ast_node_pattern_get_identifier(cypher_ast_pattern_path_get_element(path, 0)); const cypher_astnode_t *end = cypher_ast_node_pattern_get_identifier(cypher_ast_pattern_path_get_element(path, elements - 1)); if(start == NULL || end == NULL) { - ErrorCtx_SetError("A shortestPath requires bound nodes"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_BOUND_NODES); return VISITOR_BREAK; } const char *start_id = cypher_ast_identifier_get_name(start); const char *end_id = cypher_ast_identifier_get_name(end); if(raxFind(vctx->defined_identifiers, (unsigned char *)start_id, strlen(start_id)) == raxNotFound || raxFind(vctx->defined_identifiers, (unsigned char *)end_id, strlen(end_id)) == raxNotFound) { - ErrorCtx_SetError("A shortestPath requires bound nodes"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_BOUND_NODES); return VISITOR_BREAK; } return VISITOR_RECURSE; @@ -908,7 +905,7 @@ static VISITOR_STRATEGY _Validate_shortest_path const cypher_astnode_t *start = cypher_ast_range_get_start(r); if(start) min_hops = AST_ParseIntegerNode(start); if(min_hops != 1) { - ErrorCtx_SetError("allShortestPaths(...) does not support a minimal length different from 1"); + ErrorCtx_SetError(EMSG_ALLSHORTESTPATH_MINIMAL_LENGTH); break; } } @@ -974,7 +971,7 @@ static AST_Validation _Validate_LIMIT_SKIP_Modifiers // The value validation of integer node or parameter node is done in run time evaluation. if(cypher_astnode_type(limit) != CYPHER_AST_INTEGER && cypher_astnode_type(limit) != CYPHER_AST_PARAMETER) { - ErrorCtx_SetError("LIMIT specified value of invalid type, must be a positive integer"); + ErrorCtx_SetError(EMSG_LIMIT_MUST_BE_NON_NEGATIVE); return AST_INVALID; } } @@ -984,7 +981,7 @@ static AST_Validation _Validate_LIMIT_SKIP_Modifiers // The value validation of integer node or parameter node is done in run time evaluation. if(cypher_astnode_type(skip) != CYPHER_AST_INTEGER && cypher_astnode_type(skip) != CYPHER_AST_PARAMETER) { - ErrorCtx_SetError("SKIP specified value of invalid type, must be a positive integer"); + ErrorCtx_SetError(EMSG_SKIP_MUST_BE_NON_NEGATIVE); return AST_INVALID; } } @@ -997,51 +994,28 @@ static AST_Validation _ValidateUnion_Clauses ( const AST *ast // ast-node ) { - // get amount of UNION clauses AST_Validation res = AST_VALID; + uint *union_indices = AST_GetClauseIndices(ast, CYPHER_AST_UNION); uint union_clause_count = array_len(union_indices); array_free(union_indices); - if(union_clause_count == 0) { - return AST_VALID; - } + if(union_clause_count != 0) { + // Require all RETURN clauses to perform the exact same projection + uint *return_indices = AST_GetClauseIndices(ast, CYPHER_AST_RETURN); + uint return_clause_count = array_len(return_indices); - // Require all RETURN clauses to perform the exact same projection - uint *return_indices = AST_GetClauseIndices(ast, CYPHER_AST_RETURN); - uint return_clause_count = array_len(return_indices); - - // We should have one more RETURN clauses than we have UNION clauses. - if(return_clause_count != union_clause_count + 1) { - ErrorCtx_SetError("Found %d UNION clauses but only %d RETURN clauses.", union_clause_count, - return_clause_count); - array_free(return_indices); - return AST_INVALID; - } - - const cypher_astnode_t *return_clause = cypher_ast_query_get_clause(ast->root, return_indices[0]); - uint proj_count = cypher_ast_return_nprojections(return_clause); - const char *projections[proj_count]; - - for(uint j = 0; j < proj_count; j++) { - const cypher_astnode_t *proj = cypher_ast_return_get_projection(return_clause, j); - const cypher_astnode_t *alias_node = cypher_ast_projection_get_alias(proj); - if(alias_node == NULL) { - // The projection was not aliased, so the projection itself must be an identifier. - alias_node = cypher_ast_projection_get_expression(proj); - ASSERT(cypher_astnode_type(alias_node) == CYPHER_AST_IDENTIFIER); + // We should have one more RETURN clauses than we have UNION clauses. + if(return_clause_count != union_clause_count + 1) { + ErrorCtx_SetError(EMSG_UNION_MISSING_RETURNS, union_clause_count, + return_clause_count); + array_free(return_indices); + return AST_INVALID; } - const char *alias = cypher_ast_identifier_get_name(alias_node); - projections[j] = alias; - } - for(uint i = 1; i < return_clause_count; i++) { - return_clause = cypher_ast_query_get_clause(ast->root, return_indices[i]); - if(proj_count != cypher_ast_return_nprojections(return_clause)) { - ErrorCtx_SetError("All sub queries in a UNION must have the same column names."); - res = AST_INVALID; - goto cleanup; - } + const cypher_astnode_t *return_clause = cypher_ast_query_get_clause(ast->root, return_indices[0]); + uint proj_count = cypher_ast_return_nprojections(return_clause); + const char *projections[proj_count]; for(uint j = 0; j < proj_count; j++) { const cypher_astnode_t *proj = cypher_ast_return_get_projection(return_clause, j); @@ -1052,16 +1026,60 @@ static AST_Validation _ValidateUnion_Clauses ASSERT(cypher_astnode_type(alias_node) == CYPHER_AST_IDENTIFIER); } const char *alias = cypher_ast_identifier_get_name(alias_node); - if(strcmp(projections[j], alias) != 0) { - ErrorCtx_SetError("All sub queries in a UNION must have the same column names."); + projections[j] = alias; + } + + for(uint i = 1; i < return_clause_count; i++) { + return_clause = cypher_ast_query_get_clause(ast->root, return_indices[i]); + if(proj_count != cypher_ast_return_nprojections(return_clause)) { + ErrorCtx_SetError(EMSG_UNION_MISMATCHED_RETURNS); res = AST_INVALID; goto cleanup; } + + for(uint j = 0; j < proj_count; j++) { + const cypher_astnode_t *proj = cypher_ast_return_get_projection(return_clause, j); + const cypher_astnode_t *alias_node = cypher_ast_projection_get_alias(proj); + if(alias_node == NULL) { + // The projection was not aliased, so the projection itself must be an identifier. + alias_node = cypher_ast_projection_get_expression(proj); + ASSERT(cypher_astnode_type(alias_node) == CYPHER_AST_IDENTIFIER); + } + const char *alias = cypher_ast_identifier_get_name(alias_node); + if(strcmp(projections[j], alias) != 0) { + ErrorCtx_SetError(EMSG_UNION_MISMATCHED_RETURNS); + res = AST_INVALID; + goto cleanup; + } + } + } + + cleanup: + array_free(return_indices); + if(res == AST_INVALID) { + return res; } } -cleanup: - array_free(return_indices); + // validate union clauses of subqueries + uint *call_subquery_indices = AST_GetClauseIndices(ast, + CYPHER_AST_CALL_SUBQUERY); + uint n_subqueries = array_len(call_subquery_indices); + + for(uint i = 0; i < n_subqueries; i++) { + AST subquery_ast = { + .root = cypher_ast_call_subquery_get_query( + cypher_ast_query_get_clause(ast->root, + call_subquery_indices[i])), + }; + + if(_ValidateUnion_Clauses(&subquery_ast) == AST_INVALID) { + res = AST_INVALID; + break; + } + } + array_free(call_subquery_indices); + return res; } @@ -1092,7 +1110,7 @@ static VISITOR_STRATEGY _Validate_CALL_Clause proc = Proc_Get(proc_name); if(proc == NULL) { - ErrorCtx_SetError("Procedure `%s` is not registered", proc_name); + ErrorCtx_SetError(EMSG_PROCEDURE_NOT_REGISTERED, proc_name); goto cleanup; } @@ -1100,7 +1118,7 @@ static VISITOR_STRATEGY _Validate_CALL_Clause if(proc->argc != PROCEDURE_VARIABLE_ARG_COUNT) { unsigned int given_arg_count = cypher_ast_call_narguments(n); if(Procedure_Argc(proc) != given_arg_count) { - ErrorCtx_SetError("Procedure `%s` requires %d arguments, got %d", proc_name, proc->argc, + ErrorCtx_SetError(EMSG_PROCEDURE_INVALID_ARGUMENTS, proc_name, proc->argc, given_arg_count); goto cleanup; } @@ -1119,13 +1137,13 @@ static VISITOR_STRATEGY _Validate_CALL_Clause // make sure each yield output is mentioned only once if(!raxInsert(rax, (unsigned char *)identifier, strlen(identifier), NULL, NULL)) { - ErrorCtx_SetError("Variable `%s` already declared", identifier); + ErrorCtx_SetError(EMSG_VAIABLE_ALREADY_DECLARED, identifier); goto cleanup; } // make sure procedure is aware of output if(!Procedure_ContainsOutput(proc, identifier)) { - ErrorCtx_SetError("Procedure `%s` does not yield output `%s`", + ErrorCtx_SetError(EMSG_PROCEDURE_INVALID_OUTPUT, proc_name, identifier); goto cleanup; } @@ -1158,6 +1176,224 @@ static VISITOR_STRATEGY _Validate_CALL_Clause return VISITOR_CONTINUE; } +// validates that root does not contain (bound) identifiers. For instance, would +// fail on `MATCH (a) CALL {WITH a AS b RETURN b}` +static bool _ValidateSubqueryFirstWithClauseIdentifiers +( + const cypher_astnode_t *root // root to validate +) { + ASSERT(root != NULL); + + if(cypher_astnode_type(root) == CYPHER_AST_IDENTIFIER) { + return false; + } + + // recursively traverse all children + uint nchildren = cypher_astnode_nchildren(root); + for(uint i = 0; i < nchildren; i ++) { + const cypher_astnode_t *child = cypher_astnode_get_child(root, i); + if(!_ValidateSubqueryFirstWithClauseIdentifiers(child)) { + return false; + } + } + + return true; +} + +// validates a leading `WITH` clause of a subquery +static bool _ValidateCallInitialWith +( + const cypher_astnode_t *with_clause, // `WITH` clause to validate + validations_ctx *vctx // validation context +) { + bool found_simple = false; + bool found_non_simple = false; + + for(uint i = 0; i < cypher_ast_with_nprojections(with_clause); i++) { + const cypher_astnode_t *curr_proj = + cypher_ast_with_get_projection(with_clause, i); + const cypher_astnode_t *exp = + cypher_ast_projection_get_expression(curr_proj); + const cypher_astnode_type_t t = cypher_astnode_type(exp); + + if (t == CYPHER_AST_IDENTIFIER ) { + const cypher_astnode_t *alias = + cypher_ast_projection_get_alias(curr_proj); + // if this is an internal representation of a variable, skip it + if(alias != NULL && cypher_ast_identifier_get_name(alias)[0] == '@') { + continue; + } + const char *identifier = cypher_ast_identifier_get_name(exp); + int len = strlen(identifier); + if(found_non_simple || alias != NULL) { + return false; + } + found_simple = true; + } else { + // check that the import does not make reference to an outer scope + // identifier. This is invalid: + // 'WITH 1 AS a CALL {WITH a + 1 AS b RETURN b} RETURN b' + if(found_simple || + !_ValidateSubqueryFirstWithClauseIdentifiers(exp)) { + return false; + } + found_non_simple = true; + } + } + + // order by, predicates, limit and skips are not valid + if(cypher_ast_with_get_skip(with_clause) != NULL || + cypher_ast_with_get_limit(with_clause) != NULL || + cypher_ast_with_get_order_by(with_clause) != NULL || + cypher_ast_with_get_predicate(with_clause) != NULL) { + + return false; + } + + return true; +} + +// validate a CALL {} (subquery) clause +static VISITOR_STRATEGY _Validate_call_subquery +( + const cypher_astnode_t *n, // ast-node + bool start, // first traversal + ast_visitor *visitor // visitor +) { + validations_ctx *vctx = AST_Visitor_GetContext(visitor); + + vctx->clause = cypher_astnode_type(n); + + // create a query astnode with the body of the subquery as its body + cypher_astnode_t *body = cypher_ast_call_subquery_get_query(n); + uint nclauses = cypher_ast_query_nclauses(body); + + // clone the bound vars context. + rax *in_env = raxClone(vctx->defined_identifiers); + + // if there are no imports, set the env of bound-vars to the empty env + const cypher_astnode_t *first_clause = cypher_ast_query_get_clause(body, 0); + if(cypher_astnode_type(first_clause) != + CYPHER_AST_WITH) { + raxFree(vctx->defined_identifiers); + vctx->defined_identifiers = raxNew(); + } else { + // validate that the with imports (if exist) are simple, i.e., 'WITH a' + if(!_ValidateCallInitialWith(first_clause, vctx)) { + raxFree(in_env); + ErrorCtx_SetError(EMSG_CALLSUBQUERY_INVALID_REFERENCES); + return VISITOR_BREAK; + } + } + + // visit the subquery clauses + bool last_is_union = false; + for(uint i = 0; i < nclauses; i++) { + const cypher_astnode_t *clause = + cypher_ast_query_get_clause(body, i); + cypher_astnode_type_t type = cypher_astnode_type(clause); + + // if the current clause is a `UNION` clause, it has reset the bound + // vars env to the empty env. We compensate for that in case there is no + // initial `WITH` clause + if(last_is_union && type == CYPHER_AST_WITH) { + // set the env of bound-vars to the input env + raxFree(vctx->defined_identifiers); + vctx->defined_identifiers = raxClone(in_env); + + // validate that the with imports (if exist) are simple, i.e., + // 'WITH a' + if(!_ValidateCallInitialWith(clause, vctx)) { + raxFree(in_env); + ErrorCtx_SetError(EMSG_CALLSUBQUERY_INVALID_REFERENCES); + return VISITOR_BREAK; + } + } + + AST_Visitor_visit(clause, visitor); + if(ErrorCtx_EncounteredError()) { + raxFree(in_env); + return VISITOR_BREAK; + } + + if(type == CYPHER_AST_UNION) { + last_is_union = true; + } else if(type == CYPHER_AST_RETURN && + cypher_ast_return_has_include_existing(clause)){ + vctx->ignore_identifiers = true; + last_is_union = false; + } else { + last_is_union = false; + } + } + + // free the temporary environment + raxFree(vctx->defined_identifiers); + vctx->defined_identifiers = in_env; + + const cypher_astnode_t *last_clause = cypher_ast_query_get_clause(body, + nclauses-1); + bool is_returning = cypher_astnode_type(last_clause) == CYPHER_AST_RETURN; + + if(is_returning) { + // merge projected aliases from in_env into vctx->defined_identifiers + // make sure no returned aliases are bound + // notice: this can be done only once for the last branch of a UNION + // since the returned aliases are always the same + + const cypher_astnode_t *return_clause + = cypher_ast_query_get_clause(body, nclauses-1); + + uint n_projections = cypher_ast_return_nprojections(return_clause); + for(uint i = 0; i < n_projections; i++) { + const cypher_astnode_t *proj = + cypher_ast_return_get_projection(return_clause, i); + const char *var_name; + const cypher_astnode_t *identifier = + cypher_ast_projection_get_alias(proj); + const cypher_astnode_t *exp = + cypher_ast_projection_get_expression(proj); + if(identifier) { + var_name = cypher_ast_identifier_get_name(identifier); + if(exp && + cypher_astnode_type(exp) == CYPHER_AST_IDENTIFIER && + cypher_ast_identifier_get_name(exp)[0] == '@') { + // this is an artificial projection, skip it + continue; + } + } else { + var_name = cypher_ast_identifier_get_name(exp); + } + + if(!raxTryInsert(vctx->defined_identifiers, + (unsigned char *)var_name, strlen(var_name), NULL, NULL)) { + ErrorCtx_SetError( + EMSG_VAIABLE_ALREADY_DECLARED_IN_OUTER_SCOPE, + var_name); + return VISITOR_BREAK; + } + } + } + + // don't traverse children + return VISITOR_CONTINUE; +} + +// returns true if the clause is an updating clause, false otherwise +static bool _is_updating_clause +( + const cypher_astnode_t *clause // clause +) { + cypher_astnode_type_t type = cypher_astnode_type(clause); + + return type == CYPHER_AST_CREATE || + type == CYPHER_AST_MERGE || + type == CYPHER_AST_DELETE || + type == CYPHER_AST_SET || + type == CYPHER_AST_REMOVE || + type == CYPHER_AST_FOREACH; +} + // validate a WITH clause static VISITOR_STRATEGY _Validate_WITH_Clause ( @@ -1167,38 +1403,66 @@ static VISITOR_STRATEGY _Validate_WITH_Clause ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(start) { - vctx->clause = cypher_astnode_type(n); + vctx->clause = cypher_astnode_type(n); - if(!_AST_GetWithAliases(n, vctx->defined_identifiers)) { + if(_Validate_LIMIT_SKIP_Modifiers(cypher_ast_with_get_limit(n), + cypher_ast_with_get_skip(n)) == AST_INVALID) { + return VISITOR_BREAK; + } + + // manually traverse children. order by and predicate should be aware of the + // vars introduced in the with projections, but the projections should not + for(uint i = 0; i < cypher_ast_with_nprojections(n); i++) { + // visit the projection + const cypher_astnode_t *proj = cypher_ast_with_get_projection(n, i); + AST_Visitor_visit(proj, visitor); + if(ErrorCtx_EncounteredError()) { return VISITOR_BREAK; } + } - if(_Validate_LIMIT_SKIP_Modifiers(cypher_ast_with_get_limit(n), - cypher_ast_with_get_skip(n)) == AST_INVALID) { + // introduce WITH aliases to the bound vars context + if(!_AST_GetWithAliases(n, vctx->defined_identifiers)) { + return VISITOR_BREAK; + } + + // visit predicate clause + const cypher_astnode_t *predicate = cypher_ast_with_get_predicate(n); + if(predicate) { + AST_Visitor_visit(predicate, visitor); + if(ErrorCtx_EncounteredError()) { return VISITOR_BREAK; } + } - return VISITOR_RECURSE; + // visit ORDER BY clause + const cypher_astnode_t *order_by = cypher_ast_with_get_order_by(n); + if(order_by) { + AST_Visitor_visit(order_by, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; + } } // if one of the 'projections' is a star -> proceed with current env // otherwise build a new environment using the new column names (aliases) if(!cypher_ast_with_has_include_existing(n)) { - rax *new_env = raxNew(); + // free old env, set new one + raxFree(vctx->defined_identifiers); + vctx->defined_identifiers = raxNew(); + + // introduce the WITH aliases to the bound vars context for(uint i = 0; i < cypher_ast_with_nprojections(n); i++) { const cypher_astnode_t *proj = cypher_ast_with_get_projection(n, i); - const cypher_astnode_t *ast_alias = cypher_ast_projection_get_alias(proj); + const cypher_astnode_t *ast_alias = + cypher_ast_projection_get_alias(proj); if(!ast_alias) { ast_alias = cypher_ast_projection_get_expression(proj); } const char *alias = cypher_ast_identifier_get_name(ast_alias); - raxInsert(new_env, (unsigned char *)alias, strlen(alias), NULL, NULL); + raxInsert(vctx->defined_identifiers, (unsigned char *)alias, + strlen(alias), NULL, NULL); } - - // free old env, set new one - raxFree(vctx->defined_identifiers); - vctx->defined_identifiers = new_env; } return VISITOR_CONTINUE; @@ -1225,11 +1489,11 @@ static VISITOR_STRATEGY _Validate_DELETE_Clause // expecting an identifier or a function call // identifiers and calls that don't resolve to a node, path or edge // will raise an error at run-time - if(type != CYPHER_AST_IDENTIFIER && - type != CYPHER_AST_APPLY_OPERATOR && - type != CYPHER_AST_APPLY_ALL_OPERATOR && - type != CYPHER_AST_SUBSCRIPT_OPERATOR) { - ErrorCtx_SetError("DELETE can only be called on nodes, paths and relationships"); + if(type != CYPHER_AST_IDENTIFIER && + type != CYPHER_AST_APPLY_OPERATOR && + type != CYPHER_AST_APPLY_ALL_OPERATOR && + type != CYPHER_AST_SUBSCRIPT_OPERATOR) { + ErrorCtx_SetError(EMSG_DELETE_INVALID_ARGUMENTS); return VISITOR_BREAK; } } @@ -1252,7 +1516,7 @@ static VISITOR_STRATEGY _Validate_set_property const cypher_astnode_t *ast_prop = cypher_ast_set_property_get_property(n); const cypher_astnode_t *ast_entity = cypher_ast_property_operator_get_expression(ast_prop); if(cypher_astnode_type(ast_entity) != CYPHER_AST_IDENTIFIER) { - ErrorCtx_SetError("RedisGraph does not currently support non-alias references on the left-hand side of SET expressions"); + ErrorCtx_SetError(EMSG_SET_LHS_NON_ALIAS); return VISITOR_BREAK; } @@ -1293,7 +1557,7 @@ static VISITOR_STRATEGY _Validate_UNION_Clause if(vctx->union_all == NOT_DEFINED) { vctx->union_all = cypher_ast_union_has_all(n); } else if(vctx->union_all != cypher_ast_union_has_all(n)) { - ErrorCtx_SetError("Invalid combination of UNION and UNION ALL."); + ErrorCtx_SetError(EMSG_UNION_COMBINATION); return VISITOR_BREAK; } @@ -1371,63 +1635,62 @@ static VISITOR_STRATEGY _Validate_FOREACH_Clause ) { validations_ctx *vctx = visitor->ctx; - // first (and only) traversal - if(start) { - // build a new environment of bounded vars from the current one to be - // used in the traversal of the visitor in the clauses of the FOREACH - // clause - as they are local to the FOREACH clause - rax *orig_env = vctx->defined_identifiers; - rax *scoped_env = raxClone(orig_env); - vctx->defined_identifiers = scoped_env; - - // set the clause of the context - vctx->clause = CYPHER_AST_FOREACH; - - // visit FOREACH array expression - const cypher_astnode_t *list_node = - cypher_ast_foreach_get_expression(n); - AST_Visitor_visit(list_node, visitor); - - // introduce loop variable to bound vars - const cypher_astnode_t *identifier_node = - cypher_ast_foreach_get_identifier(n); - - const char *identifier = - cypher_ast_identifier_get_name(identifier_node); - - raxInsert(vctx->defined_identifiers, (unsigned char *) identifier, - strlen(identifier), NULL, NULL); - - // visit FOREACH loop body clauses - uint nclauses = cypher_ast_foreach_nclauses(n); - for(uint i = 0; i < nclauses; i++) { - const cypher_astnode_t *clause = cypher_ast_foreach_get_clause(n, i); - // make sure it is an updating clause - cypher_astnode_type_t child_clause_type = - cypher_astnode_type(clause); - if(child_clause_type != CYPHER_AST_CREATE && - child_clause_type != CYPHER_AST_SET && - child_clause_type != CYPHER_AST_REMOVE && - child_clause_type != CYPHER_AST_MERGE && - child_clause_type != CYPHER_AST_DELETE && - child_clause_type != CYPHER_AST_FOREACH - ) { - ErrorCtx_SetError("Error: Only updating clauses may reside in FOREACH"); - break; - } - - // visit the clause - AST_Visitor_visit(clause, visitor); + // we enter ONLY when start=true, so no check is needed + + // build a new environment of bounded vars from the current one to be + // used in the traversal of the visitor in the clauses of the FOREACH + // clause - as they are local to the FOREACH clause + rax *orig_env = vctx->defined_identifiers; + rax *scoped_env = raxClone(orig_env); + vctx->defined_identifiers = scoped_env; + + // set the clause of the context + vctx->clause = CYPHER_AST_FOREACH; + + // visit FOREACH array expression + const cypher_astnode_t *list_node = + cypher_ast_foreach_get_expression(n); + AST_Visitor_visit(list_node, visitor); + + // introduce loop variable to bound vars + const cypher_astnode_t *identifier_node = + cypher_ast_foreach_get_identifier(n); + + const char *identifier = + cypher_ast_identifier_get_name(identifier_node); + + raxInsert(vctx->defined_identifiers, (unsigned char *) identifier, + strlen(identifier), NULL, NULL); + + // visit FOREACH loop body clauses + uint nclauses = cypher_ast_foreach_nclauses(n); + for(uint i = 0; i < nclauses; i++) { + const cypher_astnode_t *clause = cypher_ast_foreach_get_clause(n, i); + // make sure it is an updating clause + cypher_astnode_type_t child_clause_type = + cypher_astnode_type(clause); + if(child_clause_type != CYPHER_AST_CREATE && + child_clause_type != CYPHER_AST_SET && + child_clause_type != CYPHER_AST_REMOVE && + child_clause_type != CYPHER_AST_MERGE && + child_clause_type != CYPHER_AST_DELETE && + child_clause_type != CYPHER_AST_FOREACH + ) { + ErrorCtx_SetError(EMSG_FOREACH_INVALID_BODY); + break; } - // restore original environment of bounded vars - vctx->defined_identifiers = orig_env; - raxFree(scoped_env); + // visit the clause + AST_Visitor_visit(clause, visitor); + } - // check for errors - if(ErrorCtx_EncounteredError()) { - return VISITOR_BREAK; - } + // restore original environment of bounded vars + vctx->defined_identifiers = orig_env; + raxFree(scoped_env); + + // check for errors + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; } // do not traverse children @@ -1443,13 +1706,44 @@ static VISITOR_STRATEGY _Validate_RETURN_Clause ) { validations_ctx *vctx = AST_Visitor_GetContext(visitor); - if(!start) { - return VISITOR_CONTINUE; - } - vctx->clause = cypher_astnode_type(n); uint num_return_projections = cypher_ast_return_nprojections(n); + // visit LIMIT and SKIP + if(_Validate_LIMIT_SKIP_Modifiers(cypher_ast_return_get_limit(n), cypher_ast_return_get_skip(n)) + == AST_INVALID) { + return VISITOR_BREAK; + } + + if(!cypher_ast_return_has_include_existing(n)) { + // check for duplicate column names + rax *rax = raxNew(); + const char **columns = AST_BuildReturnColumnNames(n); + uint column_count = array_len(columns); + + for (uint i = 0; i < column_count; i++) { + // column with same name is invalid + if(raxTryInsert(rax, (unsigned char *)columns[i], strlen(columns[i]), NULL, NULL) == 0) { + ErrorCtx_SetError(EMSG_SAME_RESULT_COLUMN_NAME); + break; + } + } + + raxFree(rax); + array_free(columns); + } + + // manually traverse children. order by and predicate should be aware of the + // vars introduced in the with projections, but the projections should not + for(uint i = 0; i < cypher_ast_return_nprojections(n); i++) { + // visit the projection + const cypher_astnode_t *proj = cypher_ast_return_get_projection(n, i); + AST_Visitor_visit(proj, visitor); + if(ErrorCtx_EncounteredError()) { + return VISITOR_BREAK; + } + } + // introduce bound vars for(uint i = 0; i < num_return_projections; i ++) { const cypher_astnode_t *child = cypher_ast_return_get_projection(n, i); @@ -1461,32 +1755,17 @@ static VISITOR_STRATEGY _Validate_RETURN_Clause raxInsert(vctx->defined_identifiers, (unsigned char *)alias, strlen(alias), NULL, NULL); } - if(_Validate_LIMIT_SKIP_Modifiers(cypher_ast_return_get_limit(n), cypher_ast_return_get_skip(n)) - == AST_INVALID) { + // visit ORDER BY clause + const cypher_astnode_t *order_by = cypher_ast_return_get_order_by(n); + if(order_by) { + AST_Visitor_visit(order_by, visitor); + if(ErrorCtx_EncounteredError()) { return VISITOR_BREAK; - } - - if(cypher_ast_return_has_include_existing(n)) { - return VISITOR_RECURSE; - } - - // check for duplicate column names - rax *rax = raxNew(); - const char **columns = AST_BuildReturnColumnNames(n); - uint column_count = array_len(columns); - - for (uint i = 0; i < column_count; i++) { - // column with same name is invalid - if(raxTryInsert(rax, (unsigned char *)columns[i], strlen(columns[i]), NULL, NULL) == 0) { - ErrorCtx_SetError("Error: Multiple result columns with the same name are not supported."); - break; } } - raxFree(rax); - array_free(columns); - - return !ErrorCtx_EncounteredError() ? VISITOR_RECURSE : VISITOR_BREAK; + // do not traverse children + return !ErrorCtx_EncounteredError() ? VISITOR_CONTINUE : VISITOR_BREAK; } // validate a MATCH clause @@ -1528,51 +1807,76 @@ static VISITOR_STRATEGY _Validate_index_creation } // A query must end in a RETURN clause, a procedure, or an updating clause -// (CREATE, MERGE, DELETE, SET, REMOVE or FOREACH) +// (CREATE, MERGE, DELETE, SET, REMOVE, FOREACH or CALL {}) static AST_Validation _ValidateQueryTermination ( const AST *ast // ast ) { ASSERT(ast != NULL); + const cypher_astnode_t *root = ast->root; uint clause_idx = 0; const cypher_astnode_t *return_clause = NULL; const cypher_astnode_t *following_clause = NULL; - uint clause_count = cypher_ast_query_nclauses(ast->root); + uint clause_count = cypher_ast_query_nclauses(root); - // libcypher-parser does not enforce clause sequence order: - // queries such as 'RETURN CREATE' and 'RETURN RETURN' are considered - // valid by the parser - // make sure the only clause following RETURN is UNION - - // get first instance of a RETURN clause - return_clause = AST_GetClause(ast, CYPHER_AST_RETURN, &clause_idx); - if(return_clause != NULL && clause_idx < clause_count - 1) { - // RETURN clause isn't the last clause - // the only clause which can follow a RETURN is the UNION clause - following_clause = AST_GetClauseByIdx(ast, clause_idx + 1); - if(cypher_astnode_type(following_clause) != CYPHER_AST_UNION) { - // unexpected clause following RETURN - ErrorCtx_SetError("Unexpected clause following RETURN"); - return AST_INVALID; - } - } - - const cypher_astnode_t *last_clause = cypher_ast_query_get_clause(ast->root, clause_count - 1); + const cypher_astnode_t *last_clause = cypher_ast_query_get_clause(root, + clause_count - 1); cypher_astnode_type_t type = cypher_astnode_type(last_clause); - if(type != CYPHER_AST_RETURN && - type != CYPHER_AST_CREATE && - type != CYPHER_AST_MERGE && - type != CYPHER_AST_DELETE && - type != CYPHER_AST_SET && - type != CYPHER_AST_CALL && - type != CYPHER_AST_REMOVE && + if(type != CYPHER_AST_RETURN && + type != CYPHER_AST_CREATE && + type != CYPHER_AST_MERGE && + type != CYPHER_AST_DELETE && + type != CYPHER_AST_SET && + type != CYPHER_AST_CALL && + type != CYPHER_AST_CALL_SUBQUERY && + type != CYPHER_AST_REMOVE && type != CYPHER_AST_FOREACH ) { - ErrorCtx_SetError("Query cannot conclude with %s (must be RETURN or an update clause)", - cypher_astnode_typestr(type)); + ErrorCtx_SetError(EMSG_QUERY_INVALID_LAST_CLAUSE, + cypher_astnode_typestr(type)); return AST_INVALID; } + + // if the last clause is CALL {}, it must be non-returning + if(type == CYPHER_AST_CALL_SUBQUERY) { + cypher_astnode_t *query = + cypher_ast_call_subquery_get_query(last_clause); + if(cypher_astnode_type(cypher_ast_query_get_clause(query, + cypher_ast_query_nclauses(query)-1)) == + CYPHER_AST_RETURN) { + ErrorCtx_SetError(EMSG_QUERY_INVALID_LAST_CLAUSE, + "a returning subquery"); + + return AST_INVALID; + } + } + + // validate that `UNION` is the only clause following a `RETURN` clause, and + // termination of embedded call {} clauses + bool last_was_return = false; + for(uint i = 0; i < clause_count; i++) { + const cypher_astnode_t *clause = cypher_ast_query_get_clause(root, i); + cypher_astnode_type_t type = cypher_astnode_type(clause); + if(type != CYPHER_AST_UNION && last_was_return) { + // unexpected clause following RETURN + ErrorCtx_SetError(EMSG_UNEXPECTED_CLAUSE_FOLLOWING_RETURN); + return AST_INVALID; + } else if(type == CYPHER_AST_RETURN) { + last_was_return = true; + } else if(type == CYPHER_AST_CALL_SUBQUERY) { + AST subquery_ast = { + .root = cypher_ast_call_subquery_get_query(clause) + }; + if(_ValidateQueryTermination(&subquery_ast) != AST_VALID) { + return AST_INVALID; + } + last_was_return = false; + } else { + last_was_return = false; + } + } + return AST_VALID; } @@ -1602,14 +1906,14 @@ static AST_Validation _ValidateQuerySequence const cypher_astnode_t *start_clause = cypher_ast_query_get_clause(ast->root, 0); if(cypher_astnode_type(start_clause) == CYPHER_AST_WITH && cypher_ast_with_has_include_existing(start_clause)) { - ErrorCtx_SetError("Query cannot begin with 'WITH *'."); + ErrorCtx_SetError(EMSG_QUERY_CANNOT_BEGIN_WITH, "WITH"); return AST_INVALID; } // The query cannot begin with a "RETURN *" projection. if(cypher_astnode_type(start_clause) == CYPHER_AST_RETURN && cypher_ast_return_has_include_existing(start_clause)) { - ErrorCtx_SetError("Query cannot begin with 'RETURN *'."); + ErrorCtx_SetError(EMSG_QUERY_CANNOT_BEGIN_WITH, "RETURN"); return AST_INVALID; } @@ -1631,27 +1935,28 @@ static AST_Validation _ValidateClauseOrder for(uint i = 0; i < clause_count; i ++) { const cypher_astnode_t *clause = cypher_ast_query_get_clause(ast->root, i); cypher_astnode_type_t type = cypher_astnode_type(clause); - encountered_updating_clause = (encountered_updating_clause || - (type == CYPHER_AST_CREATE || - type == CYPHER_AST_MERGE || - type == CYPHER_AST_DELETE || - type == CYPHER_AST_SET || - type == CYPHER_AST_REMOVE || - type == CYPHER_AST_FOREACH)); - if(encountered_updating_clause && (type == CYPHER_AST_MATCH || - type == CYPHER_AST_UNWIND || - type == CYPHER_AST_CALL)) { - ErrorCtx_SetError("A WITH clause is required to introduce %s after an updating clause.", - cypher_astnode_typestr(type)); + if(encountered_updating_clause && (type == CYPHER_AST_MATCH || + type == CYPHER_AST_UNWIND || + type == CYPHER_AST_CALL || + type == CYPHER_AST_CALL_SUBQUERY)) { + ErrorCtx_SetError(EMSG_MISSING_WITH, cypher_astnode_typestr(type)); return AST_INVALID; } + if(type == CYPHER_AST_UNION) { + encountered_optional_match = false; + encountered_updating_clause = false; + continue; + } + encountered_updating_clause = (encountered_updating_clause || + _is_updating_clause(clause)); if(type == CYPHER_AST_MATCH) { - // Check whether this match is optional. + // Check whether this match is optional bool current_clause_is_optional = cypher_ast_match_is_optional(clause); - // If the current clause is non-optional but we have already encountered an optional match, emit an error. + // If the current clause is non-optional but we have already + // encountered an optional match, emit an error if(!current_clause_is_optional && encountered_optional_match) { - ErrorCtx_SetError("A WITH clause is required to introduce a MATCH clause after an OPTIONAL MATCH."); + ErrorCtx_SetError(EMSG_MISSING_WITH_AFTER_MATCH); return AST_INVALID; } encountered_optional_match |= current_clause_is_optional; @@ -1661,6 +1966,15 @@ static AST_Validation _ValidateClauseOrder encountered_optional_match = false; encountered_updating_clause = false; } + + if(type == CYPHER_AST_CALL_SUBQUERY) { + AST subquery_ast = { + .root = cypher_ast_call_subquery_get_query(clause) + }; + if(_ValidateClauseOrder(&subquery_ast) != AST_VALID) { + return AST_INVALID; + } + } } return AST_VALID; @@ -1700,9 +2014,11 @@ static AST_Validation _ValidateScopes AST *ast // ast ) { // create a context for the traversal - validations_ctx ctx; - ctx.union_all = NOT_DEFINED; - ctx.defined_identifiers = raxNew(); + validations_ctx ctx = { + .union_all = NOT_DEFINED, + .defined_identifiers = raxNew(), + .ignore_identifiers = false + }; // create a visitor ast_visitor visitor = {&ctx, validations_mapping}; @@ -1721,7 +2037,7 @@ bool AST_ValidationsMappingInit(void) { // create a mapping for the validations // set default entries - for(uint i = 0; i < 114; i++) { + for(uint i = 0; i < 115; i++) { validations_mapping[i] = _default_visit; } @@ -1755,6 +2071,7 @@ bool AST_ValidationsMappingInit(void) { validations_mapping[CYPHER_AST_SET_PROPERTY] = _Validate_set_property; validations_mapping[CYPHER_AST_NODE_PATTERN] = _Validate_node_pattern; validations_mapping[CYPHER_AST_PATTERN_PATH] = _Validate_pattern_path; + validations_mapping[CYPHER_AST_CALL_SUBQUERY] = _Validate_call_subquery; validations_mapping[CYPHER_AST_SHORTEST_PATH] = _Validate_shortest_path; validations_mapping[CYPHER_AST_APPLY_OPERATOR] = _Validate_apply_operator; validations_mapping[CYPHER_AST_APPLY_ALL_OPERATOR] = _Validate_apply_all_operator; @@ -1828,7 +2145,7 @@ AST_Validation AST_Validate_ParseResultRoot root_type == CYPHER_AST_COMMENT) { continue; } else if(root_type != CYPHER_AST_STATEMENT) { - ErrorCtx_SetError("Encountered unsupported query type '%s'", cypher_astnode_typestr(root_type)); + ErrorCtx_SetError(EMSG_UNSUPPORTED_QUERY_TYPE, cypher_astnode_typestr(root_type)); return AST_INVALID; } else { // We got a statement. @@ -1839,7 +2156,7 @@ AST_Validation AST_Validate_ParseResultRoot // query with no roots like ';' if(nroots == 0) { - ErrorCtx_SetError("Error: empty query."); + ErrorCtx_SetError(EMSG_EMPTY_QUERY); } return AST_INVALID; @@ -1878,12 +2195,12 @@ AST_Validation AST_Validate_Query // validate positions of allShortestPaths if(!_ValidateAllShortestPaths(body)) { - ErrorCtx_SetError("RedisGraph support allShortestPaths only in match clauses"); + ErrorCtx_SetError(EMSG_ALLSHORTESTPATH_SUPPORT); return AST_INVALID; } if(!_ValidateShortestPaths(body)) { - ErrorCtx_SetError("RedisGraph currently only supports shortestPath in WITH or RETURN clauses"); + ErrorCtx_SetError(EMSG_SHORTESTPATH_SUPPORT); return AST_INVALID; } @@ -1906,7 +2223,7 @@ static AST_Validation _ValidateParamsOnly const cypher_astnode_type_t type = cypher_astnode_type(option); if((type == CYPHER_AST_EXPLAIN_OPTION) || (type == CYPHER_AST_PROFILE_OPTION)) { const char *invalid_option_name = cypher_astnode_typestr(type); - ErrorCtx_SetError("Please use GRAPH.%s 'key' 'query' command instead of GRAPH.QUERY 'key' '%s query'", + ErrorCtx_SetError(EMSG_EXPLAIN_PROFILE_USAGE, invalid_option_name, invalid_option_name); return AST_INVALID; } @@ -1929,7 +2246,7 @@ static AST_Validation _ValidateDuplicateParameters const char *paramName = cypher_ast_string_get_value(cypher_ast_cypher_option_param_get_name(param)); // If parameter already exists return an error. if(!raxInsert(param_names, (unsigned char *) paramName, strlen(paramName), NULL, NULL)) { - ErrorCtx_SetError("Duplicated parameter: %s", paramName); + ErrorCtx_SetError(EMSG_DUPLICATE_PARAMETERS, paramName); raxFree(param_names); return AST_INVALID; } @@ -1964,9 +2281,11 @@ AST_Validation AST_Validate_QueryParams } // create a context for the traversal - validations_ctx ctx; - ctx.union_all = NOT_DEFINED; - ctx.defined_identifiers = raxNew(); + validations_ctx ctx = { + .union_all = NOT_DEFINED, + .defined_identifiers = raxNew(), + .ignore_identifiers = false + }; // create a visitor ast_visitor visitor = {&ctx, validations_mapping}; @@ -2008,6 +2327,6 @@ void AST_ReportErrors // this to be reported to the user, typically with an arrow pointing to the // invalid character. size_t errCtxOffset = cypher_parse_error_context_offset(error); - ErrorCtx_SetError("errMsg: %s line: %u, column: %u, offset: %zu errCtx: %s errCtxOffset: %zu", + ErrorCtx_SetError(EMSG_PARSER_ERROR, errMsg, errPos.line, errPos.column, errPos.offset, errCtx, errCtxOffset); } diff --git a/src/ast/ast_validations.h b/src/ast/ast_validations.h index 60eefd138f..c14fd818b8 100644 --- a/src/ast/ast_validations.h +++ b/src/ast/ast_validations.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/ast_visitor.c b/src/ast/ast_visitor.c index 8d315b7e0f..f130d04481 100644 --- a/src/ast/ast_visitor.c +++ b/src/ast/ast_visitor.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "ast_visitor.h" @@ -38,9 +41,10 @@ static VISITOR_STRATEGY _AST_Visitor_visit uint nchildren = cypher_astnode_nchildren(node); for (uint i = 0; i < nchildren; i++) { - if(_AST_Visitor_visit(cypher_astnode_get_child(node, i), visitor) == VISITOR_BREAK) { - // error occurred, fast fold - return VISITOR_BREAK; + if(_AST_Visitor_visit(cypher_astnode_get_child(node, i), visitor) == + VISITOR_BREAK) { + // error occurred, fast fold + return VISITOR_BREAK; } } diff --git a/src/ast/ast_visitor.h b/src/ast/ast_visitor.h index 3f893dba7d..546a048cdd 100644 --- a/src/ast/ast_visitor.h +++ b/src/ast/ast_visitor.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/ast/enrichment/annotate_projected_named_paths.c b/src/ast/enrichment/annotate_projected_named_paths.c index 5a143cc165..77593c63f2 100644 --- a/src/ast/enrichment/annotate_projected_named_paths.c +++ b/src/ast/enrichment/annotate_projected_named_paths.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "annotate_projected_named_paths.h" #include "../../util/arr.h" @@ -299,11 +302,60 @@ static void _annotate_foreach_clause_projected_named_path // annotate named paths referring the outer scope _annotate_relevant_projected_named_path_identifier(ast, identifier_map, scope_start, scope_end); + raxFreeWithCallback(identifier_map, array_free); // annotate named paths defined inside the body _annotate_projected_named_path(&subquery_clauses_ast); array_free(clauses); cypher_astnode_free(query_node); +} + +static void _annotate_callsubquery_clause_projected_named_path +( + AST *ast, + const cypher_astnode_t *callsubquery_clause, + uint scope_start, + uint scope_end +) { + rax *identifier_map = raxNew(); + + const cypher_astnode_t *subquery = cypher_ast_call_subquery_get_query( + callsubquery_clause); + + AST subquery_clauses_ast = { + .root = subquery, + .anot_ctx_collection = ast->anot_ctx_collection, + .referenced_entities = ast->referenced_entities + }; + + // collect identifiers from importing WITH clauses (if exist) + // annotate them only. the later references of imported paths with already + // have the value in the record + uint *union_indices = AST_GetClauseIndices(&subquery_clauses_ast, + CYPHER_AST_UNION); + uint n_union_clauses = array_len(union_indices); + // handle first `UNION` branch + const cypher_astnode_t *first_in_branch = + cypher_ast_query_get_clause(subquery, 0); + if(cypher_astnode_type(first_in_branch) == CYPHER_AST_WITH) { + _collect_projected_identifier(first_in_branch, identifier_map); + } + // handle rest of `UNION` branches + for(uint i = 0; i < n_union_clauses; i++) { + first_in_branch = + cypher_ast_query_get_clause(subquery, union_indices[i] + 1); + if(cypher_astnode_type(first_in_branch) == CYPHER_AST_WITH) { + _collect_projected_identifier(first_in_branch, identifier_map); + } + } + array_free(union_indices); + + // annotate named paths referring the outer scope + _annotate_relevant_projected_named_path_identifier(ast, identifier_map, + scope_start, scope_end); + + // annotate named paths defined inside the body + _annotate_projected_named_path(&subquery_clauses_ast); raxFreeWithCallback(identifier_map, array_free); } @@ -314,31 +366,33 @@ static void _annotate_projected_named_path(AST *ast) { uint clause_count = cypher_ast_query_nclauses(ast->root); for(uint i = 0; i < clause_count; i++) { scope_end = i; - const cypher_astnode_t *child = cypher_ast_query_get_clause(ast->root, i); + const cypher_astnode_t *child = + cypher_ast_query_get_clause(ast->root, i); if(cypher_astnode_type(child) == CYPHER_AST_WITH) { _annotate_with_clause_projected_named_path(ast, child, scope_start, scope_end); + // update scope scope_start = scope_end; } else if(cypher_astnode_type(child) == CYPHER_AST_RETURN) { _annotate_return_clause_projected_named_path(ast, child, scope_start, scope_end); + // update scope scope_start = scope_end; } else if(cypher_astnode_type(child) == CYPHER_AST_DELETE) { _annotate_delete_clause_projected_named_path(ast, child, scope_start, scope_end); - // Do not update scope start! } else if(cypher_astnode_type(child) == CYPHER_AST_UNWIND) { _annotate_unwind_clause_projected_named_path(ast, child, scope_start, scope_end); - // Do not update scope start! } else if(cypher_astnode_type(child) == CYPHER_AST_MATCH) { _annotate_match_clause_projected_named_path(ast, child, scope_start, scope_end); - // Do not update scope start! } else if(cypher_astnode_type(child) == CYPHER_AST_FOREACH) { _annotate_foreach_clause_projected_named_path(ast, child, scope_start, scope_end); - // Do not update scope start! + } else if(cypher_astnode_type(child) == CYPHER_AST_CALL_SUBQUERY) { + _annotate_callsubquery_clause_projected_named_path(ast, child, + scope_start, scope_end); } } } diff --git a/src/ast/enrichment/annotate_projected_named_paths.h b/src/ast/enrichment/annotate_projected_named_paths.h index 4a9d1b3bee..4da0887a05 100644 --- a/src/ast/enrichment/annotate_projected_named_paths.h +++ b/src/ast/enrichment/annotate_projected_named_paths.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/bulk_insert/bulk_insert.c b/src/bulk_insert/bulk_insert.c index 62025ed2b4..faf2930bbd 100644 --- a/src/bulk_insert/bulk_insert.c +++ b/src/bulk_insert/bulk_insert.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "bulk_insert.h" @@ -226,7 +229,7 @@ static int _BulkInsert_ProcessNodeFile //-------------------------------------------------------------------------- while (data_idx < data_len) { - Node n; + Node n = GE_NEW_NODE(); GraphEntity* ge; Graph_CreateNode(gc->g, &n, label_ids, label_count); ge = (GraphEntity*)&n; diff --git a/src/bulk_insert/bulk_insert.h b/src/bulk_insert/bulk_insert.h index 382448973c..f6f94896e1 100644 --- a/src/bulk_insert/bulk_insert.h +++ b/src/bulk_insert/bulk_insert.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #ifndef BULKINSERT_H #define BULKINSERT_H diff --git a/src/commands/cmd_bulk_insert.c b/src/commands/cmd_bulk_insert.c index 86a9bb9d04..876dff045f 100644 --- a/src/commands/cmd_bulk_insert.c +++ b/src/commands/cmd_bulk_insert.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "cmd_bulk_insert.h" #include "query_ctx.h" diff --git a/src/commands/cmd_bulk_insert.h b/src/commands/cmd_bulk_insert.h index 2118cd4e52..16985a6608 100644 --- a/src/commands/cmd_bulk_insert.h +++ b/src/commands/cmd_bulk_insert.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/commands/cmd_config.c b/src/commands/cmd_config.c index 1533fb0602..48edc054b8 100644 --- a/src/commands/cmd_config.c +++ b/src/commands/cmd_config.c @@ -1,14 +1,20 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include "RG.h" #include "configuration/config.h" -void _Config_get_all(RedisModuleCtx *ctx) { +void _Config_get_all +( + RedisModuleCtx *ctx +) { uint config_count = Config_END_MARKER; RedisModule_ReplyWithArray(ctx, config_count); @@ -28,7 +34,12 @@ void _Config_get_all(RedisModuleCtx *ctx) { } } -void _Config_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +void _Config_get +( + RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc +) { // return the given config's value to the user Config_Option_Field config_field; const char *config_name = RedisModule_StringPtrLen(argv[2], NULL); @@ -56,7 +67,12 @@ void _Config_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { } } -void _Config_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +void _Config_set +( + RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc +) { //-------------------------------------------------------------------------- // validate configuration //-------------------------------------------------------------------------- @@ -132,21 +148,32 @@ void _Config_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_ReplyWithSimpleString(ctx, "OK"); } -int Graph_Config(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +int Graph_Config +( + RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc +) { // GRAPH.CONFIG [value] - if(argc < 3) return RedisModule_WrongArity(ctx); + if(argc < 3) { + return RedisModule_WrongArity(ctx); + } const char *action = RedisModule_StringPtrLen(argv[1], NULL); if(!strcasecmp(action, "GET")) { // GRAPH.CONFIG GET - if(argc != 3) return RedisModule_WrongArity(ctx); + if(argc != 3) { + return RedisModule_WrongArity(ctx); + } _Config_get(ctx, argv, argc); } else if(!strcasecmp(action, "SET")) { // GRAPH.CONFIG SET [value] [value] ... // emit an error if we received an odd number of arguments, // as this indicates an invalid configuration - if(argc < 4 || (argc % 2) == 1) return RedisModule_WrongArity(ctx); + if(argc < 4 || (argc % 2) == 1) { + return RedisModule_WrongArity(ctx); + } _Config_set(ctx, argv+2, argc-2); } else { RedisModule_ReplyWithError(ctx, "Unknown subcommand for GRAPH.CONFIG"); diff --git a/src/commands/cmd_constraint.c b/src/commands/cmd_constraint.c index 99aa4356b8..13fa19a874 100644 --- a/src/commands/cmd_constraint.c +++ b/src/commands/cmd_constraint.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "util/strutil.h" @@ -263,7 +266,7 @@ static bool _Constraint_Create Attribute_ID attr_ids[n]; for(uint i = 0; i < n; i++) { - attr_ids[i] = FindOrAddAttribute(gc, props[i]); + attr_ids[i] = FindOrAddAttribute(gc, props[i], true); } //-------------------------------------------------------------------------- @@ -304,7 +307,7 @@ static bool _Constraint_Create SchemaType st = (et == GETYPE_NODE) ? SCHEMA_NODE : SCHEMA_EDGE; Schema *s = GraphContext_GetSchema(gc, lbl, st); if(s == NULL) { - s = AddSchema(gc, lbl, st); + s = AddSchema(gc, lbl, st, true); } int s_id = Schema_GetID(s); @@ -351,8 +354,7 @@ static bool _Constraint_Create // operation failed perform clean up if(res == false) { - UndoLog undolog = QueryCtx_GetUndoLog(); - UndoLog_Rollback(undolog); + QueryCtx_Rollback(); } // release graph R/W lock diff --git a/src/commands/cmd_context.c b/src/commands/cmd_context.c index 624b869779..cbc6804771 100644 --- a/src/commands/cmd_context.c +++ b/src/commands/cmd_context.c @@ -1,55 +1,63 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "cmd_context.h" #include "RG.h" -#include "../query_ctx.h" +#include "cmd_context.h" +#include "../globals.h" #include "../util/rmalloc.h" #include "../util/thpool/pools.h" #include "../slow_log/slow_log.h" #include "../util/blocked_client.h" -/* Array with one entry per worker thread - * keeps track after currently executing commands - * initialized at module.c accessed via cmd_* and debug.c */ -CommandCtx **command_ctxs = NULL; +#include +// create a new command context CommandCtx *CommandCtx_New ( - RedisModuleCtx *ctx, - RedisModuleBlockedClient *bc, - RedisModuleString *cmd_name, - RedisModuleString *query, - GraphContext *graph_ctx, - ExecutorThread thread, - bool replicated_command, - bool compact, - long long timeout, - bool timeout_rw + RedisModuleCtx *ctx, // redis module context + RedisModuleBlockedClient *bc, // blocked client + RedisModuleString *cmd_name, // command to execute + RedisModuleString *query, // query string + GraphContext *graph_ctx, // graph context + ExecutorThread thread, // which thread executes this command + bool replicated_command, // whether this instance was spawned by a replication command + bool compact, // whether this query was issued with the compact flag + long long timeout, // the query timeout, if specified + bool timeout_rw, // apply timeout on both read and write queries + uint64_t received_ts, // command received at this UNIX timestamp + simple_timer_t timer // stopwatch started upon command received ) { - CommandCtx *context = rm_malloc(sizeof(CommandCtx)); + CommandCtx *context = rm_malloc(sizeof(CommandCtx)); + context->bc = bc; context->ctx = ctx; context->query = NULL; context->thread = thread; context->compact = compact; context->timeout = timeout; + context->ref_count = ATOMIC_VAR_INIT(1); context->graph_ctx = graph_ctx; - context->command_name = NULL; context->timeout_rw = timeout_rw; + context->received_ts = received_ts; + context->command_name = NULL; context->replicated_command = replicated_command; + simple_timer_copy(timer, context->timer); + if(cmd_name) { - // Make a copy of command name. + // make a copy of command name const char *command_name = RedisModule_StringPtrLen(cmd_name, NULL); context->command_name = rm_strdup(command_name); } if(query) { - // Make a copy of query. + // make a copy of query const char *q = RedisModule_StringPtrLen(query, NULL); context->query = rm_strdup(q); } @@ -57,95 +65,117 @@ CommandCtx *CommandCtx_New return context; } -// place given 'ctx' in 'command_ctxs' at position 'tid' -// representing the current thread -void CommandCtx_TrackCtx(CommandCtx *ctx) { - ASSERT(ctx != NULL); - ASSERT(command_ctxs != NULL); - - int tid = ThreadPools_GetThreadID(); - ASSERT(command_ctxs[tid] == NULL); - - // set ctx at the current thread entry - // CommandCtx_Free will remove it eventually - command_ctxs[tid] = ctx; - - // reset thread memory consumption to 0 (no memory consumed) - rm_reset_n_alloced(); -} - -void CommandCtx_UntrackCtx(CommandCtx *ctx) { - ASSERT(ctx != NULL); - ASSERT(command_ctxs != NULL); - - int tid = ThreadPools_GetThreadID(); - if(command_ctxs[tid] == NULL) return; // nothing to clean - - ASSERT(command_ctxs[tid] == ctx); +// increment command context reference count +void CommandCtx_Incref +( + CommandCtx *command_ctx +) { + ASSERT(command_ctx != NULL); - // set ctx at the current thread entry - // CommandCtx_Free will remove it eventually - command_ctxs[tid] = NULL; + // atomicly increment reference count + atomic_fetch_add(&command_ctx->ref_count, 1); } -RedisModuleCtx *CommandCtx_GetRedisCtx(CommandCtx *command_ctx) { +RedisModuleCtx *CommandCtx_GetRedisCtx +( + CommandCtx *command_ctx +) { ASSERT(command_ctx != NULL); - // Either we already have a context or block client is set. - if(command_ctx->ctx) return command_ctx->ctx; + // either we already have a context or block client is set + if(command_ctx->ctx) { + return command_ctx->ctx; + } ASSERT(command_ctx->bc != NULL); + command_ctx->ctx = RedisModule_GetThreadSafeContext(command_ctx->bc); return command_ctx->ctx; } -RedisModuleBlockedClient *CommandCtx_GetBlockingClient(const CommandCtx *command_ctx) { +RedisModuleBlockedClient *CommandCtx_GetBlockingClient +( + const CommandCtx *command_ctx +) { ASSERT(command_ctx != NULL); return command_ctx->bc; } -GraphContext *CommandCtx_GetGraphContext(const CommandCtx *command_ctx) { +GraphContext *CommandCtx_GetGraphContext +( + const CommandCtx *command_ctx +) { ASSERT(command_ctx != NULL); return command_ctx->graph_ctx; } -const char *CommandCtx_GetCommandName(const CommandCtx *command_ctx) { +const char *CommandCtx_GetCommandName +( + const CommandCtx *command_ctx +) { ASSERT(command_ctx != NULL); return command_ctx->command_name; } -const char *CommandCtx_GetQuery(const CommandCtx *command_ctx) { +const char *CommandCtx_GetQuery +( + const CommandCtx *command_ctx +) { ASSERT(command_ctx != NULL); return command_ctx->query; } -void CommandCtx_ThreadSafeContextLock(const CommandCtx *command_ctx) { - /* Acquire lock only when working with a blocked client - * otherwise we're running on Redis main thread, - * no need to acquire lock. */ +void CommandCtx_ThreadSafeContextLock +( + const CommandCtx *command_ctx +) { + // acquire lock only when working with a blocked client + // otherwise we're running on Redis main thread + // no need to acquire lock ASSERT(command_ctx != NULL && command_ctx->ctx != NULL); - if(command_ctx->bc) RedisModule_ThreadSafeContextLock(command_ctx->ctx); + if(command_ctx->bc) { + RedisModule_ThreadSafeContextLock(command_ctx->ctx); + } } -void CommandCtx_ThreadSafeContextUnlock(const CommandCtx *command_ctx) { - /* Release lock only when working with a blocked client - * otherwise we're running on Redis main thread, - * no need to release lock. */ +void CommandCtx_ThreadSafeContextUnlock +( + const CommandCtx *command_ctx +) { + // release lock only when working with a blocked client + // otherwise we're running on Redis main thread + // no need to release lock ASSERT(command_ctx != NULL && command_ctx->ctx != NULL); - if(command_ctx->bc) RedisModule_ThreadSafeContextUnlock(command_ctx->ctx); + if(command_ctx->bc) { + RedisModule_ThreadSafeContextUnlock(command_ctx->ctx); + } } -void CommandCtx_Free(CommandCtx *command_ctx) { +void CommandCtx_UnblockClient +( + CommandCtx *command_ctx +) { + ASSERT(command_ctx != NULL); if(command_ctx->bc) { RedisGraph_UnblockClient(command_ctx->bc); + command_ctx->bc = NULL; if(command_ctx->ctx) { RedisModule_FreeThreadSafeContext(command_ctx->ctx); + command_ctx->ctx = NULL; } } - - CommandCtx_UntrackCtx(command_ctx); - - if(command_ctx->query) rm_free(command_ctx->query); - rm_free(command_ctx->command_name); - rm_free(command_ctx); } +void CommandCtx_Free +( + CommandCtx *command_ctx +) { + // decrement reference count + if(atomic_fetch_sub(&command_ctx->ref_count, 1) == 1) { + // reference count is zero, free command context + ASSERT(command_ctx->bc == NULL); + + if(command_ctx->query != NULL) rm_free(command_ctx->query); + rm_free(command_ctx->command_name); + rm_free(command_ctx); + } +} diff --git a/src/commands/cmd_context.h b/src/commands/cmd_context.h index f53a88bf30..002af95db1 100644 --- a/src/commands/cmd_context.h +++ b/src/commands/cmd_context.h @@ -1,15 +1,21 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "cypher-parser.h" #include "../redismodule.h" +#include "../util/simple_timer.h" #include "../graph/graphcontext.h" +#include + // ExecutorThread lists the diffrent types of threads in the system typedef enum { EXEC_THREAD_MAIN, // redis main thread @@ -17,85 +23,97 @@ typedef enum { EXEC_THREAD_WRITER, // write only thread } ExecutorThread; -/* Query context, used for concurent query processing. */ +// command context, used for concurrent query processing typedef struct { - char *query; // Query string. - RedisModuleCtx *ctx; // Redis module context. - char *command_name; // Command to execute. - GraphContext *graph_ctx; // Graph context. - RedisModuleBlockedClient *bc; // Blocked client. - bool replicated_command; // Whether this instance was spawned by a replication command. - bool compact; // Whether this query was issued with the compact flag. - ExecutorThread thread; // Which thread executes this command - long long timeout; // The query timeout, if specified. - bool timeout_rw; // Apply timeout on both read and write queries. + char *query; // query string + RedisModuleCtx *ctx; // redis module context + char *command_name; // command to execute + GraphContext *graph_ctx; // graph context + atomic_int ref_count; // reference count + RedisModuleBlockedClient *bc; // blocked client + bool replicated_command; // whether this instance was spawned by a replication command + bool compact; // whether this query was issued with the compact flag + ExecutorThread thread; // which thread executes this command + long long timeout; // the query timeout, if specified + bool timeout_rw; // apply timeout on both read and write queries + uint64_t received_ts; // command received at this UNIX timestamp + simple_timer_t timer; // stopwatch started upon command received } CommandCtx; -// Create a new command context. +// create a new command context CommandCtx *CommandCtx_New ( - RedisModuleCtx *ctx, // Redis module context. - RedisModuleBlockedClient *bc, // Blocked client. - RedisModuleString *cmd_name, // Command to execute. - RedisModuleString *query, // Query string. - GraphContext *graph_ctx, // Graph context. - ExecutorThread thread, // Which thread executes this command - bool replicated_command, // Whether this instance was spawned by a replication command. - bool compact, // Whether this query was issued with the compact flag. - long long timeout, // The query timeout, if specified. - bool timeout_rw // Apply timeout on both read and write queries. + RedisModuleCtx *ctx, // redis module context + RedisModuleBlockedClient *bc, // blocked client + RedisModuleString *cmd_name, // command to execute + RedisModuleString *query, // query string + GraphContext *graph_ctx, // graph context + ExecutorThread thread, // which thread executes this command + bool replicated_command, // whether this instance was spawned by a replication command + bool compact, // whether this query was issued with the compact flag + long long timeout, // the query timeout, if specified + bool timeout_rw, // apply timeout on both read and write queries + uint64_t received_ts, // command received at this UNIX timestamp + simple_timer_t timer // stopwatch started upon command received ); -// Tracks given 'ctx' such that in case of a crash we will be able to report -// back all of the currently running commands -void CommandCtx_TrackCtx(CommandCtx *ctx); - -// Remove the given CommandCtx from tracking. -void CommandCtx_UntrackCtx(CommandCtx *ctx); +// increment command context reference count +void CommandCtx_Incref +( + CommandCtx *command_ctx +); -// Get Redis module context +// get Redis module context RedisModuleCtx *CommandCtx_GetRedisCtx ( CommandCtx *command_ctx ); -// Get blocking client. +// get blocking client RedisModuleBlockedClient *CommandCtx_GetBlockingClient ( const CommandCtx *command_ctx ); -// Get GraphContext. +// get GraphContext GraphContext *CommandCtx_GetGraphContext ( const CommandCtx *command_ctx ); -// Get command name. +// get command name const char *CommandCtx_GetCommandName ( const CommandCtx *command_ctx ); +// get query string const char *CommandCtx_GetQuery ( const CommandCtx *command_ctx ); -// Acquire Redis global lock. +// acquire Redis global lock void CommandCtx_ThreadSafeContextLock ( const CommandCtx *command_ctx ); -// Release Redis global lock. +// release Redis global lock void CommandCtx_ThreadSafeContextUnlock ( const CommandCtx *command_ctx ); -// Free command context. +// unblock the client +void CommandCtx_UnblockClient +( + CommandCtx *command_ctx +); + +// free command context void CommandCtx_Free ( CommandCtx *command_ctx ); + diff --git a/src/commands/cmd_debug.c b/src/commands/cmd_debug.c index 21356aea76..111d090c6e 100644 --- a/src/commands/cmd_debug.c +++ b/src/commands/cmd_debug.c @@ -1,19 +1,21 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "../util/arr.h" + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" #include "../redismodule.h" -#include "../graph/graphcontext.h" #include "../module_event_handlers.h" +#include + void ModuleEventHandler_AUXBeforeKeyspaceEvent(void); void ModuleEventHandler_AUXAfterKeyspaceEvent(void); -// Global array tracking all extant GraphContexts (defined in module.c) -extern GraphContext **graphs_in_keyspace; extern uint aux_field_counter; static void Debug_AUX(RedisModuleString **argv, int argc) { @@ -30,7 +32,6 @@ static void Debug_AUX(RedisModuleString **argv, int argc) { int Graph_Debug(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { ASSERT(ctx != NULL); - ASSERT(graphs_in_keyspace != NULL); RedisModule_ReplicateVerbatim(ctx); if(strcmp(RedisModule_StringPtrLen(argv[1], NULL), "AUX") == 0) { @@ -40,4 +41,5 @@ int Graph_Debug(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_ReplyWithLongLong(ctx, aux_field_counter); return REDISMODULE_OK; -} \ No newline at end of file +} + diff --git a/src/commands/cmd_delete.c b/src/commands/cmd_delete.c index f7f1507ba7..32d1ae686d 100644 --- a/src/commands/cmd_delete.c +++ b/src/commands/cmd_delete.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "cmd_context.h" #include "graph/graph.h" @@ -10,40 +13,44 @@ #include "query_ctx.h" #include "resultset/resultset.h" -/* Delete graph, removing the key from Redis and - * freeing every resource allocated by the graph. */ -int Graph_Delete(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { - if(argc != 2) return RedisModule_WrongArity(ctx); +// graphContext type as it is registered at Redis +extern RedisModuleType *GraphContextRedisModuleType; + +// delete graph, removing the key from Redis and +// freeing every resource allocated by the graph +int Graph_Delete +( + RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc +) { + if(argc != 2) { + return RedisModule_WrongArity(ctx); + } int res = REDISMODULE_OK; - char *strElapsed = NULL; - QueryCtx_BeginTimer(); // Start deletion timing. + bool deleted = false; + RedisModuleString *key_name = argv[1]; + + // remove graph from keyspace + RedisModuleKey *key = RedisModule_OpenKey(ctx, key_name, REDISMODULE_WRITE); + if(key != NULL) { + if(RedisModule_ModuleTypeGetType(key) == GraphContextRedisModuleType) { + deleted = true; + RedisModule_DeleteKey(key); // untrack graph & decreases graph ref count + RedisModule_ReplyWithSimpleString(ctx, "OK"); + // delete commands should always modify slaves + RedisModule_ReplicateVerbatim(ctx); + } + RedisModule_CloseKey(key); // close key handle + } - RedisModuleString *graph_name = argv[1]; - GraphContext *gc = GraphContext_Retrieve(ctx, graph_name, false, false); // Increase ref count. - // If the GraphContext is null, key access failed and an error has been emitted. - if(!gc) { + // unable to delete graph + if(!deleted) { res = REDISMODULE_ERR; - goto cleanup; + RedisModule_ReplyWithError(ctx, "ERR Invalid graph operation on empty key"); } - // Remove graph from keyspace. - RedisModuleKey *key = RedisModule_OpenKey(ctx, graph_name, REDISMODULE_WRITE); - RedisModule_DeleteKey(key); // Decreases graph ref count. - RedisModule_CloseKey(key); // Free key handle. - GraphContext_DecreaseRefCount(gc); // Decrease graph ref count. - - double t = QueryCtx_GetExecutionTime(); - int rc __attribute__((unused)); - rc = asprintf(&strElapsed, "Graph removed, internal execution time: %.6f milliseconds", t); - RedisModule_ReplyWithStringBuffer(ctx, strElapsed, strlen(strElapsed)); - - // Delete commands should always modify slaves. - RedisModule_ReplicateVerbatim(ctx); - -cleanup: - QueryCtx_Free(); // Reset the QueryCtx and free its allocations. - if(strElapsed) free(strElapsed); return res; } diff --git a/src/commands/cmd_dispatcher.c b/src/commands/cmd_dispatcher.c index 337f39e13b..d3280ebb43 100644 --- a/src/commands/cmd_dispatcher.c +++ b/src/commands/cmd_dispatcher.c @@ -1,13 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "commands.h" #include "cmd_context.h" #include "../util/thpool/pools.h" +#include "../util/simple_timer.h" #include "../util/blocked_client.h" #include "../configuration/config.h" @@ -23,7 +27,7 @@ static int _read_flags RedisModuleString **argv, // commands arguments int argc, // number of arguments bool *compact, // compact result-set format - long long *timeout, // query level timeout + long long *timeout, // query level timeout bool *timeout_rw, // apply timeout on both read and write queries uint *graph_version, // graph version [UNUSED] char **errmsg // reported error message @@ -170,14 +174,23 @@ static bool should_command_create_graph(GRAPH_Commands cmd) { return false; } -int CommandDispatch(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +int CommandDispatch +( + RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc +) { char *errmsg; uint version; bool compact; bool timeout_rw; long long timeout; + simple_timer_t timer; CommandCtx *context = NULL; + simple_tic(timer); + uint64_t received_ts = unix_timestamp(); + RedisModuleString *graph_name = argv[1]; RedisModuleString *query = (argc > 2) ? argv[2] : NULL; const char *command_name = RedisModule_StringPtrLen(argv[0], NULL); @@ -187,17 +200,18 @@ int CommandDispatch(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // parse additional arguments int res = _read_flags(argv, argc, &compact, &timeout, &timeout_rw, &version, - &errmsg); + &errmsg); if(res == REDISMODULE_ERR) { // emit error and exit if argument parsing failed RedisModule_ReplyWithError(ctx, errmsg); free(errmsg); - // the API reference dictates that registered functions should always return OK return REDISMODULE_OK; } bool shouldCreate = should_command_create_graph(cmd); - GraphContext *gc = GraphContext_Retrieve(ctx, graph_name, true, shouldCreate); + GraphContext *gc = GraphContext_Retrieve(ctx, graph_name, true, + shouldCreate); + // if GraphContext is null, key access failed and an error been emitted if(!gc) return REDISMODULE_ERR; @@ -210,30 +224,36 @@ int CommandDispatch(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { return REDISMODULE_OK; } - /* Determine the query execution context. - * queries issued within a LUA script or multi exec block must - * run on Redis main thread, others can run on different threads. */ + + // determine the query execution context + // queries issued within a LUA script or multi exec block must + // run on Redis main thread, others can run on different threads int flags = RedisModule_GetContextFlags(ctx); - bool is_replicated = RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_REPLICATED; + bool is_replicated = RedisModule_GetContextFlags(ctx) & + REDISMODULE_CTX_FLAGS_REPLICATED; bool main_thread = (is_replicated || (flags & (REDISMODULE_CTX_FLAGS_MULTI | REDISMODULE_CTX_FLAGS_LUA | REDISMODULE_CTX_FLAGS_DENY_BLOCKING | REDISMODULE_CTX_FLAGS_LOADING))); - ExecutorThread exec_thread = main_thread ? EXEC_THREAD_MAIN : EXEC_THREAD_READER; + ExecutorThread exec_thread = (main_thread) + ? EXEC_THREAD_MAIN + : EXEC_THREAD_READER; Command_Handler handler = get_command_handler(cmd); if(exec_thread == EXEC_THREAD_MAIN) { // run query on Redis main thread context = CommandCtx_New(ctx, NULL, argv[0], query, gc, exec_thread, - is_replicated, compact, timeout, timeout_rw); + is_replicated, compact, timeout, timeout_rw, + received_ts, timer); handler(context); } else { // run query on a dedicated thread RedisModuleBlockedClient *bc = RedisGraph_BlockClient(ctx); context = CommandCtx_New(NULL, bc, argv[0], query, gc, exec_thread, - is_replicated, compact, timeout, timeout_rw); + is_replicated, compact, timeout, timeout_rw, + received_ts, timer); if(ThreadPools_AddWorkReader(handler, context, false) == THPOOL_QUEUE_FULL) { @@ -244,6 +264,7 @@ int CommandDispatch(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // release the GraphContext, as we increased its reference count // when retrieving it GraphContext_DecreaseRefCount(gc); + CommandCtx_UnblockClient(context); CommandCtx_Free(context); } } diff --git a/src/commands/cmd_effect.c b/src/commands/cmd_effect.c new file mode 100644 index 0000000000..173ed2b84a --- /dev/null +++ b/src/commands/cmd_effect.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include "../effects/effects.h" +#include "../graph/graphcontext.h" + +// GRAPH.EFFECT command handler +int Graph_Effect +( + RedisModuleCtx *ctx, // redis module context + RedisModuleString **argv, // command arguments + int argc // number of arguments +) { + // GRAPH.EFFECT + if(argc != 3) { + return RedisModule_WrongArity(ctx); + } + + // get graph context + GraphContext *gc = GraphContext_Retrieve(ctx, argv[1], false, true); + ASSERT(gc != NULL); + + //-------------------------------------------------------------------------- + // process effects + //-------------------------------------------------------------------------- + + size_t l = 0; // effects buffer length + const char *effects_buff = RedisModule_StringPtrLen(argv[2], &l); + + // apply effects + Effects_Apply(gc, effects_buff, l); + + // release GraphContext + GraphContext_DecreaseRefCount(gc); + + // replicate effect + RedisModule_ReplicateVerbatim(ctx); + + // reply back to caller + RedisModule_ReplyWithSimpleString(ctx, "OK"); + + return REDISMODULE_OK; +} + diff --git a/src/commands/cmd_explain.c b/src/commands/cmd_explain.c index f779b8cf0a..cd45d0b233 100644 --- a/src/commands/cmd_explain.c +++ b/src/commands/cmd_explain.c @@ -1,47 +1,48 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "../errors.h" #include "cmd_context.h" +#include "../globals.h" #include "../query_ctx.h" #include "execution_ctx.h" #include "../index/index.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../execution_plan/execution_plan.h" -/* Builds an execution plan but does not execute it - * reports plan back to the client - * Args: - * argv[1] graph name - * argv[2] query */ +// builds an execution plan but does not execute it +// reports plan back to the client +// Args: +// argv[1] graph name +// argv[2] query void Graph_Explain(void *args) { bool lock_acquired = false; CommandCtx *command_ctx = (CommandCtx *)args; RedisModuleCtx *ctx = CommandCtx_GetRedisCtx(command_ctx); GraphContext *gc = CommandCtx_GetGraphContext(command_ctx); ExecutionCtx *exec_ctx = NULL; + QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); QueryCtx_SetGlobalExecutionCtx(command_ctx); - CommandCtx_TrackCtx(command_ctx); + Globals_TrackCommandCtx(command_ctx); - if(strcmp(command_ctx->query, "") == 0) { - ErrorCtx_SetError("Error: empty query."); + // retrieve the required execution items and information: + // 1. Execution plan + // 2. Whether these items were cached or not + bool cached = false; + ExecutionPlan *plan = NULL; + exec_ctx = ExecutionCtx_FromQuery(command_ctx->query); + if (exec_ctx == NULL) { + query_ctx->status = QueryExecutionStatus_FAILURE; goto cleanup; } - QueryCtx_BeginTimer(); // Start query timing. - - /* Retrieve the required execution items and information: - * 1. Execution plan - * 2. Whether these items were cached or not */ - bool cached = false; - ExecutionPlan *plan = NULL; - exec_ctx = ExecutionCtx_FromQuery(command_ctx->query); - if(exec_ctx == NULL) goto cleanup; - plan = exec_ctx->plan; ExecutionType exec_type = exec_ctx->exec_type; @@ -59,7 +60,10 @@ void Graph_Explain(void *args) { ExecutionPlan_PreparePlan(plan); ExecutionPlan_Init(plan); // Initialize the plan's ops. - if(ErrorCtx_EncounteredError()) goto cleanup; + if (ErrorCtx_EncounteredError()) { + query_ctx->status = QueryExecutionStatus_FAILURE; + goto cleanup; + } ExecutionPlan_Print(plan, ctx); // Print the execution plan. @@ -68,6 +72,8 @@ void Graph_Explain(void *args) { if(lock_acquired) Graph_ReleaseLock(gc->g); ExecutionCtx_Free(exec_ctx); GraphContext_DecreaseRefCount(gc); + Globals_UntrackCommandCtx(command_ctx); + CommandCtx_UnblockClient(command_ctx); CommandCtx_Free(command_ctx); QueryCtx_Free(); // Reset the QueryCtx and free its allocations. ErrorCtx_Clear(); diff --git a/src/commands/cmd_info.c b/src/commands/cmd_info.c index 0e8f9d2a0e..439f3c721f 100644 --- a/src/commands/cmd_info.c +++ b/src/commands/cmd_info.c @@ -1,31 +1,312 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - /* This file contains the implementation of the GRAPH.INFO command. */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" +#include "commands.h" +#include "../globals.h" #include "redismodule.h" +#include "cmd_context.h" +#include "../util/thpool/pools.h" -// GRAPH.INFO key -// GRAPH.INFO key RESET -// GRAPH.INFO key STATS -// GRAPH.INFO key QUERIES -// Dispatch the subcommand. +#include +#include + +#define QUERY_KEY_NAME "Query" +#define GRAPH_NAME_KEY_NAME "Graph name" +#define REPLICATION_KEY_NAME "Replicated command" +#define WAIT_DURATION_KEY_NAME "Wait duration" +#define RECEIVED_TIMESTAMP_KEY_NAME "Received at" +#define EXECUTION_DURATION_KEY_NAME "Execution duration" + +#define SUBCOMMAND_NAME_RUNNING_QUERIES "RunningQueries" +#define SUBCOMMAND_NAME_WAITING_QUERIES "WaitingQueries" + +//------------------------------------------------------------------------------ +// Info section API +//------------------------------------------------------------------------------ + +// adds a new section to the info output +static void Info_AddSection +( + RedisModuleCtx *ctx, // redis module context + const char *section, // section name + uint32_t n_entries // number of entries +) { + // validate arguments + ASSERT(ctx != NULL); + ASSERT(section != NULL); + + RedisModule_ReplyWithCString(ctx, section); + RedisModule_ReplyWithArray(ctx, n_entries); +} + +// adds a new entry to the current section +static void Info_SectionAddEntryString +( + RedisModuleCtx *ctx, // redis module context + const char *entry_name, // entry name + const char *entry_value // entry value +) { + // validate arguments + ASSERT(ctx != NULL); + ASSERT(entry_name != NULL); + ASSERT(entry_value != NULL); + + RedisModule_ReplyWithCString(ctx, entry_name); + RedisModule_ReplyWithCString(ctx, entry_value); +} + +// adds a new entry to the current section +static void Info_SectionAddEntryLongLong +( + RedisModuleCtx *ctx, // redis module context + const char *entry_name, // entry name + long long entry_value // entry value +) { + // validate arguments + ASSERT(ctx != NULL); + ASSERT(entry_name != NULL); + + RedisModule_ReplyWithCString(ctx, entry_name); + RedisModule_ReplyWithLongLong(ctx, entry_value); +} + +// adds a new entry to the current section +static void Info_SectionAddEntryDouble +( + RedisModuleCtx *ctx, // redis module context + const char *entry_name, // entry name + double entry_value // entry value +) { + // validate arguments + ASSERT(ctx != NULL); + ASSERT(entry_name != NULL); + + RedisModule_ReplyWithCString(ctx, entry_name); + RedisModule_ReplyWithDouble(ctx, entry_value); +} + +// replies with query information +static void _emit_running_query +( + RedisModuleCtx *ctx, // redis module context + const CommandCtx *cmd // command context +) { + ASSERT(ctx != NULL); + ASSERT(cmd != NULL); + + // compute query execution time + const double total_time = TIMER_GET_ELAPSED_MILLISECONDS(cmd->timer); + + RedisModule_ReplyWithArray(ctx, 5 * 2); + + // emit query received timestamp + Info_SectionAddEntryLongLong(ctx, RECEIVED_TIMESTAMP_KEY_NAME, + cmd->received_ts); + + // emit graph name + Info_SectionAddEntryString(ctx, GRAPH_NAME_KEY_NAME, + GraphContext_GetName(cmd->graph_ctx)); + + // emit query + Info_SectionAddEntryString(ctx, QUERY_KEY_NAME, cmd->query); + + // emit query wait duration + Info_SectionAddEntryDouble(ctx, EXECUTION_DURATION_KEY_NAME, total_time); + + // emit rather or not query was replicated + Info_SectionAddEntryLongLong(ctx, REPLICATION_KEY_NAME, + cmd->replicated_command); +} + +// replies with query information +static void _emit_waiting_query +( + RedisModuleCtx *ctx, // redis module context + const CommandCtx *cmd // command context +) { + ASSERT(ctx != NULL); + ASSERT(cmd != NULL); + + // compute query execution time + const double total_time = TIMER_GET_ELAPSED_MILLISECONDS(cmd->timer); + + RedisModule_ReplyWithArray(ctx, 4 * 2); + + // emit query received timestamp + Info_SectionAddEntryLongLong(ctx, RECEIVED_TIMESTAMP_KEY_NAME, + cmd->received_ts); + + // emit graph name + Info_SectionAddEntryString(ctx, GRAPH_NAME_KEY_NAME, + GraphContext_GetName(cmd->graph_ctx)); + + // emit query + Info_SectionAddEntryString(ctx, QUERY_KEY_NAME, cmd->query); + + // emit query execution duration + Info_SectionAddEntryDouble(ctx, WAIT_DURATION_KEY_NAME, total_time); +} + +// handles the "GRAPH.INFO RunningQueries" section +// "GRAPH.INFO RunningQueries" +static void _info_running_queries +( + RedisModuleCtx *ctx // redis context +) { + // an example for a command and reply: + // command: + // GRAPH.INFO RunningQueries + // reply: + // "RunningQueries" + // "Received at" + // "Graph name" + // "Query" + // "Execution duration" + // "Replicated command" + + ASSERT(ctx != NULL); + + //-------------------------------------------------------------------------- + // collect running queries + //-------------------------------------------------------------------------- + + // get all currently executing commands + // #readers + #writers + Redis main thread + uint32_t n = ThreadPools_ThreadCount() + 1; + CommandCtx* cmds[n]; + Globals_GetCommandCtxs(cmds, &n); + + // create a new subsection in the reply + Info_AddSection(ctx, "# Running queries", n); + + for(uint32_t i = 0; i < n; i++) { + CommandCtx *cmd = cmds[i]; + ASSERT(cmd != NULL); + + // emit the command + _emit_running_query(ctx, cmd); + + // decrease the command's ref count + // free the command if it's no longer referenced + CommandCtx_Free(cmd); + } +} + +// handles the "GRAPH.INFO WaitingQueries" section +// "GRAPH.INFO WaitingQueries" +static void _info_waiting_queries +( + RedisModuleCtx *ctx // redis context +) { + // an example for a command and reply: + // command: + // GRAPH.INFO WaitingQueries + // reply: + // "WaitingQueries" + // "Received at" + // "Graph name" + // "Query" + // "Wait duration" + + ASSERT(ctx != NULL); + + //-------------------------------------------------------------------------- + // collect waiting queries + //-------------------------------------------------------------------------- + + uint32_t n = ThreadPools_ThreadCount() + 1; + CommandCtx **cmds = (CommandCtx**)ThreadPools_GetTasksByHandler(Graph_Query, + (void(*)(void *))CommandCtx_Incref, &n); + + // create a new subsection in the reply + Info_AddSection(ctx, "# Waiting queries", n); + + for(uint32_t i = 0; i < n; i++) { + CommandCtx *cmd = cmds[i]; + ASSERT(cmd != NULL); + + // emit the command + _emit_waiting_query(ctx, cmd); + + // decrease the command's ref count + // free the command if it's no longer referenced + CommandCtx_Free(cmd); + } + + free(cmds); +} + +// attempts to find the specified sections of "GRAPH.INFO" and dispatch it +static void _handle_sections +( + RedisModuleCtx *ctx, // redis module context + RedisModuleString **argv, // command arguments + const int argc // number of arguments +) { + ASSERT(ctx != NULL); + ASSERT(argv != NULL); + + int section_count = 0; + bool running_queries = false; + bool waiting_queries = false; + + if(argc == 0) { + running_queries = true; + waiting_queries = true; + section_count = 2; + } else { + for(uint i = 0; i < argc; i++) { + const char *subcmd = RedisModule_StringPtrLen(argv[i], NULL); + if(!running_queries && + !strcasecmp(subcmd, SUBCOMMAND_NAME_RUNNING_QUERIES)) { + running_queries = true; + section_count++; + } else if(!waiting_queries && + !strcasecmp(subcmd, SUBCOMMAND_NAME_WAITING_QUERIES)) { + waiting_queries = true; + section_count++; + } + } + } + + if(section_count == 0) { + RedisModule_ReplyWithCString(ctx, "no section found"); + return; + } + + RedisModule_ReplyWithArray(ctx, section_count * 2); + if(running_queries) { + _info_running_queries(ctx); + } + if(waiting_queries) { + _info_waiting_queries(ctx); + } +} + +// graph.info command handler +// GRAPH.INFO [Section [Section ...]] +// GRAPH.INFO RunningQueries WaitingQueries int Graph_Info ( - RedisModuleCtx *ctx, - RedisModuleString **argv, - const int argc + RedisModuleCtx *ctx, // redis module context + RedisModuleString **argv, // command arguments + const int argc // number of arguments ) { - ASSERT(ctx); + ASSERT(ctx != NULL); - if (argc < 2) { - return RedisModule_WrongArity(ctx); - } + // expecting at least two arguments + if (argc < 1) { + return RedisModule_WrongArity(ctx); + } - RedisModule_ReplyWithError(ctx, "Unimplemented."); + _handle_sections(ctx, argv + 1, argc - 1); - return REDISMODULE_ERR; + return REDISMODULE_OK; } diff --git a/src/commands/cmd_list.c b/src/commands/cmd_list.c index 09b3b6704a..62743ed473 100644 --- a/src/commands/cmd_list.c +++ b/src/commands/cmd_list.c @@ -1,30 +1,46 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "../util/arr.h" +#include "RG.h" +#include "../globals.h" #include "../redismodule.h" #include "../graph/graphcontext.h" -// Global array tracking all extant GraphContexts (defined in module.c) -extern GraphContext **graphs_in_keyspace; - -int Graph_List(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +int Graph_List +( + RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc +) { ASSERT(ctx != NULL); - ASSERT(graphs_in_keyspace != NULL); - uint count = array_len(graphs_in_keyspace); - RedisModule_ReplyWithArray(ctx, count); + if(argc != 1) { + return RedisModule_WrongArity(ctx); + } + + KeySpaceGraphIterator it; + Globals_ScanGraphs(&it); + RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN); // reply with each graph name - for(uint i = 0; i < count; i ++) { - GraphContext *gc = graphs_in_keyspace[i]; + uint64_t n = 0; + GraphContext *gc = NULL; + + while((gc = GraphIterator_Next(&it)) != NULL) { const char *name = GraphContext_GetName(gc); RedisModule_ReplyWithStringBuffer(ctx, name, strlen(name)); + n++; + GraphContext_DecreaseRefCount(gc); } + RedisModule_ReplySetArrayLength(ctx, n); + return REDISMODULE_OK; } diff --git a/src/commands/cmd_query.c b/src/commands/cmd_query.c index e0830c37ae..1607d7d624 100644 --- a/src/commands/cmd_query.c +++ b/src/commands/cmd_query.c @@ -1,23 +1,29 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" -#include "../errors.h" -#include "cmd_context.h" #include "../ast/ast.h" +#include "cmd_context.h" #include "../util/arr.h" -#include "../util/cron.h" +#include "cron/cron.h" +#include "../globals.h" #include "../query_ctx.h" +#include "execution_ctx.h" #include "../graph/graph.h" -#include "../index/indexer.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" +#include "../index/indexer.h" +#include "../effects/effects.h" #include "../util/cache/cache.h" #include "../util/thpool/pools.h" +#include "../configuration/config.h" #include "../execution_plan/execution_plan.h" -#include "execution_ctx.h" // GraphQueryCtx stores the allocations required to execute a query. typedef struct { @@ -26,8 +32,6 @@ typedef struct { QueryCtx *query_ctx; // query context ExecutionCtx *exec_ctx; // execution context CommandCtx *command_ctx; // command context - bool readonly_query; // read only query - bool profile; // profile query CronTaskHandle timeout; // timeout cron task } GraphQueryCtx; @@ -37,20 +41,18 @@ static GraphQueryCtx *GraphQueryCtx_New RedisModuleCtx *rm_ctx, ExecutionCtx *exec_ctx, CommandCtx *command_ctx, - bool readonly_query, - bool profile, + QueryExecutionTypeFlag flags, CronTaskHandle timeout ) { GraphQueryCtx *ctx = rm_malloc(sizeof(GraphQueryCtx)); - ctx->rm_ctx = rm_ctx; - ctx->exec_ctx = exec_ctx; - ctx->graph_ctx = graph_ctx; - ctx->query_ctx = QueryCtx_GetQueryCtx(); - ctx->command_ctx = command_ctx; - ctx->readonly_query = readonly_query; - ctx->profile = profile; - ctx->timeout = timeout; + ctx->rm_ctx = rm_ctx; + ctx->exec_ctx = exec_ctx; + ctx->graph_ctx = graph_ctx; + ctx->query_ctx = QueryCtx_GetQueryCtx(); + ctx->query_ctx->flags = flags; + ctx->command_ctx = command_ctx; + ctx->timeout = timeout; return ctx; } @@ -63,7 +65,48 @@ static void inline GraphQueryCtx_Free rm_free(ctx); } -static void abort_and_check_timeout +// checks if we should replicate command to replicas via +// the original GRAPH.QUERY command +// or via a set of effects GRAPH.EFFECT +// we would prefer to use effects when the number of effects is relatively small +// compared to query's execution time +static bool _should_replicate_effects(void) +{ + // GRAPH.EFFECT will be used to replicate a query when + // the average modification time > configuted replicate effects threshold + // + // for example: + // a query which ran for 10ms and performed 5 changes + // the average change time is 10/5 = 2ms + // if 2ms > configured replicate effects threshold + // then the query will be replicated via GRAPH.EFFECT + // + // on the other hand if a query ran for 1ms and performed 4 changes + // the average change timw is 1/4 = 0.25ms + // 0.25 < configured replicate effects threshold + // then the query will be replicate via GRAPH.QUERY + + //-------------------------------------------------------------------------- + // consult with configuration + //-------------------------------------------------------------------------- + + uint64_t effects_threshold; + Config_Option_get(Config_EFFECTS_THRESHOLD, &effects_threshold); + + // compute average change time: + // avg modification time = query execution time / #modifications + double exec_time = QueryCtx_GetRuntime(); + uint64_t n = EffectsBuffer_Length(QueryCtx_GetEffectsBuffer()); + ASSERT(n > 0); + double avg_mod_time = exec_time / n; + + avg_mod_time *= 1000; // convert from ms to μs microseconds + + // use GRAPH.EFFECT when avg_mod_time > effects_threshold + return (avg_mod_time > (double)effects_threshold); +} + +static bool abort_and_check_timeout ( GraphQueryCtx *gq_ctx, ExecutionPlan *plan @@ -74,9 +117,14 @@ static void abort_and_check_timeout } // emit error if query timed out - if(ExecutionPlan_Drained(plan)) { - ErrorCtx_SetError("Query timed out"); + // TODO for the abort feature this won't necessarily mean a timeout, + // it will also flag the aborted queries. + const bool has_timed_out = ExecutionPlan_Drained(plan); + if (has_timed_out) { + ErrorCtx_SetError(EMSG_QUERY_TIMEOUT); } + + return has_timed_out; } static bool _index_operation_delete @@ -119,8 +167,7 @@ static bool _index_operation_delete } // no matching index - ErrorCtx_SetError("ERR Unable to drop index on :%s(%s): no such index.", - label, attr); + ErrorCtx_SetError(EMSG_UNABLE_TO_DROP_INDEX, label, attr); return false; } @@ -210,7 +257,7 @@ static void _index_operation _index_operation_delete(gc, ast); break; default: - ErrorCtx_SetError("ERR Encountered unknown query execution type."); + ErrorCtx_SetError(EMSG_UNKNOWN_EXECUTION_TYPE); } } @@ -228,7 +275,7 @@ void QueryTimedOut(void *pdata) { // set timeout for query execution CronTaskHandle Query_SetTimeOut(uint timeout, ExecutionPlan *plan) { // increase execution plan ref count - return Cron_AddTask(timeout, QueryTimedOut, plan); + return Cron_AddTask(timeout, QueryTimedOut, NULL, plan); } inline static bool _readonly_cmd_mode(CommandCtx *ctx) { @@ -241,23 +288,25 @@ inline static bool _readonly_cmd_mode(CommandCtx *ctx) { static void _ExecuteQuery(void *args) { ASSERT(args != NULL); - GraphQueryCtx *gq_ctx = args; - QueryCtx *query_ctx = gq_ctx->query_ctx; - GraphContext *gc = gq_ctx->graph_ctx; - RedisModuleCtx *rm_ctx = gq_ctx->rm_ctx; - bool profile = gq_ctx->profile; - bool readonly = gq_ctx->readonly_query; - ExecutionCtx *exec_ctx = gq_ctx->exec_ctx; - CommandCtx *command_ctx = gq_ctx->command_ctx; - AST *ast = exec_ctx->ast; - ExecutionPlan *plan = exec_ctx->plan; - ExecutionType exec_type = exec_ctx->exec_type; + GraphQueryCtx *gq_ctx = args; + QueryCtx *query_ctx = gq_ctx->query_ctx; + GraphContext *gc = gq_ctx->graph_ctx; + RedisModuleCtx *rm_ctx = gq_ctx->rm_ctx; + ExecutionCtx *exec_ctx = gq_ctx->exec_ctx; + CommandCtx *command_ctx = gq_ctx->command_ctx; + AST *ast = exec_ctx->ast; + ExecutionPlan *plan = exec_ctx->plan; + ExecutionType exec_type = exec_ctx->exec_type; + const bool profile = (query_ctx->flags & QueryExecutionTypeFlag_PROFILE); + const bool readonly = !(query_ctx->flags & QueryExecutionTypeFlag_WRITE); // if we have migrated to a writer thread, // update thread-local storage and track the CommandCtx - if(command_ctx->thread == EXEC_THREAD_WRITER) { + if (command_ctx->thread == EXEC_THREAD_WRITER) { + // transition the query from waiting to executing + QueryCtx_AdvanceStage(query_ctx); QueryCtx_SetTLS(query_ctx); - CommandCtx_TrackCtx(command_ctx); + Globals_TrackCommandCtx(command_ctx); } // instantiate the query ResultSet @@ -270,7 +319,7 @@ static void _ExecuteQuery(void *args) { ? FORMATTER_COMPACT : FORMATTER_VERBOSE; ResultSet *result_set = NewResultSet(rm_ctx, resultset_format); - if (exec_ctx->cached) { + if(exec_ctx->cached) { ResultSet_CachedExecution(result_set); // indicate a cached execution } @@ -298,15 +347,21 @@ static void _ExecuteQuery(void *args) { ExecutionPlan_PreparePlan(plan); if(profile) { ExecutionPlan_Profile(plan); - abort_and_check_timeout(gq_ctx, plan); + if (abort_and_check_timeout(gq_ctx, plan)) { + query_ctx->status = QueryExecutionStatus_TIMEDOUT; + } if(!ErrorCtx_EncounteredError()) { + // transition the query from executing reporting + QueryCtx_AdvanceStage(query_ctx); ExecutionPlan_Print(plan, rm_ctx); } } else { result_set = ExecutionPlan_Execute(plan); - abort_and_check_timeout(gq_ctx, plan); + if (abort_and_check_timeout(gq_ctx, plan)) { + query_ctx->status = QueryExecutionStatus_TIMEDOUT; + } } ExecutionPlan_Free(plan); @@ -320,14 +375,33 @@ static void _ExecuteQuery(void *args) { // in case of an error, rollback any modifications if(ErrorCtx_EncounteredError()) { - UndoLog_Rollback(query_ctx->undo_log); + QueryCtx_Rollback(); // clear resultset statistics, avoiding commnad being replicated ResultSet_Clear(result_set); - } - - // replicate command if graph was modified - if(ResultSetStat_IndicateModification(&result_set->stats)) { - QueryCtx_Replicate(query_ctx); + if (query_ctx->status != QueryExecutionStatus_TIMEDOUT) { + query_ctx->status = QueryExecutionStatus_FAILURE; + } + } else { + // replicate if graph was modified + if(ResultSetStat_IndicateModification(&result_set->stats)) { + // determine rather or not to replicate via effects + if(EffectsBuffer_Length(QueryCtx_GetEffectsBuffer()) > 0 && + _should_replicate_effects()) { + // compute effects buffer + size_t effects_len = 0; + u_char *effects = EffectsBuffer_Buffer( + QueryCtx_GetEffectsBuffer(), &effects_len); + ASSERT(effects_len > 0 && effects != NULL); + + // replicate effects + RedisModule_Replicate(rm_ctx, "GRAPH.EFFECT", "cb!", + GraphContext_GetName(gc), effects, effects_len); + rm_free(effects); + } else { + // replicate original query + QueryCtx_Replicate(query_ctx); + } + } } QueryCtx_UnlockCommit(); @@ -335,7 +409,12 @@ static void _ExecuteQuery(void *args) { if(!profile || ErrorCtx_EncounteredError()) { // if we encountered an error, ResultSet_Reply will emit the error // send result-set back to client + // transition the query from executing reporting + QueryCtx_AdvanceStage(query_ctx); ResultSet_Reply(result_set); + + // transition the query from reporting to finished + QueryCtx_AdvanceStage(query_ctx); } if(readonly) Graph_ReleaseLock(gc->g); // release read lock @@ -343,11 +422,13 @@ static void _ExecuteQuery(void *args) { // log query to slowlog SlowLog *slowlog = GraphContext_GetSlowLog(gc); SlowLog_Add(slowlog, command_ctx->command_name, command_ctx->query, - QueryCtx_GetExecutionTime(), NULL); + QueryCtx_GetRuntime(), NULL); // clean up ExecutionCtx_Free(exec_ctx); GraphContext_DecreaseRefCount(gc); + Globals_UntrackCommandCtx(command_ctx); + CommandCtx_UnblockClient(command_ctx); CommandCtx_Free(command_ctx); QueryCtx_Free(); // reset the QueryCtx and free its allocations ErrorCtx_Clear(); @@ -368,36 +449,44 @@ static void _DelegateWriter(GraphQueryCtx *gq_ctx) { QueryCtx_RemoveFromTLS(); // untrack the CommandCtx - CommandCtx_UntrackCtx(gq_ctx->command_ctx); + Globals_UntrackCommandCtx(gq_ctx->command_ctx); // update execution thread to writer gq_ctx->command_ctx->thread = EXEC_THREAD_WRITER; + // reset query stage from executing back to waiting + QueryCtx_ResetStage(gq_ctx->query_ctx); + // dispatch work to the writer thread int res = ThreadPools_AddWorkWriter(_ExecuteQuery, gq_ctx, 0); ASSERT(res == 0); } -void _query(bool profile, void *args) { +void _query +( + bool profile, + void *args +) { CommandCtx *command_ctx = (CommandCtx *)args; + QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); RedisModuleCtx *ctx = CommandCtx_GetRedisCtx(command_ctx); GraphContext *gc = CommandCtx_GetGraphContext(command_ctx); ExecutionCtx *exec_ctx = NULL; - CommandCtx_TrackCtx(command_ctx); + Globals_TrackCommandCtx(command_ctx); QueryCtx_SetGlobalExecutionCtx(command_ctx); - if(strcmp(command_ctx->query, "") == 0) { - ErrorCtx_SetError("Error: empty query."); - goto cleanup; - } - - QueryCtx_BeginTimer(); // start query timing + // transition the query from waiting to executing + QueryCtx_AdvanceStage(query_ctx); - // parse query parameters and build an execution plan or retrieve it from the cache + // parse query parameters and build an execution plan + // or retrieve it from the cache exec_ctx = ExecutionCtx_FromQuery(command_ctx->query); if(exec_ctx == NULL) goto cleanup; + // update cached flag + QueryCtx_SetUtilizedCache(query_ctx, exec_ctx->cached); + ExecutionType exec_type = exec_ctx->exec_type; bool readonly = AST_ReadOnly(exec_ctx->ast->root); bool index_op = (exec_type == EXECUTION_TYPE_INDEX_CREATE || @@ -410,7 +499,7 @@ void _query(bool profile, void *args) { // write query executing via GRAPH.RO_QUERY isn't allowed if(!profile && !readonly && _readonly_cmd_mode(command_ctx)) { - ErrorCtx_SetError("graph.RO_QUERY is to be executed only on read-only queries"); + ErrorCtx_SetError(EMSG_MISUSE_GRAPH_ROQUERY); goto cleanup; } @@ -426,8 +515,15 @@ void _query(bool profile, void *args) { } // populate the container struct for invoking _ExecuteQuery. + QueryExecutionTypeFlag flags = QueryExecutionTypeFlag_READ; + if (!readonly) { + flags |= QueryExecutionTypeFlag_WRITE; + } + if (profile) { + flags |= QueryExecutionTypeFlag_PROFILE; + } GraphQueryCtx *gq_ctx = GraphQueryCtx_New(gc, ctx, exec_ctx, command_ctx, - readonly, profile, timeout_task); + flags, timeout_task); // if 'thread' is redis main thread, continue running // if readonly is true we're executing on a worker thread from @@ -442,11 +538,15 @@ void _query(bool profile, void *args) { cleanup: // if there were any query compile time errors, report them - if(ErrorCtx_EncounteredError()) ErrorCtx_EmitException(); + if(ErrorCtx_EncounteredError()) { + ErrorCtx_EmitException(); + } // Cleanup routine invoked after encountering errors in this function. ExecutionCtx_Free(exec_ctx); GraphContext_DecreaseRefCount(gc); + Globals_UntrackCommandCtx(command_ctx); + CommandCtx_UnblockClient(command_ctx); CommandCtx_Free(command_ctx); QueryCtx_Free(); // Reset the QueryCtx and free its allocations. ErrorCtx_Clear(); @@ -459,3 +559,4 @@ void Graph_Profile(void *args) { void Graph_Query(void *args) { _query(false, args); } + diff --git a/src/commands/cmd_slowlog.c b/src/commands/cmd_slowlog.c index 8c4b972fc8..a5eacb1128 100644 --- a/src/commands/cmd_slowlog.c +++ b/src/commands/cmd_slowlog.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../redismodule.h" diff --git a/src/commands/commands.c b/src/commands/commands.c index aeb2a2cd75..becdb8d1d0 100644 --- a/src/commands/commands.c +++ b/src/commands/commands.c @@ -1,24 +1,31 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "commands.h" -// Convert from string representation to an enum. +// convert from string representation to an enum GRAPH_Commands CommandFromString(const char *cmd_name) { - if (!strcasecmp(cmd_name, "graph.QUERY")) return CMD_QUERY; + if (!strcasecmp(cmd_name, "graph.INFO")) return CMD_INFO; + if (!strcasecmp(cmd_name, "graph.LIST")) return CMD_LIST; + if (!strcasecmp(cmd_name, "graph.QUERY")) return CMD_QUERY; + if (!strcasecmp(cmd_name, "graph.DEBUG")) return CMD_DEBUG; + if (!strcasecmp(cmd_name, "graph.EFFECT")) return CMD_EFFECT; + if (!strcasecmp(cmd_name, "graph.DELETE")) return CMD_DELETE; + if (!strcasecmp(cmd_name, "graph.CONFIG")) return CMD_CONFIG; + if (!strcasecmp(cmd_name, "graph.PROFILE")) return CMD_PROFILE; + if (!strcasecmp(cmd_name, "graph.EXPLAIN")) return CMD_EXPLAIN; + if (!strcasecmp(cmd_name, "graph.SLOWLOG")) return CMD_SLOWLOG; if (!strcasecmp(cmd_name, "graph.RO_QUERY")) return CMD_RO_QUERY; - if (!strcasecmp(cmd_name, "graph.DELETE")) return CMD_DELETE; - if (!strcasecmp(cmd_name, "graph.EXPLAIN")) return CMD_EXPLAIN; - if (!strcasecmp(cmd_name, "graph.PROFILE")) return CMD_PROFILE; - if (!strcasecmp(cmd_name, "graph.BULK")) return CMD_BULK_INSERT; - if (!strcasecmp(cmd_name, "graph.SLOWLOG")) return CMD_SLOWLOG; - if (!strcasecmp(cmd_name, "graph.CONFIG")) return CMD_CONFIG; - if (!strcasecmp(cmd_name, "graph.LIST")) return CMD_LIST; + if (!strcasecmp(cmd_name, "graph.BULK")) return CMD_BULK_INSERT; // we shouldn't reach this point ASSERT(false); return CMD_UNKNOWN; } + diff --git a/src/commands/commands.h b/src/commands/commands.h index bfdbdba087..6d419e6750 100644 --- a/src/commands/commands.h +++ b/src/commands/commands.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -27,6 +30,7 @@ typedef enum { CMD_LIST = 9, CMD_DEBUG = 10, CMD_INFO = 11, + CMD_EFFECT = 12 } GRAPH_Commands; //------------------------------------------------------------------------------ @@ -43,9 +47,8 @@ int Graph_List(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int Graph_Info(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int Graph_Debug(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int Graph_Delete(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); +int Graph_Effect(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int Graph_Config(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int Graph_Slowlog(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); -int Graph_Constraint(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); - int CommandDispatch(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); - +int Graph_Constraint(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); diff --git a/src/commands/execution_ctx.c b/src/commands/execution_ctx.c index b102a8d4f6..f224a7dcdf 100644 --- a/src/commands/execution_ctx.c +++ b/src/commands/execution_ctx.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "execution_ctx.h" #include "RG.h" -#include "../errors.h" #include "../query_ctx.h" +#include "../errors/errors.h" #include "../execution_plan/execution_plan_clone.h" static ExecutionType _GetExecutionTypeFromAST @@ -103,6 +106,11 @@ ExecutionCtx *ExecutionCtx_FromQuery ExecutionCtx *ret; const char *q_str; // query string excluding query parameters + if(unlikely(strlen(q) == 0)) { + ErrorCtx_SetError(EMSG_EMPTY_QUERY); + return NULL; + } + // parse and validate parameters only // extract query string // return invalid execution context if failed to parse params @@ -119,11 +127,12 @@ ExecutionCtx *ExecutionCtx_FromQuery // query included only params e.g. 'cypher a=1' was provided if(unlikely(strlen(q_str) == 0)) { parse_result_free(params_parse_result); - ErrorCtx_SetError("Error: empty query."); + ErrorCtx_SetError(EMSG_EMPTY_QUERY); return NULL; } // update query context with the query without params + // (here the QueryInfo is created as well, starting the stage timer) QueryCtx *ctx = QueryCtx_GetQueryCtx(); ctx->query_data.query_no_params = q_str; @@ -156,7 +165,7 @@ ExecutionCtx *ExecutionCtx_FromQuery // if no error has been set, emit one now if(!ErrorCtx_EncounteredError()) { - ErrorCtx_SetError("Error: could not parse query"); + ErrorCtx_SetError(EMSG_COULD_NOT_PARSE_QUERY); } return NULL; } @@ -171,12 +180,12 @@ ExecutionCtx *ExecutionCtx_FromQuery //---------------------------------------------------------------------- // build execution-plan //---------------------------------------------------------------------- - ExecutionPlan *plan = NewExecutionPlan(); + ExecutionPlan *plan = ExecutionPlan_FromTLS_AST(); // TODO: there must be a better way to understand if the execution-plan // was constructed correctly, - // maybe free the plan within NewExecutionPlan, if error was encountered - // and return NULL ? + // maybe free the plan within ExecutionPlan_FromTLS_AST, if error was + // encountered and return NULL ? if(ErrorCtx_EncounteredError()) { // failed to construct plan // clean up and return NULL diff --git a/src/commands/execution_ctx.h b/src/commands/execution_ctx.h index 445aa576a5..92125f1d7e 100644 --- a/src/commands/execution_ctx.h +++ b/src/commands/execution_ctx.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/common.h b/src/common.h index a4c5406562..13496df09b 100644 --- a/src/common.h +++ b/src/common.h @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/configuration/config.c b/src/configuration/config.c index 48e1eddfe2..6c41e57a6a 100644 --- a/src/configuration/config.c +++ b/src/configuration/config.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "config.h" @@ -55,13 +58,25 @@ // size of node creation buffer #define NODE_CREATION_BUFFER "NODE_CREATION_BUFFER" +// The GRAPH.INFO command +#define CMD_INFO "CMD_INFO" + +// The GRAPH.INFO QUERIES maximum element count +#define CMD_INFO_MAX_QUERIES_COUNT_OPTION_NAME "MAX_INFO_QUERIES" + +// effects replication threshold +#define EFFECTS_THRESHOLD "EFFECTS_THRESHOLD" + + //------------------------------------------------------------------------------ // Configuration defaults //------------------------------------------------------------------------------ -#define CACHE_SIZE_DEFAULT 25 -#define QUEUED_QUERIES_UNLIMITED UINT64_MAX -#define VKEY_MAX_ENTITY_COUNT_DEFAULT 100000 +#define CACHE_SIZE_DEFAULT 25 +#define QUEUED_QUERIES_UNLIMITED UINT64_MAX +#define VKEY_MAX_ENTITY_COUNT_DEFAULT 100000 +#define CMD_INFO_DEFAULT true +#define CMD_INFO_QUERIES_MAX_COUNT_DEFAULT 1000 // configuration object typedef struct { @@ -79,6 +94,9 @@ typedef struct { uint64_t node_creation_buffer; // Number of extra node creations to buffer as margin in matrices int64_t delta_max_pending_changes; // number of pending changed befor RG_Matrix flushed Config_on_change cb; // callback function which being called when config param changed + bool cmd_info_on; // If true, the GRAPH.INFO is enabled. + uint64_t effects_threshold; // replicate via effects when runtime exceeds threshold + uint32_t max_info_queries_count; // Maximum number of query info elements. } RG_Config; RG_Config config; // global module configuration @@ -376,6 +394,51 @@ static uint64_t Config_node_creation_buffer_get(void) { return config.node_creation_buffer; } +//------------------------------------------------------------------------------ +// cmd info +//------------------------------------------------------------------------------ + +static bool Config_cmd_info_get(void) { + return config.cmd_info_on; +} + +static void Config_cmd_info_set +( + const bool cmd_info_on +) { + config.cmd_info_on = cmd_info_on; +} + +static uint32_t Config_cmd_info_max_queries_get(void) { + return config.max_info_queries_count; +} + +static void Config_cmd_info_max_queries_set +( + const uint32_t count +) { + if (count > CMD_INFO_QUERIES_MAX_COUNT_DEFAULT) { + config.max_info_queries_count = CMD_INFO_QUERIES_MAX_COUNT_DEFAULT; + } else { + config.max_info_queries_count = count; + } +} + +//------------------------------------------------------------------------------ +// effects threshold +//------------------------------------------------------------------------------ + +static void Config_effects_threshold_set +( + uint64_t threshold +) { + config.effects_threshold = threshold; +} + +static uint64_t Config_effects_threshold_get (void) { + return config.effects_threshold; +} + bool Config_Contains_field ( const char *field_str, @@ -409,6 +472,14 @@ bool Config_Contains_field f = Config_DELTA_MAX_PENDING_CHANGES; } else if(!(strcasecmp(field_str, NODE_CREATION_BUFFER))) { f = Config_NODE_CREATION_BUFFER; + } else if(!(strcasecmp(field_str, ASYNC_DELETE))) { + f = Config_ASYNC_DELETE; + } else if(!(strcasecmp(field_str, CMD_INFO))) { + f = Config_CMD_INFO; + } else if(!(strcasecmp(field_str, CMD_INFO_MAX_QUERIES_COUNT_OPTION_NAME))) { + f = Config_CMD_INFO_MAX_QUERY_COUNT; + } else if (!(strcasecmp(field_str, EFFECTS_THRESHOLD))) { + f = Config_EFFECTS_THRESHOLD; } else { return false; } @@ -475,6 +546,18 @@ const char *Config_Field_name name = NODE_CREATION_BUFFER; break; + case Config_CMD_INFO: + name = CMD_INFO; + break; + + case Config_CMD_INFO_MAX_QUERY_COUNT: + name = CMD_INFO_MAX_QUERIES_COUNT_OPTION_NAME; + break; + + case Config_EFFECTS_THRESHOLD: + name = EFFECTS_THRESHOLD; + break; + //---------------------------------------------------------------------- // invalid option //---------------------------------------------------------------------- @@ -533,6 +616,15 @@ static void _Config_SetToDefaults(void) { // the amount of empty space to reserve for node creations in matrices config.node_creation_buffer = NODE_CREATION_BUFFER_DEFAULT; + + // GRAPH.INFO command on/off. + config.cmd_info_on = CMD_INFO_DEFAULT; + + // GRAPH.INFO maximum queries count. + config.max_info_queries_count = CMD_INFO_QUERIES_MAX_COUNT_DEFAULT; + + // replicate effects if avg change time μs > effects_threshold μs + config.effects_threshold = 300 ; } int Config_Init @@ -798,6 +890,49 @@ bool Config_Option_get } break; + //---------------------------------------------------------------------- + // cmd info + //---------------------------------------------------------------------- + + case Config_CMD_INFO: { + va_start(ap, field); + bool *cmd_info_on = va_arg(ap, bool *); + va_end(ap); + + ASSERT(cmd_info_on != NULL); + (*cmd_info_on) = Config_cmd_info_get(); + } + break; + + //---------------------------------------------------------------------- + // cmd info maximum queries count + //---------------------------------------------------------------------- + + case Config_CMD_INFO_MAX_QUERY_COUNT: { + va_start(ap, field); + uint32_t *count = va_arg(ap, uint32_t *); + va_end(ap); + + ASSERT(count != NULL); + (*count) = Config_cmd_info_max_queries_get(); + } + break; + + //---------------------------------------------------------------------- + // effects threshold + //---------------------------------------------------------------------- + + case Config_EFFECTS_THRESHOLD: { + va_start(ap, field); + uint64_t *effects_threshold = va_arg(ap, uint64_t *); + va_end(ap); + + ASSERT(effects_threshold != NULL); + (*effects_threshold) = Config_effects_threshold_get(); + + } + break; + //---------------------------------------------------------------------- // invalid option //---------------------------------------------------------------------- @@ -998,6 +1133,45 @@ bool Config_Option_set } break; + //---------------------------------------------------------------------- + // cmd info + //---------------------------------------------------------------------- + + case Config_CMD_INFO: { + bool cmd_info_on = false; + if (!_Config_ParseYesNo(val, &cmd_info_on)) { + return false; + } + + Config_cmd_info_set(cmd_info_on); + } + break; + + //---------------------------------------------------------------------- + // cmd info max queries count + //---------------------------------------------------------------------- + + case Config_CMD_INFO_MAX_QUERY_COUNT: { + long long count = 0; + if (!_Config_ParseNonNegativeInteger(val, &count)) return false; + + // A downcast from to . + Config_cmd_info_max_queries_set(count); + } + break; + + // effects threshold + //---------------------------------------------------------------------- + + case Config_EFFECTS_THRESHOLD: { + long long threshold; + if(!_Config_ParseNonNegativeInteger(val, &threshold)) { + return false; + } + Config_effects_threshold_set(threshold); + } + break; + //---------------------------------------------------------------------- // invalid option //---------------------------------------------------------------------- diff --git a/src/configuration/config.h b/src/configuration/config.h index 08a3fa9182..240c332819 100644 --- a/src/configuration/config.h +++ b/src/configuration/config.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -30,7 +33,10 @@ typedef enum { Config_QUERY_MEM_CAPACITY = 10, // max mem(bytes) that query/thread can utilize at any given time Config_DELTA_MAX_PENDING_CHANGES = 11, // number of pending changes before RG_Matrix flushed Config_NODE_CREATION_BUFFER = 12, // size of buffer to maintain as margin in matrices - Config_END_MARKER = 13 + Config_CMD_INFO = 13, // toggle on/off the GRAPH.INFO + Config_CMD_INFO_MAX_QUERY_COUNT = 14, // the max number of info queries count + Config_EFFECTS_THRESHOLD = 15, // replicate queries via effects + Config_END_MARKER = 16 } Config_Option_Field; // callback function, invoked once configuration changes as a result of @@ -41,17 +47,22 @@ typedef void (*Config_on_change)(Config_Option_Field type); static const Config_Option_Field RUNTIME_CONFIGS[] = { Config_TIMEOUT, Config_TIMEOUT_MAX, + Config_ASYNC_DELETE, Config_TIMEOUT_DEFAULT, Config_RESULTSET_MAX_SIZE, Config_MAX_QUEUED_QUERIES, Config_QUERY_MEM_CAPACITY, Config_VKEY_MAX_ENTITY_COUNT, - Config_DELTA_MAX_PENDING_CHANGES + Config_DELTA_MAX_PENDING_CHANGES, + Config_CMD_INFO, + Config_CMD_INFO_MAX_QUERY_COUNT, + Config_EFFECTS_THRESHOLD }; static const size_t RUNTIME_CONFIG_COUNT = sizeof(RUNTIME_CONFIGS) / sizeof(RUNTIME_CONFIGS[0]); -// Set module-level configurations to defaults or to user arguments where provided. -// returns REDISMODULE_OK on success, emits an error and returns REDISMODULE_ERR on failure. +// set module-level configurations to defaults or to user provided arguments +// returns REDISMODULE_OK on success +// emits an error and returns REDISMODULE_ERR on failure int Config_Init ( RedisModuleCtx *ctx, diff --git a/src/configuration/reconf_handler.c b/src/configuration/reconf_handler.c index dbb678fa26..b3a4fa1ded 100644 --- a/src/configuration/reconf_handler.c +++ b/src/configuration/reconf_handler.c @@ -1,10 +1,14 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" +#include "cron/cron.h" #include "util/rmalloc.h" #include "reconf_handler.h" #include "util/thpool/pools.h" @@ -39,6 +43,17 @@ void reconf_handler(Config_Option_Field type) { } break; + case Config_CMD_INFO: + { + bool info_enabled; + bool res = Config_Option_get(type, &info_enabled); + ASSERT(res); + if(info_enabled) { + CronTask_AddStreamFinishedQueries(); + } + } + break; + //---------------------------------------------------------------------- // all other options //---------------------------------------------------------------------- diff --git a/src/configuration/reconf_handler.h b/src/configuration/reconf_handler.h index 661e386d5c..185c595a48 100644 --- a/src/configuration/reconf_handler.h +++ b/src/configuration/reconf_handler.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/constraint/constraint.c b/src/constraint/constraint.c index 146c6f9511..c7ae76919d 100644 --- a/src/constraint/constraint.c +++ b/src/constraint/constraint.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "value.h" @@ -319,6 +322,67 @@ void Constraint_DecPendingChanges c->pending_changes--; } +// replicate constraint to both persistency and replicas +void Constraint_Replicate +( + RedisModuleCtx *ctx, // redis module context + const Constraint c, // constraint to replicate + const struct GraphContext *gc // graph context +) { + // CREATE UNIQUE/MANDATORY [NODE label / RELATIONSHIP type] PROPERTIES prop_count prop0, prop1... + + // command format + // 1. c - CREATE + // 2. c - graph_name + // 3. c - constraint type + // 4. c - entity type NODE/RELATIONSHIP + // 5. c - label + // 6. c - PROPERTIES + // 7. l - #props + // 8. v - [prop0, prop1, ...] + char *fmt = "cccccclv"; + + // graph name + GraphContext *_gc = (GraphContext*)gc; + const char *graph_name = GraphContext_GetName(_gc); + + // constraint type + const char *c_type = (Constraint_GetType(c) == CT_UNIQUE) // constraint type + ? "UNIQUE" + : "MANDATORY"; + + // entity type + char *et; + SchemaType st; + if(Constraint_GetEntityType(c) == GETYPE_NODE) { + et = "NODE"; + st = SCHEMA_NODE; + } else { + et = "RELATIONSHIP"; + st = SCHEMA_EDGE; + } + + // label + Schema *s = GraphContext_GetSchemaByID(_gc, Constraint_GetSchemaID(c), st); + const char *label = Schema_GetName(s); + + // properties + RedisModuleString *attrs[c->n_attr]; + for(uint i = 0; i < c->n_attr; i++) { + const char *attr = c->attr_names[i]; + attrs[i] = RedisModule_CreateString(ctx, attr, strlen(attr)); + } + + // replicate + RedisModule_Replicate(ctx, "GRAPH.CONSTRAINT", fmt, "CREATE", graph_name, + c_type, et, label, "PROPERTIES", c->n_attr, attrs, (size_t)c->n_attr); + + // free strings + for(uint i = 0; i < c->n_attr; i++) { + RedisModule_FreeString(ctx, attrs[i]); + } +} + // tries to enforce constraint void Constraint_Enforce ( @@ -493,8 +557,8 @@ void Constraint_EnforceEdges do { Edge e; - e.srcNodeID = src_id; - e.destNodeID = dest_id; + e.src_id = src_id; + e.dest_id = dest_id; e.relationID = schema_id; if(SINGLE_EDGE(edge_id)) { diff --git a/src/constraint/constraint.h b/src/constraint/constraint.h index 6715401783..8f0f2e8bdb 100644 --- a/src/constraint/constraint.h +++ b/src/constraint/constraint.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -12,7 +15,7 @@ #include "../graph/entities/graph_entity.h" #include "../graph/entities/attribute_set.h" -// forward declaration of opaque constraint structures +// forward declaration of opaque constraint structure typedef struct _Constraint *Constraint; // constraint enforcement callback function @@ -158,6 +161,14 @@ void Constraint_DecPendingChanges Constraint c // constraint to update ); +// replicate constraint to both persistency and replicas +void Constraint_Replicate +( + RedisModuleCtx *ctx, // redis module context + const Constraint c, // constraint to replicate + const struct GraphContext *gc // graph context +); + // tries to enforce constraint on all relevant entities // sets constraint status to pending void Constraint_Enforce diff --git a/src/constraint/mandatory_constraint.c b/src/constraint/mandatory_constraint.c index c7463917c6..4680ea8de9 100644 --- a/src/constraint/mandatory_constraint.c +++ b/src/constraint/mandatory_constraint.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "constraint.h" @@ -31,10 +34,10 @@ struct _MandatoryConstraint { typedef struct _MandatoryConstraint* MandatoryConstraint; static const char *_node_violation_err_msg = - "mandatory constraint violation: node with label %s missing property %s"; + EMSG_MANDATORY_CONSTRAINT_VIOLATION_NODE; static const char *_edge_violation_err_msg = - "mandatory constraint violation: edge with relationship-type %s missing property %s"; + EMSG_MANDATORY_CONSTRAINT_VIOLATION_EDGE; // enforces mandatory constraint on given entity bool Constraint_EnforceMandatory diff --git a/src/constraint/unique_constraint.c b/src/constraint/unique_constraint.c index e6b79ae364..6bac30274d 100644 --- a/src/constraint/unique_constraint.c +++ b/src/constraint/unique_constraint.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "constraint.h" @@ -33,10 +36,10 @@ struct _UniqueConstraint { typedef struct _UniqueConstraint* UniqueConstraint; static const char *_node_violation_err_msg = - "unique constraint violation on node of type %s"; + EMSG_UNIQUE_CONSTRAINT_VIOLATION_NODE; static const char *_edge_violation_err_msg = - "unique constraint violation, on edge of relationship-type %s"; + EMSG_UNIQUE_CONSTRAINT_VIOLATION_EDGE; // sets constraint private data static void _SetPrivateData diff --git a/src/util/cron.c b/src/cron/cron.c similarity index 60% rename from src/util/cron.c rename to src/cron/cron.c index 6aef694b58..606325f04f 100644 --- a/src/util/cron.c +++ b/src/cron/cron.c @@ -1,8 +1,19 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" #include "cron.h" -#include "heap.h" -#include "rmalloc.h" -#include "../RG.h" +#include "util/heap.h" +#include "util/rmalloc.h" + #include +#include #include #include @@ -16,17 +27,19 @@ typedef struct { struct timespec due; // absolute time for when task should run CronTaskCB cb; // callback to call when task is due + CronTaskFree free; // [optional] private data free function void *pdata; // [optional] private data passed to callback } CRON_TASK; // CRON object typedef struct { - bool alive; // indicates cron is active - heap_t *tasks; // min heap of cron tasks - pthread_mutex_t mutex; // mutex control access to tasks - pthread_mutex_t condv_mutex; // mutex control access to condv - pthread_cond_t condv; // conditional variable - pthread_t thread; // thread running cron main loop + bool alive; // indicates cron is active + heap_t *tasks; // min heap of cron tasks + CRON_TASK* volatile current_task; // current task being executed + pthread_mutex_t mutex; // mutex control access to tasks + pthread_mutex_t condv_mutex; // mutex control access to condv + pthread_cond_t condv; // conditional variable + pthread_t thread; // thread running cron main loop } CRON; // single static CRON instance, initialized at CRON_Start @@ -71,6 +84,10 @@ static struct timespec due_in_ms due.tv_sec += ms / 1000; due.tv_nsec += (ms % 1000) * 1000000; + // add the overflow seconds otherwise the time will be invalid + // and the thread will wake up immediately which lead to busy loop + due.tv_sec += due.tv_nsec / 1000000000; + due.tv_nsec %= 1000000000; return due; } @@ -113,6 +130,18 @@ static bool CRON_RemoveTask return res != NULL; } +static bool CRON_RemoveCurrentTask +( + const CRON_TASK *t // task to remove +) { + ASSERT(t != NULL); + + pthread_mutex_lock(&cron->mutex); + cron->current_task = Heap_remove_item(cron->tasks, t); + pthread_mutex_unlock(&cron->mutex); + return cron->current_task != NULL; +} + static void CRON_InsertTask ( CRON_TASK *t @@ -137,7 +166,13 @@ static void CRON_FreeTask ( CRON_TASK *t ) { - ASSERT(t); + ASSERT(t != NULL); + + // free task private data + if(t->pdata != NULL && t->free != NULL) { + t->free(t->pdata); + } + rm_free(t); } @@ -160,20 +195,22 @@ static void *Cron_Run // execute due tasks CRON_TASK *task = NULL; while((task = CRON_Peek()) && CRON_TaskDue(task)) { - if(!CRON_RemoveTask(task)) { + if(!CRON_RemoveCurrentTask(task)) { // task is aborted continue; } // perform and free task CRON_PerformTask(task); + cron->current_task = NULL; CRON_FreeTask(task); } // sleep struct timespec timeout = (task) ? task->due : due_in_ms(1000); pthread_mutex_lock(&cron->condv_mutex); - pthread_cond_timedwait(&cron->condv, &cron->condv_mutex, &timeout); + int res = pthread_cond_timedwait(&cron->condv, &cron->condv_mutex, &timeout); + ASSERT(res == 0 || res == ETIMEDOUT); pthread_mutex_unlock(&cron->condv_mutex); } @@ -184,30 +221,38 @@ static void *Cron_Run // User facing API //------------------------------------------------------------------------------ -void Cron_Start(void) { +bool Cron_Start(void) { ASSERT(cron == NULL); cron = rm_malloc(sizeof(CRON)); + cron->alive = true; cron->tasks = Heap_new(CRON_JobCmp, NULL); - pthread_cond_init(&cron->condv, NULL); - pthread_mutex_init(&cron->mutex, NULL); - pthread_mutex_init(&cron->condv_mutex, NULL); - pthread_create(&cron->thread, NULL, Cron_Run, NULL); + + bool res = true; + res &= pthread_cond_init(&cron->condv, NULL) == 0; + res &= pthread_mutex_init(&cron->mutex, NULL) == 0; + res &= pthread_mutex_init(&cron->condv_mutex, NULL) == 0; + res &= pthread_create(&cron->thread, NULL, Cron_Run, NULL) == 0; + + return res; } +// stops CRON +// clears all tasks and waits for thread to terminate void Cron_Stop(void) { ASSERT(cron != NULL); - // Stop cron main loop + // stop cron main loop cron->alive = false; CRON_WakeUp(); - // Wait for thread to terminate + // wait for thread to terminate pthread_join(cron->thread, NULL); clear_tasks(); + // free resources Heap_free(cron->tasks); pthread_mutex_destroy(&cron->mutex); pthread_mutex_destroy(&cron->condv_mutex); @@ -216,29 +261,35 @@ void Cron_Stop(void) { cron = NULL; } +// create a new CRON task CronTaskHandle Cron_AddTask ( - uint when, - CronTaskCB cb, - void *pdata + uint when, // number of miliseconds until task invocation + CronTaskCB work, // callback to call when task is due + CronTaskFree free, // [optional] task private data free function + void *pdata // [optional] private data to pass to callback ) { - ASSERT(cb != NULL); - ASSERT(cron != NULL); + ASSERT(work != NULL); + ASSERT(cron != NULL); + ASSERT(!(free != NULL && pdata == NULL)); CRON_TASK *task = rm_malloc(sizeof(CRON_TASK)); - task->cb = cb; - task->pdata = pdata; + task->cb = work; task->due = due_in_ms(when); + task->free = free; + task->pdata = pdata; CRON_InsertTask(task); return (uintptr_t)task; } -void Cron_AbortTask +// tries to abort given task +// in case task is currently being executed, it will wait for it to finish +bool Cron_AbortTask ( - CronTaskHandle t + CronTaskHandle t // task to abort ) { ASSERT(cron != NULL); @@ -246,10 +297,17 @@ void Cron_AbortTask // try remove the task if(!CRON_RemoveTask(task)) { - // task performed - return; + // in case task is currently being performed, wait for it to finish + while (cron->current_task == task) { } + + // task wan't aborted + return false; } // free task CRON_FreeTask(task); + + // managed to abort task + return true; } + diff --git a/src/cron/cron.h b/src/cron/cron.h new file mode 100644 index 0000000000..374fa370da --- /dev/null +++ b/src/cron/cron.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include +#include +#include + +// CRON is a task scheduler +// a task is defined by: +// when it should run; delta in ms from the time it's introduced +// a callback to call when it is time to execute the task +// and an optional private data passed to the callback + +// task callback functions +typedef void (*CronTaskCB)(void *pdata); // task work function +typedef void (*CronTaskFree)(void *pdata); // task private data free function +typedef uintptr_t CronTaskHandle; + +// start CRON, should be called once +bool Cron_Start(void); + +// stop CRON +void Cron_Stop(void); + +// add recurring tasks +void Cron_AddRecurringTasks(void); + +// add stream finished queries task +void CronTask_AddStreamFinishedQueries(); + +// create a new CRON task +CronTaskHandle Cron_AddTask +( + uint when, // number of miliseconds until task invocation + CronTaskCB work, // callback to call when task is due + CronTaskFree free, // [optional] task private data free function + void *pdata // [optional] private data to pass to callback +); + +// aborts the CRON task passed (if found). +// this function wait until the task is completed if it has +// already started at the moment of invocation. +bool Cron_AbortTask +( + CronTaskHandle t +); + diff --git a/src/cron/tasks.c b/src/cron/tasks.c new file mode 100644 index 0000000000..2bd629fb83 --- /dev/null +++ b/src/cron/tasks.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include "cron.h" +#include "util/rmalloc.h" +#include "configuration/config.h" +#include "tasks/stream_finished_queries.h" + +typedef struct RecurringTaskCtx { + uint32_t when; + uint32_t min_interval; + uint32_t max_interval; + Config_Option_Field field; + bool (*task)(void*); + void *(*new)(void*); + void (*free)(void*); + void *ctx; +} RecurringTaskCtx; + +void CronTask_RecurringTaskFree(void *pdata) { + ASSERT(pdata != NULL); + RecurringTaskCtx *current_ctx = (RecurringTaskCtx*)pdata; + current_ctx->free(current_ctx->ctx); + rm_free(current_ctx); +} + +void CronTask_RecurringTask(void *pdata) { + ASSERT(pdata != NULL); + RecurringTaskCtx *current_ctx = (RecurringTaskCtx*)pdata; + bool speed_up = current_ctx->task(current_ctx->ctx); + + bool info_enabled = false; + if(Config_Option_get(Config_CMD_INFO, &info_enabled) && info_enabled) { + RecurringTaskCtx *re_ctx = rm_malloc(sizeof(RecurringTaskCtx)); + *re_ctx = *current_ctx; + re_ctx->ctx = re_ctx->new(re_ctx->ctx); + + // determine next invocation + if(speed_up) { + // reduce delay, lower limit: 250ms + re_ctx->when = (re_ctx->min_interval + re_ctx->when) / 2; + } else { + // increase delay, upper limit: 3sec + re_ctx->when = (re_ctx->max_interval + re_ctx->when) / 2; + } + + // re-add task to CRON + Cron_AddTask(re_ctx->when, CronTask_RecurringTask, CronTask_RecurringTaskFree, (void*)re_ctx); + } +} + +void CronTask_AddStreamFinishedQueries() { + //-------------------------------------------------------------------------- + // add query logging task + //-------------------------------------------------------------------------- + + // make sure info tracking is enabled + bool info_enabled = false; + if(Config_Option_get(Config_CMD_INFO, &info_enabled) && info_enabled) { + RecurringTaskCtx *re_ctx = rm_malloc(sizeof(RecurringTaskCtx)); + re_ctx->new = CronTask_newStreamFinishedQueries; + re_ctx->task = CronTask_streamFinishedQueries; + re_ctx->free = rm_free; + re_ctx->when = 10; // 10ms from now + re_ctx->min_interval = 250; // 250ms + re_ctx->max_interval = 3000; // 3s + + // create task context + StreamFinishedQueryCtx *ctx = rm_malloc(sizeof(StreamFinishedQueryCtx)); + ctx->graph_idx = 0; + + re_ctx->ctx = ctx; + + // add recurring task + Cron_AddTask(0, CronTask_RecurringTask, CronTask_RecurringTaskFree, (void*)re_ctx); + } +} + +// add recurring tasks +void Cron_AddRecurringTasks(void) { + CronTask_AddStreamFinishedQueries(); +} + diff --git a/src/cron/tasks/stream_finished_queries.c b/src/cron/tasks/stream_finished_queries.c new file mode 100644 index 0000000000..013c2bc8c3 --- /dev/null +++ b/src/cron/tasks/stream_finished_queries.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "globals.h" +#include "cron/cron.h" +#include "redismodule.h" +#include "graph/graphcontext.h" +#include "configuration/config.h" +#include "util/circular_buffer.h" +#include "stream_finished_queries.h" + +// event fields count +#define FLD_COUNT 9 + +// field names +#define FLD_WRITE "Write" +#define FLD_TIMEOUT "Timeout" +#define FLD_NAME_QUERY "Query" +#define FLD_NAME_UTILIZED_CACHE "Utilized cache" +#define FLD_NAME_WAIT_DURATION "Wait duration" +#define FLD_NAME_TOTAL_DURATION "Total duration" +#define FLD_NAME_RECEIVED_TIMESTAMP "Received at" +#define FLD_NAME_REPORT_DURATION "Report duration" +#define FLD_NAME_EXECUTION_DURATION "Execution duration" + + +// event field:value pairs +static RedisModuleString *_event[FLD_COUNT * 2] = {0}; + +// initialize '_event' template +// this function should be called only once +static void _initEventTemplate +( + RedisModuleCtx *ctx // redis module context +) { + ASSERT(ctx != NULL); + ASSERT(_event[0] == NULL); + + //-------------------------------------------------------------------------- + // create field names + //-------------------------------------------------------------------------- + + _event[0] = RedisModule_CreateString( + ctx, + FLD_NAME_RECEIVED_TIMESTAMP, + strlen(FLD_NAME_RECEIVED_TIMESTAMP) + ); + + _event[2] = RedisModule_CreateString( + ctx, + FLD_NAME_QUERY, + strlen(FLD_NAME_QUERY) + ); + + _event[4] = RedisModule_CreateString( + ctx, + FLD_NAME_TOTAL_DURATION, + strlen(FLD_NAME_TOTAL_DURATION) + ); + + _event[6] = RedisModule_CreateString( + ctx, + FLD_NAME_WAIT_DURATION, + strlen(FLD_NAME_WAIT_DURATION) + ); + + _event[8] = RedisModule_CreateString( + ctx, + FLD_NAME_EXECUTION_DURATION, + strlen(FLD_NAME_EXECUTION_DURATION) + ); + + _event[10] = RedisModule_CreateString( + ctx, + FLD_NAME_REPORT_DURATION, + strlen(FLD_NAME_REPORT_DURATION) + ); + + _event[12] = RedisModule_CreateString( + ctx, + FLD_NAME_UTILIZED_CACHE, + strlen(FLD_NAME_UTILIZED_CACHE) + ); + + _event[14] = RedisModule_CreateString( + ctx, + FLD_WRITE, + strlen(FLD_WRITE) + ); + + _event[16] = RedisModule_CreateString( + ctx, + FLD_TIMEOUT, + strlen(FLD_TIMEOUT) + ); +} + +// populate event +// sets event values +static void _populateEvent +( + RedisModuleCtx *ctx, // redis module context + const LoggedQuery *q // query information +) { + int l = 0; + char buff[512] = {0}; + + const double total_duration = q->wait_duration + + q->execution_duration + + q->report_duration; + + // FLD_NAME_RECEIVED_TIMESTAMP + _event[1] = RedisModule_CreateStringFromLongLong(ctx, q->received); + + // FLD_NAME_QUERY + _event[3] = RedisModule_CreateString(ctx, q->query, strlen(q->query)); + + // FLD_NAME_TOTAL_DURATION + l = sprintf(buff, "%.6f", total_duration); + _event[5] = RedisModule_CreateString(ctx, buff, l); + + // FLD_NAME_WAIT_DURATION + l = sprintf(buff, "%.6f", q->wait_duration); + _event[7] = RedisModule_CreateString(ctx, buff, l); + + // FLD_NAME_EXECUTION_DURATION + l = sprintf(buff, "%.6f", q->execution_duration); + _event[9] = RedisModule_CreateString(ctx, buff, l); + + // FLD_NAME_REPORT_DURATION + l = sprintf(buff, "%.6f", q->report_duration); + _event[11] = RedisModule_CreateString(ctx, buff, l); + + // FLD_NAME_UTILIZED_CACHE + _event[13] = RedisModule_CreateStringFromLongLong(ctx, q->utilized_cache); + + // FLD_WRITE + _event[15] = RedisModule_CreateStringFromLongLong(ctx, q->write); + + // FLD_TIMEOUT + _event[17] = RedisModule_CreateStringFromLongLong(ctx, q->timeout); +} + +// free event values +static void _clearEvent +( + RedisModuleCtx *ctx // redis module context +) { + if(unlikely(_event[1] == NULL)) return; + + for(int i = 1; i < FLD_COUNT * 2; i += 2) { + RedisModule_FreeString(ctx, _event[i]); + } +} + +// add queries to stream +static void _stream_queries +( + RedisModuleCtx *ctx, // redis module context + RedisModuleKey *key, // stream key + CircularBuffer queries // queries to stream +) { + LoggedQuery *q = NULL; + + // reset reader + CircularBuffer_ResetReader(queries); + + while((q = CircularBuffer_Read(queries, NULL)) != NULL) { + _populateEvent(ctx, q); + + RedisModule_StreamAdd(key, REDISMODULE_STREAM_ADD_AUTOID, NULL, + _event, FLD_COUNT); + + // clean up + rm_free(q->query); + q->query = NULL; + _clearEvent(ctx); + } +} + +void *CronTask_newStreamFinishedQueries +( + void *pdata // task context +) { + ASSERT(pdata != NULL); + StreamFinishedQueryCtx *ctx = (StreamFinishedQueryCtx*)pdata; + + // create private data for next invocation + StreamFinishedQueryCtx *new_ctx = rm_malloc(sizeof(StreamFinishedQueryCtx)); + + // set next iteration graph index + new_ctx->graph_idx = ctx->graph_idx; + + return new_ctx; +} + +// cron task +// stream finished queries for each graph in the keyspace +bool CronTask_streamFinishedQueries +( + void *pdata // task context +) { + StreamFinishedQueryCtx *ctx = (StreamFinishedQueryCtx*)pdata; + RedisModuleCtx *rm_ctx = RedisModule_GetThreadSafeContext(NULL); + + // initialize stream event template + if(unlikely(_event[0] == NULL)) { + _initEventTemplate(rm_ctx); + } + + // start stopwatch + double deadline = 3; // 3ms + simple_timer_t stopwatch; + simple_tic(stopwatch); + + uint32_t max_query_count = 0; // determine max number of queries to collect + Config_Option_get(Config_CMD_INFO_MAX_QUERY_COUNT, &max_query_count); + + KeySpaceGraphIterator it; + Globals_ScanGraphs(&it); + + // pick up from where we've left + GraphIterator_Seek(&it, ctx->graph_idx); + + GraphContext *gc = NULL; + + // as long as we've got processing time + bool gil_acquired = false; + while(TIMER_GET_ELAPSED_MILLISECONDS(stopwatch) < deadline) { + // get next graph to populate + QueriesLog queries_log = NULL; + while((gc = GraphIterator_Next(&it)) != NULL) { + ctx->graph_idx++; // prepare next iteration + if(QueriesLog_GetQueriesCount(gc->queries_log) > 0) { + queries_log = gc->queries_log; + break; + } + GraphContext_DecreaseRefCount(gc); + } + + // iterator depleted + if((gc) == NULL) { + break; + } + + //---------------------------------------------------------------------- + // try to acquire GIL + //---------------------------------------------------------------------- + + while(!gil_acquired && TIMER_GET_ELAPSED_MILLISECONDS(stopwatch) < deadline) { + gil_acquired = + RedisModule_ThreadSafeContextTryLock(rm_ctx) == REDISMODULE_OK; + } + + if(!gil_acquired) { + GraphContext_DecreaseRefCount(gc); + break; + } + + CircularBuffer queries = QueriesLog_ResetQueries(queries_log); + + //---------------------------------------------------------------------- + // stream queries + //---------------------------------------------------------------------- + + RedisModuleString *keyname = + (RedisModuleString*)GraphContext_GetTelemetryStreamName(gc); + + RedisModuleKey *key = RedisModule_OpenKey(rm_ctx, keyname, + REDISMODULE_WRITE); + + // make sure key is of type stream + int key_type = RedisModule_KeyType(key); + if(key_type == REDISMODULE_KEYTYPE_STREAM || + key_type == REDISMODULE_KEYTYPE_EMPTY) { + // add queries to stream + _stream_queries(rm_ctx, key, queries); + + // cap stream + RedisModule_StreamTrimByLength(key, + REDISMODULE_STREAM_TRIM_APPROX, max_query_count); + } else { + // TODO: decide how to handle this... + } + + // clean up + RedisModule_CloseKey(key); + + GraphContext_DecreaseRefCount(gc); + } + + if(gil_acquired) { + RedisModule_ThreadSafeContextUnlock(rm_ctx); + } + + RedisModule_FreeThreadSafeContext(rm_ctx); + + // set next iteration graph index + ctx->graph_idx = (gc == NULL) ? 0 : ctx->graph_idx; + + return (gc != NULL); +} + diff --git a/src/cron/tasks/stream_finished_queries.h b/src/cron/tasks/stream_finished_queries.h new file mode 100644 index 0000000000..dd2964dc78 --- /dev/null +++ b/src/cron/tasks/stream_finished_queries.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "util/simple_timer.h" + +// task context +typedef struct { + uint32_t graph_idx; // last processed graph index +} StreamFinishedQueryCtx; + +// create task context +void *CronTask_newStreamFinishedQueries +( + void *pdata // task context +); + +// cron task +// stream finished queries for each graph in the keyspace +bool CronTask_streamFinishedQueries +( + void *pdata // task context +); + diff --git a/src/datatypes/array.c b/src/datatypes/array.c index b4e78bf7ea..5555bbe017 100644 --- a/src/datatypes/array.c +++ b/src/datatypes/array.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "array.h" #include "../util/arr.h" @@ -180,6 +183,27 @@ XXH64_hash_t SIArray_HashCode(SIValue siarray) { return hashCode; } +// creates an array from its binary representation +// this is the reverse of SIArray_ToBinary +// x = SIArray_FromBinary(SIArray_ToBinary(y)); +// x == y +SIValue SIArray_FromBinary +( + FILE *stream // stream containing binary representation of an array +) { + // read number of elements + uint32_t n; + fread_assert(&n, sizeof(uint32_t), stream); + + SIValue arr = SIArray_New(n); + + for(uint32_t i = 0; i < n; i++) { + array_append(arr.array, SIValue_FromBinary(stream)); + } + + return arr; +} + void SIArray_Free(SIValue siarray) { uint arrayLen = SIArray_Length(siarray); for(uint i = 0; i < arrayLen; i++) { diff --git a/src/datatypes/array.h b/src/datatypes/array.h index f64ef4230a..a62ac951e0 100644 --- a/src/datatypes/array.h +++ b/src/datatypes/array.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -97,6 +100,15 @@ void SIArray_ToString(SIValue list, char **buf, size_t *bufferLen, size_t *bytes */ XXH64_hash_t SIArray_HashCode(SIValue siarray); +// creates an array from its binary representation +// this is the reverse of SIArray_ToBinary +// x = SIArray_FromBinary(SIArray_ToBinary(y)); +// x == y +SIValue SIArray_FromBinary +( + FILE *stream // stream containing binary representation of an array +); + /** * @brief delete an array * @param siarray: diff --git a/src/datatypes/datatypes.h b/src/datatypes/datatypes.h index 9fec55235d..9537f74aa4 100644 --- a/src/datatypes/datatypes.h +++ b/src/datatypes/datatypes.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/datatypes/map.c b/src/datatypes/map.c index ac61d50915..c46af32539 100644 --- a/src/datatypes/map.c +++ b/src/datatypes/map.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "map.h" #include "array.h" diff --git a/src/datatypes/map.h b/src/datatypes/map.h index 6a1dc59ca0..042df6c2c5 100644 --- a/src/datatypes/map.h +++ b/src/datatypes/map.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/datatypes/path/path.c b/src/datatypes/path/path.c index 093d31576a..6d3780befc 100644 --- a/src/datatypes/path/path.c +++ b/src/datatypes/path/path.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./path.h" #include "../../util/arr.h" diff --git a/src/datatypes/path/path.h b/src/datatypes/path/path.h index 0e88afc908..37c1794609 100644 --- a/src/datatypes/path/path.h +++ b/src/datatypes/path/path.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/datatypes/path/sipath.c b/src/datatypes/path/sipath.c index de073910b9..828ac29796 100644 --- a/src/datatypes/path/sipath.c +++ b/src/datatypes/path/sipath.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "sipath.h" #include "RG.h" diff --git a/src/datatypes/path/sipath.h b/src/datatypes/path/sipath.h index 496873546b..522fae7a8e 100644 --- a/src/datatypes/path/sipath.h +++ b/src/datatypes/path/sipath.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/datatypes/path/sipath_builder.c b/src/datatypes/path/sipath_builder.c index 25d1ab9130..ccb3bff002 100644 --- a/src/datatypes/path/sipath_builder.c +++ b/src/datatypes/path/sipath_builder.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "sipath_builder.h" #include "../../RG.h" @@ -17,8 +20,8 @@ */ static Edge _Edge_ReverseDirection(Edge *e) { Edge edge = *e; - edge.srcNodeID = e->destNodeID; - edge.destNodeID = e->srcNodeID; + edge.src_id = e->dest_id; + edge.dest_id = e->src_id; return edge; } @@ -50,7 +53,7 @@ void SIPathBuilder_AppendEdge(SIValue p, SIValue e, bool RTLEdge) { Node *n = Path_GetNode(path, edge_count); EntityID nId = ENTITY_GET_ID(n); // Validate source node is in the right place. - ASSERT(nId == edge->srcNodeID || nId == edge->destNodeID); + ASSERT(nId == edge->src_id || nId == edge->dest_id); /* Reverse direction if needed. A direction change is needed if the last node in the path, reading * RTL is the source node in the edge, and the edge direction in the query is LTR. * path =[(a)] @@ -58,7 +61,7 @@ void SIPathBuilder_AppendEdge(SIValue p, SIValue e, bool RTLEdge) { * Query: MATCH p=(a)<-[]-(b) * e direction needs to be change. */ - Edge edge_to_append = (RTLEdge && nId == edge->srcNodeID) ? _Edge_ReverseDirection(edge) : *edge; + Edge edge_to_append = (RTLEdge && nId == edge->src_id) ? _Edge_ReverseDirection(edge) : *edge; Path_AppendEdge(path, edge_to_append); } diff --git a/src/datatypes/path/sipath_builder.h b/src/datatypes/path/sipath_builder.h index 95b091ac88..8c5bcc5a9b 100644 --- a/src/datatypes/path/sipath_builder.h +++ b/src/datatypes/path/sipath_builder.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "sipath.h" diff --git a/src/datatypes/point.c b/src/datatypes/point.c index 31d15bc0f3..360a7c2ac9 100644 --- a/src/datatypes/point.c +++ b/src/datatypes/point.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "point.h" diff --git a/src/datatypes/point.h b/src/datatypes/point.h index d69beaaeef..ec6d1ab07e 100644 --- a/src/datatypes/point.h +++ b/src/datatypes/point.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/datatypes/set.c b/src/datatypes/set.c index 824114d605..7a36f89b71 100644 --- a/src/datatypes/set.c +++ b/src/datatypes/set.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "set.h" diff --git a/src/datatypes/set.h b/src/datatypes/set.h index b9989f483d..9739c43d90 100644 --- a/src/datatypes/set.h +++ b/src/datatypes/set.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ /* TODO: not sure if this is the right place for this file * another possibility would be ./src/util */ diff --git a/src/datatypes/temporal_value.c b/src/datatypes/temporal_value.c index c714d30ab3..81ca75ae9a 100644 --- a/src/datatypes/temporal_value.c +++ b/src/datatypes/temporal_value.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include "temporal_value.h" diff --git a/src/datatypes/temporal_value.h b/src/datatypes/temporal_value.h index 6efd3c9a3a..cfefe552d3 100644 --- a/src/datatypes/temporal_value.h +++ b/src/datatypes/temporal_value.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include diff --git a/src/debug.c b/src/debug.c index 8e4604a08b..adab802a09 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,19 +1,21 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include #include #include #include "RG.h" +#include "globals.h" #include "util/thpool/pools.h" #include "commands/cmd_context.h" -extern CommandCtx **command_ctxs; - static struct sigaction old_act; static void startCrashReport(void) { @@ -26,18 +28,26 @@ static void endCrashReport(void) { static void logCommands(void) { // #readers + #writers + Redis main thread - int nthreads = ThreadPools_ThreadCount() + 1; - - for(int i = 0; i < nthreads; i++) { - CommandCtx *cmd = command_ctxs[i]; - if(cmd != NULL) { - RedisModule_Log(NULL, "warning", "%s %s", cmd->command_name, - cmd->query); - } + uint32_t n = ThreadPools_ThreadCount() + 1; + CommandCtx* commands[n]; + Globals_GetCommandCtxs(commands, &n); + + for(uint32_t i = 0; i < n; i++) { + CommandCtx *cmd = commands[i]; + ASSERT(cmd != NULL); + + RedisModule_Log(NULL, "warning", "%s %s", cmd->command_name, + cmd->query); + + CommandCtx_Free(cmd); } } -void InfoFunc(RedisModuleInfoCtx *ctx, int for_crash_report) { +void InfoFunc +( + RedisModuleInfoCtx *ctx, + int for_crash_report +) { // make sure information is requested for crash report if(!for_crash_report) return; @@ -46,24 +56,33 @@ void InfoFunc(RedisModuleInfoCtx *ctx, int for_crash_report) { // other threads can potentially change states before being interrupted. ThreadPools_Pause(); - char *command_desc = NULL; // #readers + #writers + Redis main thread - int nthreads = ThreadPools_ThreadCount() + 1; + uint32_t n = ThreadPools_ThreadCount() + 1; + CommandCtx* commands[n]; + Globals_GetCommandCtxs(commands, &n); RedisModule_InfoAddSection(ctx, "executing commands"); - for(int i = 0; i < nthreads; i++) { - CommandCtx *cmd = command_ctxs[i]; - if(cmd != NULL) { - int rc __attribute__((unused)); - rc = asprintf(&command_desc, "%s %s", cmd->command_name, cmd->query); - RedisModule_InfoAddFieldCString(ctx, "command", command_desc); - free(command_desc); - } + for(int i = 0; i < n; i++) { + CommandCtx *cmd = commands[i]; + ASSERT(cmd != NULL); + + int rc __attribute__((unused)); + char *command_desc = NULL; + rc = asprintf(&command_desc, "%s %s", cmd->command_name, cmd->query); + RedisModule_InfoAddFieldCString(ctx, "command", command_desc); + + free(command_desc); + CommandCtx_Free(cmd); } } -void crashHandler(int sig, siginfo_t *info, void *ucontext) { +void crashHandler +( + int sig, + siginfo_t *info, + void *ucontext +) { // pause all working threads // NOTE: pausing is an async operation ThreadPools_Pause(); @@ -79,7 +98,10 @@ void crashHandler(int sig, siginfo_t *info, void *ucontext) { (*old_act.sa_sigaction)(sig, info, ucontext); } -void setupCrashHandlers(RedisModuleCtx *ctx) { +void setupCrashHandlers +( + RedisModuleCtx *ctx +) { // if RedisModule_RegisterInfoFunc is available use it // to report RedisGraph additional information in case of a crash // otherwise overwrite Redis signal handler diff --git a/src/debug.h b/src/debug.h index 201ede546f..193010d577 100644 --- a/src/debug.h +++ b/src/debug.h @@ -1,13 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "redismodule.h" -// Register sigsegv signal hander -void setupCrashHandlers(RedisModuleCtx *ctx); +// register sigsegv signal hander +void setupCrashHandlers +( + RedisModuleCtx *ctx +); diff --git a/src/effects/effects.c b/src/effects/effects.c new file mode 100644 index 0000000000..826282e4d8 --- /dev/null +++ b/src/effects/effects.c @@ -0,0 +1,817 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include "effects.h" +#include "../query_ctx.h" + +// determine block available space +#define BLOCK_AVAILABLE_SPACE(b) (b->cap - BLOCK_USED_SPACE(b)) + +// determine how many bytes been written to buffer +#define BLOCK_USED_SPACE(b) (b->offset - b->buffer) + +// linked list of EffectsBufferblocks +struct EffectsBufferBlock { + size_t cap; // block capacity + unsigned char *offset; // buffer offset + struct EffectsBufferBlock *next; // pointer to next buffer + unsigned char buffer[]; // buffer +}; + +// effects buffer is a linked-list of buffers +struct _EffectsBuffer { + size_t block_size; // block size + struct EffectsBufferBlock *head; // first block + struct EffectsBufferBlock *current; // current block + uint64_t n; // number of effects in buffer +}; + +// forward declarations +static void EffectsBuffer_WriteSIArray +( + const SIValue *arr, // array + EffectsBuffer *buff // effect buffer +); + +// create a new effects-buffer block +static struct EffectsBufferBlock *EffectsBufferBlock_New +( + size_t n // size of block +) { + size_t _n = sizeof(struct EffectsBufferBlock) + n; + struct EffectsBufferBlock *b = rm_malloc(_n); + + b->cap = n; + b->next = NULL; + b->offset = b->buffer; + + return b; +} + +// add a new block to effects-buffer +static void EffectsBuffer_AddBlock +( + EffectsBuffer *eb // effects-buffer +) { + // create a new block and link + struct EffectsBufferBlock *b = EffectsBufferBlock_New(eb->block_size); + eb->current->next = b; + eb->current = b; +} + +// write n bytes from ptr into block +// returns actual number of bytes written +// if buffer isn't large enough only a portion of the bytes will be written +static size_t EffectsBufferBlock_WriteBytes +( + const unsigned char *ptr, // data to write + size_t n, // number of bytes to write + struct EffectsBufferBlock *b // block to write to +) { + // validations + ASSERT(n > 0); + ASSERT(b != NULL); + ASSERT(ptr != NULL); + + // determine number of bytes we can write + n = MIN(n, BLOCK_AVAILABLE_SPACE(b)); + + // write n bytes to buffer + memcpy(b->offset, ptr, n); + + // update offset + b->offset += n; + + return n; +} + +// write n bytes from ptr into effects-buffer +static void EffectsBuffer_WriteBytes +( + const void *ptr, // data to write + size_t n, // number of bytes to write + EffectsBuffer *eb // effects-buffer +) { + ASSERT(n > 0); + ASSERT(eb != NULL); + ASSERT(ptr != NULL); + + while(n > 0) { + struct EffectsBufferBlock *b = eb->current; + size_t written = EffectsBufferBlock_WriteBytes(ptr, n, b); + + // advance ptr + ptr += written; + + if(written == 0) { + // no bytes written block is full, create a new block + EffectsBuffer_AddBlock(eb); + } + + // update remaining bytes to write + n -= written; + } +} + +static void EffectsBuffer_WriteString +( + const char *str, + EffectsBuffer *eb +) { + ASSERT(eb != NULL); + ASSERT(str != NULL); + + size_t l = strlen(str) + 1; + EffectsBuffer_WriteBytes(&l, sizeof(size_t), eb); + EffectsBuffer_WriteBytes(str, l, eb); +} + +// writes a binary representation of v into Effect-Buffer +static void EffectsBuffer_WriteSIValue +( + const SIValue *v, + EffectsBuffer *buff +) { + ASSERT(v != NULL); + ASSERT(buff != NULL); + + // format: + // type + // value + bool b; + size_t len = 0; + + SIType t = v->type; + + // write type + EffectsBuffer_WriteBytes(&t, sizeof(SIType), buff); + + // write value + switch(t) { + case T_POINT: + // write value to stream + EffectsBuffer_WriteBytes(&v->point, sizeof(Point), buff); + break; + case T_ARRAY: + // write array to stream + EffectsBuffer_WriteSIArray(v, buff); + break; + case T_STRING: + EffectsBuffer_WriteString(v->stringval, buff); + break; + case T_BOOL: + // write bool to stream + b = SIValue_IsTrue(*v); + EffectsBuffer_WriteBytes(&b, sizeof(bool), buff); + break; + case T_INT64: + // write int to stream + EffectsBuffer_WriteBytes(&v->longval, sizeof(v->longval), buff); + break; + case T_DOUBLE: + // write double to stream + EffectsBuffer_WriteBytes(&v->doubleval, sizeof(v->doubleval), buff); + break; + case T_NULL: + // no additional data is required to represent NULL + break; + default: + assert(false && "unknown SIValue type"); + } +} + +// writes a binary representation of arr into Effect-Buffer +static void EffectsBuffer_WriteSIArray +( + const SIValue *arr, // array + EffectsBuffer *buff // effect buffer +) { + // format: + // number of elements + // elements + + SIValue *elements = arr->array; + uint32_t len = array_len(elements); + + // write number of elements + EffectsBuffer_WriteBytes(&len, sizeof(uint32_t), buff); + + // write each element + for (uint32_t i = 0; i < len; i++) { + EffectsBuffer_WriteSIValue(elements + i, buff); + } +} + +// dump attributes to stream +static void EffectsBuffer_WriteAttributeSet +( + const AttributeSet attrs, // attribute set to write to stream + EffectsBuffer *buff +) { + //-------------------------------------------------------------------------- + // write attribute count + //-------------------------------------------------------------------------- + + ushort attr_count = AttributeSet_Count(attrs); + EffectsBuffer_WriteBytes(&attr_count, sizeof(attr_count), buff); + + //-------------------------------------------------------------------------- + // write attributes + //-------------------------------------------------------------------------- + + for(ushort i = 0; i < attr_count; i++) { + // get current attribute name and value + Attribute_ID attr_id; + SIValue attr = AttributeSet_GetIdx(attrs, i, &attr_id); + + // write attribute ID + EffectsBuffer_WriteBytes(&attr_id, sizeof(Attribute_ID), buff); + + // write attribute value + EffectsBuffer_WriteSIValue(&attr, buff); + } +} + +static inline void EffectsBuffer_IncEffectCount +( + EffectsBuffer *buff +) { + ASSERT(buff != NULL); + + buff->n++; +} + +// create a new effects-buffer +EffectsBuffer *EffectsBuffer_New +( + void +) { + size_t n = 62500; // initial size of buffer + EffectsBuffer *eb = rm_malloc(sizeof(EffectsBuffer)); + + struct EffectsBufferBlock *b = EffectsBufferBlock_New(n); + + eb->n = 0; + eb->head = b; + eb->current = b; + eb->block_size = n; + + // write effects version to newly created buffer + uint8_t v = EFFECTS_VERSION; + EffectsBuffer_WriteBytes(&v, sizeof(v), eb); + + return eb; +} + +// returns number of effects in buffer +uint64_t EffectsBuffer_Length +( + const EffectsBuffer *buff // effects-buffer +) { + ASSERT(buff != NULL); + + return buff->n; +} + +// get a copy of effects-buffer internal buffer +unsigned char *EffectsBuffer_Buffer +( + const EffectsBuffer *eb, // effects-buffer + size_t *n // size of returned buffer +) { + ASSERT(eb != NULL); + + //-------------------------------------------------------------------------- + // determine required buffer size + //-------------------------------------------------------------------------- + + size_t l = 0; // required buffer size + struct EffectsBufferBlock *b = eb->head; + while(b != NULL) { + l += BLOCK_USED_SPACE(b); + b = b->next; + } + + //-------------------------------------------------------------------------- + // allocate buffer and populate + //-------------------------------------------------------------------------- + + unsigned char *buffer = rm_malloc(sizeof(unsigned char) * l); + unsigned char *offset = buffer; + + b = eb->head; + while(b != NULL) { + // write block's data to buffer + size_t _n = BLOCK_USED_SPACE(b); + memcpy(offset, b->buffer, _n); + offset += _n; + + // advance to next block + b = b->next; + } + + *n = l; + return buffer; +} + +//------------------------------------------------------------------------------ +// effects creation API +//------------------------------------------------------------------------------ + +// add a node creation effect to buffer +void EffectsBuffer_AddCreateNodeEffect +( + EffectsBuffer *buff, // effect buffer + const Node *n, // node created + const LabelID *labels, // node labels + ushort label_count // number of labels +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // label count + // labels + // attribute count + // attributes (id,value) pair + //-------------------------------------------------------------------------- + + ResultSetStatistics *stats = QueryCtx_GetResultSetStatistics(); + stats->nodes_created++; + stats->properties_set += AttributeSet_Count(*n->attributes); + + EffectType t = EFFECT_CREATE_NODE; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + //-------------------------------------------------------------------------- + // write label count + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&label_count, sizeof(label_count), buff); + + //-------------------------------------------------------------------------- + // write labels + //-------------------------------------------------------------------------- + + if(label_count > 0) { + EffectsBuffer_WriteBytes(labels, sizeof(LabelID) * label_count, buff); + } + + //-------------------------------------------------------------------------- + // write attribute set + //-------------------------------------------------------------------------- + + const AttributeSet attrs = GraphEntity_GetAttributes((const GraphEntity*)n); + EffectsBuffer_WriteAttributeSet(attrs, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add a edge creation effect to buffer +void EffectsBuffer_AddCreateEdgeEffect +( + EffectsBuffer *buff, // effect buffer + const Edge *edge // edge created +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // relationship count + // relationships + // src node ID + // dest node ID + // attribute count + // attributes (id,value) pair + //-------------------------------------------------------------------------- + + ResultSetStatistics *stats = QueryCtx_GetResultSetStatistics(); + stats->relationships_created++; + stats->properties_set += AttributeSet_Count(*edge->attributes); + + EffectType t = EFFECT_CREATE_EDGE; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + //-------------------------------------------------------------------------- + // write relationship type + //-------------------------------------------------------------------------- + + ushort rel_count = 1; + EffectsBuffer_WriteBytes(&rel_count, sizeof(rel_count), buff); + + RelationID rel_id = Edge_GetRelationID(edge); + EffectsBuffer_WriteBytes(&rel_id, sizeof(RelationID), buff); + + //-------------------------------------------------------------------------- + // write src node ID + //-------------------------------------------------------------------------- + + NodeID src_id = Edge_GetSrcNodeID(edge); + EffectsBuffer_WriteBytes(&src_id, sizeof(NodeID), buff); + + //-------------------------------------------------------------------------- + // write dest node ID + //-------------------------------------------------------------------------- + + NodeID dest_id = Edge_GetDestNodeID(edge); + EffectsBuffer_WriteBytes(&dest_id, sizeof(NodeID), buff); + + //-------------------------------------------------------------------------- + // write attribute set + //-------------------------------------------------------------------------- + + const AttributeSet attrs = GraphEntity_GetAttributes((GraphEntity*)edge); + EffectsBuffer_WriteAttributeSet(attrs, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add a node deletion effect to buffer +void EffectsBuffer_AddDeleteNodeEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node // node deleted +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // node ID + //-------------------------------------------------------------------------- + + QueryCtx_GetResultSetStatistics()->nodes_deleted++; + + EffectType t = EFFECT_DELETE_NODE; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + // write node ID + EffectsBuffer_WriteBytes(&ENTITY_GET_ID(node), sizeof(EntityID), buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add a edge deletion effect to buffer +void EffectsBuffer_AddDeleteEdgeEffect +( + EffectsBuffer *eb, // effect buffer + const Edge *edge // edge deleted +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // edge ID + // relation ID + // src ID + // dest ID + //-------------------------------------------------------------------------- + + QueryCtx_GetResultSetStatistics()->relationships_deleted++; + + EffectType t = EFFECT_DELETE_EDGE; + EffectsBuffer_WriteBytes(&t, sizeof(t), eb); + + EffectsBuffer_WriteBytes(&ENTITY_GET_ID(edge), sizeof(EntityID), eb); + + RelationID r_id = Edge_GetRelationID(edge); + EffectsBuffer_WriteBytes(&r_id, sizeof(RelationID), eb); + + NodeID src_id = Edge_GetSrcNodeID(edge); + EffectsBuffer_WriteBytes(&src_id, sizeof(EntityID), eb); + + NodeID dest_id = Edge_GetDestNodeID(edge); + EffectsBuffer_WriteBytes(&dest_id, sizeof(EntityID), eb); + + EffectsBuffer_IncEffectCount(eb); +}; + +// add an entity update effect to buffer +static void EffectsBuffer_AddNodeUpdateEffect +( + EffectsBuffer *buff, // effect buffer + Node *node, // updated node + Attribute_ID attr_id, // updated attribute ID + SIValue value // value +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // entity ID + // attribute id + // attribute value + //-------------------------------------------------------------------------- + + EffectType t = EFFECT_UPDATE_NODE; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + //-------------------------------------------------------------------------- + // write entity ID + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&ENTITY_GET_ID(node), sizeof(EntityID), buff); + + //-------------------------------------------------------------------------- + // write attribute ID + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&attr_id, sizeof(Attribute_ID), buff); + + //-------------------------------------------------------------------------- + // write attribute value + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteSIValue(&value, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add an entity update effect to buffer +static void EffectsBuffer_AddEdgeUpdateEffect +( + EffectsBuffer *buff, // effect buffer + Edge *edge, // updated edge + Attribute_ID attr_id, // updated attribute ID + SIValue value // value +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // edge ID + // relation ID + // src ID + // dest ID + // attribute count (=n) + // attributes (id,value) pair + //-------------------------------------------------------------------------- + + EffectType t = EFFECT_UPDATE_EDGE; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + //-------------------------------------------------------------------------- + // write edge ID + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&ENTITY_GET_ID(edge), sizeof(EntityID), buff); + + //-------------------------------------------------------------------------- + // write relation ID + //-------------------------------------------------------------------------- + + RelationID r = Edge_GetRelationID(edge); + EffectsBuffer_WriteBytes(&r, sizeof(RelationID), buff); + + //-------------------------------------------------------------------------- + // write src ID + //-------------------------------------------------------------------------- + + NodeID s = Edge_GetSrcNodeID(edge); + EffectsBuffer_WriteBytes(&s, sizeof(NodeID), buff); + + //-------------------------------------------------------------------------- + // write dest ID + //-------------------------------------------------------------------------- + + NodeID d = Edge_GetDestNodeID(edge); + EffectsBuffer_WriteBytes(&d, sizeof(NodeID), buff); + + //-------------------------------------------------------------------------- + // write attribute ID + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&attr_id, sizeof(Attribute_ID), buff); + + //-------------------------------------------------------------------------- + // write attribute value + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteSIValue(&value, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add an entity attribute removal effect to buffer +void EffectsBuffer_AddEntityRemoveAttributeEffect +( + EffectsBuffer *buff, // effect buffer + GraphEntity *entity, // updated entity ID + Attribute_ID attr_id, // updated attribute ID + GraphEntityType entity_type // entity type +) { + // attribute was deleted + int n = (attr_id == ATTRIBUTE_ID_ALL) + ? AttributeSet_Count(*entity->attributes) + : 1; + + ResultSetStatistics *stats = QueryCtx_GetResultSetStatistics(); + stats->properties_removed += n; + + SIValue v = SI_NullVal(); + if(entity_type == GETYPE_NODE) { + EffectsBuffer_AddNodeUpdateEffect(buff, (Node*)entity, attr_id, v); + } else { + EffectsBuffer_AddEdgeUpdateEffect(buff, (Edge*)entity, attr_id, v); + } +} + +// add an entity add new attribute effect to buffer +void EffectsBuffer_AddEntityAddAttributeEffect +( + EffectsBuffer *buff, // effect buffer + GraphEntity *entity, // updated entity ID + Attribute_ID attr_id, // updated attribute ID + SIValue value, // value + GraphEntityType entity_type // entity type +) { + // attribute was added + QueryCtx_GetResultSetStatistics()->properties_set++; + + if(entity_type == GETYPE_NODE) { + EffectsBuffer_AddNodeUpdateEffect(buff, (Node*)entity, attr_id, value); + } else { + EffectsBuffer_AddEdgeUpdateEffect(buff, (Edge*)entity, attr_id, value); + } +} + +// add an entity update attribute effect to buffer +void EffectsBuffer_AddEntityUpdateAttributeEffect +( + EffectsBuffer *buff, // effect buffer + GraphEntity *entity, // updated entity ID + Attribute_ID attr_id, // updated attribute ID + SIValue value, // value + GraphEntityType entity_type // entity type +) { + ResultSetStatistics *stats = QueryCtx_GetResultSetStatistics(); + stats->properties_set++; // attribute was set + stats->properties_removed++; // old attribute was deleted + + if(entity_type == GETYPE_NODE) { + EffectsBuffer_AddNodeUpdateEffect(buff, (Node*)entity, attr_id, value); + } else { + EffectsBuffer_AddEdgeUpdateEffect(buff, (Edge*)entity, attr_id, value); + } +} + +// add a node add label effect to buffer +void EffectsBuffer_AddSetRemoveLabelsEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node, // updated node + const LabelID *lbl_ids, // labels + uint8_t lbl_count, // number of labels + EffectType t // effect type +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // node ID + // labels count + // label IDs + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + // write node ID + EffectsBuffer_WriteBytes(&ENTITY_GET_ID(node), sizeof(EntityID), buff); + + // write labels count + EffectsBuffer_WriteBytes(&lbl_count, sizeof(lbl_count), buff); + + // write label IDs + EffectsBuffer_WriteBytes(lbl_ids, sizeof(LabelID) * lbl_count, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add a node add labels effect to buffer +void EffectsBuffer_AddLabelsEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node, // updated node + const LabelID *lbl_ids, // added labels + size_t lbl_count // number of removed labels +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // node ID + // labels count + // label IDs + //-------------------------------------------------------------------------- + + QueryCtx_GetResultSetStatistics()->labels_added += lbl_count; + + EffectType t = EFFECT_SET_LABELS; + EffectsBuffer_AddSetRemoveLabelsEffect(buff, node, lbl_ids, lbl_count, t); + + EffectsBuffer_IncEffectCount(buff); +} + +// add a node remove labels effect to buffer +void EffectsBuffer_AddRemoveLabelsEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node, // updated node + const LabelID *lbl_ids, // removed labels + size_t lbl_count // number of removed labels +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // node ID + // labels count + // label IDs + //-------------------------------------------------------------------------- + + QueryCtx_GetResultSetStatistics()->labels_removed += lbl_count; + + EffectType t = EFFECT_REMOVE_LABELS; + EffectsBuffer_AddSetRemoveLabelsEffect(buff, node, lbl_ids, lbl_count, t); + + EffectsBuffer_IncEffectCount(buff); +} + +// add a schema addition effect to buffer +void EffectsBuffer_AddNewSchemaEffect +( + EffectsBuffer *buff, // effect buffer + const char *schema_name, // id of the schema + SchemaType st // type of the schema +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // schema type + // schema name + //-------------------------------------------------------------------------- + + EffectType t = EFFECT_ADD_SCHEMA; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + //-------------------------------------------------------------------------- + // write schema type + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteBytes(&st, sizeof(st), buff); + + //-------------------------------------------------------------------------- + // write schema name + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteString(schema_name, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +// add an attribute addition effect to buffer +void EffectsBuffer_AddNewAttributeEffect +( + EffectsBuffer *buff, // effect buffer + const char *attr // attribute name +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // attribute name + //-------------------------------------------------------------------------- + + EffectType t = EFFECT_ADD_ATTRIBUTE; + EffectsBuffer_WriteBytes(&t, sizeof(t), buff); + + //-------------------------------------------------------------------------- + // write attribute name + //-------------------------------------------------------------------------- + + EffectsBuffer_WriteString(attr, buff); + + EffectsBuffer_IncEffectCount(buff); +} + +static inline void EffectsBufferBlock_Free +( + struct EffectsBufferBlock *b +) { + ASSERT(b != NULL); + rm_free(b); +} + +void EffectsBuffer_Free +( + EffectsBuffer *eb +) { + if(eb == NULL) return; + + // free blocks + struct EffectsBufferBlock *b = eb->head; + while(b != NULL) { + struct EffectsBufferBlock *next = b->next; + EffectsBufferBlock_Free(b); + b = next; + } + + rm_free(eb); +} + diff --git a/src/effects/effects.h b/src/effects/effects.h new file mode 100644 index 0000000000..b055515f76 --- /dev/null +++ b/src/effects/effects.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "../graph/graphcontext.h" + +#define EFFECTS_VERSION 1 // current effects encoding/decoding version + +// EffectsBuffer is an opaque data structure +typedef struct _EffectsBuffer EffectsBuffer; + +// types of effects +typedef enum { + EFFECT_UNKNOWN = 0, // unknown effect + EFFECT_UPDATE_NODE, // node update + EFFECT_UPDATE_EDGE, // edge update + EFFECT_CREATE_NODE, // node creation + EFFECT_CREATE_EDGE, // edge creation + EFFECT_DELETE_NODE, // node deletion + EFFECT_DELETE_EDGE, // edge deletion + EFFECT_SET_LABELS, // set labels + EFFECT_REMOVE_LABELS, // remove labels + EFFECT_ADD_SCHEMA, // schema addition + EFFECT_ADD_ATTRIBUTE, // add attribute +} EffectType; + +//------------------------------------------------------------------------------ +// effects API +//------------------------------------------------------------------------------ + +// applys effects encoded in buffer +void Effects_Apply +( + GraphContext *gc, // graph to operate on + const char *effects_buff, // encoded effects + size_t l // size of buffer +); + +// create a new effects-buffer +EffectsBuffer *EffectsBuffer_New(void); + +// returns number of effects in buffer +uint64_t EffectsBuffer_Length +( + const EffectsBuffer *buff // effects-buffer +); + +// get a copy of effectspbuffer internal buffer +unsigned char *EffectsBuffer_Buffer +( + const EffectsBuffer *eb, // effects-buffer + size_t *n // size of returned buffer +); + +// add a node creation effect to buffer +void EffectsBuffer_AddCreateNodeEffect +( + EffectsBuffer *buff, // effect buffer + const Node *n, // node created + const LabelID *labels, // node labels + ushort label_count // number of labels +); + +// add a edge creation effect to buffer +void EffectsBuffer_AddCreateEdgeEffect +( + EffectsBuffer *buff, // effect buffer + const Edge *edge // edge created +); + +// add a node deletion effect to buffer +void EffectsBuffer_AddDeleteNodeEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node // node deleted +); + +// add a edge deletion effect to buffer +void EffectsBuffer_AddDeleteEdgeEffect +( + EffectsBuffer *buff, // effect buffer + const Edge *edge // edge deleted +); + +// add an entity attribute removal effect to buffer +void EffectsBuffer_AddEntityRemoveAttributeEffect +( + EffectsBuffer *buff, // effect buffer + GraphEntity *entity, // updated entity ID + Attribute_ID attr_id, // updated attribute ID + GraphEntityType entity_type // entity type +); + +// add an entity add new attribute effect to buffer +void EffectsBuffer_AddEntityAddAttributeEffect +( + EffectsBuffer *buff, // effect buffer + GraphEntity *entity, // updated entity ID + Attribute_ID attr_id, // updated attribute ID + SIValue value, // value + GraphEntityType entity_type // entity type +); + +// add an entity update attribute effect to buffer +void EffectsBuffer_AddEntityUpdateAttributeEffect +( + EffectsBuffer *buff, // effect buffer + GraphEntity *entity, // updated entity ID + Attribute_ID attr_id, // updated attribute ID + SIValue value, // value + GraphEntityType entity_type // entity type +); + +// add a node add label effect to buffer +void EffectsBuffer_AddLabelsEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node, // updated node + const LabelID *lbl_ids, // added labels + size_t lbl_count // number of removed labels +); + +// add a node remove label effect to buffer +void EffectsBuffer_AddRemoveLabelsEffect +( + EffectsBuffer *buff, // effect buffer + const Node *node, // updated node + const LabelID *lbl_ids, // removed labels + size_t lbl_count // number of removed labels +); + +// add a schema addition effect to buffer +void EffectsBuffer_AddNewSchemaEffect +( + EffectsBuffer *buff, // effect buffer + const char *schema_name, // id of the schema + SchemaType t // type of the schema +); + +// add an attribute addition effect to buffer +void EffectsBuffer_AddNewAttributeEffect +( + EffectsBuffer *buff, // effect buffer + const char *attr // attribute name +); + +// free effects-buffer +void EffectsBuffer_Free +( + EffectsBuffer *eb +); + diff --git a/src/effects/effects_apply.c b/src/effects/effects_apply.c new file mode 100644 index 0000000000..bb3e671ea5 --- /dev/null +++ b/src/effects/effects_apply.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include "effects.h" +#include "../graph/graph_hub.h" + +#include + +// read effect type from stream +static inline EffectType ReadEffectType +( + FILE *stream // effects stream +) { + EffectType t = EFFECT_UNKNOWN; // default to unknown effect type + + // read EffectType off of stream + fread_assert(&t, sizeof(EffectType), stream); + + return t; +} + +static AttributeSet ReadAttributeSet +( + FILE *stream +) { + //-------------------------------------------------------------------------- + // effect format: + // attribute count + // attributes (id,value) pair + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // read attribute count + //-------------------------------------------------------------------------- + + ushort attr_count; + fread_assert(&attr_count, sizeof(attr_count), stream); + + //-------------------------------------------------------------------------- + // read attributes + //-------------------------------------------------------------------------- + + SIValue values[attr_count]; + Attribute_ID ids[attr_count]; + + for(ushort i = 0; i < attr_count; i++) { + // read attribute ID + fread_assert(ids + i, sizeof(Attribute_ID), stream); + + // read attribute value + values[i] = SIValue_FromBinary(stream); + } + + AttributeSet attr_set = NULL; + AttributeSet_AddNoClone(&attr_set, ids, values, attr_count, false); + + return attr_set; +} + +static void ApplyCreateNode +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // label count + // labels + // attribute count + // attributes (id,value) pair + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // read label count + //-------------------------------------------------------------------------- + + ushort lbl_count; + fread_assert(&lbl_count, sizeof(lbl_count), stream); + + //-------------------------------------------------------------------------- + // read labels + //-------------------------------------------------------------------------- + + LabelID labels[lbl_count]; + for(ushort i = 0; i < lbl_count; i++) { + fread_assert(labels + i, sizeof(LabelID), stream); + } + + //-------------------------------------------------------------------------- + // read attributes + //-------------------------------------------------------------------------- + + AttributeSet attr_set = ReadAttributeSet(stream); + + //-------------------------------------------------------------------------- + // create node + //-------------------------------------------------------------------------- + + Node n = GE_NEW_NODE(); + CreateNode(gc, &n, labels, lbl_count, attr_set, false); +} + +static void ApplyCreateEdge +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // relationship count + // relationships + // src node ID + // dest node ID + // attribute count + // attributes (id,value) pair + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // read relationship type count + //-------------------------------------------------------------------------- + + ushort rel_count; + fread_assert(&rel_count, sizeof(rel_count), stream); + ASSERT(rel_count == 1); + + //-------------------------------------------------------------------------- + // read relationship type + //-------------------------------------------------------------------------- + + RelationID r; + fread_assert(&r, sizeof(r), stream); + + //-------------------------------------------------------------------------- + // read src node ID + //-------------------------------------------------------------------------- + + NodeID src_id; + fread_assert(&src_id, sizeof(NodeID), stream); + + //-------------------------------------------------------------------------- + // read dest node ID + //-------------------------------------------------------------------------- + + NodeID dest_id; + fread_assert(&dest_id, sizeof(NodeID), stream); + + //-------------------------------------------------------------------------- + // read attributes + //-------------------------------------------------------------------------- + + AttributeSet attr_set = ReadAttributeSet(stream); + + //-------------------------------------------------------------------------- + // create edge + //-------------------------------------------------------------------------- + + Edge e; + CreateEdge(gc, &e, src_id, dest_id, r, attr_set, false); +} + +static void ApplyLabels +( + FILE *stream, // effects stream + GraphContext *gc, // graph to operate on + bool add // add or remove labels +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // node ID + // labels count + // label IDs + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // read node ID + //-------------------------------------------------------------------------- + + EntityID id; + fread_assert(&id, sizeof(id), stream); + + //-------------------------------------------------------------------------- + // get updated node + //-------------------------------------------------------------------------- + + Node n; + Graph *g = gc->g; + + bool found = Graph_GetNode(g, id, &n); + ASSERT(found == true); + + //-------------------------------------------------------------------------- + // read labels count + //-------------------------------------------------------------------------- + + uint8_t lbl_count; + fread_assert(&lbl_count, sizeof(lbl_count), stream); + ASSERT(lbl_count > 0); + + // TODO: move to LabelID + uint n_add_labels = 0; + uint n_remove_labels = 0; + const char **add_labels = NULL; + const char **remove_labels = NULL; + const char *lbl[lbl_count]; + + // assign lbl to the appropriate array + if(add) { + add_labels = lbl; + n_add_labels = lbl_count; + } else { + remove_labels = lbl; + n_remove_labels = lbl_count; + } + + //-------------------------------------------------------------------------- + // read labels + //-------------------------------------------------------------------------- + + for(ushort i = 0; i < lbl_count; i++) { + LabelID l; + fread_assert(&l, sizeof(LabelID), stream); + Schema *s = GraphContext_GetSchemaByID(gc, l, SCHEMA_NODE); + ASSERT(s != NULL); + lbl[i] = Schema_GetName(s); + } + + //-------------------------------------------------------------------------- + // update node labels + //-------------------------------------------------------------------------- + + UpdateNodeLabels(gc, &n, add_labels, remove_labels, n_add_labels, + n_remove_labels, false); +} + +static void ApplyAddSchema +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // schema type + // schema name + //-------------------------------------------------------------------------- + + // read schema type + SchemaType t; + fread_assert(&t, sizeof(t), stream); + + // read schema name + // read string length + size_t l; + fread_assert(&l, sizeof(l), stream); + + // read string + char schema_name[l]; + fread_assert(schema_name, l, stream); + + // create schema + AddSchema(gc, schema_name, t, false); +} + +static void ApplyAddAttribute +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // effect type + // attribute name + //-------------------------------------------------------------------------- + + // read attribute name length + size_t l; + fread_assert(&l, sizeof(l), stream); + + // read attribute name + const char attr[l]; + fread_assert(attr, l, stream); + + // attr should not exist + ASSERT(GraphContext_GetAttributeID(gc, attr) == ATTRIBUTE_ID_NONE); + + // add attribute + FindOrAddAttribute(gc, attr, false); +} + +// process Update_Edge effect +static void ApplyUpdateEdge +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // edge ID + // attribute ID + // attribute value + //-------------------------------------------------------------------------- + + SIValue v; // updated value + uint props_set; // number of attributes updated + uint props_removed; // number of attributes removed + Attribute_ID attr_id; // entity ID + + NodeID s_id = INVALID_ENTITY_ID; // edge src node ID + NodeID t_id = INVALID_ENTITY_ID; // edge dest node ID + RelationID r_id = GRAPH_UNKNOWN_RELATION; // edge rel-type + + EntityID id = INVALID_ENTITY_ID; + + //-------------------------------------------------------------------------- + // read edge ID + //-------------------------------------------------------------------------- + + fread_assert(&id, sizeof(EntityID), stream); + ASSERT(id != INVALID_ENTITY_ID); + + //-------------------------------------------------------------------------- + // read relation ID + //-------------------------------------------------------------------------- + + fread_assert(&r_id, sizeof(RelationID), stream); + ASSERT(r_id >= 0); + + //-------------------------------------------------------------------------- + // read src ID + //-------------------------------------------------------------------------- + + fread_assert(&s_id, sizeof(NodeID), stream); + ASSERT(s_id != INVALID_ENTITY_ID); + + //-------------------------------------------------------------------------- + // read dest ID + //-------------------------------------------------------------------------- + + fread_assert(&t_id, sizeof(NodeID), stream); + ASSERT(t_id != INVALID_ENTITY_ID); + + //-------------------------------------------------------------------------- + // read attribute ID + //-------------------------------------------------------------------------- + + fread_assert(&attr_id, sizeof(Attribute_ID), stream); + + //-------------------------------------------------------------------------- + // read attribute value + //-------------------------------------------------------------------------- + + v = SIValue_FromBinary(stream); + ASSERT(SI_TYPE(v) & (SI_VALID_PROPERTY_VALUE | T_NULL)); + ASSERT((attr_id != ATTRIBUTE_ID_ALL || SIValue_IsNull(v)) && attr_id != ATTRIBUTE_ID_NONE); + + UpdateEdgeProperty(gc, id, r_id, s_id, t_id, attr_id, v); +} + +// process UpdateNode effect +static void ApplyUpdateNode +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // entity ID + // attribute ID + // attribute value + //-------------------------------------------------------------------------- + + SIValue v; // updated value + uint props_set; // number of attributes updated + uint props_removed; // number of attributes removed + Attribute_ID attr_id; // entity ID + + EntityID id = INVALID_ENTITY_ID; + + //-------------------------------------------------------------------------- + // read node ID + //-------------------------------------------------------------------------- + + fread_assert(&id, sizeof(EntityID), stream); + + //-------------------------------------------------------------------------- + // read attribute ID + //-------------------------------------------------------------------------- + + fread_assert(&attr_id, sizeof(Attribute_ID), stream); + + //-------------------------------------------------------------------------- + // read attribute ID + //-------------------------------------------------------------------------- + + v = SIValue_FromBinary(stream); + ASSERT(SI_TYPE(v) & (SI_VALID_PROPERTY_VALUE | T_NULL)); + ASSERT((attr_id != ATTRIBUTE_ID_ALL || SIValue_IsNull(v)) && attr_id != ATTRIBUTE_ID_NONE); + + UpdateNodeProperty(gc, id, attr_id, v); +} + +// process DeleteNode effect +static void ApplyDeleteNode +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // node ID + //-------------------------------------------------------------------------- + + Node n; // node to delete + EntityID id; // node ID + Graph *g = gc->g; // graph to delete node from + + // read node ID off of stream + fread_assert(&id, sizeof(EntityID), stream); + + // retrieve node from graph + int res = Graph_GetNode(g, id, &n); + ASSERT(res != 0); + + // delete node + DeleteNodes(gc, &n, 1, false); +} + +// process DeleteNode effect +static void ApplyDeleteEdge +( + FILE *stream, // effects stream + GraphContext *gc // graph to operate on +) { + //-------------------------------------------------------------------------- + // effect format: + // edge ID + // relation ID + // src ID + // dest ID + //-------------------------------------------------------------------------- + + Edge e; // edge to delete + + EntityID id = INVALID_ENTITY_ID; // edge ID + int r_id = GRAPH_UNKNOWN_RELATION; // edge rel-type + NodeID s_id = INVALID_ENTITY_ID; // edge src node ID + NodeID t_id = INVALID_ENTITY_ID; // edge dest node ID + + int res; + UNUSED(res); + + Graph *g = gc->g; // graph to delete edge from + + // read edge ID + fread_assert(&id, sizeof(EntityID), stream); + + // read relation ID + fread_assert(&r_id, sizeof(RelationID), stream); + + // read src node ID + fread_assert(&s_id, sizeof(EntityID), stream); + + // read dest node ID + fread_assert(&t_id, sizeof(EntityID), stream); + + // get edge from the graph + res = Graph_GetEdge(g, id, (Edge*)&e); + ASSERT(res != 0); + + // set edge relation, src and destination node + Edge_SetSrcNodeID(&e, s_id); + Edge_SetDestNodeID(&e, t_id); + Edge_SetRelationID(&e, r_id); + + // delete edge + DeleteEdges(gc, &e, 1, false); +} + +// returns false in case of effect encode/decode version mismatch +static bool ValidateVersion +( + FILE *stream // effects stream +) { + ASSERT(stream != NULL); + + // read version + uint8_t v; + fread_assert(&v, sizeof(uint8_t), stream); + + if(v != EFFECTS_VERSION) { + // unexpected effects version + RedisModule_Log(NULL, "warning", + "GRAPH.EFFECT version mismatch expected: %d got: %d", + EFFECTS_VERSION, v); + return false; + } + + return true; +} + +// applys effects encoded in buffer +void Effects_Apply +( + GraphContext *gc, // graph to operate on + const char *effects_buff, // encoded effects + size_t l // size of buffer +) { + // validations + ASSERT(l > 0); // buffer can't be empty + ASSERT(effects_buff != NULL); // buffer can't be NULL + + // read buffer in a stream fashion + FILE *stream = fmemopen((void*)effects_buff, l, "r"); + + // validate effects version + if(ValidateVersion(stream) == false) { + // replica/primary out of sync + exit(1); + } + + // lock graph for writing + Graph *g = GraphContext_GetGraph(gc); + Graph_AcquireWriteLock(g); + + // update graph sync policy + MATRIX_POLICY policy = Graph_SetMatrixPolicy(g, SYNC_POLICY_RESIZE); + + // as long as there's data in stream + while(ftell(stream) < l) { + // read effect type + EffectType t = ReadEffectType(stream); + switch(t) { + case EFFECT_DELETE_NODE: + ApplyDeleteNode(stream, gc); + break; + case EFFECT_DELETE_EDGE: + ApplyDeleteEdge(stream, gc); + break; + case EFFECT_UPDATE_NODE: + ApplyUpdateNode(stream, gc); + break; + case EFFECT_UPDATE_EDGE: + ApplyUpdateEdge(stream, gc); + break; + case EFFECT_CREATE_NODE: + ApplyCreateNode(stream, gc); + break; + case EFFECT_CREATE_EDGE: + ApplyCreateEdge(stream, gc); + break; + case EFFECT_SET_LABELS: + ApplyLabels(stream, gc, true); + break; + case EFFECT_REMOVE_LABELS: + ApplyLabels(stream, gc, false); + break; + case EFFECT_ADD_SCHEMA: + ApplyAddSchema(stream, gc); + break; + case EFFECT_ADD_ATTRIBUTE: + ApplyAddAttribute(stream, gc); + break; + default: + assert(false && "unknown effect type"); + break; + } + } + + // restore graph sync policy + Graph_SetMatrixPolicy(g, policy); + + // release write lock + Graph_ReleaseLock(g); + + // close stream + fclose(stream); +} + diff --git a/src/errors/error_msgs.h b/src/errors/error_msgs.h new file mode 100644 index 0000000000..d65d1d4407 --- /dev/null +++ b/src/errors/error_msgs.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#define EMSG_EMPTY_KEY "Encountered an empty key when opened key %s" +#define EMSG_NON_GRAPH_KEY "Encountered a non-graph value type when opened key %s" +#define EMSG_DIFFERENT_VALUE "Encountered different graph value when opened key %s" +#define EMSG_ACCESS_VAR "Attempted to access variable before it has been defined" +#define EMSG_INVALID_NUMERIC "Invalid numeric value '%s'" +#define EMSG_INTEGER_OVERFLOW "Integer overflow '%s'" +#define EMSG_FLOAT_OVERFLOW "Float overflow '%s'" +#define EMSG_UNHANDLED_TYPE_MAP_PROJECTION "Encountered unhandled type when trying to read map projection identifier" +#define EMSG_SHORTESTPATH_SINGLE_RELATIONSHIP "shortestPath requires a path containing a single relationship" +#define EMSG_SHORTESTPATH_MINIMAL_LENGTH "shortestPath does not support a minimal length different from 0 or 1" +#define EMSG_SHORTESTPATH_MAX_HOPS "Maximum number of hops must be greater than or equal to minimum number of hops" +#define EMSG_SHORTESTPATH_UNDIRECTED "RedisGraph does not currently support undirected shortestPath traversals" +#define EMSG_SHORTESTPATH_RELATIONSHIP_FILTERS "RedisGraph does not currently support filters on relationships in shortestPath" +#define EMSG_SHORTESTPATH_NODE_FILTERS "Node filters may not be introduced in shortestPath" +#define EMSG_FUNCTION_REQUIER_PREDICATE "'%s' function requires a WHERE predicate" +#define EMSG_NESTED_AGGREGATION "Can't use aggregate functions inside of aggregate functions." +#define EMSG_FUNCTION_MIN_ARGS "Received %d arguments to function '%s', expected at least %d" +#define EMSG_FUNCTION_MAX_ARGS "Received %d arguments to function '%s', expected at most %d" +#define EMSG_MISSING_RECORD "_AR_EXP_UpdateEntityIdx: No record was given to locate a value with alias %s" +#define EMSG_MISSING_VALUE "_AR_EXP_UpdateEntityIdx: Unable to locate a value with alias %s within the record" +#define EMSG_MISSING_PARAMETERS "Missing parameters" +#define EMSG_PREC_INPUT_RANGE "Invalid input - '%f' is not a valid argument, must be a number in the range 0.0 to 1.0" +#define EMSG_NODE_DEGREE_ARGUMENTS "Received %d arguments, expected at most 2 because second argument is List" +#define EMSG_MUST_BE_NON_NEGATIVE "%s must be a non-negative integer" +#define EMSG_INVALID_REGEX "Invalid regex, err=%s" +#define EMSG_INVALIDE_NOT_USAGE "Invalid usage of 'NOT' filter with expressions on left and right sides." +#define EMSG_RETURN_STAR_NO_VARIABLES "RETURN * is not allowed when there are no variables in scope" +#define EMSG_WITH_PROJ_MISSING_ALIAS "WITH clause projections must be aliased" +#define EMSG_SAME_RESULT_COLUMN_NAME "Error: Multiple result columns with the same name are not supported." +#define EMSG_VAR_LEN_INVALID_RANGE "Variable length path, maximum number of hops must be greater or equal to minimum number of hops." +#define EMSG_VAR_LEN "Variable length relationships cannot be used in %s" +#define EMSG_REDECLARE "The bound %s '%s' can't be redeclared in a %s clause" +#define EMSG_ONE_RELATIONSHIP_TYPE "Exactly one relationship type must be specified for each relation in a %s pattern." +#define EMSG_NOT_DEFINED_LEN "'%.*s' not defined" +#define EMSG_NOT_DEFINED "'%s' not defined" +#define EMSG_UNKNOWN_FUNCTION "Unknown function '%s'" +#define EMSG_INVALID_USE_OF_AGGREGATION_FUNCTION "Invalid use of aggregating function '%s'" +#define EMSG_INVALID_USAGE_OF_STAR_PARAMETER "COUNT is the only function which can accept * as an argument" +#define EMSG_INVALID_USAGE_OF_DISTINCT_STAR_PARAMETER "Cannot specify both DISTINCT and * in COUNT(DISTINCT *)" +#define EMSG_MISSING_EVAL_EXP_IN_REDUCE "No eval expression given in reduce" +#define EMSG_UNHANDLED_TYPE_INLINE_PROPERTIES "Encountered unhandled type in inlined properties." +#define EMSG_CREATE_DIRECTED_RELATIONSHIP "Only directed relationships are supported in CREATE" +#define EMSG_SAME_ALIAS_NODE_RELATIONSHIP "The alias '%s' was specified for both a node and a relationship." +#define EMSG_SAME_ALIAS_MULTIPLE_PATTERNS "Cannot use the same relationship variable '%s' for multiple patterns." +#define EMSG_SHORTESTPATH_BOUND_NODES "A shortestPath requires bound nodes" +#define EMSG_ALLSHORTESTPATH_MINIMAL_LENGTH "allShortestPaths(...) does not support a minimal length different from 1" +#define EMSG_LIMIT_MUST_BE_NON_NEGATIVE "LIMIT specified value of invalid type, must be a positive integer" +#define EMSG_SKIP_MUST_BE_NON_NEGATIVE "SKIP specified value of invalid type, must be a positive integer" +#define EMSG_UNION_MISSING_RETURNS "Found %d UNION clauses but only %d RETURN clauses." +#define EMSG_UNION_MISMATCHED_RETURNS "All sub queries in a UNION must have the same column names." +#define EMSG_PROCEDURE_NOT_REGISTERED "Procedure `%s` is not registered" +#define EMSG_PROCEDURE_INVALID_ARGUMENTS "Procedure `%s` requires %d arguments, got %d" +#define EMSG_VAIABLE_ALREADY_DECLARED "Variable `%s` already declared" +#define EMSG_PROCEDURE_INVALID_OUTPUT "Procedure `%s` does not yield output `%s`" +#define EMSG_CALLSUBQUERY_INVALID_REFERENCES "WITH imports in CALL {} must consist of only simple references to outside variables" +#define EMSG_VAIABLE_ALREADY_DECLARED_IN_OUTER_SCOPE "Variable `%s` already declared in outer scope" +#define EMSG_DELETE_INVALID_ARGUMENTS "DELETE can only be called on nodes, paths and relationships" +#define EMSG_SET_LHS_NON_ALIAS "RedisGraph does not currently support non-alias references on the left-hand side of SET expressions" +#define EMSG_UNION_COMBINATION "Invalid combination of UNION and UNION ALL." +#define EMSG_FOREACH_INVALID_BODY "Error: Only updating clauses may reside in FOREACH" +#define EMSG_QUERY_INVALID_LAST_CLAUSE "Query cannot conclude with %s (must be a RETURN clause, an update clause, a procedure call or a non-returning subquery)" +#define EMSG_UNEXPECTED_CLAUSE_FOLLOWING_RETURN "Unexpected clause following RETURN" +#define EMSG_QUERY_CANNOT_BEGIN_WITH "Query cannot begin with '%s *'." +#define EMSG_MISSING_WITH "A WITH clause is required to introduce %s after an updating clause." +#define EMSG_MISSING_WITH_AFTER_MATCH "A WITH clause is required to introduce a MATCH clause after an OPTIONAL MATCH." +#define EMSG_UNSUPPORTED_QUERY_TYPE "Encountered unsupported query type '%s'" +#define EMSG_EMPTY_QUERY "Error: empty query." +#define EMSG_ALLSHORTESTPATH_SUPPORT "RedisGraph support allShortestPaths only in match clauses" +#define EMSG_SHORTESTPATH_SUPPORT "RedisGraph currently only supports shortestPaths in WITH or RETURN clauses" +#define EMSG_EXPLAIN_PROFILE_USAGE "Please use GRAPH.%s 'key' 'query' command instead of GRAPH.QUERY 'key' '%s query'" +#define EMSG_DUPLICATE_PARAMETERS "Duplicated parameter: %s" +#define EMSG_PARSER_ERROR "errMsg: %s line: %u, column: %u, offset: %zu errCtx: %s errCtxOffset: %zu" +#define EMSG_QUERY_WITH_MULTIPLE_STATEMENTS "Error: query with more than one statement is not supported." +#define EMSG_QUERY_TIMEOUT "Query timed out" +#define EMSG_UNABLE_TO_DROP_INDEX "ERR Unable to drop index on :%s(%s): no such index." +#define EMSG_UNKNOWN_EXECUTION_TYPE "ERR Encountered unknown query execution type." +#define EMSG_MISUSE_GRAPH_ROQUERY "graph.RO_QUERY is to be executed only on read-only queries" +#define EMSG_COULD_NOT_PARSE_QUERY "Error: could not parse query" +#define EMSG_UNABLE_TO_RESOLVE_FILTER_ALIAS "Unable to resolve filtered alias '%s'" +#define EMSG_TYPE_MISMATCH "Type mismatch: expected %s but was %s" +#define EMSG_REDISGRAPH_SUPPORT "RedisGraph does not currently support %s" +#define EMSG_INVALID_PROPERTY_VALUE "Property values can only be of primitive types or arrays of primitive types" +#define EMSG_DIVISION_BY_ZERO "Division by zero" +#define EMSG_ALLSHORTESTPATH_SRC_DST_RESLOVED "Source and destination must already be resolved to call allShortestPaths" +#define EMSG_DELETE_OPERATE_ON_CHILD "Delete was constructed without a child operation" +#define EMSG_OPERATE_ON_NON_NEGATIVE_INT "%s operates only on non-negative integers" +#define EMSG_EXPECTED_BOOLEAN_PREDICATE "Expected boolean predicate." +#define EMSG_FILTER_INVALID_COMPARISON "Filter predicate did not compare two expressions." +#define EMSG_EMPTY_FILTER "Empty filter condition." +#define EMSG_INVALID_NOT_USAGE "Invalid usage of 'NOT' filter." +#define EMSG_ACCESS_UNDEFINED_ATTRIBUTE "Attempted to access undefined attribute" +#define EMSG_IS_MISSING "%s is missing" +#define EMSG_INDEX_ALREADY_EXISTS "Index already exists configuration can't be changed" +#define EMSG_MUST_BE "%s must be %s" +#define EMSG_NOT_SUPPORTED "%s is not supported" +#define EMSG_FULLTEXT_MIN_ARGS "Minimum number of arguments is 2" +#define EMSG_FULLTEXT_LABEL_TYPE "Label argument can be string or map" +#define EMSG_FULLTEXT_FIELD_TYPE "Field argument must be string or map" +#define EMSG_FULLTEXT_DROP_INDEX "ERR Unable to drop index on :%s: no such index." +#define EMSG_REDISEARCH "RediSearch: %s" +#define EMSG_MANDATORY_CONSTRAINT_VIOLATION_NODE "mandatory constraint violation: node with label %s missing property %s" +#define EMSG_MANDATORY_CONSTRAINT_VIOLATION_EDGE "mandatory constraint violation: edge with relationship-type %s missing property %s"; +#define EMSG_UNIQUE_CONSTRAINT_VIOLATION_NODE "unique constraint violation on node of type %s" +#define EMSG_UNIQUE_CONSTRAINT_VIOLATION_EDGE "unique constraint violation, on edge of relationship-type %s" +#define EMSG_SPPATH_REQUIRED "sourceNode and targetNode are required" +#define EMSG_SPPATH_INVALID_TYPE "sourceNode and targetNode must be of type Node" +#define EMSG_REL_DIRECTION "relDirection values must be 'incoming', 'outgoing' or 'both'" +#define EMSG_SSPATH_REQUIRED "sourceNode is required" +#define EMSG_SSPATH_INVALID_TYPE "sourceNode must be of type Node" +#define EMSG_INDEX_SUPPORT_CONSTRAINTS "Index supports constraint" +#define EMSG_QUERY_MEM_CONSUMPTION "Query's mem consumption exceeded capacity" diff --git a/src/errors.c b/src/errors/errors.c similarity index 88% rename from src/errors.c rename to src/errors/errors.c index 1def201112..6e410d00e9 100644 --- a/src/errors.c +++ b/src/errors/errors.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "errors.h" @@ -135,7 +138,7 @@ void Error_InvalidFilterPlacement(rax *entitiesRax) { memcpy(invalid_entity, it.key, it.key_len); invalid_entity[it.key_len] = 0; // Emit compile-time error. - ErrorCtx_SetError("Unable to resolve filtered alias '%s'", invalid_entity); + ErrorCtx_SetError(EMSG_UNABLE_TO_RESOLVE_FILTER_ALIAS, invalid_entity); raxFree(entitiesRax); } @@ -144,7 +147,7 @@ void Error_SITypeMismatch(SIValue received, SIType expected) { char buf[bufferLen]; SIType_ToMultipleTypeString(expected, buf, bufferLen); - ErrorCtx_SetError("Type mismatch: expected %s but was %s", buf, + ErrorCtx_SetError(EMSG_TYPE_MISMATCH, buf, SIType_ToString(SI_TYPE(received))); } @@ -153,20 +156,20 @@ void Error_UnsupportedASTNodeType(const cypher_astnode_t *node) { cypher_astnode_type_t type = cypher_astnode_type(node); const char *type_str = cypher_astnode_typestr(type); - ErrorCtx_SetError("RedisGraph does not currently support %s", type_str); + ErrorCtx_SetError(EMSG_REDISGRAPH_SUPPORT, type_str); } void Error_UnsupportedASTOperator(const cypher_operator_t *op) { ASSERT(op != NULL); - ErrorCtx_SetError("RedisGraph does not currently support %s", op->str); + ErrorCtx_SetError(EMSG_REDISGRAPH_SUPPORT, op->str); } inline void Error_InvalidPropertyValue(void) { - ErrorCtx_SetError("Property values can only be of primitive types or arrays of primitive types"); + ErrorCtx_SetError(EMSG_INVALID_PROPERTY_VALUE); } void Error_DivisionByZero(void) { - ErrorCtx_SetError("Division by zero"); + ErrorCtx_SetError(EMSG_DIVISION_BY_ZERO); } diff --git a/src/errors.h b/src/errors/errors.h similarity index 91% rename from src/errors.h rename to src/errors/errors.h index 6ad563627a..a3ae6af5d7 100644 --- a/src/errors.h +++ b/src/errors/errors.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -10,6 +13,7 @@ #include #include "rax.h" #include "value.h" +#include "error_msgs.h" #include "cypher-parser.h" extern pthread_key_t _tlsErrorCtx; // Error-handling context held in thread-local storage. diff --git a/src/execution_plan/execution_plan.c b/src/execution_plan/execution_plan.c index 0397c878f7..114adc932b 100644 --- a/src/execution_plan/execution_plan.c +++ b/src/execution_plan/execution_plan.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "execution_plan.h" #include "../RG.h" #include "./ops/ops.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "./optimizations/optimizer.h" #include "../ast/ast_build_filter_tree.h" #include "execution_plan_build/execution_plan_modify.h" @@ -54,15 +57,15 @@ static ExecutionPlan *_ExecutionPlan_UnionPlans(AST *ast) { int union_count = array_len(union_indices); ASSERT(union_count > 1); - /* Placeholder for each execution plan, these all will be joined - * via a single UNION operation. */ + // Placeholder for each execution plan, these all will be joined + // via a single UNION operation ExecutionPlan *plans[union_count]; for(int i = 0; i < union_count; i++) { // Create an AST segment from which we will build an execution plan. end_offset = union_indices[i]; AST *ast_segment = AST_NewSegment(ast, start_offset, end_offset); - plans[i] = NewExecutionPlan(); + plans[i] = ExecutionPlan_FromTLS_AST(); AST_Free(ast_segment); // Free the AST segment. // Next segment starts where this one ends. @@ -163,9 +166,9 @@ static ExecutionPlan **_process_segments(AST *ast) { // bound segments //-------------------------------------------------------------------------- - /* retrieve the indices of each WITH clause to properly set - * the segment's bounds. - * Every WITH clause demarcates the beginning of a new segment. */ + // retrieve the indices of each WITH clause to properly set + // the segment's bounds. + // Every WITH clause demarcates the beginning of a new segment segment_indices = AST_GetClauseIndices(ast, CYPHER_AST_WITH); // last segment @@ -201,6 +204,29 @@ static ExecutionPlan **_process_segments(AST *ast) { return segments; } +static bool _ExecutionPlan_HasLocateTaps +( + OpBase *root +) { + if((root->childCount == 0 && root->type != OPType_ARGUMENT && + root->type != OPType_ARGUMENT_LIST) || + // when Foreach or Call {} have a single child, they don't need a tap + (root->childCount == 1 && + (root->type == OPType_FOREACH || root->type == OPType_CALLSUBQUERY)) + ) { + return true; + } + + // recursively visit children + for(int i = 0; i < root->childCount; i++) { + if(_ExecutionPlan_HasLocateTaps(root->children[i])) { + return true; + } + } + + return false; +} + static ExecutionPlan *_tie_segments ( ExecutionPlan **segments, @@ -223,17 +249,17 @@ static ExecutionPlan *_tie_segments // find the first non-argument op with no children in this segment prev_connecting_op = connecting_op; - OpBase **taps = ExecutionPlan_LocateTaps(segment); // in the case of a single segment with FOREACH as its root, there is no // tap (of the current definition) // for instance: FOREACH(i in [i] | CREATE (n:N)) // in any other case, there must be a tap - ASSERT((array_len(taps) > 0) || - (segment_count == 1 && - (OpBase_Type(segment->root) == OPType_FOREACH))); - connecting_op = taps[0]; - array_free(taps); + ASSERT(_ExecutionPlan_HasLocateTaps(segment->root) == true); + + connecting_op = segment->root; + while(connecting_op->childCount > 0) { + connecting_op = connecting_op->children[0]; + } // tie the current segment's tap to the previous segment's root op if(prev_segment != NULL) { @@ -324,7 +350,7 @@ static inline void _implicit_result(ExecutionPlan *plan) { } } -ExecutionPlan *NewExecutionPlan(void) { +ExecutionPlan *ExecutionPlan_FromTLS_AST(void) { AST *ast = QueryCtx_GetAST(); // handle UNION if there are any @@ -384,8 +410,8 @@ void ExecutionPlan_ReturnRecord(const ExecutionPlan *plan, Record r) { static inline void _ExecutionPlan_InitRecordPool(ExecutionPlan *plan) { if(plan->record_pool) return; - /* Initialize record pool. - * Determine Record size to inform ObjectPool allocation. */ + // Initialize record pool. + // Determine Record size to inform ObjectPool allocation uint entries_count = raxSize(plan->record_map); uint rec_size = sizeof(_Record) + (sizeof(Entry) * entries_count); @@ -412,9 +438,9 @@ void ExecutionPlan_Init(ExecutionPlan *plan) { ResultSet *ExecutionPlan_Execute(ExecutionPlan *plan) { ASSERT(plan->prepared) - /* Set an exception-handling breakpoint to capture run-time errors. - * encountered_error will be set to 0 when setjmp is invoked, and will be nonzero if - * a downstream exception returns us to this breakpoint. */ + // Set an exception-handling breakpoint to capture run-time errors. + // encountered_error will be set to 0 when setjmp is invoked, and will be nonzero if + // a downstream exception returns us to this breakpoint int encountered_error = SET_EXCEPTION_HANDLER(); // Encountered a run-time error - return immediately. @@ -501,17 +527,12 @@ ResultSet *ExecutionPlan_Profile(ExecutionPlan *plan) { // Execution plan free functions //------------------------------------------------------------------------------ -static void _ExecutionPlan_FreeInternals(ExecutionPlan *plan) { +static void _ExecutionPlan_FreeInternals +( + ExecutionPlan *plan +) { if(plan == NULL) return; - if(plan->connected_components) { - uint connected_component_count = array_len(plan->connected_components); - for(uint i = 0; i < connected_component_count; i ++) { - QueryGraph_Free(plan->connected_components[i]); - } - array_free(plan->connected_components); - } - if(plan->query_graph) { QueryGraph_Free(plan->query_graph); } @@ -527,39 +548,67 @@ static void _ExecutionPlan_FreeInternals(ExecutionPlan *plan) { rm_free(plan); } -// Free an op tree and its associated ExecutionPlan segments. -static ExecutionPlan *_ExecutionPlan_FreeOpTree(OpBase *op) { - if(op == NULL) return NULL; - ExecutionPlan *child_plan = NULL; - ExecutionPlan *prev_child_plan = NULL; - // Store a reference to the current plan. - ExecutionPlan *current_plan = (ExecutionPlan *)op->plan; - for(uint i = 0; i < op->childCount; i ++) { - child_plan = _ExecutionPlan_FreeOpTree(op->children[i]); - // In most cases all children will share the same plan, but if they don't - // (for an operation like UNION) then free the now-obsolete previous child plan. - if(prev_child_plan != child_plan && prev_child_plan != current_plan) { - _ExecutionPlan_FreeInternals(prev_child_plan); - prev_child_plan = child_plan; - } +// free the execution plans and all of the operations +void ExecutionPlan_Free +( + ExecutionPlan *plan +) { + ASSERT(plan != NULL); + if(plan->root == NULL) { + _ExecutionPlan_FreeInternals(plan); + return; } - // Free this op. - OpBase_Free(op); + // ------------------------------------------------------------------------- + // free op tree and collect execution-plans + // ------------------------------------------------------------------------- - // Free each ExecutionPlan segment once all ops associated with it have been freed. - if(current_plan != child_plan) _ExecutionPlan_FreeInternals(child_plan); + // traverse the execution-plan graph (DAG -> no endless cycles), while + // collecting the different segments, and freeing the op tree + dict *plans = HashTableCreate(&def_dt); + OpBase **visited = array_new(OpBase *, 1); + OpBase **to_visit = array_new(OpBase *, 1); - return current_plan; -} + OpBase *op = plan->root; + array_append(to_visit, op); -void ExecutionPlan_Free(ExecutionPlan *plan) { - if(plan == NULL) return; + while(array_len(to_visit) > 0) { + op = array_pop(to_visit); - // Free all ops and ExecutionPlan segments. - _ExecutionPlan_FreeOpTree(plan->root); + // add the plan this op is affiliated with + HashTableAdd(plans, (void *)op->plan, (void *)op->plan); - // Free the final ExecutionPlan segment. - _ExecutionPlan_FreeInternals(plan); -} + // add all direct children of op to to_visit + for(uint i = 0; i < op->childCount; i++) { + if(op->children[i] != NULL) { + array_append(to_visit, op->children[i]); + } + } + + // add op to `visited` array + array_append(visited, op); + } + // free the collected ops + for(int i = array_len(visited)-1; i >= 0; i--) { + op = visited[i]; + OpBase_Free(op); + } + array_free(visited); + array_free(to_visit); + + // ------------------------------------------------------------------------- + // free internals of the plans + // ------------------------------------------------------------------------- + + dictEntry *entry; + ExecutionPlan *curr_plan; + dictIterator *it = HashTableGetIterator(plans); + while((entry = HashTableNext(it)) != NULL) { + curr_plan = (ExecutionPlan *)HashTableGetVal(entry); + _ExecutionPlan_FreeInternals(curr_plan); + } + + HashTableReleaseIterator(it); + HashTableRelease(plans); +} diff --git a/src/execution_plan/execution_plan.h b/src/execution_plan/execution_plan.h index b93f86d946..965fb6b555 100644 --- a/src/execution_plan/execution_plan.h +++ b/src/execution_plan/execution_plan.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -19,54 +22,52 @@ struct ExecutionPlan { AST *ast_segment; // The segment which the current ExecutionPlan segment is built from. rax *record_map; // Mapping between identifiers and record indices. QueryGraph *query_graph; // QueryGraph representing all graph entities in this segment. - QueryGraph **connected_components; // Array of all connected components in this segment. ObjectPool *record_pool; bool prepared; // Indicates if the execution plan is ready for execute. }; -/* Creates a new execution plan from AST */ -ExecutionPlan *NewExecutionPlan(void); +// Creates a new execution plan from AST +ExecutionPlan *ExecutionPlan_FromTLS_AST(void); -/* Prepare an execution plan for execution: optimize, initialize result set schema. */ +// Prepare an execution plan for execution: optimize, initialize result set schema. void ExecutionPlan_PreparePlan(ExecutionPlan *plan); -/* Allocate a new ExecutionPlan segment. */ +// Allocate a new ExecutionPlan segment. ExecutionPlan *ExecutionPlan_NewEmptyExecutionPlan(void); -/* Build a tree of operations that performs all the work required by the clauses of the current AST. */ +// Build a tree of operations that performs all the work required by the clauses of the current AST. void ExecutionPlan_PopulateExecutionPlan(ExecutionPlan *plan); -/* Re position filter op. */ +// Re position filter op. void ExecutionPlan_RePositionFilterOp(ExecutionPlan *plan, OpBase *lower_bound, const OpBase *upper_bound, OpBase *filter); -/* Retrieve the map of aliases to Record offsets in this ExecutionPlan segment. */ +// Retrieve the map of aliases to Record offsets in this ExecutionPlan segment. rax *ExecutionPlan_GetMappings(const ExecutionPlan *plan); -/* Retrieves a Record from the ExecutionPlan's Record pool. */ +// Retrieves a Record from the ExecutionPlan's Record pool. Record ExecutionPlan_BorrowRecord(ExecutionPlan *plan); -/* Free Record contents and return it to the Record pool. */ +// Free Record contents and return it to the Record pool. void ExecutionPlan_ReturnRecord(const ExecutionPlan *plan, Record r); -/* Prints execution plan. */ +// Prints execution plan. void ExecutionPlan_Print(const ExecutionPlan *plan, RedisModuleCtx *ctx); -/* Initialize all operations in an ExecutionPlan. */ +// Initialize all operations in an ExecutionPlan. void ExecutionPlan_Init(ExecutionPlan *plan); -/* Executes plan */ +// Executes plan ResultSet *ExecutionPlan_Execute(ExecutionPlan *plan); -/* Checks if execution plan been drained */ +// Checks if execution plan been drained bool ExecutionPlan_Drained(ExecutionPlan *plan); -/* Drains execution plan */ +// Drains execution plan void ExecutionPlan_Drain(ExecutionPlan *plan); -/* Profile executes plan */ +// Profile executes plan ResultSet *ExecutionPlan_Profile(ExecutionPlan *plan); -/* Free execution plan */ +// Free execution plan void ExecutionPlan_Free(ExecutionPlan *plan); - diff --git a/src/execution_plan/execution_plan_build/build_call_op.c b/src/execution_plan/execution_plan_build/build_call_op.c index 12a59e1ca5..8ad5aa71a2 100644 --- a/src/execution_plan/execution_plan_build/build_call_op.c +++ b/src/execution_plan/execution_plan_build/build_call_op.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../../ast/ast.h" diff --git a/src/execution_plan/execution_plan_build/build_call_subquery.c b/src/execution_plan/execution_plan_build/build_call_subquery.c new file mode 100644 index 0000000000..80b8ac4869 --- /dev/null +++ b/src/execution_plan/execution_plan_build/build_call_subquery.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "../../ast/ast.h" +#include "../ops/op_join.h" +#include "../../util/arr.h" +#include "../../query_ctx.h" +#include "../execution_plan.h" +#include "../ops/op_project.h" +#include "../ops/op_argument.h" +#include "execution_plan_util.h" +#include "../ops/op_aggregate.h" +#include "execution_plan_modify.h" +#include "../ops/op_argument_list.h" +#include "../ops/op_call_subquery.h" + +// adds an empty projection as the child of parent, such that the records passed +// to parent are "filtered" to contain no bound vars +static OpBase *_add_empty_projection +( + OpBase *parent +) { + OpBase *empty_proj = + NewProjectOp(parent->plan, array_new(AR_ExpNode *, 0)); + + OPType type = OpBase_Type(parent); + if(type == OPType_CALLSUBQUERY || type == OPType_FOREACH) { + ExecutionPlan_AddOpInd(parent, empty_proj, 0); + } else { + ExecutionPlan_AddOp(parent, empty_proj); + } + + return empty_proj; +} + +// returns true if op is effectively a deepest op (i.e., no lhs) +static inline bool _is_deepest_call_foreach +( + OpBase *op // op to check +) { + OPType type = OpBase_Type(op); + return (type == OPType_CALLSUBQUERY || type == OPType_FOREACH) && + op->childCount == 1; +} + +// finds the deepest operation starting from root, and appends it to deepest_ops +// if a call {} op with one child is found, it is appended to deepest_ops +static void _get_deepest +( + OpBase *root, // root op from which to look for the deepest op + OpBase ***deepest_ops // target array to which the deepest op is appended +) { + OpBase *deepest = root; + + // check root + if(_is_deepest_call_foreach(deepest)) { + array_append(*deepest_ops, deepest); + return; + } + + // traverse children + OPType type; + while(OpBase_ChildCount(deepest) > 0) { + deepest = deepest->children[0]; + // in case of a CallSubquery op with no lhs, we want to stop + // here, as the added op should be its first child (instead of + // the current child, which will be moved to be the second) + // Example: + // "CALL {CALL {RETURN 1 AS one} RETURN one} RETURN one" + type = OpBase_Type(deepest); + if(_is_deepest_call_foreach(deepest)){ + array_append(*deepest_ops, deepest); + return; + } + } + + array_append(*deepest_ops, deepest); +} + +// looks for a Join operation at root or root->children[0] and returns it, or +// NULL if not found +static OpBase *_get_join +( + OpBase *root // root op from which to look for the Join op +) { + // check if there is a Join operation (from UNION or UNION ALL) + OpBase *join_op = NULL; + if(root->type == OPType_JOIN) { + join_op = root; + } else if(root->childCount > 0 && root->children[0]->type == OPType_JOIN) { + join_op = root->children[0]; + } + + return join_op; +} + +// returns an array with the deepest ops of an execution plan +// note: it's that caller's responsibility to free the array +static OpBase **_find_feeding_points +( + const ExecutionPlan *plan +) { + ASSERT(plan != NULL); + + // the root is a Results op if the subquery is returning. + // search for a Join op in its first child or its first child's first child + // (depending on whether there is a `UNION` or `UNION ALL` clause) + OpBase *join = (OpBase_ChildCount(plan->root) > 0) ? + _get_join(plan->root->children[0]) : + NULL; + + // get the deepest op(s) + uint n_branches = 1; + OpBase **feeding_points = array_new(OpBase *, n_branches); + + if(join != NULL) { + n_branches = OpBase_ChildCount(join); + for(uint i = 0; i < n_branches; i++) { + OpBase *branch = OpBase_GetChild(join, i); + _get_deepest(branch, &feeding_points); + } + } else { + _get_deepest(plan->root, &feeding_points); + } + + ASSERT(array_len(feeding_points) == n_branches); + return feeding_points; +} + +// binds the returning ops (effectively, all ops between the first +// Project\Aggregate and CallSubquery in every branch other than the Join op, +// inclusive) in embedded_plan to plan +// returns true if `embedded_plan` should be free'd after binding its root to +// the call {} op (if there are no more ops left in it), false otherwise +static bool _bind_returning_ops_to_plan +( + const ExecutionPlan *embedded_plan, // embedded plan + const ExecutionPlan *plan // plan to migrate ops to +) { + // check if there is a Join operation (from UNION or UNION ALL) + OpBase *root = embedded_plan->root; + OpBase *join_op = _get_join(root); + + // 5 place-holders are allocated for a maximum of 5 operations between the + // returning op (Project/Aggregate) and the CallSubquery op + // (Sort, Join, Distinct, Skip, Limit) + OpBase *ops[5]; + OPType return_types[] = {OPType_PROJECT, OPType_AGGREGATE}; + + if(join_op == NULL) { + // only one returning projection/aggregation + OpBase *returning_op = + ExecutionPlan_LocateOpMatchingTypes(root, return_types, 2); + // if the returning op has no children, we need to free its exec-plan + // after binding it to a new plan + ExecutionPlan *old_plan = (ExecutionPlan *)returning_op->plan; + uint n_ops = ExecutionPlan_CollectUpwards(ops, returning_op); + ExecutionPlan_MigrateOpsExcludeType(ops, OPType_JOIN, n_ops, plan); + if(returning_op->childCount == 0) { + if(old_plan == embedded_plan) { + return true; + } else { + old_plan->root = NULL; + ExecutionPlan_Free(old_plan); + return false; + } + } + + // there are more ops in the plan of the binded op, so we don't free its + // plan + return false; + } else { + // if there is a Union operation, we need to look at all of its branches + for(uint i = 0; i < join_op->childCount; i++) { + OpBase *child = join_op->children[i]; + OpBase *returning_op = + ExecutionPlan_LocateOpMatchingTypes(child, return_types, 2); + if(returning_op->childCount == 0) { + ExecutionPlan *old_plan = (ExecutionPlan *)returning_op->plan; + old_plan->root = NULL; + ExecutionPlan_Free(old_plan); + } + uint n_ops = ExecutionPlan_CollectUpwards(ops, child); + ExecutionPlan_MigrateOpsExcludeType(ops, OPType_JOIN, n_ops, plan); + + } + + // if there is a join op, we never free the embedded plan + return false; + } +} + +// add empty projections to the branches which do not contain an importing WITH +// clause, in order to 'reset' the bound-vars environment +static void _add_empty_projections +( + OpBase **feeding_points // deepest op in each of the UNION branches +) { + uint n_branches = array_len(feeding_points); + for(uint i = 0; i < n_branches; i++) { + if(OpBase_Type(feeding_points[i]) != OPType_PROJECT) { + feeding_points[i] = _add_empty_projection(feeding_points[i]); + } + } +} + +// construct the execution-plan corresponding to a call {} clause +void buildCallSubqueryPlan +( + ExecutionPlan *plan, // execution plan to add plan to + const cypher_astnode_t *clause // call subquery clause +) { + //-------------------------------------------------------------------------- + // build an AST from the subquery + //-------------------------------------------------------------------------- + + // save the original AST + AST *orig_ast = QueryCtx_GetAST(); + + // create an AST from the body of the subquery + AST subquery_ast = {0}; + subquery_ast.root = cypher_ast_call_subquery_get_query(clause); + subquery_ast.anot_ctx_collection = orig_ast->anot_ctx_collection; + + //-------------------------------------------------------------------------- + // build the embedded execution plan corresponding to the subquery + //-------------------------------------------------------------------------- + + QueryCtx_SetAST(&subquery_ast); + ExecutionPlan *embedded_plan = ExecutionPlan_FromTLS_AST(); + QueryCtx_SetAST(orig_ast); + + // characterize whether the query is eager or not + bool is_eager = ExecutionPlan_isEager(embedded_plan->root); + + // characterize whether the query is returning or not + bool is_returning = (OpBase_Type(embedded_plan->root) == OPType_RESULTS); + + // find the feeding points, to which we will add the projections and feeders + OpBase **feeding_points = _find_feeding_points(embedded_plan); + + // if no variables are imported, add an 'empty' projection so that the + // records within the subquery will be cleared from the outer-context + _add_empty_projections(feeding_points); + + //-------------------------------------------------------------------------- + // Bind returning projection(s)\aggregation(s) to the outer plan + //-------------------------------------------------------------------------- + + bool free_embedded_plan = false; + if(is_returning) { + // remove the Results op from the embedded execution-plan + OpBase *results_op = embedded_plan->root; + ASSERT(OpBase_Type(results_op) == OPType_RESULTS); + ExecutionPlan_RemoveOp(embedded_plan, embedded_plan->root); + OpBase_Free(results_op); + + // bind the returning ops to the outer plan + free_embedded_plan = _bind_returning_ops_to_plan(embedded_plan, plan); + } + + //-------------------------------------------------------------------------- + // plant feeders + //-------------------------------------------------------------------------- + + uint n_feeding_points = array_len(feeding_points); + if(is_eager) { + for(uint i = 0; i < n_feeding_points; i++) { + OpBase *argument_list = NewArgumentListOp(plan); + ExecutionPlan_AddOp(feeding_points[i], argument_list); + } + } else { + for(uint i = 0; i < n_feeding_points; i++) { + OpBase *argument = NewArgumentOp(plan, NULL); + ExecutionPlan_AddOp(feeding_points[i], argument); + } + } + + array_free(feeding_points); + + //-------------------------------------------------------------------------- + // introduce a Call-Subquery op + //-------------------------------------------------------------------------- + + OpBase *call_op = NewCallSubqueryOp(plan, is_eager, is_returning); + ExecutionPlan_UpdateRoot(plan, call_op); + + // add the embedded plan as a child of the Call-Subquery op + ExecutionPlan_AddOp(call_op, embedded_plan->root); + + if(free_embedded_plan) { + embedded_plan->root = NULL; + ExecutionPlan_Free(embedded_plan); + } +} diff --git a/src/execution_plan/execution_plan_build/build_call_subquery.h b/src/execution_plan/execution_plan_build/build_call_subquery.h new file mode 100644 index 0000000000..687de7c805 --- /dev/null +++ b/src/execution_plan/execution_plan_build/build_call_subquery.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +// construct the execution-plan corresponding to a call {} clause +void buildCallSubqueryPlan +( + ExecutionPlan *plan, // execution plan to add plan to + const cypher_astnode_t *clause // call subquery clause +); diff --git a/src/execution_plan/execution_plan_build/build_limit_op.c b/src/execution_plan/execution_plan_build/build_limit_op.c index f57e1a935e..4f7e21e289 100644 --- a/src/execution_plan/execution_plan_build/build_limit_op.c +++ b/src/execution_plan/execution_plan_build/build_limit_op.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../execution_plan.h" #include "../ops/op_limit.h" diff --git a/src/execution_plan/execution_plan_build/build_match_op_tree.c b/src/execution_plan/execution_plan_build/build_match_op_tree.c index 5e0d82f0c6..a037157836 100644 --- a/src/execution_plan/execution_plan_build/build_match_op_tree.c +++ b/src/execution_plan/execution_plan_build/build_match_op_tree.c @@ -1,15 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "execution_plan_construct.h" -#include "execution_plan_modify.h" #include "../ops/ops.h" -#include "../../errors.h" #include "../../query_ctx.h" #include "../execution_plan.h" +#include "../../errors/errors.h" +#include "execution_plan_util.h" +#include "execution_plan_modify.h" +#include "execution_plan_construct.h" #include "../../util/rax_extensions.h" #include "../optimizations/optimizations.h" #include "../../ast/ast_build_filter_tree.h" @@ -26,7 +30,7 @@ static void _ExecutionPlan_ProcessQueryGraph // so that we can order traversals properly FT_FilterNode *ft = AST_BuildFilterTree(ast); QueryGraph **connectedComponents = QueryGraph_ConnectedComponents(qg); - plan->connected_components = connectedComponents; + // if we have already constructed any ops // the plan's record map contains all variables bound at this time uint connectedComponentsCount = array_len(connectedComponents); @@ -66,11 +70,13 @@ static void _ExecutionPlan_ProcessQueryGraph orderExpressions(qg, exps, &expCount, ft, bound_vars); // Create the SCAN operation that will be the tail of the traversal chain. - QGNode *src = QueryGraph_GetNodeByAlias(qg, AlgebraicExpression_Src(exps[0])); + QGNode *src = QueryGraph_GetNodeByAlias(qg, + AlgebraicExpression_Src(exps[0])); uint label_count = QGNode_LabelCount(src); if(label_count > 0) { - AlgebraicExpression *ae_src = AlgebraicExpression_RemoveSource(&exps[0]); + AlgebraicExpression *ae_src = + AlgebraicExpression_RemoveSource(&exps[0]); ASSERT(AlgebraicExpression_DiagonalOperand(ae_src, 0)); const char *label = AlgebraicExpression_Label(ae_src); @@ -83,7 +89,8 @@ static void _ExecutionPlan_ProcessQueryGraph if(s != NULL) label_id = Schema_GetID(s); // resolve source node by performing label scan - NodeScanCtx ctx = NODE_CTX_NEW(alias, label, label_id); + NodeScanCtx *ctx = NodeScanCtx_New((char *)alias, (char *)label, + label_id, src); root = tail = NewNodeByLabelScanOp(plan, ctx); // first operand has been converted into a label scan op @@ -127,7 +134,7 @@ static void _ExecutionPlan_ProcessQueryGraph // TODO: would be great if we can perform this validation // at AST validation time if(!src_bounded || !dest_bounded) { - ErrorCtx_SetError("Source and destination must already be resolved to call allShortestPaths"); + ErrorCtx_SetError(EMSG_ALLSHORTESTPATH_SRC_DST_RESLOVED); } } root = NewCondVarLenTraverseOp(plan, gc->g, exp); @@ -151,6 +158,11 @@ static void _ExecutionPlan_ProcessQueryGraph ExecutionPlan_UpdateRoot(plan, root); } } + + for(uint i = 0; i < connectedComponentsCount; i++) { + QueryGraph_Free(connectedComponents[i]); + } + array_free(connectedComponents); FilterTree_Free(ft); } @@ -165,7 +177,7 @@ static void _buildOptionalMatchOps(ExecutionPlan *plan, AST *ast, const cypher_a bound_vars = raxNew(); // Rather than cloning the record map, collect the bound variables along with their // parser-generated constant strings. - ExecutionPlan_BoundVariables(plan->root, bound_vars); + ExecutionPlan_BoundVariables(plan->root, bound_vars, plan); // Collect the variable names from bound_vars to populate the Argument op we will build. arguments = (const char **)raxValues(bound_vars); raxFree(bound_vars); @@ -196,46 +208,21 @@ void buildMatchOpTree(ExecutionPlan *plan, AST *ast, const cypher_astnode_t *cla return; } - // only add at most one set of traversals per plan - // TODO Revisit and improve this logic - if(plan->root && ExecutionPlan_LocateOpMatchingType(plan->root, SCAN_OPS, SCAN_OP_COUNT)) { - return; - } - - //-------------------------------------------------------------------------- - // Extract mandatory patterns - //-------------------------------------------------------------------------- - - uint mandatory_match_count = 0; // Number of mandatory patterns - const cypher_astnode_t **match_clauses = AST_GetClauses(ast, CYPHER_AST_MATCH); - uint match_clause_count = array_len(match_clauses); - const cypher_astnode_t *patterns[match_clause_count]; - const cypher_astnode_t *mandatory_matches[match_clause_count]; - - for(uint i = 0; i < match_clause_count; i++) { - const cypher_astnode_t *match_clause = match_clauses[i]; - if(cypher_ast_match_is_optional(match_clause)) continue; - mandatory_matches[mandatory_match_count] = match_clause; - patterns[mandatory_match_count] = cypher_ast_match_get_pattern(match_clause); - mandatory_match_count++; - } + const cypher_astnode_t *pattern = cypher_ast_match_get_pattern(clause); // collect the QueryGraph entities referenced in the clauses being converted - QueryGraph *qg = plan->query_graph; - QueryGraph *sub_qg = QueryGraph_ExtractPatterns(qg, patterns, - mandatory_match_count); + QueryGraph *sub_qg = + QueryGraph_ExtractPatterns(plan->query_graph, &pattern, 1); _ExecutionPlan_ProcessQueryGraph(plan, sub_qg, ast); if(ErrorCtx_EncounteredError()) goto cleanup; // Build the FilterTree to model any WHERE predicates on these clauses and place ops appropriately. - FT_FilterNode *sub_ft = AST_BuildFilterTreeFromClauses(ast, mandatory_matches, - mandatory_match_count); + FT_FilterNode *sub_ft = AST_BuildFilterTreeFromClauses(ast, + &clause, 1); ExecutionPlan_PlaceFilterOps(plan, plan->root, NULL, sub_ft); // Clean up cleanup: QueryGraph_Free(sub_qg); - array_free(match_clauses); } - diff --git a/src/execution_plan/execution_plan_build/build_merge_op_tree.c b/src/execution_plan/execution_plan_build/build_merge_op_tree.c index 33be3c55eb..7087d9a6c7 100644 --- a/src/execution_plan/execution_plan_build/build_merge_op_tree.c +++ b/src/execution_plan/execution_plan_build/build_merge_op_tree.c @@ -1,14 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "execution_plan_construct.h" -#include "execution_plan_modify.h" -#include "../execution_plan.h" #include "../ops/ops.h" #include "../../query_ctx.h" +#include "../execution_plan.h" +#include "execution_plan_util.h" +#include "execution_plan_modify.h" +#include "execution_plan_construct.h" #include "../../util/rax_extensions.h" #include "../../ast/ast_build_op_contexts.h" @@ -63,7 +67,7 @@ void buildMergeOp(ExecutionPlan *plan, AST *ast, const cypher_astnode_t *clause, bound_vars = raxNew(); // Rather than cloning the record map, collect the bound variables along with their // parser-generated constant strings. - ExecutionPlan_BoundVariables(plan->root, bound_vars); + ExecutionPlan_BoundVariables(plan->root, bound_vars, plan); // Collect the variable names from bound_vars to populate the Argument ops we will build. arguments = (const char **)raxValues(bound_vars); } diff --git a/src/execution_plan/execution_plan_build/build_pattern_comprehension_ops.c b/src/execution_plan/execution_plan_build/build_pattern_comprehension_ops.c index e4b3c0ab99..acbdc9b02d 100644 --- a/src/execution_plan/execution_plan_build/build_pattern_comprehension_ops.c +++ b/src/execution_plan/execution_plan_build/build_pattern_comprehension_ops.c @@ -1,13 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "execution_plan_construct.h" #include "RG.h" #include "../ops/ops.h" #include "../../query_ctx.h" +#include "execution_plan_util.h" +#include "execution_plan_construct.h" #include "../../util/rax_extensions.h" #include "../../ast/ast_build_filter_tree.h" #include "../execution_plan_build/execution_plan_modify.h" @@ -63,7 +67,8 @@ void buildPatternComprehensionOps if(root->childCount > 0) { // get the bound variable to use when building the traversal ops rax *bound_vars = raxNew(); - ExecutionPlan_BoundVariables(root->children[0], bound_vars); + ExecutionPlan_BoundVariables(root->children[0], bound_vars, + root->children[0]->plan); arguments = (const char **)raxValues(bound_vars); raxFree(bound_vars); } @@ -186,7 +191,8 @@ void buildPatternPathOps if(root->childCount > 0) { // get the bound variable to use when building the traversal ops rax *bound_vars = raxNew(); - ExecutionPlan_BoundVariables(root->children[0], bound_vars); + ExecutionPlan_BoundVariables(root->children[0], bound_vars, + root->children[0]->plan); arguments = (const char **)raxValues(bound_vars); raxFree(bound_vars); } diff --git a/src/execution_plan/execution_plan_build/build_projection_ops.c b/src/execution_plan/execution_plan_build/build_projection_ops.c index f262ea94d8..5968c899e4 100644 --- a/src/execution_plan/execution_plan_build/build_projection_ops.c +++ b/src/execution_plan/execution_plan_build/build_projection_ops.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "execution_plan_construct.h" #include "execution_plan_modify.h" diff --git a/src/execution_plan/execution_plan_build/build_skip_op.c b/src/execution_plan/execution_plan_build/build_skip_op.c index 0a9d4cce25..ea51f2ae6c 100644 --- a/src/execution_plan/execution_plan_build/build_skip_op.c +++ b/src/execution_plan/execution_plan_build/build_skip_op.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../ops/op_skip.h" #include "../execution_plan.h" diff --git a/src/execution_plan/execution_plan_build/execution_plan_construct.c b/src/execution_plan/execution_plan_build/execution_plan_construct.c index 8d09c65ff9..b865b9e28c 100644 --- a/src/execution_plan/execution_plan_build/execution_plan_construct.c +++ b/src/execution_plan/execution_plan_build/execution_plan_construct.c @@ -1,19 +1,20 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "execution_plan_construct.h" -#include "../../ast/enrichment/annotate_projected_named_paths.h" -#include "execution_plan_modify.h" -#include "../execution_plan.h" -#include "../../RG.h" #include "../ops/ops.h" -#include "../../errors.h" #include "../../query_ctx.h" +#include "../../ast/ast_mock.h" +#include "build_call_subquery.h" +#include "execution_plan_util.h" +#include "execution_plan_modify.h" +#include "execution_plan_construct.h" #include "../../util/rax_extensions.h" -#include "../../ast/ast_build_filter_tree.h" #include "../../ast/ast_build_op_contexts.h" #include "../../arithmetic/arithmetic_expression_construct.h" @@ -24,9 +25,9 @@ static inline void _PushDownPathFilters(ExecutionPlan *plan, while(relocate_to->parent && relocate_to->parent->type == OPType_FILTER) { relocate_to = relocate_to->parent; } - /* If the filter op is part of a chain of filter ops, migrate it - * to be the topmost. This ensures that cheaper filters will be - * applied first. */ + // If the filter op is part of a chain of filter ops, migrate it + // to be the topmost. This ensures that cheaper filters will be + // applied first if(relocate_to != path_filter_op) { ExecutionPlan_RemoveOp(plan, path_filter_op); ExecutionPlan_PushBelow(relocate_to, path_filter_op); @@ -77,8 +78,8 @@ void ExecutionPlan_RePositionFilterOp(ExecutionPlan *plan, OpBase *lower_bound, uint64_t references_count = raxSize(references); if(references_count > 0) { - /* Scan execution plan, locate the earliest position where all - * references been resolved. */ + // Scan execution plan, locate the earliest position where all + // references been resolved op = ExecutionPlan_LocateReferencesExcludingOps(lower_bound, upper_bound, FILTER_RECURSE_BLACKLIST, BLACKLIST_OP_COUNT, references); if(!op) { @@ -88,10 +89,10 @@ void ExecutionPlan_RePositionFilterOp(ExecutionPlan *plan, OpBase *lower_bound, return; } } else { - /* The filter tree does not contain references, like: - * WHERE 1=1 - * Place the op directly below the first projection if there is one, - * otherwise update the ExecutionPlan root. */ + // The filter tree does not contain references, like: + // WHERE 1=1 + // Place the op directly below the first projection if there is one, + // otherwise update the ExecutionPlan root op = plan->root; while(op && op->childCount > 0 && op->type != OPType_PROJECT && op->type != OPType_AGGREGATE) { op = op->children[0]; @@ -115,9 +116,9 @@ void ExecutionPlan_RePositionFilterOp(ExecutionPlan *plan, OpBase *lower_bound, ExecutionPlan_PushBelow(op, (OpBase *)filter); } - /* Filter may have migrated a segment, update the filter segment - * and check if the segment root needs to be updated. - * The filter should be associated with the op's segment. */ + // Filter may have migrated a segment, update the filter segment + // and check if the segment root needs to be updated. + // The filter should be associated with the op's segment filter->plan = op->plan; // Re-set the segment root if needed. if(op == op->plan->root) { @@ -130,12 +131,12 @@ void ExecutionPlan_RePositionFilterOp(ExecutionPlan *plan, OpBase *lower_bound, void ExecutionPlan_PlaceFilterOps(ExecutionPlan *plan, OpBase *root, const OpBase *recurse_limit, FT_FilterNode *ft) { - /* Decompose the filter tree into an array of the smallest possible subtrees - * that do not violate the rules of AND/OR combinations. */ + // Decompose the filter tree into an array of the smallest possible subtrees + // that do not violate the rules of AND/OR combinations const FT_FilterNode **sub_trees = FilterTree_SubTrees(ft); - /* For each filter tree, find the earliest position in the op tree - * after which the filter tree can be applied. */ + // For each filter tree, find the earliest position in the op tree + // after which the filter tree can be applied uint nfilters = array_len(sub_trees); for(uint i = 0; i < nfilters; i++) { FT_FilterNode *tree = FilterTree_Clone(sub_trees[i]); @@ -183,7 +184,7 @@ static inline void _buildDeleteOp(ExecutionPlan *plan, const cypher_astnode_t *c if(plan->root == NULL) { // delete must operate on child data, prepare an error if there // is no child op - ErrorCtx_SetError("Delete was constructed without a child operation"); + ErrorCtx_SetError(EMSG_DELETE_OPERATE_ON_CHILD); } AR_ExpNode **exps = AST_PrepareDeleteOp(clause); OpBase *op = NewDeleteOp(plan, exps); @@ -280,6 +281,62 @@ static void _buildForeachOp ExecutionPlan_AddOp(foreach, embedded_plan->root); } +OpBase *ExecutionPlan_BuildOpsFromPath +( + ExecutionPlan *plan, + const char **bound_vars, + const cypher_astnode_t *node +) { + // Initialize an ExecutionPlan that shares this plan's Record mapping. + ExecutionPlan *match_stream_plan = ExecutionPlan_NewEmptyExecutionPlan(); + match_stream_plan->record_map = plan->record_map; + + // If we have bound variables, build an Argument op that represents them. + if(bound_vars) match_stream_plan->root = NewArgumentOp(match_stream_plan, + bound_vars); + + AST *ast = QueryCtx_GetAST(); + // Build a temporary AST holding a MATCH clause. + cypher_astnode_type_t type = cypher_astnode_type(node); + + /* The AST node we're building a mock MATCH clause for will be a path + * if we're converting a MERGE clause or WHERE filter, and we must build + * and later free a CYPHER_AST_PATTERN node to contain it. + * If instead we're converting an OPTIONAL MATCH, the node is itself a MATCH clause, + * and we will reuse its CYPHER_AST_PATTERN node rather than building a new one. */ + bool node_is_path = (type == CYPHER_AST_PATTERN_PATH || type == CYPHER_AST_NAMED_PATH); + AST *match_stream_ast = AST_MockMatchClause(ast, (cypher_astnode_t *)node, node_is_path); + + //-------------------------------------------------------------------------- + // Build plan's query graph + //-------------------------------------------------------------------------- + + // Extract pattern from holistic query graph. + const cypher_astnode_t **match_clauses = AST_GetClauses(match_stream_ast, CYPHER_AST_MATCH); + ASSERT(array_len(match_clauses) == 1); + const cypher_astnode_t *pattern = cypher_ast_match_get_pattern(match_clauses[0]); + array_free(match_clauses); + QueryGraph *sub_qg = QueryGraph_ExtractPatterns(plan->query_graph, &pattern, 1); + match_stream_plan->query_graph = sub_qg; + + ExecutionPlan_PopulateExecutionPlan(match_stream_plan); + + AST_MockFree(match_stream_ast, node_is_path); + QueryCtx_SetAST(ast); // Reset the AST. + + // Associate all new ops with the correct ExecutionPlan and QueryGraph. + OpBase *match_stream_root = match_stream_plan->root; + ExecutionPlan_BindOpsToPlan(plan, match_stream_root, true); + + // NULL-set variables shared between the match_stream_plan and the overall plan. + match_stream_plan->root = NULL; + match_stream_plan->record_map = NULL; + // Free the temporary plan. + ExecutionPlan_Free(match_stream_plan); + + return match_stream_root; +} + void ExecutionPlanSegment_ConvertClause ( GraphContext *gc, @@ -312,6 +369,8 @@ void ExecutionPlanSegment_ConvertClause buildWithOps(plan, clause); } else if(t == CYPHER_AST_FOREACH) { _buildForeachOp(plan, clause, gc); + } else if(t == CYPHER_AST_CALL_SUBQUERY) { + buildCallSubqueryPlan(plan, clause); } else { assert(false && "unhandeled clause"); } diff --git a/src/execution_plan/execution_plan_build/execution_plan_construct.h b/src/execution_plan/execution_plan_build/execution_plan_construct.h index bdd4694f4b..14b41b6481 100644 --- a/src/execution_plan/execution_plan_build/execution_plan_construct.h +++ b/src/execution_plan/execution_plan_build/execution_plan_construct.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -55,3 +58,12 @@ void buildPatternPathOps( OpBase *root, const cypher_astnode_t *ast ); + +// given an AST path pattern, generate the tree of scan, traverse, +// and filter operations required to represent it. +OpBase *ExecutionPlan_BuildOpsFromPath +( + ExecutionPlan *plan, + const char **vars, + const cypher_astnode_t *path +); diff --git a/src/execution_plan/execution_plan_build/execution_plan_modify.c b/src/execution_plan/execution_plan_build/execution_plan_modify.c index 01bb4e7a8e..15239d95ab 100644 --- a/src/execution_plan/execution_plan_build/execution_plan_modify.c +++ b/src/execution_plan/execution_plan_build/execution_plan_modify.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "execution_plan_modify.h" #include "../../RG.h" @@ -75,6 +78,21 @@ inline void ExecutionPlan_AddOp(OpBase *parent, OpBase *newOp) { _OpBase_AddChild(parent, newOp); } +// adds child to be the ind'th child of parent +void ExecutionPlan_AddOpInd +( + OpBase *parent, // parent op + OpBase *child, // child op + uint ind // index of child +) { + ASSERT(parent != NULL); + ASSERT(child != NULL); + + OpBase *to_replace = parent->children[ind]; + _ExecutionPlan_ParentReplaceChild(parent, to_replace, child); + _OpBase_AddChild(parent, to_replace); +} + // Introduce the new operation B between A and A's parent op. void ExecutionPlan_PushBelow(OpBase *a, OpBase *b) { // B belongs to A's plan. @@ -164,202 +182,9 @@ void ExecutionPlan_DetachOp(OpBase *op) { op->parent = NULL; } -OpBase *ExecutionPlan_LocateOpResolvingAlias(OpBase *root, const char *alias) { - if(!root) return NULL; - - uint count = array_len(root->modifies); - - for(uint i = 0; i < count; i++) { - const char *resolved_alias = root->modifies[i]; - /* NOTE - if this function is later used to modify the returned operation, we should return - * the deepest operation that modifies the alias rather than the shallowest, as done here. */ - if(strcmp(resolved_alias, alias) == 0) return root; - } - - for(int i = 0; i < root->childCount; i++) { - OpBase *op = ExecutionPlan_LocateOpResolvingAlias(root->children[i], alias); - if(op) return op; - } - - return NULL; -} - -OpBase *ExecutionPlan_LocateOpMatchingType(OpBase *root, const OPType *types, uint type_count) { - for(int i = 0; i < type_count; i++) { - // Return the current op if it matches any of the types we're searching for. - if(root->type == types[i]) return root; - } - - for(int i = 0; i < root->childCount; i++) { - // Recursively visit children. - OpBase *op = ExecutionPlan_LocateOpMatchingType(root->children[i], types, type_count); - if(op) return op; - } - - return NULL; -} - -OpBase *ExecutionPlan_LocateOp(OpBase *root, OPType type) { - if(!root) return NULL; - - const OPType type_arr[1] = {type}; - return ExecutionPlan_LocateOpMatchingType(root, type_arr, 1); -} - -OpBase *ExecutionPlan_LocateReferencesExcludingOps(OpBase *root, - const OpBase *recurse_limit, const OPType *blacklisted_ops, - int nblacklisted_ops, rax *refs_to_resolve) { - - int dependency_count = 0; - bool blacklisted = false; - OpBase *resolving_op = NULL; - bool all_refs_resolved = false; - - // check if this op is blacklisted - for(int i = 0; i < nblacklisted_ops && !blacklisted; i++) { - blacklisted = (root->type == blacklisted_ops[i]); - } - - // we're not allowed to inspect child operations of blacklisted ops - // also we're not allowed to venture further than 'recurse_limit' - if(blacklisted == false && root != recurse_limit) { - for(int i = 0; i < root->childCount && !all_refs_resolved; i++) { - // Visit each child and try to resolve references, storing a pointer to the child if successful. - OpBase *tmp_op = ExecutionPlan_LocateReferencesExcludingOps(root->children[i], - recurse_limit, blacklisted_ops, nblacklisted_ops, refs_to_resolve); - - if(tmp_op) dependency_count ++; // Count how many children resolved references. - // If there is more than one child resolving an op, set the root as the resolver. - resolving_op = resolving_op ? root : tmp_op; - all_refs_resolved = (raxSize(refs_to_resolve) == 0); // We're done when the rax is empty. - } - } - - // If we've resolved all references, our work is done. - if(all_refs_resolved) return resolving_op; - - char **modifies = NULL; - if(blacklisted) { - // If we've reached a blacklisted op, all variables in its subtree are - // considered to be modified by it, as we can't recurse farther. - rax *bound_vars = raxNew(); - ExecutionPlan_BoundVariables(root, bound_vars); - modifies = (char **)raxKeys(bound_vars); - raxFree(bound_vars); - } else { - modifies = (char **)root->modifies; - } - - // Try to resolve references in the current operation. - bool refs_resolved = false; - uint modifies_count = array_len(modifies); - for(uint i = 0; i < modifies_count; i++) { - const char *ref = modifies[i]; - // Attempt to remove the current op's references, marking whether any removal was succesful. - refs_resolved |= raxRemove(refs_to_resolve, (unsigned char *)ref, strlen(ref), NULL); - } - - // Free the modified array and its contents if it was generated to represent a blacklisted op. - if(blacklisted) { - for(uint i = 0; i < modifies_count; i++) rm_free(modifies[i]); - array_free(modifies); - } - - if(refs_resolved) resolving_op = root; - return resolving_op; -} - -OpBase *ExecutionPlan_LocateReferences -( - OpBase *root, - const OpBase *recurse_limit, - rax *refs_to_resolve -) { - return ExecutionPlan_LocateReferencesExcludingOps( - root, recurse_limit, NULL, 0, refs_to_resolve); -} - -void _ExecutionPlan_LocateTaps -( - OpBase *root, - OpBase ***taps -) { - if(root == NULL) { - return; - } - - if(root->childCount == 0) { - // op Argument isn't considered a tap - if(root->type != OPType_ARGUMENT) { - array_append(*taps, root); - } - } - - // recursively visit children - for(int i = 0; i < root->childCount; i++) { - _ExecutionPlan_LocateTaps(root->children[i], taps); - } -} - -OpBase **ExecutionPlan_LocateTaps(const ExecutionPlan *plan) { - ASSERT(plan != NULL); - OpBase **taps = array_new(OpBase *, 1); - _ExecutionPlan_LocateTaps(plan->root, &taps); - return taps; -} - -static void _ExecutionPlan_CollectOpsMatchingType(OpBase *root, const OPType *types, int type_count, - OpBase ***ops) { - for(int i = 0; i < type_count; i++) { - // Check to see if the op's type matches any of the types we're searching for. - if(root->type == types[i]) { - array_append(*ops, root); - break; - } - } - - for(int i = 0; i < root->childCount; i++) { - // Recursively visit children. - _ExecutionPlan_CollectOpsMatchingType(root->children[i], types, type_count, ops); - } -} - -OpBase **ExecutionPlan_CollectOpsMatchingType(OpBase *root, const OPType *types, uint type_count) { - OpBase **ops = array_new(OpBase *, 0); - _ExecutionPlan_CollectOpsMatchingType(root, types, type_count, &ops); - return ops; -} - -OpBase **ExecutionPlan_CollectOps(OpBase *root, OPType type) { - OpBase **ops = array_new(OpBase *, 0); - const OPType type_arr[1] = {type}; - _ExecutionPlan_CollectOpsMatchingType(root, type_arr, 1, &ops); - return ops; -} - -// Collect all aliases that have been resolved by the given tree of operations. -void ExecutionPlan_BoundVariables(const OpBase *op, rax *modifiers) { - ASSERT(op != NULL && modifiers != NULL); - if(op->modifies) { - uint modifies_count = array_len(op->modifies); - for(uint i = 0; i < modifies_count; i++) { - const char *modified = op->modifies[i]; - raxTryInsert(modifiers, (unsigned char *)modified, strlen(modified), (void *)modified, NULL); - } - } - - /* Project and Aggregate operations demarcate variable scopes, - * collect their projections but do not recurse into their children. - * Note that future optimizations which operate across scopes will require different logic - * than this for application. */ - if(op->type == OPType_PROJECT || op->type == OPType_AGGREGATE) return; - - for(int i = 0; i < op->childCount; i++) { - ExecutionPlan_BoundVariables(op->children[i], modifiers); - } -} - -void ExecutionPlan_BindPlanToOps +// For all ops in the given tree, associate the provided ExecutionPlan. +// if qg is set, merge the query graphs of the temporary and main plans +void ExecutionPlan_BindOpsToPlan ( ExecutionPlan *plan, // plan to bind the operations to OpBase *root, // root operation @@ -375,59 +200,21 @@ void ExecutionPlan_BindPlanToOps root->plan = plan; for(int i = 0; i < root->childCount; i ++) { - ExecutionPlan_BindPlanToOps(plan, root->children[i], qg); + ExecutionPlan_BindOpsToPlan(plan, root->children[i], qg); } } -OpBase *ExecutionPlan_BuildOpsFromPath(ExecutionPlan *plan, const char **bound_vars, - const cypher_astnode_t *node) { - // Initialize an ExecutionPlan that shares this plan's Record mapping. - ExecutionPlan *match_stream_plan = ExecutionPlan_NewEmptyExecutionPlan(); - match_stream_plan->record_map = plan->record_map; - - // If we have bound variables, build an Argument op that represents them. - if(bound_vars) match_stream_plan->root = NewArgumentOp(match_stream_plan, - bound_vars); - - AST *ast = QueryCtx_GetAST(); - // Build a temporary AST holding a MATCH clause. - cypher_astnode_type_t type = cypher_astnode_type(node); - - /* The AST node we're building a mock MATCH clause for will be a path - * if we're converting a MERGE clause or WHERE filter, and we must build - * and later free a CYPHER_AST_PATTERN node to contain it. - * If instead we're converting an OPTIONAL MATCH, the node is itself a MATCH clause, - * and we will reuse its CYPHER_AST_PATTERN node rather than building a new one. */ - bool node_is_path = (type == CYPHER_AST_PATTERN_PATH || type == CYPHER_AST_NAMED_PATH); - AST *match_stream_ast = AST_MockMatchClause(ast, (cypher_astnode_t *)node, node_is_path); - - //-------------------------------------------------------------------------- - // Build plan's query graph - //-------------------------------------------------------------------------- - - // Extract pattern from holistic query graph. - const cypher_astnode_t **match_clauses = AST_GetClauses(match_stream_ast, CYPHER_AST_MATCH); - ASSERT(array_len(match_clauses) == 1); - const cypher_astnode_t *pattern = cypher_ast_match_get_pattern(match_clauses[0]); - array_free(match_clauses); - QueryGraph *sub_qg = QueryGraph_ExtractPatterns(plan->query_graph, &pattern, 1); - match_stream_plan->query_graph = sub_qg; - - ExecutionPlan_PopulateExecutionPlan(match_stream_plan); - - AST_MockFree(match_stream_ast, node_is_path); - QueryCtx_SetAST(ast); // Reset the AST. - - // Associate all new ops with the correct ExecutionPlan and QueryGraph. - OpBase *match_stream_root = match_stream_plan->root; - ExecutionPlan_BindPlanToOps(plan, match_stream_root, true); - - // NULL-set variables shared between the match_stream_plan and the overall plan. - match_stream_plan->root = NULL; - match_stream_plan->record_map = NULL; - // Free the temporary plan. - ExecutionPlan_Free(match_stream_plan); - - return match_stream_root; +// binds all ops in `ops` to `plan`, other than ops of type `exclude_type` +void ExecutionPlan_MigrateOpsExcludeType +( + OpBase * ops[], // array of ops to bind + OPType exclude_type, // type of ops to exclude + uint op_count, // number of ops in the array + const ExecutionPlan *plan // plan to bind the ops to +) { + for(uint i = 0; i < op_count; i++) { + if(ops[i]->type != exclude_type) { + OpBase_BindOpToPlan(ops[i], (ExecutionPlan *)plan); + } + } } - diff --git a/src/execution_plan/execution_plan_build/execution_plan_modify.h b/src/execution_plan/execution_plan_build/execution_plan_modify.h index 0cf0479a5e..14b85c0693 100644 --- a/src/execution_plan/execution_plan_build/execution_plan_modify.h +++ b/src/execution_plan/execution_plan_build/execution_plan_modify.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -10,7 +13,7 @@ typedef struct ExecutionPlan ExecutionPlan; //------------------------------------------------------------------------------ -// Helper functions to move and analyze operations in an ExecutionPlan. +// Helper functions to modify execution plans. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ @@ -26,6 +29,14 @@ void ExecutionPlan_DetachOp(OpBase *op); /* Adds operation to execution plan as a child of parent. */ void ExecutionPlan_AddOp(OpBase *parent, OpBase *newOp); +// adds child to be the ind'th child of parent +void ExecutionPlan_AddOpInd +( + OpBase *parent, // parent op + OpBase *child, // child op + uint ind // index of child +); + /* Push b right below a. */ void ExecutionPlan_PushBelow(OpBase *a, OpBase *b); @@ -39,75 +50,23 @@ void ExecutionPlan_UpdateRoot(ExecutionPlan *plan, OpBase *new_root); void ExecutionPlan_ReplaceOp(ExecutionPlan *plan, OpBase *a, OpBase *b); //------------------------------------------------------------------------------ -// ExecutionPlan_Locate API: -// For performing existence checks and looking up individual operations in tree. +// API for binding ops to plans. //------------------------------------------------------------------------------ -/* Traverse upwards until an operation that resolves the given alias is found. - * Returns NULL if alias is not resolved. */ -OpBase *ExecutionPlan_LocateOpResolvingAlias(OpBase *root, const char *alias); - -/* Locate the first operation matching one of the given types in the op tree by performing DFS. - * Returns NULL if no matching operation was found. */ -OpBase *ExecutionPlan_LocateOpMatchingType(OpBase *root, const OPType *types, uint type_count); - -/* Convenience wrapper around ExecutionPlan_LocateOpMatchingType for lookups of a single type. - * Locate the first operation of a given type within execution plan by performing DFS. - * Returns NULL if operation wasn't found. */ -OpBase *ExecutionPlan_LocateOp(OpBase *root, OPType type); - -/* Find the earliest operation above the provided recurse_limit, if any, - * at which all references are resolved. */ -OpBase *ExecutionPlan_LocateReferences(OpBase *root, const OpBase *recurse_limit, - rax *references_to_resolve); - -// Returns all tap operations for given execution plan. -OpBase **ExecutionPlan_LocateTaps(const ExecutionPlan *plan); - -/* Find the earliest operation at which all references are resolved, if any, - * both above the provided recurse_limit and without recursing past a blacklisted op. */ -OpBase *ExecutionPlan_LocateReferencesExcludingOps(OpBase *root, - const OpBase *recurse_limit, const OPType *blacklisted_ops, - int nblacklisted_ops, rax *refs_to_resolve); - -//------------------------------------------------------------------------------ -// ExecutionPlan_Collect API: -// For collecting all matching operations in tree. -//------------------------------------------------------------------------------ - -/* Collect all operations matching the given types in the op tree. - * Returns an array of operations. */ -OpBase **ExecutionPlan_CollectOpsMatchingType(OpBase *root, const OPType *types, uint type_count); - -/* Convenience wrapper around ExecutionPlan_LocateOpMatchingType for - * collecting all operations of a given type within the op tree. - * Returns an array of operations. */ -OpBase **ExecutionPlan_CollectOps(OpBase *root, OPType type); - -//------------------------------------------------------------------------------ -// API for building and relocating operations in transient ExecutionPlans. -//------------------------------------------------------------------------------ - -/* Populate a rax with all aliases that have been resolved by the given operation - * and its children. These are the bound variables at this point in execution, and - * subsequent operations should not introduce them as new entities. For example, in the query: - * MATCH (a:A) CREATE (a)-[:E]->(b:B) - * The Create operation should never introduce a new node 'a'. */ -void ExecutionPlan_BoundVariables(const OpBase *op, rax *modifiers); - // For all ops in the given tree, associate the provided ExecutionPlan. -// This is for use for updating ops that have been built with a temporary -// ExecutionPlan. // if qg is set, merge the query graphs of the temporary and main plans -void ExecutionPlan_BindPlanToOps +void ExecutionPlan_BindOpsToPlan ( ExecutionPlan *plan, // plan to bind the operations to OpBase *root, // root operation bool qg // whether to merge QueryGraphs or not ); -/* Given an AST path pattern, generate the tree of scan, traverse, - * and filter operations required to represent it. */ -OpBase *ExecutionPlan_BuildOpsFromPath(ExecutionPlan *plan, const char **vars, - const cypher_astnode_t *path); - +// binds all ops in `ops` to `plan`, except for ops of type `exclude_type` +void ExecutionPlan_MigrateOpsExcludeType +( + OpBase * ops[], // array of ops to bind + OPType exclude_type, // type of ops to exclude + uint op_count, // number of ops in the array + const ExecutionPlan *plan // plan to bind the ops to +); diff --git a/src/execution_plan/execution_plan_build/execution_plan_util.c b/src/execution_plan/execution_plan_build/execution_plan_util.c new file mode 100644 index 0000000000..1a773199c5 --- /dev/null +++ b/src/execution_plan/execution_plan_build/execution_plan_util.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "execution_plan_util.h" + +// returns true if an operation in the op-tree rooted at `root` is eager +bool ExecutionPlan_isEager +( + OpBase *root +) { + return ExecutionPlan_LocateOpMatchingTypes(root, EAGER_OPERATIONS, 6) != NULL; +} + +OpBase *ExecutionPlan_LocateOpResolvingAlias +( + OpBase *root, + const char *alias +) { + if(!root) return NULL; + + uint count = array_len(root->modifies); + + for(uint i = 0; i < count; i++) { + const char *resolved_alias = root->modifies[i]; + // NOTE - if this function is later used to modify the returned + // operation, we should return the deepest operation that modifies the + // alias rather than the shallowest, as done here + if(strcmp(resolved_alias, alias) == 0) return root; + } + + for(int i = 0; i < root->childCount; i++) { + OpBase *op = ExecutionPlan_LocateOpResolvingAlias(root->children[i], alias); + if(op) return op; + } + + return NULL; +} + +// locate the first operation matching one of the given types in the op tree by +// performing DFS. Returns NULL if no matching operation was found +OpBase *ExecutionPlan_LocateOpMatchingTypes +( + OpBase *root, + const OPType *types, + uint type_count +) { + for(int i = 0; i < type_count; i++) { + // Return the current op if it matches any of the types we're searching for. + if(root->type == types[i]) return root; + } + + for(int i = 0; i < root->childCount; i++) { + // Recursively visit children. + OpBase *op = ExecutionPlan_LocateOpMatchingTypes(root->children[i], types, type_count); + if(op) return op; + } + + return NULL; +} + +OpBase *ExecutionPlan_LocateOp +( + OpBase *root, + OPType type +) { + if(!root) return NULL; + + const OPType type_arr[1] = {type}; + return ExecutionPlan_LocateOpMatchingTypes(root, type_arr, 1); +} + +// searches for an operation of a given type, up to the given depth in the +// execution-plan +OpBase *ExecutionPlan_LocateOpDepth +( + OpBase *root, + OPType type, + uint depth +) { + if(root == NULL) { + return NULL; + } + + if(root->type == type) { + return root; + } + + if(depth == 0) { + return NULL; + } + + for(int i = 0; i < root->childCount; i++) { + OpBase *op = ExecutionPlan_LocateOpDepth(root->children[i], type, + depth - 1); + if(op) { + return op; + } + } + + return NULL; +} + +// returns all operations of a certain type in a execution plan +void ExecutionPlan_LocateOps +( + OpBase ***plans, // array in which ops are stored + OpBase *root, // root operation of the plan to traverse + OPType type // operation type to search +) { + if(root->type == type) { + array_append(*plans, root); + } + + for(uint i = 0; i < root->childCount; i++) { + ExecutionPlan_LocateOps(plans, root->children[i], type); + } +} + +OpBase *ExecutionPlan_LocateReferencesExcludingOps +( + OpBase *root, + const OpBase *recurse_limit, + const OPType *blacklisted_ops, + int nblacklisted_ops, + rax *refs_to_resolve +) { + int dependency_count = 0; + bool blacklisted = false; + OpBase *resolving_op = NULL; + bool all_refs_resolved = false; + + // check if this op is blacklisted + for(int i = 0; i < nblacklisted_ops && !blacklisted; i++) { + blacklisted = (root->type == blacklisted_ops[i]); + } + + // we're not allowed to inspect child operations of blacklisted ops + // also we're not allowed to venture further than 'recurse_limit' + if(blacklisted == false && root != recurse_limit) { + for(int i = 0; i < root->childCount && !all_refs_resolved; i++) { + // Visit each child and try to resolve references, storing a pointer to the child if successful. + OpBase *tmp_op = ExecutionPlan_LocateReferencesExcludingOps(root->children[i], + recurse_limit, blacklisted_ops, nblacklisted_ops, refs_to_resolve); + + // Count how many children resolved references + if(tmp_op) { + dependency_count ++; + } + // If there is more than one child resolving an op, set the root as the resolver. + resolving_op = resolving_op ? root : tmp_op; + all_refs_resolved = (raxSize(refs_to_resolve) == 0); // We're done when the rax is empty. + } + } + + // If we've resolved all references, our work is done. + if(all_refs_resolved) return resolving_op; + + char **modifies = NULL; + if(blacklisted) { + // If we've reached a blacklisted op, all variables in its subtree are + // considered to be modified by it, as we can't recurse farther. + rax *bound_vars = raxNew(); + ExecutionPlan_BoundVariables(root, bound_vars, root->plan); + modifies = (char **)raxKeys(bound_vars); + raxFree(bound_vars); + } else { + modifies = (char **)root->modifies; + } + + // Try to resolve references in the current operation. + bool refs_resolved = false; + uint modifies_count = array_len(modifies); + for(uint i = 0; i < modifies_count; i++) { + const char *ref = modifies[i]; + // Attempt to remove the current op's references, marking whether any removal was succesful. + refs_resolved |= raxRemove(refs_to_resolve, (unsigned char *)ref, strlen(ref), NULL); + } + + // Free the modified array and its contents if it was generated to represent a blacklisted op. + if(blacklisted) { + for(uint i = 0; i < modifies_count; i++) rm_free(modifies[i]); + array_free(modifies); + } + + if(refs_resolved) resolving_op = root; + return resolving_op; +} + +OpBase *ExecutionPlan_LocateReferences +( + OpBase *root, + const OpBase *recurse_limit, + rax *refs_to_resolve +) { + return ExecutionPlan_LocateReferencesExcludingOps( + root, recurse_limit, NULL, 0, refs_to_resolve); +} + +// populates `ops` with all operations with a type in `types` in an +// execution plan, based at `root` +static void _ExecutionPlan_CollectOpsMatchingTypes(OpBase *root, const OPType *types, int type_count, + OpBase ***ops) { + for(int i = 0; i < type_count; i++) { + // Check to see if the op's type matches any of the types we're searching for. + if(root->type == types[i]) { + array_append(*ops, root); + break; + } + } + + for(int i = 0; i < root->childCount; i++) { + // Recursively visit children. + _ExecutionPlan_CollectOpsMatchingTypes(root->children[i], types, type_count, ops); + } +} + +// returns an array of all operations with a type in `types` in an +// execution plan, based at `root` +OpBase **ExecutionPlan_CollectOpsMatchingTypes +( + OpBase *root, + const OPType *types, + uint type_count +) { + OpBase **ops = array_new(OpBase *, 0); + _ExecutionPlan_CollectOpsMatchingTypes(root, types, type_count, &ops); + return ops; +} + +OpBase **ExecutionPlan_CollectOps +( + OpBase *root, + OPType type +) { + OpBase **ops = array_new(OpBase *, 0); + const OPType type_arr[1] = {type}; + _ExecutionPlan_CollectOpsMatchingTypes(root, type_arr, 1, &ops); + return ops; +} + +// fills `ops` with all operations from `op` an upward (towards parent) in the +// execution plan +// returns the amount of ops collected +uint ExecutionPlan_CollectUpwards +( + OpBase *ops[], + OpBase *op +) { + ASSERT(op != NULL); + ASSERT(ops != NULL); + + uint i = 0; + while(op != NULL) { + ops[i] = op; + op = op->parent; + i++; + } + + return i; +} + +// collect all aliases that have been resolved by the given tree of operations +void ExecutionPlan_BoundVariables +( + const OpBase *op, + rax *modifiers, + const ExecutionPlan *plan +) { + ASSERT(op != NULL && modifiers != NULL); + if(op->modifies && op->plan == plan) { + uint modifies_count = array_len(op->modifies); + for(uint i = 0; i < modifies_count; i++) { + const char *modified = op->modifies[i]; + raxTryInsert(modifiers, (unsigned char *)modified, strlen(modified), (void *)modified, NULL); + } + } + + // Project and Aggregate operations demarcate variable scopes, + // collect their projections but do not recurse into their children. + // Note that future optimizations which operate across scopes will require different logic + // than this for application + if(op->type == OPType_PROJECT || op->type == OPType_AGGREGATE) return; + + for(int i = 0; i < op->childCount; i++) { + ExecutionPlan_BoundVariables(op->children[i], modifiers, plan); + } +} diff --git a/src/execution_plan/execution_plan_build/execution_plan_util.h b/src/execution_plan/execution_plan_build/execution_plan_util.h new file mode 100644 index 0000000000..185ee83200 --- /dev/null +++ b/src/execution_plan/execution_plan_build/execution_plan_util.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "../ops/op.h" +#include "../execution_plan.h" +#include "../../util/rax_extensions.h" + +// returns true if an operation in the op-tree rooted at `root` is eager +bool ExecutionPlan_isEager +( + OpBase *root +); + +//------------------------------------------------------------------------------ +// ExecutionPlan_Locate API: +// For performing existence checks and looking up individual operations in tree. +//------------------------------------------------------------------------------ + +// Traverse upwards until an operation that resolves the given alias is found. +// Returns NULL if alias is not resolved +OpBase *ExecutionPlan_LocateOpResolvingAlias +( + OpBase *root, + const char *alias +); + +// Locate the first operation matching one of the given types in the op tree by +// performing DFS. Returns NULL if no matching operation was found +OpBase *ExecutionPlan_LocateOpMatchingTypes +( + OpBase *root, + const OPType *types, + uint type_count +); + +// Convenience wrapper around ExecutionPlan_LocateOpMatchingType for lookups of a single type. +// Locate the first operation of a given type within execution plan by performing DFS. +// Returns NULL if operation wasn't found +OpBase *ExecutionPlan_LocateOp +( + OpBase *root, + OPType type +); + +// searches for an operation of a given type, up to the given depth in the +// execution-plan +OpBase *ExecutionPlan_LocateOpDepth +( + OpBase *root, + OPType type, + uint depth +); + +// returns all operations of a certain type in a execution plan +void ExecutionPlan_LocateOps +( + OpBase ***plans, // array in which ops are stored + OpBase *root, // root operation of the plan to traverse + OPType type // operation type to search +); + +// Find the earliest operation above the provided recurse_limit, if any, +// at which all references are resolved +OpBase *ExecutionPlan_LocateReferences +( + OpBase *root, + const OpBase *recurse_limit, + rax *references_to_resolve +); + +// Find the earliest operation at which all references are resolved, if any, +// both above the provided recurse_limit and without recursing past a +// blacklisted op +OpBase *ExecutionPlan_LocateReferencesExcludingOps +( + OpBase *root, + const OpBase *recurse_limit, + const OPType *blacklisted_ops, + int nblacklisted_ops, + rax *refs_to_resolve +); + +//------------------------------------------------------------------------------ +// ExecutionPlan_Collect API: +// For collecting all matching operations in tree. +//------------------------------------------------------------------------------ + +// Collect all operations matching the given types in the op tree. +// Returns an array of operations +OpBase **ExecutionPlan_CollectOpsMatchingTypes +( + OpBase *root, + const OPType *types, + uint type_count +); + +// Convenience wrapper around ExecutionPlan_LocateOpMatchingType for +// collecting all operations of a given type within the op tree. +// Returns an array of operations +OpBase **ExecutionPlan_CollectOps +( + OpBase *root, + OPType type +); + +// fills `ops` with all operations from `op` an upward (towards parent) in the +// execution plan +// returns the amount of ops collected +uint ExecutionPlan_CollectUpwards +( + OpBase *ops[], + OpBase *op +); + +//------------------------------------------------------------------------------ +// API for building and relocating operations in transient ExecutionPlans. +//------------------------------------------------------------------------------ + +// Populate a rax with all aliases that have been resolved by the given operation +// and its children. These are the bound variables at this point in execution, and +// subsequent operations should not introduce them as new entities. For example, in the query: +// MATCH (a:A) CREATE (a)-[:E]->(b:B) +// The Create operation should never introduce a new node 'a' +void ExecutionPlan_BoundVariables +( + const OpBase *op, + rax *modifiers, + const ExecutionPlan *plan +); diff --git a/src/execution_plan/execution_plan_build/reduce_to_apply.c b/src/execution_plan/execution_plan_build/reduce_to_apply.c index 238e1e33e0..77666c337c 100644 --- a/src/execution_plan/execution_plan_build/reduce_to_apply.c +++ b/src/execution_plan/execution_plan_build/reduce_to_apply.c @@ -1,16 +1,20 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "execution_plan_construct.h" #include "RG.h" -#include "execution_plan_modify.h" -#include "../execution_plan.h" #include "../ops/ops.h" #include "../../query_ctx.h" +#include "../execution_plan.h" #include "../../ast/ast_mock.h" +#include "execution_plan_util.h" +#include "execution_plan_modify.h" +#include "execution_plan_construct.h" #include "../../util/rax_extensions.h" #include "../optimizations/optimizer.h" @@ -97,7 +101,8 @@ static OpBase *_ReduceFilterToOp(ExecutionPlan *plan, const char **vars, void ExecutionPlan_ReduceFilterToApply(ExecutionPlan *plan, OpFilter *filter) { // Collect all variables that are bound at this position in the op tree. rax *bound_vars = raxNew(); - ExecutionPlan_BoundVariables((OpBase *)filter, bound_vars); + ExecutionPlan_BoundVariables((OpBase *)filter, bound_vars, + ((OpBase *)filter)->plan); // Collect the variable names from bound_vars to populate the Argument ops we will build. const char **vars = (const char **)raxValues(bound_vars); diff --git a/src/execution_plan/execution_plan_clone.c b/src/execution_plan/execution_plan_clone.c index beaaa2bcce..ff7fa407bd 100644 --- a/src/execution_plan/execution_plan_clone.c +++ b/src/execution_plan/execution_plan_clone.c @@ -1,12 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "execution_plan_clone.h" #include "../RG.h" +#include "../util/dict.h" #include "../query_ctx.h" +#include "execution_plan_clone.h" #include "../util/rax_extensions.h" #include "execution_plan_build/execution_plan_modify.h" @@ -19,24 +23,19 @@ static ExecutionPlan *_ClonePlanInternals(const ExecutionPlan *template) { QueryGraph_ResolveUnknownRelIDs(template->query_graph); clone->query_graph = QueryGraph_Clone(template->query_graph); } - // TODO improve QueryGraph logic so that we do not need to store or clone connected_components. - if(template->connected_components) { - array_clone_with_cb(clone->connected_components, template->connected_components, QueryGraph_Clone); - } return clone; } -static OpBase *_CloneOpTree(OpBase *template_parent, OpBase *template_current, - OpBase *clone_parent) { - const ExecutionPlan *plan_segment; - if(!template_parent || (template_current->plan != template_parent->plan)) { - /* If this is the first operation or it was built using a different ExecutionPlan - * segment than its parent, clone the ExecutionPlan segment. */ +static OpBase *_CloneOpTree(OpBase *template_current, dict* old_to_new) { + ExecutionPlan *plan_segment; + + dictEntry *entry = HashTableFind(old_to_new, template_current->plan); + if(entry == NULL) { plan_segment = _ClonePlanInternals(template_current->plan); + HashTableAdd(old_to_new, (void *)template_current->plan, (void *)plan_segment); } else { - // This op was built as part of the same segment as its parent, don't change ExecutionPlans. - plan_segment = clone_parent->plan; + plan_segment = (ExecutionPlan *)HashTableGetVal(entry); } // Temporarily set the thread-local AST to be the one referenced by this ExecutionPlan segment. @@ -44,10 +43,12 @@ static OpBase *_CloneOpTree(OpBase *template_parent, OpBase *template_current, // Clone the current operation. OpBase *clone_current = OpBase_Clone(plan_segment, template_current); + if(plan_segment->root == NULL) plan_segment->root = clone_current; for(uint i = 0; i < template_current->childCount; i++) { // Recursively visit and clone the op's children. - OpBase *child_op = _CloneOpTree(template_current, template_current->children[i], clone_current); + OpBase *child_op = _CloneOpTree(template_current->children[i], + old_to_new); ExecutionPlan_AddOp(clone_current, child_op); } @@ -55,11 +56,14 @@ static OpBase *_CloneOpTree(OpBase *template_parent, OpBase *template_current, } static ExecutionPlan *_ExecutionPlan_Clone(const ExecutionPlan *template) { - OpBase *clone_root = _CloneOpTree(NULL, template->root, NULL); + // create mapping from old exec-plans to the ones + dict *old_to_new = HashTableCreate(&def_dt); + + OpBase *clone_root = _CloneOpTree(template->root, old_to_new); // The "master" execution plan is the one constructed with the root op. ExecutionPlan *clone = (ExecutionPlan *)clone_root->plan; - // The root op is currently NULL; set it now. - clone->root = clone_root; + + HashTableRelease(old_to_new); return clone; } diff --git a/src/execution_plan/execution_plan_clone.h b/src/execution_plan/execution_plan_clone.h index 5192bfaa57..ae4e019464 100644 --- a/src/execution_plan/execution_plan_clone.h +++ b/src/execution_plan/execution_plan_clone.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/execution_plan_debug.c b/src/execution_plan/execution_plan_debug.c index 7e3b2facb2..c5d95a8ea7 100644 --- a/src/execution_plan/execution_plan_debug.c +++ b/src/execution_plan/execution_plan_debug.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "execution_plan.h" #include "../RG.h" diff --git a/src/execution_plan/ops/op.c b/src/execution_plan/ops/op.c index affe135118..155117ce54 100644 --- a/src/execution_plan/ops/op.c +++ b/src/execution_plan/ops/op.c @@ -1,18 +1,32 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op.h" #include "RG.h" +#include "op_project.h" +#include "op_aggregate.h" #include "../../util/rmalloc.h" #include "../../util/simple_timer.h" // forward declarations Record ExecutionPlan_BorrowRecord(struct ExecutionPlan *plan); rax *ExecutionPlan_GetMappings(const struct ExecutionPlan *plan); -void ExecutionPlan_ReturnRecord(struct ExecutionPlan *plan, Record r); +void ExecutionPlan_ReturnRecord(const struct ExecutionPlan *plan, Record r); + +// default reset function for operations +OpResult _OpBase_reset_noop +( + OpBase *op +) { + ASSERT(op != NULL); + return OP_OK; +} void OpBase_Init ( @@ -44,7 +58,7 @@ void OpBase_Init op->init = init; op->free = free; op->clone = clone; - op->reset = reset; + op->reset = (reset) ? reset : _OpBase_reset_noop; op->profile = NULL; op->consume = consume; op->toString = toString; @@ -80,11 +94,13 @@ int OpBase_Modifies return (intptr_t)id; } +// adds an alias to an existing modifier +// such that record[modifier] = record[alias] int OpBase_AliasModifier ( - OpBase *op, - const char *modifier, - const char *alias + OpBase *op, // op + const char *modifier, // existing alias + const char *alias // new alias ) { rax *mapping = ExecutionPlan_GetMappings(op->plan); void *id = raxFind(mapping, (unsigned char *)modifier, strlen(modifier)); @@ -137,15 +153,47 @@ bool OpBase_Aware return (rec_idx != raxNotFound); } +// collects writing operations under `op` into `write_ops`, and resets the +// reading ops (including `op` itself) +static void _OpBase_PropagateReset +( + OpBase *op, + OpBase ***write_ops +) { + if(op->reset) { + if(OpBase_IsWriter(op)) { + array_append(*write_ops, op); + } else { + OpResult res = op->reset(op); + ASSERT(res == OP_OK); + } + } + + // recursively reset children + for(int i = 0; i < op->childCount; i++) { + _OpBase_PropagateReset(op->children[i], write_ops); + } +} + void OpBase_PropagateReset ( OpBase *op ) { - if(op->reset) { - OpResult res = op->reset(op); + // hold write operations until the read operations have been reset + OpBase **write_ops = array_new(OpBase *, 0); + + // reset read operations + _OpBase_PropagateReset(op, &write_ops); + + // reset write operations + uint write_op_count = array_len(write_ops); + for(uint i = 0; i < write_op_count; i++) { + OpBase *write_op = write_ops[i]; + OpResult res = write_op->reset(write_op); ASSERT(res == OP_OK); } - for(int i = 0; i < op->childCount; i++) OpBase_PropagateReset(op->children[i]); + + array_free(write_ops); } static void _OpBase_StatsToString @@ -205,6 +253,24 @@ void OpBase_UpdateConsume else op->consume = consume; } +// updates the plan of an operation +void OpBase_BindOpToPlan +( + OpBase *op, + const struct ExecutionPlan *plan +) { + ASSERT(op != NULL); + + OPType type = OpBase_Type(op); + if(type == OPType_PROJECT) { + ProjectBindToPlan(op, plan); + } else if(type == OPType_AGGREGATE) { + AggregateBindToPlan(op, plan); + } else { + op->plan = plan; + } +} + inline Record OpBase_CreateRecord ( const OpBase *op @@ -238,6 +304,26 @@ inline OPType OpBase_Type return op->type; } +// returns the number of children of the op +inline uint OpBase_ChildCount +( + const OpBase *op +) { + ASSERT(op != NULL); + return op->childCount; +} + +// returns the i'th child of the op +OpBase *OpBase_GetChild +( + OpBase *op, // op + uint i // child index +) { + ASSERT(op != NULL); + ASSERT(i < op->childCount); + return op->children[i]; +} + inline void OpBase_DeleteRecord ( Record r diff --git a/src/execution_plan/ops/op.h b/src/execution_plan/ops/op.h index b170e06505..453266e7d8 100644 --- a/src/execution_plan/ops/op.h +++ b/src/execution_plan/ops/op.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -43,6 +46,7 @@ typedef enum { OPType_UNWIND, OPType_FOREACH, OPType_PROC_CALL, + OPType_CALLSUBQUERY, OPType_ARGUMENT, OPType_ARGUMENT_LIST, OPType_CARTESIAN_PRODUCT, @@ -94,13 +98,15 @@ static const OPType FILTER_RECURSE_BLACKLIST[] = { OPType_MERGE }; -#define EAGER_OP_COUNT 5 +#define EAGER_OP_COUNT 7 static const OPType EAGER_OPERATIONS[] = { OPType_AGGREGATE, OPType_CREATE, - OPType_UPDATE, OPType_DELETE, - OPType_MERGE + OPType_UPDATE, + OPType_MERGE, + OPType_FOREACH, + OPType_SORT }; struct OpBase; @@ -192,6 +198,19 @@ OPType OpBase_Type const OpBase *op ); +// returns the number of children of the op +uint OpBase_ChildCount +( + const OpBase *op +); + +// returns the i'th child of the op +OpBase *OpBase_GetChild +( + OpBase *join, // op + uint i // child index +); + // mark alias as being modified by operation // returns the ID associated with alias int OpBase_Modifies @@ -204,9 +223,9 @@ int OpBase_Modifies // such that record[modifier] = record[alias] int OpBase_AliasModifier ( - OpBase *op, - const char *modifier, - const char *alias + OpBase *op, // op + const char *modifier, // existing alias + const char *alias // new alias ); // returns true if any of an op's children are aware of the given alias @@ -246,6 +265,13 @@ void OpBase_UpdateConsume fpConsume consume ); +// updates the plan of an operation +void OpBase_BindOpToPlan +( + OpBase *op, + const struct ExecutionPlan *plan +); + // creates a new record that will be populated during execution Record OpBase_CreateRecord ( diff --git a/src/execution_plan/ops/op_aggregate.c b/src/execution_plan/ops/op_aggregate.c index 8b542fd5ec..bdc1badd01 100644 --- a/src/execution_plan/ops/op_aggregate.c +++ b/src/execution_plan/ops/op_aggregate.c @@ -1,25 +1,28 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "op_aggregate.h" #include "RG.h" #include "op_sort.h" +#include "op_aggregate.h" #include "../../util/arr.h" #include "../../query_ctx.h" #include "../../util/rmalloc.h" // forward declarations +static void AggregateFree(OpBase *opBase); static Record AggregateConsume(OpBase *opBase); static OpResult AggregateReset(OpBase *opBase); static OpBase *AggregateClone(const ExecutionPlan *plan, const OpBase *opBase); -static void AggregateFree(OpBase *opBase); // fake hash function // hash of key is simply key -static uint64_t nop_hash +static uint64_t _id_hash ( const void *key ) { @@ -27,7 +30,7 @@ static uint64_t nop_hash } // hashtable entry free callback -void freeCallback +static void freeCallback ( dict *d, void *val @@ -36,7 +39,7 @@ void freeCallback } // hashtable callbacks -static dictType dt = { nop_hash, NULL, NULL, NULL, NULL, freeCallback, NULL, +static dictType _dt = { _id_hash, NULL, NULL, NULL, NULL, freeCallback, NULL, NULL, NULL, NULL}; // migrate each expression projected by this operation to either @@ -229,7 +232,7 @@ OpBase *NewAggregateOp ) { OpAggregate *op = rm_malloc(sizeof(OpAggregate)); - op->groups = HashTableCreate(&dt); + op->groups = HashTableCreate(&_dt); op->group_iter = NULL; OpBase_Init((OpBase *)op, OPType_AGGREGATE, "Aggregate", NULL, @@ -336,7 +339,7 @@ static OpResult AggregateReset unsigned long elem_count = HashTableElemCount(op->groups); HashTableRelease(op->groups); - op->groups = HashTableCreate(&dt); + op->groups = HashTableCreate(&_dt); // expand hashtable to previous element count int res = HashTableExpand(op->groups, elem_count); @@ -368,6 +371,33 @@ static OpBase *AggregateClone return NewAggregateOp(plan, exps); } +// bind the Aggregate operation to the execution plan +void AggregateBindToPlan +( + OpBase *opBase, // op to bind + const ExecutionPlan *plan // plan to bind the op to +) { + OpAggregate *op = (OpAggregate *)opBase; + opBase->plan = plan; + + // introduce the projected aliases to the plan record-mapping, and reset the + // record offsets to the correct indexes + array_clear(op->record_offsets); + + for(uint i = 0; i < op->key_count; i ++) { + // The projected record will associate values with their resolved name + // to ensure that space is allocated for each entry. + int record_idx = OpBase_Modifies((OpBase *)op, op->key_exps[i]->resolved_name); + array_append(op->record_offsets, record_idx); + } + for(uint i = 0; i < op->aggregate_count; i++) { + // store the index of each aggregating expression + int record_idx = OpBase_Modifies((OpBase *)op, + op->aggregate_exps[i]->resolved_name); + array_append(op->record_offsets, record_idx); + } +} + static void AggregateFree ( OpBase *opBase @@ -408,4 +438,3 @@ static void AggregateFree op->record_offsets = NULL; } } - diff --git a/src/execution_plan/ops/op_aggregate.h b/src/execution_plan/ops/op_aggregate.h index 71587759a9..661abaf19e 100644 --- a/src/execution_plan/ops/op_aggregate.h +++ b/src/execution_plan/ops/op_aggregate.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -29,3 +32,9 @@ OpBase *NewAggregateOp AR_ExpNode **exps ); +// bind the Aggregate operation to the execution plan +void AggregateBindToPlan +( + OpBase *opBase, // op to bind + const ExecutionPlan *plan // plan to bind the op to +); diff --git a/src/execution_plan/ops/op_all_node_scan.c b/src/execution_plan/ops/op_all_node_scan.c index b9ec8de552..5ddb44297c 100644 --- a/src/execution_plan/ops/op_all_node_scan.c +++ b/src/execution_plan/ops/op_all_node_scan.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_all_node_scan.h" #include "../../query_ctx.h" diff --git a/src/execution_plan/ops/op_all_node_scan.h b/src/execution_plan/ops/op_all_node_scan.h index f25c22d1e5..824b90dac7 100644 --- a/src/execution_plan/ops/op_all_node_scan.h +++ b/src/execution_plan/ops/op_all_node_scan.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_apply.c b/src/execution_plan/ops/op_apply.c index 86212f0c85..aad370159b 100644 --- a/src/execution_plan/ops/op_apply.c +++ b/src/execution_plan/ops/op_apply.c @@ -1,11 +1,14 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_apply.h" -#include "../execution_plan_build/execution_plan_modify.h" +#include "../execution_plan_build/execution_plan_util.h" /* Forward declarations. */ static OpResult ApplyInit(OpBase *opBase); @@ -16,14 +19,16 @@ static void ApplyFree(OpBase *opBase); OpBase *NewApplyOp(const ExecutionPlan *plan) { Apply *op = rm_malloc(sizeof(Apply)); - op->r = NULL; - op->op_arg = NULL; + + op->r = NULL; + op->op_arg = NULL; + op->records = NULL; + op->rhs_branch = NULL; op->bound_branch = NULL; - op->rhs_branch = NULL; // Set our Op operations - OpBase_Init((OpBase *)op, OPType_APPLY, "Apply", ApplyInit, ApplyConsume, ApplyReset, NULL, - ApplyClone, ApplyFree, false, plan); + OpBase_Init((OpBase *)op, OPType_APPLY, "Apply", ApplyInit, ApplyConsume, + ApplyReset, NULL, ApplyClone, ApplyFree, false, plan); return (OpBase *)op; } @@ -32,13 +37,15 @@ static OpResult ApplyInit(OpBase *opBase) { ASSERT(opBase->childCount == 2); Apply *op = (Apply *)opBase; - /* The op's bound branch and optional match branch have already been built as - * the Apply op's first and second child ops, respectively. */ + // the op's bound branch and optional match branch have already been + // built as the Apply op's first and second child ops, respectively + op->records = array_new(Record, 1); + op->rhs_branch = opBase->children[1]; op->bound_branch = opBase->children[0]; - op->rhs_branch = opBase->children[1]; - // Locate branch's Argument op tap. - op->op_arg = (Argument *)ExecutionPlan_LocateOp(op->rhs_branch, OPType_ARGUMENT); + // locate branch's Argument op tap + op->op_arg = (Argument *)ExecutionPlan_LocateOp(op->rhs_branch, + OPType_ARGUMENT); return OP_OK; } @@ -48,9 +55,14 @@ static Record ApplyConsume(OpBase *opBase) { while(true) { if(op->r == NULL) { - // Retrieve a Record from the bound branch. + // retrieve a Record from the bound branch op->r = OpBase_Consume(op->bound_branch); - if(!op->r) return NULL; // Bound branch and this op are depleted. + if(op->r == NULL) { + return NULL; // Bound branch and this op are depleted. + } + + // collect record for future freeing + array_append(op->records, op->r); // Successfully pulled a new Record, propagate to the top of the RHS branch. if(op->op_arg) { @@ -58,23 +70,22 @@ static Record ApplyConsume(OpBase *opBase) { } } - // Pull a Record from the RHS branch. + // pull a Record from the RHS branch Record rhs_record = OpBase_Consume(op->rhs_branch); if(rhs_record == NULL) { - /* RHS branch depleted for the current bound Record; - * free it and loop back to retrieve a new one. */ - OpBase_DeleteRecord(op->r); + // RHS branch depleted for the current bound Record + // free it and loop back to retrieve a new one op->r = NULL; - // Reset the RHS branch. + // reset the RHS branch OpBase_PropagateReset(op->rhs_branch); continue; } - // Clone the bound Record and merge the RHS Record into it. + // clone the bound Record and merge the RHS Record into it Record r = OpBase_CloneRecord(op->r); Record_Merge(r, rhs_record); - // Delete the RHS record, as it has been merged into r. + // delete the RHS record, as it has been merged into r OpBase_DeleteRecord(rhs_record); return r; @@ -85,10 +96,15 @@ static Record ApplyConsume(OpBase *opBase) { static OpResult ApplyReset(OpBase *opBase) { Apply *op = (Apply *)opBase; - if(op->r) { - OpBase_DeleteRecord(op->r); - op->r = NULL; + op->r = NULL; + + // free collected records + uint32_t n = array_len(op->records); + for(uint32_t i = 0; i < n; i++) { + OpBase_DeleteRecord(op->records[i]); } + array_clear(op->records); + return OP_OK; } @@ -98,9 +114,18 @@ static OpBase *ApplyClone(const ExecutionPlan *plan, const OpBase *opBase) { static void ApplyFree(OpBase *opBase) { Apply *op = (Apply *)opBase; - if(op->r) { - OpBase_DeleteRecord(op->r); - op->r = NULL; + + // free collected records + if(op->records != NULL) { + uint32_t n = array_len(op->records); + for(uint32_t i = 0; i < n; i++) { + OpBase_DeleteRecord(op->records[i]); + } + + array_free(op->records); + op->records = NULL; } + + op->r = NULL; } diff --git a/src/execution_plan/ops/op_apply.h b/src/execution_plan/ops/op_apply.h index 45f9319df9..0f9e74d50e 100644 --- a/src/execution_plan/ops/op_apply.h +++ b/src/execution_plan/ops/op_apply.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -20,10 +23,11 @@ * left-hand branch and the process repeats. */ typedef struct { OpBase op; - Record r; // Bound branch record. - OpBase *bound_branch; // Bound branch. - OpBase *rhs_branch; // Right-hand branch. - Argument *op_arg; // Right-hand branch tap. + Record r; // bound branch record + Record *records; // LHS records + OpBase *bound_branch; // bound branch + OpBase *rhs_branch; // right-hand branch + Argument *op_arg; // right-hand branch tap } Apply; OpBase *NewApplyOp(const ExecutionPlan *plan); diff --git a/src/execution_plan/ops/op_apply_multiplexer.c b/src/execution_plan/ops/op_apply_multiplexer.c index 3f370da1d4..42d82852d8 100644 --- a/src/execution_plan/ops/op_apply_multiplexer.c +++ b/src/execution_plan/ops/op_apply_multiplexer.c @@ -1,11 +1,14 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_apply_multiplexer.h" -#include "../execution_plan_build/execution_plan_modify.h" +#include "../execution_plan_build/execution_plan_util.h" // Forward declerations. static OpResult OpApplyMultiplexerInit(OpBase *opBase); diff --git a/src/execution_plan/ops/op_apply_multiplexer.h b/src/execution_plan/ops/op_apply_multiplexer.h index 8db1c50187..46566d522f 100644 --- a/src/execution_plan/ops/op_apply_multiplexer.h +++ b/src/execution_plan/ops/op_apply_multiplexer.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_argument.c b/src/execution_plan/ops/op_argument.c index 297d449543..aca319a2f3 100644 --- a/src/execution_plan/ops/op_argument.c +++ b/src/execution_plan/ops/op_argument.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_argument.h" #include "RG.h" diff --git a/src/execution_plan/ops/op_argument.h b/src/execution_plan/ops/op_argument.h index b2e134c745..6e7668935e 100644 --- a/src/execution_plan/ops/op_argument.h +++ b/src/execution_plan/ops/op_argument.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_argument_list.c b/src/execution_plan/ops/op_argument_list.c index a5de04f4ac..9df02ec145 100644 --- a/src/execution_plan/ops/op_argument_list.c +++ b/src/execution_plan/ops/op_argument_list.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op.h" #include "op_argument_list.h" @@ -52,9 +55,6 @@ static Record ArgumentListConsume return array_pop(op->records); } - // depleted - array_free(op->records); - op->records = NULL; return NULL; } diff --git a/src/execution_plan/ops/op_argument_list.h b/src/execution_plan/ops/op_argument_list.h index 027fe7964d..c189ab5178 100644 --- a/src/execution_plan/ops/op_argument_list.h +++ b/src/execution_plan/ops/op_argument_list.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_call_subquery.c b/src/execution_plan/ops/op_call_subquery.c new file mode 100644 index 0000000000..40cbdf07c3 --- /dev/null +++ b/src/execution_plan/ops/op_call_subquery.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "op_join.h" +#include "op_call_subquery.h" +#include "../execution_plan_build/execution_plan_modify.h" + +// forward declarations +static void CallSubqueryFree(OpBase *opBase); +static OpResult CallSubqueryInit(OpBase *opBase); +static OpResult CallSubqueryReset(OpBase *opBase); +static Record CallSubqueryConsume(OpBase *opBase); +static Record CallSubqueryConsumeEager(OpBase *opBase); +static OpBase *CallSubqueryClone(const ExecutionPlan *plan, + const OpBase *opBase); + +// find the deepest child of a root operation (feeder), and append it to the +// arguments/argumentLists array of the CallSubquery operation +static void _append_feeder +( + OpCallSubquery *call_subquery, // CallSubquery operation + OpBase *branch // root op of the branch +) { + while(branch->childCount > 0) { + branch = branch->children[0]; + } + + if(call_subquery->is_eager) { + ASSERT(OpBase_Type((const OpBase *)branch) == OPType_ARGUMENT_LIST); + array_append(call_subquery->feeders.argumentLists, + (ArgumentList *)branch); + } else { + ASSERT(OpBase_Type((const OpBase *)branch) == OPType_ARGUMENT); + array_append(call_subquery->feeders.arguments, (Argument *)branch); + } +} + +// plant the input record(s) in the ArgumentList operation(s) +static void _plant_records_ArgumentLists +( + OpCallSubquery *op // CallSubquery operation +) { + int n_branches = (int)array_len(op->feeders.argumentLists); + for(int i = 0; i < n_branches - 1; i++) { + Record *records_clone; + array_clone_with_cb(records_clone, op->records, + OpBase_DeepCloneRecord); + ArgumentList_AddRecordList(op->feeders.argumentLists[i], + records_clone); + } +} + +// plant the input record in the Argument operation(s) +static void _plant_records_Arguments +( + OpCallSubquery *op // CallSubquery operation +) { + uint n_branches = array_len(op->feeders.arguments); + for(uint i = 0; i < n_branches; i++) { + Argument_AddRecord(op->feeders.arguments[i], + OpBase_DeepCloneRecord(op->r)); + } +} + +// creates a new CallSubquery operation +OpBase *NewCallSubqueryOp +( + const ExecutionPlan *plan, // execution plan + bool is_eager, // is the subquery eager or not + bool is_returning // is the subquery returning or not +) { + OpCallSubquery *op = rm_calloc(1, sizeof(OpCallSubquery)); + + op->first = true; + op->is_eager = is_eager; + op->is_returning = is_returning; + + // set the consume function according to eagerness of the op + fpConsume consumeFunc = is_eager ? + CallSubqueryConsumeEager : + CallSubqueryConsume; + + OpBase_Init((OpBase *)op, OPType_CALLSUBQUERY, "CallSubquery", + CallSubqueryInit, consumeFunc, CallSubqueryReset, NULL, + CallSubqueryClone, CallSubqueryFree, false, plan); + + return (OpBase *)op; +} + +static OpResult CallSubqueryInit +( + OpBase *opBase // CallSubquery operation to initialize +) { + OpCallSubquery *op = (OpCallSubquery *)opBase; + + // set the lhs (supplier) branch to be the first child, and rhs branch + // (body) to be the second + if(op->op.childCount == 2) { + op->lhs = op->op.children[0]; + op->body = op->op.children[1]; + } else { + op->lhs = NULL; + op->body = op->op.children[0]; + } + + // search for the ArgumentList\Argument ops, depending if the op is eager + if(op->is_eager) { + op->feeders.type = FEEDER_ARGUMENT_LIST; + op->feeders.argumentLists = array_new(ArgumentList *, 1); + } else { + op->feeders.type = FEEDER_ARGUMENT; + op->feeders.arguments = array_new(Argument *, 1); + } + + // in the case the subquery contains a `UNION` or `UNION ALL` clause, we + // need to duplicate the input records to the multiple branches of the + // Join op, that will be placed in one of the first two ops of the sub-plan + // (first child or its child, according to whether there is an `ALL`) + // "CALL {RETURN 1 AS num UNION RETURN 2 AS num} RETURN num" + // "CALL {RETURN 1 AS num UNION ALL RETURN 2 AS num} RETURN num" + // + // search for a Join op + + OpJoin *op_join = NULL; + if((OpBase_Type(op->body) == OPType_JOIN)) { + op_join = (OpJoin *)op->body; + } else if(OpBase_ChildCount(op->body) > 0 && + OpBase_Type(OpBase_GetChild(op->body, 0)) == OPType_JOIN) { + op_join = (OpJoin *)OpBase_GetChild(op->body, 0); + } + + if(op_join != NULL) { + uint n_branches = OpBase_ChildCount((OpBase *)op_join); + + for(uint i = 0; i < n_branches; i++) { + OpBase *branch = OpBase_GetChild((OpBase *)op_join, i); + _append_feeder(op, branch); + } + } else { + OpBase *branch = op->body; + _append_feeder(op, branch); + } + + return OP_OK; +} + +// passes a record to the parent op. +// if the subquery is non-returning, yield input record(s) +// otherwise, yields a record produced by the subquery +static Record _handoff_eager +( + OpCallSubquery *op // CallSubquery operation +) { + ASSERT(op->is_returning || op->records != NULL); + + if(!op->is_returning) { + // if there is a record to return from the input records, return it + // NOTICE: The order of records reverses here. + return array_len(op->records) > 0 ? array_pop(op->records) : NULL; + } + + // returning subquery + return OpBase_Consume(op->body); +} + +// eagerly consume and aggregate all the records from the lhs (if exists). pass +// the aggregated record-list to the ArgumentList operation(s) +// after aggregating, return records to caller. if the subquery is returning, +// return the consumed record(s) from the body. otherwise, return the input +// record(s) +static Record CallSubqueryConsumeEager +( + OpBase *opBase // operation +) { + OpCallSubquery *op = (OpCallSubquery *)opBase; + + // if eager consumption has already occurred, don't consume again + if(!op->first) { + return _handoff_eager(op); + } + + op->first = false; + + ASSERT(op->records == NULL); + op->records = array_new(Record, 1); + // eagerly consume all records from lhs if exists or create a + // dummy-record, and place them\it in op->records + Record r; + if(op->lhs) { + while((r = OpBase_Consume(op->lhs))) { + array_append(op->records, r); + } + // propagate reset to lhs, to release RediSearch index locks (if any) + OpBase_PropagateReset(op->lhs); + } else { + r = OpBase_CreateRecord((OpBase *)op); + array_append(op->records, r); + } + + _plant_records_ArgumentLists(op); + + int n_branches = (int)array_len(op->feeders.argumentLists); + if(op->is_returning) { + // give the last branch the original records + ArgumentList_AddRecordList( + op->feeders.argumentLists[n_branches - 1], op->records); + + // responsibility for the records is passed to the argumentList op(s) + op->records = NULL; + } else { + // give the last branch a clone of the original record(s) + Record *records_clone; + array_clone_with_cb(records_clone, op->records, + OpBase_DeepCloneRecord); + ArgumentList_AddRecordList( + op->feeders.argumentLists[n_branches - 1], records_clone); + } + + if(!op->is_returning) { + // deplete body and discard records + while((r = OpBase_Consume(op->body))) { + OpBase_DeleteRecord(r); + } + } + + return _handoff_eager(op); +} + +// tries to consumes a record from the body, merge it with the current input +// record and return it. If body is depleted for this record, tries to consume +// a record from the lhs, and repeat the process (if the lhs record is not NULL) +static Record _consume_and_merge +( + OpCallSubquery *op +) { + Record consumed; + consumed = OpBase_Consume(op->body); + + while(consumed == NULL) { + OpBase_PropagateReset(op->body); + OpBase_DeleteRecord(op->r); + op->r = NULL; + + if(op->lhs && (op->r = OpBase_Consume(op->lhs)) != NULL) { + // plant a clone of the record consumed at the Argument ops + _plant_records_Arguments(op); + } else { + // lhs depleted --> CALL {} depleted as well + return NULL; + } + + consumed = OpBase_Consume(op->body); + } + + Record clone = OpBase_DeepCloneRecord(op->r); + // Merge consumed record into a clone of the received record. + Record_Merge(clone, consumed); + OpBase_DeleteRecord(consumed); + return clone; +} + +// tries to consume a record from the body. if successful, returns the +// merged\unmerged record with the input record (op->r) according to the +// is_returning flag. +// depletes child if is_returning is off (discard body records) +static Record _handoff(OpCallSubquery *op) { + ASSERT(op->r != NULL); + + //-------------------------------------------------------------------------- + // returning subquery + //-------------------------------------------------------------------------- + + if(op->is_returning) { + return _consume_and_merge(op); + } + + //-------------------------------------------------------------------------- + // non-returning subquery + //-------------------------------------------------------------------------- + + Record consumed; + // drain the body, deleting the subquery records and return current record + while((consumed = OpBase_Consume(op->body))) { + OpBase_DeleteRecord(consumed); + } + OpBase_PropagateReset(op->body); + Record r = op->r; + op->r = NULL; + return r; +} + +// consumes a record from the lhs, plants it in the Argument\List op(s), and +// consumes a record from the body until depletion. +// in case the subquery is returning, merges the input (lhs) record with the +// output record. otherwise, the input record is passed as-is +// upon depletion of the body, repeats the above. depletion of lhs yields +// depletion of this operation +static Record CallSubqueryConsume +( + OpBase *opBase // operation +) { + OpCallSubquery *op = (OpCallSubquery *)opBase; + + // if there are more records to consume from body, consume them before + // consuming another record from lhs + if(op->r) { + return _handoff(op); + } + ASSERT(op->r == NULL); + + // consume from lhs if exists, otherwise create a dummy-record to pass to + // the body (rhs). the latter case will happen AT MOST once + if(op->lhs) { + op->r = OpBase_Consume(op->lhs); + } else if(op->first) { + op->r = OpBase_CreateRecord((OpBase *)op); + op->first = false; + } + + // plant the record consumed at the Argument ops + if(op->r) { + _plant_records_Arguments(op); + } else { + // no records - lhs depleted + return NULL; + } + + return _handoff(op); +} + +// frees CallSubquery internal data structures +static void _free_records +( + OpCallSubquery *op // operation to free +) { + if(op->records != NULL) { + uint n_records = array_len(op->records); + for(uint i = 0; i < n_records; i++) { + OpBase_DeleteRecord(op->records[i]); + } + array_free(op->records); + op->records = NULL; + } + + if(op->r != NULL) { + OpBase_DeleteRecord(op->r); + op->r = NULL; + } +} + +// resets a CallSubquery operation +static OpResult CallSubqueryReset +( + OpBase *opBase // operation +) { + OpCallSubquery *op = (OpCallSubquery *)opBase; + + _free_records(op); + op->first = true; + + return OP_OK; +} + +// clones a CallSubquery operation +static OpBase *CallSubqueryClone +( + const ExecutionPlan *plan, // plan + const OpBase *opBase // operation to clone +) { + ASSERT(opBase->type == OPType_CALLSUBQUERY); + OpCallSubquery *op = (OpCallSubquery *) opBase; + + return NewCallSubqueryOp(plan, op->is_eager, op->is_returning); +} + +// frees a CallSubquery operation +static void CallSubqueryFree +( + OpBase *op +) { + OpCallSubquery *_op = (OpCallSubquery *) op; + + _free_records(_op); + + if(_op->feeders.type != FEEDER_NONE) { + if(_op->feeders.type == FEEDER_ARGUMENT) { + ASSERT(_op->feeders.arguments != NULL); + array_free(_op->feeders.arguments); + _op->feeders.arguments = NULL; + } else if(_op->feeders.type == FEEDER_ARGUMENT_LIST) { + ASSERT(_op->feeders.argumentLists != NULL); + array_free(_op->feeders.argumentLists); + _op->feeders.argumentLists = NULL; + } + } +} diff --git a/src/execution_plan/ops/op_call_subquery.h b/src/execution_plan/ops/op_call_subquery.h new file mode 100644 index 0000000000..6a035128ab --- /dev/null +++ b/src/execution_plan/ops/op_call_subquery.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "op_argument.h" +#include "op_argument_list.h" + +// The Call {} operation is used to embed a subquery in the +// execution-plan. It generally passes records from its first child (lhs), to +// the body (rhs) of the subquery via the Argument\ArgumentList operations, +// and then merges the records returned from the body with the records consumed +// from lhs, according to whether the subquery is returning or not (i.e, +// terminates with a `RETURN` clause). If there is no lhs, a dummy record +// is created and passed to the body. +// The Call {} operation is eager\non-eager according to whether its body +// is\isn't eager (non-eager -> Arguments, eager -> ArgumentLists). + +typedef enum { + FEEDER_NONE, // non-initialized + FEEDER_ARGUMENT, // Arguments + FEEDER_ARGUMENT_LIST // ArgumentLists +} FeederType; + +typedef struct Feeder{ + union { + Argument **arguments; + ArgumentList **argumentLists; + }; + FeederType type; +} Feeder; + +typedef struct { + OpBase op; + + bool first; // is this the first call to consume + bool is_eager; // is the op eager + bool is_returning; // is the subquery returning or not + OpBase *body; // first op in the embedded execution-plan + OpBase *lhs; // op from which records are pulled + Record r; // current record consumed from lhs + Record *records; // records aggregated by the operation + Feeder feeders; // feeders to the body (Args/ArgLists) +} OpCallSubquery; + +// creates a new CallSubquery operation +OpBase *NewCallSubqueryOp +( + const ExecutionPlan *plan, // execution plan + bool is_eager, // if an updating clause lies in the body, eagerly consume the records + bool is_returning // is the subquery returning or unit +); diff --git a/src/execution_plan/ops/op_cartesian_product.c b/src/execution_plan/ops/op_cartesian_product.c index f6149ec3e0..5cbee82555 100644 --- a/src/execution_plan/ops/op_cartesian_product.c +++ b/src/execution_plan/ops/op_cartesian_product.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_cartesian_product.h" #include "RG.h" diff --git a/src/execution_plan/ops/op_cartesian_product.h b/src/execution_plan/ops/op_cartesian_product.h index a7185dac8b..0b60babed7 100644 --- a/src/execution_plan/ops/op_cartesian_product.h +++ b/src/execution_plan/ops/op_cartesian_product.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_cond_var_len_traverse.c b/src/execution_plan/ops/op_cond_var_len_traverse.c index 12fe5d33d5..2f436bd6a4 100644 --- a/src/execution_plan/ops/op_cond_var_len_traverse.c +++ b/src/execution_plan/ops/op_cond_var_len_traverse.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_cond_var_len_traverse.h" #include "shared/print_functions.h" diff --git a/src/execution_plan/ops/op_cond_var_len_traverse.h b/src/execution_plan/ops/op_cond_var_len_traverse.h index 0515f66eae..f56c0ea033 100644 --- a/src/execution_plan/ops/op_cond_var_len_traverse.h +++ b/src/execution_plan/ops/op_cond_var_len_traverse.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_conditional_traverse.c b/src/execution_plan/ops/op_conditional_traverse.c index 0a14dbdccf..dfb5a2a18b 100644 --- a/src/execution_plan/ops/op_conditional_traverse.c +++ b/src/execution_plan/ops/op_conditional_traverse.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_conditional_traverse.h" #include "RG.h" @@ -154,7 +157,9 @@ static Record CondTraverseConsume(OpBase *opBase) { for(op->record_count = 0; op->record_count < op->record_cap; op->record_count++) { Record childRecord = OpBase_Consume(child); // If the Record is NULL, the child has been depleted. - if(!childRecord) break; + if(childRecord == NULL) { + break; + } if(!Record_GetNode(childRecord, op->srcNodeIdx)) { /* The child Record may not contain the source node in scenarios like * a failed OPTIONAL MATCH. In this case, delete the Record and try again. */ @@ -189,7 +194,7 @@ static Record CondTraverseConsume(OpBase *opBase) { EdgeTraverseCtx_SetEdge(op->edge_ctx, op->r); } - return OpBase_CloneRecord(op->r); + return OpBase_DeepCloneRecord(op->r); } static OpResult CondTraverseReset(OpBase *ctx) { diff --git a/src/execution_plan/ops/op_conditional_traverse.h b/src/execution_plan/ops/op_conditional_traverse.h index 23fdfdf6d6..a8338e73bf 100644 --- a/src/execution_plan/ops/op_conditional_traverse.h +++ b/src/execution_plan/ops/op_conditional_traverse.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_create.c b/src/execution_plan/ops/op_create.c index f00a048bff..70637d7c71 100644 --- a/src/execution_plan/ops/op_create.c +++ b/src/execution_plan/ops/op_create.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_create.h" #include "RG.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" -/* Forward declarations. */ +// forward declarations static Record CreateConsume(OpBase *opBase); static OpBase *CreateClone(const ExecutionPlan *plan, const OpBase *opBase); static void CreateFree(OpBase *opBase); @@ -45,22 +48,27 @@ OpBase *NewCreateOp(const ExecutionPlan *plan, NodeCreateCtx *nodes, EdgeCreateC return (OpBase *)op; } -// Prepare to create all nodes for the current Record. -static void _CreateNodes(OpCreate *op, Record r, GraphContext *gc) { +// prepare to create all nodes for the current Record +static void _CreateNodes +( + OpCreate *op, + Record r, + GraphContext *gc +) { uint nodes_to_create_count = array_len(op->pending.nodes_to_create); for(uint i = 0; i < nodes_to_create_count; i++) { // get specified node to create NodeCreateCtx *n = op->pending.nodes_to_create + i; // create a new node - Node newNode = GE_NEW_NODE(); + Node newNode = Graph_ReserveNode(gc->g); // add new node to Record and save a reference to it - Node *node_ref = Record_AddNode(r, op->pending.nodes_to_create[i].node_idx, newNode); + Node *node_ref = Record_AddNode(r, n->node_idx, newNode); // convert query-level properties AttributeSet converted_attr = NULL; - PropertyMap *map = op->pending.nodes_to_create[i].properties; + PropertyMap *map = n->properties; if(map != NULL) { ConvertPropertyMap(gc, &converted_attr, r, map, false); } @@ -89,11 +97,14 @@ static void _CreateEdges EdgeCreateCtx *e = op->pending.edges_to_create + i; // retrieve source and dest nodes - Node *src_node = Record_GetNode(r, e->src_idx); - Node *dest_node = Record_GetNode(r, e->dest_idx); - // verify that the endpoints of the new edge resolved properly - // fail otherwise - if(!src_node || !dest_node) { + GraphEntity *src_node = (GraphEntity*)Record_GetNode(r, e->src_idx); + GraphEntity *dest_node = (GraphEntity*)Record_GetNode(r, e->dest_idx); + + // verify edge endpoints resolved properly, fail otherwise + if(unlikely(!src_node || + !dest_node || + GraphEntity_IsDeleted(src_node) || + GraphEntity_IsDeleted(dest_node))) { ErrorCtx_RaiseRuntimeException( "Failed to create relationship; endpoint was not found."); } @@ -101,8 +112,8 @@ static void _CreateEdges // create the actual edge Edge newEdge = {0}; newEdge.relationship = e->relation; - Edge_SetSrcNode(&newEdge, src_node); - Edge_SetDestNode(&newEdge, dest_node); + Edge_SetSrcNodeID(&newEdge, ENTITY_GET_ID(src_node)); + Edge_SetDestNodeID(&newEdge, ENTITY_GET_ID(dest_node)); Edge *edge_ref = Record_AddEdge(r, e->edge_idx, newEdge); // convert query-level properties @@ -121,40 +132,48 @@ static void _CreateEdges } // Return mode, emit a populated Record. -static Record _handoff(OpCreate *op) { - return array_pop(op->records); +static Record _handoff +( + OpCreate *op +) { + return (array_len(op->records)) ? array_pop(op->records) : NULL; } -static Record CreateConsume(OpBase *opBase) { +static Record CreateConsume +( + OpBase *opBase +) { OpCreate *op = (OpCreate *)opBase; Record r; - // Return mode, all data was consumed. + // return mode, all data was consumed if(op->records) return _handoff(op); - // Consume mode. + // consume mode op->records = array_new(Record, 32); + // initialize the records array with NULL, which will terminate execution // upon depletion array_append(op->records, NULL); - GraphContext *gc = QueryCtx_GetGraphCtx(); - OpBase *child = NULL; - if(!op->op.childCount) { - // No child operation to call. + OpBase *child = NULL; + GraphContext *gc = QueryCtx_GetGraphCtx(); + + if(op->op.childCount == 0) { + // no child operation to call r = OpBase_CreateRecord(opBase); - /* Create entities. */ + // create entities _CreateNodes(op, r, gc); _CreateEdges(op, r, gc); - // Save record for later use. + // save record for later use array_append(op->records, r); } else { - // Pull data until child is depleted. + // pull data until child is depleted child = op->op.children[0]; while((r = OpBase_Consume(child))) { - /* Persist scalars from previous ops before storing the record, - * as those ops will be freed before the records are handed off. */ + // persist scalars from previous ops before storing the record + // as those ops will be freed before the records are handed off Record_PersistScalars(r); // create entities @@ -166,15 +185,17 @@ static Record CreateConsume(OpBase *opBase) { } } - /* Done reading, we're not going to call consume any longer - * there might be operations e.g. index scan that need to free - * index R/W lock, as such free all execution plan operation up the chain. */ - if(child) OpBase_PropagateReset(child); + // done reading, we're not going to call consume any longer + // there might be operations e.g. index scan that need to free + // index R/W lock, as such free all execution plan operation up the chain + if(child) { + OpBase_PropagateReset(child); + } - // Create entities. + // create entities CommitNewEntities(opBase, &op->pending); - // Return record. + // return record return _handoff(op); } diff --git a/src/execution_plan/ops/op_create.h b/src/execution_plan/ops/op_create.h index c5dda0a06a..3a7ae9c298 100644 --- a/src/execution_plan/ops/op_create.h +++ b/src/execution_plan/ops/op_create.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_delete.c b/src/execution_plan/ops/op_delete.c index 15d1233b34..50d03cdf28 100644 --- a/src/execution_plan/ops/op_delete.c +++ b/src/execution_plan/ops/op_delete.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./op_delete.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" #include "../../graph/graph_hub.h" #include "datatypes/path/sipath.h" #include "../../arithmetic/arithmetic_expression.h" @@ -16,9 +19,7 @@ // forward declarations static Record DeleteConsume(OpBase *opBase); -static OpResult DeleteInit(OpBase *opBase); static OpBase *DeleteClone(const ExecutionPlan *plan, const OpBase *opBase); -static OpResult DeleteReset(OpBase *opBase); static void DeleteFree(OpBase *opBase); static int entity_cmp @@ -115,21 +116,15 @@ static void _DeleteEntities // delete edges if(edge_count > 0) { - DeleteEdges(gc, distinct_edges, edge_count); + DeleteEdges(gc, distinct_edges, edge_count, true); edge_deleted = edge_count; } // delete nodes if(node_count > 0) { - DeleteNodes(gc, distinct_nodes, node_count); + DeleteNodes(gc, distinct_nodes, node_count, true); node_deleted = node_count; } - - // stats must be updated under lock due to for replication - if(op->stats != NULL) { - op->stats->nodes_deleted += node_deleted; - op->stats->relationships_deleted += edge_deleted; - } } } @@ -139,53 +134,39 @@ static void _DeleteEntities } OpBase *NewDeleteOp(const ExecutionPlan *plan, AR_ExpNode **exps) { - OpDelete *op = rm_malloc(sizeof(OpDelete)); + OpDelete *op = rm_calloc(1, sizeof(OpDelete)); op->gc = QueryCtx_GetGraphCtx(); op->exps = exps; - op->stats = NULL; op->exp_count = array_len(exps); op->deleted_nodes = array_new(Node, 32); op->deleted_edges = array_new(Edge, 32); - // Set our Op operations - OpBase_Init((OpBase *)op, OPType_DELETE, "Delete", DeleteInit, DeleteConsume, - DeleteReset, NULL, DeleteClone, DeleteFree, true, plan); + // set our Op operations + OpBase_Init((OpBase *)op, OPType_DELETE, "Delete", NULL, DeleteConsume, + NULL, NULL, DeleteClone, DeleteFree, true, plan); return (OpBase *)op; } -static OpResult DeleteInit(OpBase *opBase) { +// collect nodes and edges to be deleted +static inline void _CollectDeletedEntities(Record r, OpBase *opBase) { OpDelete *op = (OpDelete *)opBase; - op->stats = QueryCtx_GetResultSetStatistics(); - return OP_OK; -} -static Record DeleteConsume(OpBase *opBase) { - OpDelete *op = (OpDelete *)opBase; - OpBase *child = op->op.children[0]; - - Record r = OpBase_Consume(child); - if(!r) return NULL; - - // Expression should be evaluated to either a node, an edge or a path + // expression should be evaluated to either a node, an edge or a path // which will be marked for deletion, if an expression is evaluated - // to a different value type e.g. Numeric a run-time exception is thrown. */ + // to a different value type e.g. Numeric a run-time exception is thrown. for(int i = 0; i < op->exp_count; i++) { AR_ExpNode *exp = op->exps[i]; SIValue value = AR_EXP_Evaluate(exp, r); SIType type = SI_TYPE(value); - /* Enqueue entities for deletion. */ + // enqueue entities for deletion if(type & T_NODE) { Node *n = (Node *)value.ptrval; array_append(op->deleted_nodes, *n); - // If evaluating the expression allocated any memory, free it. - SIValue_Free(value); } else if(type & T_EDGE) { Edge *e = (Edge *)value.ptrval; array_append(op->deleted_edges, *e); - // If evaluating the expression allocated any memory, free it. - SIValue_Free(value); } else if(type & T_PATH) { Path *p = (Path *)value.ptrval; size_t nodeCount = Path_NodeCount(p); @@ -200,53 +181,81 @@ static Record DeleteConsume(OpBase *opBase) { Edge *e = Path_GetEdge(p, i); array_append(op->deleted_edges, *e); } - - SIValue_Free(value); } else if(!(type & T_NULL)) { - /* Expression evaluated to a non-graph entity type - * clear pending deletions and raise an exception. */ - array_clear(op->deleted_nodes); - array_clear(op->deleted_edges); - // If evaluating the expression allocated any memory, free it. + // if evaluating the expression allocated any memory, free it. SIValue_Free(value); - // free the Record this operation acted on - OpBase_DeleteRecord(r); ErrorCtx_RaiseRuntimeException("Delete type mismatch, expecting either Node or Relationship."); break; } - } - return r; + // if evaluating the expression allocated any memory, free it. + SIValue_Free(value); + } } -static OpBase *DeleteClone(const ExecutionPlan *plan, const OpBase *opBase) { - ASSERT(opBase->type == OPType_DELETE); - OpDelete *op = (OpDelete *)opBase; - AR_ExpNode **exps; - array_clone_with_cb(exps, op->exps, AR_EXP_Clone); - return NewDeleteOp(plan, exps); +static inline Record _handoff(OpDelete *op) { + return (array_len(op->records)) ? array_pop(op->records) : NULL; } -static OpResult DeleteReset(OpBase *opBase) { +static Record DeleteConsume(OpBase *opBase) { OpDelete *op = (OpDelete *)opBase; + Record r; + ASSERT(op->op.childCount > 0); - _DeleteEntities(op); + // return mode, all data was consumed + if(op->records) return _handoff(op); - if(op->deleted_nodes) { - array_clear(op->deleted_nodes); - } + // consume mode + op->records = array_new(Record, 32); + // initialize the records array with NULL + // which will terminate execution upon depletion + array_append(op->records, NULL); - if(op->deleted_edges) { - array_clear(op->deleted_edges); + GraphContext *gc = QueryCtx_GetGraphCtx(); + // pull data until child is depleted + OpBase *child = op->op.children[0]; + while((r = OpBase_Consume(child))) { + // persist scalars from previous ops before storing the record + // as those ops will be freed before the records are handed off + Record_PersistScalars(r); + + // save record for later use + array_append(op->records, r); + + // collect entities to be deleted + _CollectDeletedEntities(r, opBase); } - return OP_OK; + // done reading, we're not going to call consume any longer + // there might be operations e.g. index scan that need to free + // index R/W lock, as such reset all execution plan operation up the chain + OpBase_PropagateReset(child); + + // delete entities + _DeleteEntities(op); + + // return record + return _handoff(op); +} + +static OpBase *DeleteClone(const ExecutionPlan *plan, const OpBase *opBase) { + ASSERT(opBase->type == OPType_DELETE); + + OpDelete *op = (OpDelete *)opBase; + AR_ExpNode **exps; + array_clone_with_cb(exps, op->exps, AR_EXP_Clone); + return NewDeleteOp(plan, exps); } static void DeleteFree(OpBase *opBase) { OpDelete *op = (OpDelete *)opBase; - _DeleteEntities(op); + if(op->records) { + uint rec_count = array_len(op->records); + for(uint i = 1; i < rec_count; i++) OpBase_DeleteRecord(op->records[i]); + array_free(op->records); + op->records = NULL; + } if(op->deleted_nodes) { array_free(op->deleted_nodes); diff --git a/src/execution_plan/ops/op_delete.h b/src/execution_plan/ops/op_delete.h index 5a003c726f..dab1d0fbd6 100644 --- a/src/execution_plan/ops/op_delete.h +++ b/src/execution_plan/ops/op_delete.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -17,12 +20,11 @@ typedef struct { OpBase op; GraphContext *gc; + Record *records; // Eagerly collected records. AR_ExpNode **exps; // Expressions evaluated to an entity about to be deleted. uint exp_count; // Number of expressions. Node *deleted_nodes; // Array of nodes to be removed. Edge *deleted_edges; // Array of edges to be removed. - - ResultSetStatistics *stats; } OpDelete; OpBase *NewDeleteOp(const ExecutionPlan *plan, AR_ExpNode **exps); diff --git a/src/execution_plan/ops/op_distinct.c b/src/execution_plan/ops/op_distinct.c index 4c29c48c9e..756f2e0094 100644 --- a/src/execution_plan/ops/op_distinct.c +++ b/src/execution_plan/ops/op_distinct.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_distinct.h" #include "op_project.h" @@ -12,9 +15,10 @@ #include "../execution_plan_build/execution_plan_modify.h" /* Forward declarations. */ +static void DistinctFree(OpBase *opBase); static Record DistinctConsume(OpBase *opBase); +static OpResult DistinctReset(OpBase *opBase); static OpBase *DistinctClone(const ExecutionPlan *plan, const OpBase *opBase); -static void DistinctFree(OpBase *opBase); // compute hash on distinct values // values that are required to be distinct are located at 'offset' @@ -66,7 +70,7 @@ OpBase *NewDistinctOp(const ExecutionPlan *plan, const char **aliases, uint alia memcpy(op->aliases, aliases, alias_count * sizeof(const char *)); OpBase_Init((OpBase *)op, OPType_DISTINCT, "Distinct", NULL, DistinctConsume, - NULL, NULL, DistinctClone, DistinctFree, false, plan); + DistinctReset, NULL, DistinctClone, DistinctFree, false, plan); return (OpBase *)op; } @@ -106,6 +110,20 @@ static inline OpBase *DistinctClone(const ExecutionPlan *plan, const OpBase *opB return NewDistinctOp(plan, op->aliases, op->offset_count); } +static OpResult DistinctReset +( + OpBase *opBase +) { + OpDistinct *op = (OpDistinct *)opBase; + + if(op->found) { + raxFree(op->found); + op->found = raxNew(); + } + + return OP_OK; +} + static void DistinctFree(OpBase *ctx) { OpDistinct *op = (OpDistinct *)ctx; if(op->found) { diff --git a/src/execution_plan/ops/op_distinct.h b/src/execution_plan/ops/op_distinct.h index 370a074e19..b1c089eba5 100644 --- a/src/execution_plan/ops/op_distinct.h +++ b/src/execution_plan/ops/op_distinct.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_edge_by_index_scan.c b/src/execution_plan/ops/op_edge_by_index_scan.c index d0c26e6bcf..ca953cf58b 100644 --- a/src/execution_plan/ops/op_edge_by_index_scan.c +++ b/src/execution_plan/ops/op_edge_by_index_scan.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_edge_by_index_scan.h" #include "../../query_ctx.h" @@ -153,10 +156,10 @@ static inline void _UpdateRecord int res; UNUSED(res); - Edge e = GE_NEW_LABELED_EDGE(op->edge->reltypes[0], op->edge->reltypeIDs[0]); + Edge e = GE_NEW_LABELED_EDGE(op->edge->reltypes[0], op->edge->reltypeIDs[0]); - EntityID src_id = edge_key->src_id; - EntityID dest_id = edge_key->dest_id; + e.src_id = edge_key->src_id; + e.dest_id = edge_key->dest_id; EntityID edge_id = edge_key->edge_id; res = Graph_GetEdge(op->g, edge_id, &e); @@ -164,24 +167,16 @@ static inline void _UpdateRecord if(!op->srcAware) { Node src = GE_NEW_NODE(); - res = Graph_GetNode(op->g, src_id, &src); + res = Graph_GetNode(op->g, e.src_id, &src); ASSERT(res != 0); Record_AddNode(r, op->srcRecIdx, src); - Edge_SetSrcNode(&e, &src); - } else { - Node *src = Record_GetNode(r, op->srcRecIdx); - Edge_SetSrcNode(&e, src); } if(!op->destAware) { Node dest = GE_NEW_NODE(); - res = Graph_GetNode(op->g, dest_id, &dest); + res = Graph_GetNode(op->g, e.dest_id, &dest); ASSERT(res != 0); Record_AddNode(r, op->destRecIdx, dest); - Edge_SetDestNode(&e, &dest); - } else { - Node *dest = Record_GetNode(r, op->destRecIdx); - Edge_SetDestNode(&e, dest); } Record_AddEdge(r, op->edgeRecIdx, e); diff --git a/src/execution_plan/ops/op_edge_by_index_scan.h b/src/execution_plan/ops/op_edge_by_index_scan.h index 2dc9c3b1b4..365b023cb0 100644 --- a/src/execution_plan/ops/op_edge_by_index_scan.h +++ b/src/execution_plan/ops/op_edge_by_index_scan.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_expand_into.c b/src/execution_plan/ops/op_expand_into.c index 591f86dfe9..f790bd776f 100644 --- a/src/execution_plan/ops/op_expand_into.c +++ b/src/execution_plan/ops/op_expand_into.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_expand_into.h" #include "shared/print_functions.h" diff --git a/src/execution_plan/ops/op_expand_into.h b/src/execution_plan/ops/op_expand_into.h index 32cc79ee2e..8bbdae5cb1 100644 --- a/src/execution_plan/ops/op_expand_into.h +++ b/src/execution_plan/ops/op_expand_into.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_filter.c b/src/execution_plan/ops/op_filter.c index 6758ad0ec4..b86ef1d77a 100644 --- a/src/execution_plan/ops/op_filter.c +++ b/src/execution_plan/ops/op_filter.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_filter.h" #include "RG.h" diff --git a/src/execution_plan/ops/op_filter.h b/src/execution_plan/ops/op_filter.h index e3ed9dfed6..d630a9214d 100644 --- a/src/execution_plan/ops/op_filter.h +++ b/src/execution_plan/ops/op_filter.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_foreach.c b/src/execution_plan/ops/op_foreach.c index 6d8a577b0d..fd38f9700d 100644 --- a/src/execution_plan/ops/op_foreach.c +++ b/src/execution_plan/ops/op_foreach.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_foreach.h" @@ -76,7 +79,7 @@ static OpResult ForeachInit // otherwise, returns NULL (last value in op->records) static Record _handoff(OpForeach *op) { ASSERT(op->records != NULL); - return array_pop(op->records); + return (array_len(op->records)) ? array_pop(op->records) : NULL; } // the Foreach consume function aggregates all the records from the supplier if @@ -107,6 +110,7 @@ static Record ForeachConsume if(op->supplier) { // eagerly drain supplier while((r = OpBase_Consume(op->supplier))) { + Record_PersistScalars(r); array_append(op->records, r); // create a record with the mapping of the embedded plan @@ -117,6 +121,9 @@ static Record ForeachConsume Record_Clone(r, body_rec); array_append(op->body_records, body_rec); } + // supplier depleted + // propagate reset to release RediSearch index lock if any exists + OpBase_PropagateReset(op->supplier); } else { // static list, create a dummy empty record just to kick start the // argument-list operation, and a dummy to pass on diff --git a/src/execution_plan/ops/op_foreach.h b/src/execution_plan/ops/op_foreach.h index a5f4482003..e2e5afaf0c 100644 --- a/src/execution_plan/ops/op_foreach.h +++ b/src/execution_plan/ops/op_foreach.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_join.c b/src/execution_plan/ops/op_join.c index defbb813cc..bb6516a1a3 100644 --- a/src/execution_plan/ops/op_join.c +++ b/src/execution_plan/ops/op_join.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_join.h" #include "RG.h" @@ -12,6 +15,7 @@ static Record JoinConsume(OpBase *opBase); static OpResult JoinInit(OpBase *opBase); static OpBase *JoinClone(const ExecutionPlan *plan, const OpBase *opBase); +static OpResult JoinReset(OpBase *opBase); OpBase *NewJoinOp(const ExecutionPlan *plan) { OpJoin *op = rm_malloc(sizeof(OpJoin)); @@ -19,7 +23,11 @@ OpBase *NewJoinOp(const ExecutionPlan *plan) { // Set our Op operations OpBase_Init((OpBase *)op, OPType_JOIN, "Join", JoinInit, JoinConsume, - NULL, NULL, JoinClone, NULL, false, plan); + JoinReset, NULL, JoinClone, NULL, false, plan); + + // if the Join op is not placed directly under a Results op (or as second + // descendent in case of `UNION ALL`), don't update the result set mapping + op->update_column_map = true; return (OpBase *)op; } @@ -32,7 +40,16 @@ static OpResult JoinInit(OpBase *opBase) { // map first stream resultset mapping ResultSet *result_set = QueryCtx_GetResultSet(); - if(result_set != NULL) { + + OpBase *parent = op->op.parent; + if(parent != NULL && parent->type != OPType_RESULTS) { + parent = parent->parent; + if(parent != NULL && parent->type != OPType_RESULTS) { + op->update_column_map = false; + } + } + + if(result_set != NULL && op->update_column_map) { OpBase *child = op->stream; rax *mapping = ExecutionPlan_GetMappings(child->plan); ResultSet_MapProjection(result_set, mapping); @@ -44,24 +61,27 @@ static OpResult JoinInit(OpBase *opBase) { static Record JoinConsume(OpBase *opBase) { OpJoin *op = (OpJoin *)opBase; Record r = NULL; - bool update_column_map = false; + bool new_stream = false; while(!r) { // Try pulling from current stream. r = OpBase_Consume(op->stream); if(!r) { - // Stream depleted, see if there's a new stream to pull from. + // Stream depleted + // Propagate reset to release RediSearch index lock if any exists + OpBase_PropagateReset(op->stream); + // See if there's a new stream to pull from. op->streamIdx++; if(op->streamIdx >= op->op.childCount) break; op->stream = op->op.children[op->streamIdx]; // Switched streams, need to update the ResultSet column mapping - update_column_map = true; + new_stream = true; continue; } - if(update_column_map) { + if(op->update_column_map && new_stream) { // We have a new record mapping, update the ResultSet column map to match it. ResultSet_MapProjection(QueryCtx_GetResultSet(), r->mapping); } @@ -72,6 +92,33 @@ static Record JoinConsume(OpBase *opBase) { static inline OpBase *JoinClone(const ExecutionPlan *plan, const OpBase *opBase) { ASSERT(opBase->type == OPType_JOIN); - return NewJoinOp(plan); + OpBase *clone = NewJoinOp(plan); + return clone; +} + +static OpResult JoinReset +( + OpBase *opBase +) { + OpJoin *op = (OpJoin *)opBase; + op->streamIdx = 0; + op->stream = op->op.children[op->streamIdx]; + + // map first stream resultset mapping + ResultSet *result_set = QueryCtx_GetResultSet(); + if(result_set != NULL && op->update_column_map) { + OpBase *child = op->stream; + rax *mapping = ExecutionPlan_GetMappings(child->plan); + ResultSet_MapProjection(result_set, mapping); + } + + return OP_OK; } +bool JoinGetUpdateColumnMap +( + const OpBase *op +) { + ASSERT(op->type == OPType_JOIN); + return ((OpJoin *)op)->update_column_map; +} diff --git a/src/execution_plan/ops/op_join.h b/src/execution_plan/ops/op_join.h index f38feba6cf..51df46ce27 100644 --- a/src/execution_plan/ops/op_join.h +++ b/src/execution_plan/ops/op_join.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -13,6 +16,9 @@ typedef struct { OpBase op; OpBase *stream; // Current stream to pull from. int streamIdx; // Current stream index. + bool update_column_map; // Update column map. } OpJoin; OpBase *NewJoinOp(const ExecutionPlan *plan); + +bool JoinGetUpdateColumnMap(const OpBase *op); diff --git a/src/execution_plan/ops/op_limit.c b/src/execution_plan/ops/op_limit.c index 4a4b39423d..b7101ca7d2 100644 --- a/src/execution_plan/ops/op_limit.c +++ b/src/execution_plan/ops/op_limit.c @@ -1,12 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_limit.h" #include "../../RG.h" -#include "../../errors.h" +#include "../../errors/errors.h" #include "../../arithmetic/arithmetic_expression.h" /* Forward declarations. */ @@ -27,7 +30,7 @@ static void _eval_limit(OpLimit *op, AR_ExpNode *limit_exp) { // Validate that the limit value is numeric and non-negative. if(SI_TYPE(l) != T_INT64 || SI_GET_NUMERIC(l) < 0) { - ErrorCtx_SetError("Limit operates only on non-negative integers"); + ErrorCtx_SetError(EMSG_OPERATE_ON_NON_NEGATIVE_INT, "Limit"); } op->limit = SI_GET_NUMERIC(l); diff --git a/src/execution_plan/ops/op_limit.h b/src/execution_plan/ops/op_limit.h index 4eb083ccaf..8d33eefe65 100644 --- a/src/execution_plan/ops/op_limit.h +++ b/src/execution_plan/ops/op_limit.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_merge.c b/src/execution_plan/ops/op_merge.c index 7d162a38ae..7e3c6f6592 100644 --- a/src/execution_plan/ops/op_merge.c +++ b/src/execution_plan/ops/op_merge.c @@ -1,18 +1,21 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_merge.h" #include "../../RG.h" -#include "../../errors.h" #include "op_merge_create.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" #include "../../schema/schema.h" #include "../../util/rax_extensions.h" #include "../../arithmetic/arithmetic_expression.h" -#include "../execution_plan_build/execution_plan_modify.h" +#include "../execution_plan_build/execution_plan_util.h" // forward declarations static OpResult MergeInit(OpBase *opBase); @@ -20,6 +23,28 @@ static Record MergeConsume(OpBase *opBase); static OpBase *MergeClone(const ExecutionPlan *plan, const OpBase *opBase); static void MergeFree(OpBase *opBase); +// fake hash function +// hash of key is simply key +static uint64_t _id_hash +( + const void *key +) { + return ((uint64_t)key); +} + +// hashtable entry free callback +static void freeCallback +( + dict *d, + void *val +) { + PendingUpdateCtx_Free((PendingUpdateCtx*)val); +} + +// hashtable callbacks +static dictType _dt = { _id_hash, NULL, NULL, NULL, NULL, freeCallback, NULL, + NULL, NULL, NULL}; + //------------------------------------------------------------------------------ // ON MATCH / ON CREATE logic //------------------------------------------------------------------------------ @@ -27,9 +52,8 @@ static void MergeFree(OpBase *opBase); // apply a set of updates to the given records static void _UpdateProperties ( - PendingUpdateCtx **node_pending_updates, - PendingUpdateCtx **edge_pending_updates, - ResultSetStatistics *stats, + dict *node_pending_updates, + dict *edge_pending_updates, raxIterator updates, Record *records, uint record_count @@ -84,22 +108,12 @@ static inline void _free_pending_updates OpMerge *op ) { if(op->node_pending_updates) { - uint pending_updates_count = array_len(op->node_pending_updates); - for(uint i = 0; i < pending_updates_count; i++) { - PendingUpdateCtx *pending_update = op->node_pending_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - array_free(op->node_pending_updates); + HashTableRelease(op->node_pending_updates); op->node_pending_updates = NULL; } if(op->edge_pending_updates) { - uint pending_updates_count = array_len(op->edge_pending_updates); - for(uint i = 0; i < pending_updates_count; i++) { - PendingUpdateCtx *pending_update = op->edge_pending_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - array_free(op->edge_pending_updates); + HashTableRelease(op->edge_pending_updates); op->edge_pending_updates = NULL; } } @@ -116,7 +130,6 @@ OpBase *NewMergeOp // (see CartesianProduct and ValueHashJoin) OpMerge *op = rm_calloc(1, sizeof(OpMerge)); - op->stats = NULL; op->on_match = on_match; op->on_create = on_create; op->node_pending_updates = NULL; @@ -170,7 +183,6 @@ static OpResult MergeInit // - the last creates the pattern ASSERT(opBase->childCount == 2 || opBase->childCount == 3); OpMerge *op = (OpMerge *)opBase; - op->stats = QueryCtx_GetResultSetStatistics(); if(opBase->childCount == 2) { // if we only have 2 streams // we simply need to determine which has a MergeCreate op @@ -362,13 +374,13 @@ static Record MergeConsume } OpBase_PropagateReset(op->match_stream); - op->node_pending_updates = array_new(PendingUpdateCtx, 0); - op->edge_pending_updates = array_new(PendingUpdateCtx, 0); + op->node_pending_updates = HashTableCreate(&_dt); + op->edge_pending_updates = HashTableCreate(&_dt); // if we are setting properties with ON MATCH, compute all pending updates if(op->on_match && match_count > 0) { - _UpdateProperties(&op->node_pending_updates, &op->edge_pending_updates, - op->stats, op->on_match_it, op->output_records, match_count); + _UpdateProperties(op->node_pending_updates, op->edge_pending_updates, + op->on_match_it, op->output_records, match_count); } if(must_create_records) { @@ -379,25 +391,22 @@ static Record MergeConsume // we only need to pull the created records if we're returning results // or performing updates on creation - // TODO: isn't op->stats always != NULL ? - if(op->stats || op->on_create) { - // pull all records from the Create stream - uint create_count = 0; - Record created_record; - while((created_record = _pullFromStream(op->create_stream))) { - array_append(op->output_records, created_record); - create_count++; - } + // pull all records from the Create stream + uint create_count = 0; + Record created_record; + while((created_record = _pullFromStream(op->create_stream))) { + array_append(op->output_records, created_record); + create_count++; + } - // if we are setting properties with ON CREATE - // compute all pending updates - // TODO: note we're under lock at this point! is there a way - // to compute these changes before locking ? - if(op->on_create) { - _UpdateProperties(&op->node_pending_updates, - &op->edge_pending_updates, op->stats, op->on_create_it, - op->output_records + match_count, create_count); - } + // if we are setting properties with ON CREATE + // compute all pending updates + // TODO: note we're under lock at this point! is there a way + // to compute these changes before locking ? + if(op->on_create) { + _UpdateProperties(op->node_pending_updates, + op->edge_pending_updates, op->on_create_it, + op->output_records + match_count, create_count); } } @@ -405,14 +414,14 @@ static Record MergeConsume // update //-------------------------------------------------------------------------- - if(array_len(op->node_pending_updates) > 0 || - array_len(op->edge_pending_updates) > 0) { + if(HashTableElemCount(op->node_pending_updates) > 0 || + HashTableElemCount(op->edge_pending_updates) > 0) { GraphContext *gc = QueryCtx_GetGraphCtx(); // lock everything QueryCtx_LockForCommit(); { - CommitUpdates(gc, op->stats, op->node_pending_updates, ENTITY_NODE); + CommitUpdates(gc, op->node_pending_updates, ENTITY_NODE); if(likely(!ErrorCtx_EncounteredError())) { - CommitUpdates(gc, op->stats, op->edge_pending_updates, ENTITY_EDGE); + CommitUpdates(gc, op->edge_pending_updates, ENTITY_EDGE); } } } @@ -421,7 +430,8 @@ static Record MergeConsume // free updates //-------------------------------------------------------------------------- - _free_pending_updates(op); + HashTableEmpty(op->node_pending_updates, NULL); + HashTableEmpty(op->edge_pending_updates, NULL); return _handoff(op); } diff --git a/src/execution_plan/ops/op_merge.h b/src/execution_plan/ops/op_merge.h index 6e1f9828df..ccffa63f22 100644 --- a/src/execution_plan/ops/op_merge.h +++ b/src/execution_plan/ops/op_merge.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -28,9 +31,8 @@ typedef struct { rax *on_create; // Updates to be performed on creation. raxIterator on_match_it; // Iterator for traversing ON MATCH update contexts. raxIterator on_create_it; // Iterator for traversing ON CREATE update contexts. - PendingUpdateCtx *node_pending_updates; // Pending updates to apply, generated - PendingUpdateCtx *edge_pending_updates; // Pending updates to apply, generated - ResultSetStatistics *stats; // Required for tracking statistics updates in ON MATCH. + dict *node_pending_updates; // Pending updates to apply, generated + dict *edge_pending_updates; // Pending updates to apply, generated } OpMerge; OpBase *NewMergeOp(const ExecutionPlan *plan, rax *on_match, rax *on_create); diff --git a/src/execution_plan/ops/op_merge_create.c b/src/execution_plan/ops/op_merge_create.c index 51172f28ef..7b5d365267 100644 --- a/src/execution_plan/ops/op_merge_create.c +++ b/src/execution_plan/ops/op_merge_create.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_merge_create.h" -#include "../../errors.h" #include "../../util/arr.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" /* Forward declarations. */ static Record MergeCreateConsume(OpBase *opBase); @@ -49,18 +52,19 @@ static void _IncrementalHashEntity(XXH64_state_t *state, const char **labels, } } -// Revert the most recent set of buffered creations and free any allocations. -static void _RollbackPendingCreations(OpMergeCreate *op) { +// revert the most recent set of buffered creations and free any allocations. +static void _RollbackPendingCreations +( + OpMergeCreate *op +) { uint nodes_to_create_count = array_len(op->pending.nodes_to_create); for(uint i = 0; i < nodes_to_create_count; i++) { - array_pop(op->pending.created_nodes); AttributeSet props = array_pop(op->pending.node_attributes); AttributeSet_Free(&props); } uint edges_to_create_count = array_len(op->pending.edges_to_create); for(uint i = 0; i < edges_to_create_count; i++) { - array_pop(op->pending.created_edges); AttributeSet props = array_pop(op->pending.edge_attributes); AttributeSet_Free(&props); } @@ -118,18 +122,17 @@ static bool _CreateEntities(OpMergeCreate *op, Record r, GraphContext *gc) { UNUSED(res); ASSERT(res != XXH_ERROR); + //-------------------------------------------------------------------------- + // hash nodes + //-------------------------------------------------------------------------- + uint nodes_to_create_count = array_len(op->pending.nodes_to_create); + for(uint i = 0; i < nodes_to_create_count; i++) { // get specified node to create NodeCreateCtx *n = op->pending.nodes_to_create + i; - // create a new node - Node newNode = GE_NEW_NODE(); - - // add new node to Record and save a reference to it - Node *node_ref = Record_AddNode(r, n->node_idx, newNode); - - // convert query-level properties + // convert properties PropertyMap *map = n->properties; AttributeSet converted_attr = NULL; if(map != NULL) { @@ -141,17 +144,20 @@ static bool _CreateEntities(OpMergeCreate *op, Record r, GraphContext *gc) { _IncrementalHashEntity(op->hash_state, n->labels, label_count, &converted_attr); - // Save node for later insertion - array_append(op->pending.created_nodes, node_ref); - - // Save attributes to insert with node + // save attributes array_append(op->pending.node_attributes, converted_attr); - // save labels to assigned to node + // save labels array_append(op->pending.node_labels, n->labelsId); } + + //-------------------------------------------------------------------------- + // hash edges + //-------------------------------------------------------------------------- + uint edges_to_create_count = array_len(op->pending.edges_to_create); + for(uint i = 0; i < edges_to_create_count; i++) { // get specified edge to create EdgeCreateCtx *e = op->pending.edges_to_create + i; @@ -160,19 +166,6 @@ static bool _CreateEntities(OpMergeCreate *op, Record r, GraphContext *gc) { Node *src_node = Record_GetNode(r, e->src_idx); Node *dest_node = Record_GetNode(r, e->dest_idx); - // verify that the endpoints of the new edge resolved properly; fail otherwise - if(!src_node || !dest_node) { - ErrorCtx_RaiseRuntimeException("Failed to create relationship; endpoint was not found."); - } - - // create the actual edge - Edge newEdge = {0}; - newEdge.relationship = e->relation; - Edge_SetSrcNode(&newEdge, src_node); - Edge_SetDestNode(&newEdge, dest_node); - - Edge *edge_ref = Record_AddEdge(r, e->edge_idx, newEdge); - // convert query-level properties PropertyMap *map = e->properties; AttributeSet converted_attr = NULL; @@ -180,41 +173,89 @@ static bool _CreateEntities(OpMergeCreate *op, Record r, GraphContext *gc) { ConvertPropertyMap(gc, &converted_attr, r, map, true); } - // Update the hash code with this entity, an edge is represented by its + // update the hash code with this entity, an edge is represented by its // relation, properties, source and destination nodes. // note: unbounded nodes were already presented to the hash. - // incase node has its internal attribute-set, this means the node has been retrieved from the graph + // incase node has its internal attribute-set + // this means the node has been retrieved from the graph // i.e. bounded node + _IncrementalHashEntity(op->hash_state, &e->relation, 1, &converted_attr); - if(src_node->attributes != NULL) { + + // hash source node + if(src_node != NULL) { EntityID id = ENTITY_GET_ID(src_node); + ASSERT(id != INVALID_ENTITY_ID); void *data = &id; size_t len = sizeof(id); res = XXH64_update(op->hash_state, data, len); ASSERT(res != XXH_ERROR); } - if(dest_node->attributes != NULL) { + + // hash dest node + if(dest_node != NULL) { EntityID id = ENTITY_GET_ID(dest_node); + ASSERT(id != INVALID_ENTITY_ID); void *data = &id; size_t len = sizeof(id); res = XXH64_update(op->hash_state, data, len); ASSERT(res != XXH_ERROR); } - /* Save edge for later insertion. */ - array_append(op->pending.created_edges, edge_ref); - - /* Save attributes to insert with node. */ + // save attributes array_append(op->pending.edge_attributes, converted_attr); } - // Finalize the hash value for all processed creations. + // finalize the hash value for all processed creations XXH64_hash_t const hash = XXH64_digest(op->hash_state); - // Check if any creations are unique. - bool should_create_entities = raxTryInsert(op->unique_entities, (unsigned char *)&hash, - sizeof(hash), NULL, NULL); - // If no entity to be created is unique, roll back all the creations that have just been prepared. - if(!should_create_entities) _RollbackPendingCreations(op); + + // check if any creations are unique + bool should_create_entities = raxTryInsert(op->unique_entities, + (unsigned char *)&hash, sizeof(hash), NULL, NULL); + + // if no entity to be created is unique + // roll back all the creations that have just been prepared + if(should_create_entities) { + // reserve node ids for edges creation + for(uint i = 0; i < nodes_to_create_count; i++) { + NodeCreateCtx *n = op->pending.nodes_to_create + i; + + Node newNode = Graph_ReserveNode(gc->g); + + // add new node to Record and save a reference to it + Node *node_ref = Record_AddNode(r, n->node_idx, newNode); + + // save node for later insertion + array_append(op->pending.created_nodes, node_ref); + } + + // updated edges with reserved node ids + for(uint i = 0; i < edges_to_create_count; i++) { + EdgeCreateCtx *ctx = op->pending.edges_to_create + i; + + // retrieve source and dest nodes + Node *src_node = Record_GetNode(r, ctx->src_idx); + Node *dest_node = Record_GetNode(r, ctx->dest_idx); + + if(!src_node || !dest_node) { + ErrorCtx_RaiseRuntimeException( + "Failed to create relationship; endpoint was not found." + ); + } + + // create edge + Edge newEdge = {0}; + newEdge.relationship = ctx->relation; + Edge *e = Record_AddEdge(r, ctx->edge_idx, newEdge); + Edge_SetSrcNodeID(e, ENTITY_GET_ID(src_node)); + Edge_SetDestNodeID(e, ENTITY_GET_ID(dest_node)); + + // save edge for later insertion + array_append(op->pending.created_edges, e); + } + } else { + _RollbackPendingCreations(op); + } return should_create_entities; } diff --git a/src/execution_plan/ops/op_merge_create.h b/src/execution_plan/ops/op_merge_create.h index c3400c5a5b..4c638e14be 100644 --- a/src/execution_plan/ops/op_merge_create.h +++ b/src/execution_plan/ops/op_merge_create.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_node_by_id_seek.c b/src/execution_plan/ops/op_node_by_id_seek.c index 9faaeb6afd..8ec1600a34 100644 --- a/src/execution_plan/ops/op_node_by_id_seek.c +++ b/src/execution_plan/ops/op_node_by_id_seek.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_node_by_id_seek.h" #include "RG.h" diff --git a/src/execution_plan/ops/op_node_by_id_seek.h b/src/execution_plan/ops/op_node_by_id_seek.h index 958cec0c0e..cb1af5e933 100644 --- a/src/execution_plan/ops/op_node_by_id_seek.h +++ b/src/execution_plan/ops/op_node_by_id_seek.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_node_by_index_scan.c b/src/execution_plan/ops/op_node_by_index_scan.c index 7353e3281b..a5e59fa4cd 100644 --- a/src/execution_plan/ops/op_node_by_index_scan.c +++ b/src/execution_plan/ops/op_node_by_index_scan.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_node_by_index_scan.h" #include "../../query_ctx.h" @@ -18,10 +21,10 @@ static void IndexScanFree(OpBase *opBase); static void IndexScanToString(const OpBase *ctx, sds *buf) { IndexScan *op = (IndexScan *)ctx; - ScanToString(ctx, buf, op->n.alias, op->n.label); + ScanToString(ctx, buf, op->n->alias, op->n->label); } -OpBase *NewIndexScanOp(const ExecutionPlan *plan, Graph *g, NodeScanCtx n, +OpBase *NewIndexScanOp(const ExecutionPlan *plan, Graph *g, NodeScanCtx *n, RSIndex *idx, FT_FilterNode *filter) { // validate inputs ASSERT(g != NULL); @@ -43,7 +46,7 @@ OpBase *NewIndexScanOp(const ExecutionPlan *plan, Graph *g, NodeScanCtx n, OpBase_Init((OpBase *)op, OPType_NODE_BY_INDEX_SCAN, "Node By Index Scan", IndexScanInit, IndexScanConsume, IndexScanReset, IndexScanToString, NULL, IndexScanFree, false, plan); - op->nodeRecIdx = OpBase_Modifies((OpBase *)op, n.alias); + op->nodeRecIdx = OpBase_Modifies((OpBase *)op, n->alias); return (OpBase *)op; } @@ -63,11 +66,11 @@ static OpResult IndexScanInit(OpBase *opBase) { } // resolve label ID now if it is still unknown - if(op->n.label_id == GRAPH_UNKNOWN_LABEL) { + if(op->n->label_id == GRAPH_UNKNOWN_LABEL) { GraphContext *gc = QueryCtx_GetGraphCtx(); - Schema *schema = GraphContext_GetSchema(gc, op->n.label, SCHEMA_NODE); + Schema *schema = GraphContext_GetSchema(gc, op->n->label, SCHEMA_NODE); ASSERT(schema != NULL); - op->n.label_id = schema->id; + op->n->label_id = schema->id; } return OP_OK; @@ -235,24 +238,29 @@ static void IndexScanFree(OpBase *opBase) { * read locked, if this index scan operation is part of * a query which will modified this index we'll be stuck in * a dead lock, as we're unable to acquire index write lock. */ - if(op->iter) { + if(op->iter != NULL) { RediSearch_ResultsIteratorFree(op->iter); op->iter = NULL; } - if(op->child_record) { + if(op->child_record != NULL) { OpBase_DeleteRecord(op->child_record); op->child_record = NULL; } - if(op->filter) { + if(op->filter != NULL) { FilterTree_Free(op->filter); op->filter = NULL; } - if(op->unresolved_filters) { + if(op->unresolved_filters != NULL) { FilterTree_Free(op->unresolved_filters); op->unresolved_filters = NULL; } + + if(op->n != NULL) { + NodeScanCtx_Free(op->n); + op->n = NULL; + } } diff --git a/src/execution_plan/ops/op_node_by_index_scan.h b/src/execution_plan/ops/op_node_by_index_scan.h index 2a2ed047f4..95c9e6fe25 100644 --- a/src/execution_plan/ops/op_node_by_index_scan.h +++ b/src/execution_plan/ops/op_node_by_index_scan.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -18,7 +21,7 @@ typedef struct { Graph *g; bool rebuild_index_query; // should we rebuild RediSearch index query for each input record RSIndex *idx; // index to query - NodeScanCtx n; // label data of node being scanned + NodeScanCtx *n; // label data of node being scanned uint nodeRecIdx; // index of the node being scanned in the Record RSResultsIterator *iter; // rediSearch iterator over an index with the appropriate filters FT_FilterNode *filter; // filter from which to compose index query @@ -27,6 +30,6 @@ typedef struct { } IndexScan; // creates a new IndexScan operation -OpBase *NewIndexScanOp(const ExecutionPlan *plan, Graph *g, NodeScanCtx n, +OpBase *NewIndexScanOp(const ExecutionPlan *plan, Graph *g, NodeScanCtx *n, RSIndex *idx, FT_FilterNode *filter); diff --git a/src/execution_plan/ops/op_node_by_label_scan.c b/src/execution_plan/ops/op_node_by_label_scan.c index ed63a7c5c0..6e43f0fa26 100644 --- a/src/execution_plan/ops/op_node_by_label_scan.c +++ b/src/execution_plan/ops/op_node_by_label_scan.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_node_by_label_scan.h" #include "RG.h" @@ -19,22 +22,33 @@ static OpResult NodeByLabelScanReset(OpBase *opBase); static OpBase *NodeByLabelScanClone(const ExecutionPlan *plan, const OpBase *opBase); static void NodeByLabelScanFree(OpBase *opBase); -static inline void NodeByLabelScanToString(const OpBase *ctx, sds *buf) { +static inline void NodeByLabelScanToString +( + const OpBase *ctx, + sds *buf +) { NodeByLabelScan *op = (NodeByLabelScan *)ctx; - ScanToString(ctx, buf, op->n.alias, op->n.label); + ScanToString(ctx, buf, op->n->alias, op->n->label); } // update the label-id of a cached operation, as it may have not // been known when the plan was prepared. -static void _update_label_id(NodeByLabelScan *op) { - if(op->n.label_id != GRAPH_UNKNOWN_LABEL) return; +static void _update_label_id +( + NodeByLabelScan *op +) { + if(op->n->label_id != GRAPH_UNKNOWN_LABEL) return; GraphContext *gc = QueryCtx_GetGraphCtx(); - Schema *s = GraphContext_GetSchema(gc, op->n.label, SCHEMA_NODE); - if(s != NULL) op->n.label_id = Schema_GetID(s); + Schema *s = GraphContext_GetSchema(gc, op->n->label, SCHEMA_NODE); + if(s != NULL) op->n->label_id = Schema_GetID(s); } -OpBase *NewNodeByLabelScanOp(const ExecutionPlan *plan, NodeScanCtx n) { +OpBase *NewNodeByLabelScanOp +( + const ExecutionPlan *plan, + NodeScanCtx *n +) { NodeByLabelScan *op = rm_calloc(sizeof(NodeByLabelScan), 1); op->g = QueryCtx_GetGraph(); op->n = n; @@ -47,12 +61,16 @@ OpBase *NewNodeByLabelScanOp(const ExecutionPlan *plan, NodeScanCtx n) { NodeByLabelScanConsume, NodeByLabelScanReset, NodeByLabelScanToString, NodeByLabelScanClone, NodeByLabelScanFree, false, plan); - op->nodeRecIdx = OpBase_Modifies((OpBase *)op, n.alias); + op->nodeRecIdx = OpBase_Modifies((OpBase *)op, n->alias); return (OpBase *)op; } -void NodeByLabelScanOp_SetIDRange(NodeByLabelScan *op, UnsignedRange *id_range) { +void NodeByLabelScanOp_SetIDRange +( + NodeByLabelScan *op, + UnsignedRange *id_range +) { UnsignedRange_Free(op->id_range); op->id_range = UnsignedRange_Clone(id_range); @@ -60,15 +78,16 @@ void NodeByLabelScanOp_SetIDRange(NodeByLabelScan *op, UnsignedRange *id_range) op->op.name = "Node By Label and ID Scan"; } -static GrB_Info _ConstructIterator(NodeByLabelScan *op) { - NodeID minId; - NodeID maxId; - GrB_Info info; +static GrB_Info _ConstructIterator +( + NodeByLabelScan *op +) { + GrB_Info info; + NodeID minId; + NodeID maxId; GrB_Index nrows; - GraphContext *gc = QueryCtx_GetGraphCtx(); - RG_Matrix L = Graph_GetLabelMatrix(gc->g, op->n.label_id); - + RG_Matrix L = Graph_GetLabelMatrix(QueryCtx_GetGraph(), op->n->label_id); info = RG_Matrix_nrows(&nrows, L); ASSERT(info == GrB_SUCCESS); @@ -90,26 +109,29 @@ static GrB_Info _ConstructIterator(NodeByLabelScan *op) { return info; } -static OpResult NodeByLabelScanInit(OpBase *opBase) { +static OpResult NodeByLabelScanInit +( + OpBase *opBase +) { NodeByLabelScan *op = (NodeByLabelScan *)opBase; - OpBase_UpdateConsume(opBase, NodeByLabelScanConsume); // Default consume function. + OpBase_UpdateConsume(opBase, NodeByLabelScanConsume); // default consume function - // Operation has children, consume from child. + // operation has children, consume from child if(opBase->childCount > 0) { OpBase_UpdateConsume(opBase, NodeByLabelScanConsumeFromChild); return OP_OK; } - if(op->n.label_id == GRAPH_UNKNOWN_LABEL) { - // Missing schema, use the NOP consume function. + if(op->n->label_id == GRAPH_UNKNOWN_LABEL) { + // missing schema, use the NOP consume function OpBase_UpdateConsume(opBase, NodeByLabelScanNoOp); return OP_OK; } - // The iterator build may fail if the ID range does not match the matrix dimensions. + // the iterator build may fail if the ID range does not match the matrix dimensions GrB_Info iterator_built = _ConstructIterator(op); if(iterator_built != GrB_SUCCESS) { - // Invalid range, use the NOP consume function. + // invalid range, use the NOP consume function OpBase_UpdateConsume(opBase, NodeByLabelScanNoOp); return OP_OK; } @@ -117,56 +139,67 @@ static OpResult NodeByLabelScanInit(OpBase *opBase) { return OP_OK; } -static inline void _UpdateRecord(NodeByLabelScan *op, Record r, GrB_Index node_id) { +static inline void _UpdateRecord +( + NodeByLabelScan *op, + Record r, + GrB_Index node_id +) { // Populate the Record with the graph entity data. Node n = GE_NEW_NODE(); Graph_GetNode(op->g, node_id, &n); Record_AddNode(r, op->nodeRecIdx, n); } -static inline void _ResetIterator(NodeByLabelScan *op) { - if(op->id_range) { - // reset the range iterator - NodeID minId = op->id_range->include_min ? op->id_range->min : op->id_range->min + 1; - NodeID maxId = op->id_range->include_max ? op->id_range->max : op->id_range->max - 1 ; - RG_MatrixTupleIter_iterate_range(&op->iter, minId, maxId); - } else { - // invalid schema, our consume function is NOP - op->id_range = UnsignedRange_New(); - GrB_Info iterator_built = _ConstructIterator(op); - // if the iterator is invalid, our consume function is NOP - if(iterator_built != GrB_SUCCESS) return; - } +static inline void _ResetIterator +( + NodeByLabelScan *op +) { + _ConstructIterator(op); } -static Record NodeByLabelScanConsumeFromChild(OpBase *opBase) { +static Record NodeByLabelScanConsumeFromChild +( + OpBase *opBase +) { NodeByLabelScan *op = (NodeByLabelScan *)opBase; - // Try to get new nodeID. + // try to get new nodeID GrB_Index nodeId; GrB_Info info = RG_MatrixTupleIter_next_BOOL(&op->iter, &nodeId, NULL, NULL); while(info == GrB_NULL_POINTER || op->child_record == NULL || info == GxB_EXHAUSTED) { - // Try to get a record. - if(op->child_record) OpBase_DeleteRecord(op->child_record); + // try to get a new record + if(op->child_record != NULL) { + OpBase_DeleteRecord(op->child_record); + } + op->child_record = OpBase_Consume(op->op.children[0]); - if(op->child_record == NULL) return NULL; - // Got a record. + if(op->child_record == NULL) { + // depleted + return NULL; + } + + // got a record if(info == GrB_NULL_POINTER) { _update_label_id(op); - if(_ConstructIterator(op) != GrB_SUCCESS) continue; + if(_ConstructIterator(op) != GrB_SUCCESS) { + continue; + } } else { - // Iterator depleted - reset. + // iterator depleted - reset _ResetIterator(op); } - // Try to get new NodeID. + + // try to get new NodeID info = RG_MatrixTupleIter_next_BOOL(&op->iter, &nodeId, NULL, NULL); } - // We've got a record and NodeID. - // Clone the held Record, as it will be freed upstream. + // we've got a record and NodeID + // clone the held Record, as it will be freed upstream Record r = OpBase_DeepCloneRecord(op->child_record); - // Populate the Record with the actual node. + + // populate the Record with the actual node _UpdateRecord(op, r, nodeId); return r; } @@ -188,18 +221,27 @@ static Record NodeByLabelScanConsume(OpBase *opBase) { return r; } -/* This function is invoked when the op has no children and no valid label is requested (either no label, or non existing label). - * The op simply needs to return NULL */ -static Record NodeByLabelScanNoOp(OpBase *opBase) { +// this function is invoked when the op has no children +// and no valid label is requested (either no label, or non existing label) +// the op simply needs to return NULL +static Record NodeByLabelScanNoOp +( + OpBase *opBase +) { return NULL; } -static OpResult NodeByLabelScanReset(OpBase *ctx) { +static OpResult NodeByLabelScanReset +( + OpBase *ctx +) { NodeByLabelScan *op = (NodeByLabelScan *)ctx; + if(op->child_record) { OpBase_DeleteRecord(op->child_record); // Free old record. op->child_record = NULL; } + _ResetIterator(op); return OP_OK; } @@ -207,8 +249,7 @@ static OpResult NodeByLabelScanReset(OpBase *ctx) { static OpBase *NodeByLabelScanClone(const ExecutionPlan *plan, const OpBase *opBase) { ASSERT(opBase->type == OPType_NODE_BY_LABEL_SCAN); NodeByLabelScan *op = (NodeByLabelScan *)opBase; - OpBase *clone = NewNodeByLabelScanOp(plan, op->n); - return clone; + return NewNodeByLabelScanOp(plan, NodeScanCtx_Clone(op->n)); } static void NodeByLabelScanFree(OpBase *op) { @@ -226,5 +267,9 @@ static void NodeByLabelScanFree(OpBase *op) { UnsignedRange_Free(nodeByLabelScan->id_range); nodeByLabelScan->id_range = NULL; } -} + if(nodeByLabelScan->n != NULL) { + NodeScanCtx_Free(nodeByLabelScan->n); + nodeByLabelScan->n = NULL; + } +} diff --git a/src/execution_plan/ops/op_node_by_label_scan.h b/src/execution_plan/ops/op_node_by_label_scan.h index f583499b4d..e554670ed5 100644 --- a/src/execution_plan/ops/op_node_by_label_scan.h +++ b/src/execution_plan/ops/op_node_by_label_scan.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -20,7 +23,7 @@ typedef struct { OpBase op; Graph *g; - NodeScanCtx n; // Label data of node being scanned + NodeScanCtx *n; // Label data of node being scanned unsigned int nodeRecIdx; // Node position within record UnsignedRange *id_range; // ID range to iterate over RG_MatrixTupleIter iter; // Iterator over label matrix @@ -28,7 +31,11 @@ typedef struct { } NodeByLabelScan; /* Creates a new NodeByLabelScan operation */ -OpBase *NewNodeByLabelScanOp(const ExecutionPlan *plan, NodeScanCtx n); +OpBase *NewNodeByLabelScanOp +( + const ExecutionPlan *plan, + NodeScanCtx *n +); /* Transform a simple label scan to perform additional range query over the label matrix. */ void NodeByLabelScanOp_SetIDRange(NodeByLabelScan *op, UnsignedRange *id_range); diff --git a/src/execution_plan/ops/op_optional.c b/src/execution_plan/ops/op_optional.c index 7509122142..ccd31fe9bb 100644 --- a/src/execution_plan/ops/op_optional.c +++ b/src/execution_plan/ops/op_optional.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_optional.h" diff --git a/src/execution_plan/ops/op_optional.h b/src/execution_plan/ops/op_optional.h index c2aa3c54cd..4324df4e62 100644 --- a/src/execution_plan/ops/op_optional.h +++ b/src/execution_plan/ops/op_optional.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_procedure_call.c b/src/execution_plan/ops/op_procedure_call.c index bde8765112..c5528a3d23 100644 --- a/src/execution_plan/ops/op_procedure_call.c +++ b/src/execution_plan/ops/op_procedure_call.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_procedure_call.h" #include "../../RG.h" diff --git a/src/execution_plan/ops/op_procedure_call.h b/src/execution_plan/ops/op_procedure_call.h index 132b118bb7..8d465be624 100644 --- a/src/execution_plan/ops/op_procedure_call.h +++ b/src/execution_plan/ops/op_procedure_call.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_project.c b/src/execution_plan/ops/op_project.c index 949d28081b..acda67fd93 100644 --- a/src/execution_plan/ops/op_project.c +++ b/src/execution_plan/ops/op_project.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_project.h" #include "RG.h" @@ -61,17 +64,27 @@ static Record ProjectConsume(OpBase *opBase) { AR_ExpNode *exp = op->exps[i]; SIValue v = AR_EXP_Evaluate(exp, op->r); int rec_idx = op->record_offsets[i]; - /* Persisting a value is only necessary here if 'v' refers to a scalar held in Record 'r'. - * Graph entities don't need to be persisted here as Record_Add will copy them internally. - * The RETURN projection here requires persistence: - * MATCH (a) WITH toUpper(a.name) AS e RETURN e - * TODO This is a rare case; the logic of when to persist can be improved. */ + + // persisting a value is only necessary when + // 'v' refers to a scalar held in Record 'r' + // graph entities don't need to be persisted here as + // Record_Add will copy them internally + // + // the RETURN projection here requires persistence: + // MATCH (a) WITH toUpper(a.name) AS e RETURN e + // TODO: this is a rare case; + // the logic of when to persist can be improved + if(!(v.type & SI_GRAPHENTITY)) SIValue_Persist(&v); Record_Add(op->projection, rec_idx, v); - /* If the value was a graph entity with its own allocation, as with a query like: - * MATCH p = (src) RETURN nodes(p)[0] - * Ensure that the allocation is freed here. */ - if((v.type & SI_GRAPHENTITY)) SIValue_Free(v); + + // if the value was a graph entity with its own allocation + // as with a query like: + // MATCH p = (src) RETURN nodes(p)[0] + // ensure that the allocation is freed here + if((v.type & SI_GRAPHENTITY)) { + SIValue_Free(v); + } } OpBase_DeleteRecord(op->r); @@ -97,6 +110,26 @@ static OpBase *ProjectClone(const ExecutionPlan *plan, const OpBase *opBase) { return NewProjectOp(plan, exps); } +void ProjectBindToPlan +( + OpBase *opBase, // op to bind + const ExecutionPlan *plan // plan to bind the op to +) { + OpProject *op = (OpProject *)opBase; + opBase->plan = plan; + + // introduce the projected aliases to the plan record-mapping, and reset the + // record offsets to the correct indexes + array_clear(op->record_offsets); + + for(uint i = 0; i < op->exp_count; i ++) { + // The projected record will associate values with their resolved name + // to ensure that space is allocated for each entry. + int record_idx = OpBase_Modifies((OpBase *)op, op->exps[i]->resolved_name); + array_append(op->record_offsets, record_idx); + } +} + static void ProjectFree(OpBase *ctx) { OpProject *op = (OpProject *)ctx; @@ -121,4 +154,3 @@ static void ProjectFree(OpBase *ctx) { op->projection = NULL; } } - diff --git a/src/execution_plan/ops/op_project.h b/src/execution_plan/ops/op_project.h index 2a713b24da..67324b9b33 100644 --- a/src/execution_plan/ops/op_project.h +++ b/src/execution_plan/ops/op_project.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -21,3 +24,10 @@ typedef struct { } OpProject; OpBase *NewProjectOp(const ExecutionPlan *plan, AR_ExpNode **exps); + +// binds a Project op to an ExecutionPlan +void ProjectBindToPlan +( + OpBase *opBase, // op to bind + const ExecutionPlan *plan // plan to bind the op to +); diff --git a/src/execution_plan/ops/op_results.c b/src/execution_plan/ops/op_results.c index db72b8b82c..c0c1d5adca 100644 --- a/src/execution_plan/ops/op_results.c +++ b/src/execution_plan/ops/op_results.c @@ -1,16 +1,20 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include "op_results.h" #include "RG.h" +#include "op_join.h" +#include "op_results.h" #include "../../util/arr.h" #include "../../query_ctx.h" #include "../../configuration/config.h" #include "../../arithmetic/arithmetic_expression.h" -#include "../execution_plan_build/execution_plan_modify.h" +#include "../execution_plan_build/execution_plan_util.h" /* Forward declarations. */ static Record ResultsConsume(OpBase *opBase); @@ -33,8 +37,8 @@ static OpResult ResultsInit(OpBase *opBase) { Config_Option_get(Config_RESULTSET_MAX_SIZE, &op->result_set_size_limit); // map resultset columns to record entries - OpBase *join = ExecutionPlan_LocateOp(opBase, OPType_JOIN); - if(op->result_set != NULL && join == NULL) { + OpBase *join = ExecutionPlan_LocateOpDepth(opBase, OPType_JOIN, 2); + if(op->result_set != NULL && (join == NULL || !JoinGetUpdateColumnMap(join))) { rax *mapping = ExecutionPlan_GetMappings(opBase->plan); ResultSet_MapProjection(op->result_set, mapping); } diff --git a/src/execution_plan/ops/op_results.h b/src/execution_plan/ops/op_results.h index 1e126d6917..9fe5328b60 100644 --- a/src/execution_plan/ops/op_results.h +++ b/src/execution_plan/ops/op_results.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_semi_apply.c b/src/execution_plan/ops/op_semi_apply.c index aa283ea144..02f8b06335 100644 --- a/src/execution_plan/ops/op_semi_apply.c +++ b/src/execution_plan/ops/op_semi_apply.c @@ -1,12 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_semi_apply.h" #include "../execution_plan.h" -#include "../execution_plan_build/execution_plan_modify.h" +#include "../execution_plan_build/execution_plan_util.h" // Forward declarations. static OpResult SemiApplyInit(OpBase *opBase); diff --git a/src/execution_plan/ops/op_semi_apply.h b/src/execution_plan/ops/op_semi_apply.h index e9c70f024d..0a716f8d65 100644 --- a/src/execution_plan/ops/op_semi_apply.h +++ b/src/execution_plan/ops/op_semi_apply.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_skip.c b/src/execution_plan/ops/op_skip.c index 80ecf3d878..e0a60c5be1 100644 --- a/src/execution_plan/ops/op_skip.c +++ b/src/execution_plan/ops/op_skip.c @@ -1,12 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_skip.h" #include "../../RG.h" -#include "../../errors.h" +#include "../../errors/errors.h" #include "../../arithmetic/arithmetic_expression.h" /* Forward declarations. */ @@ -27,7 +30,7 @@ static void _eval_skip(OpSkip *op, AR_ExpNode *skip_exp) { // Validate that the skip value is numeric and non-negative. if(SI_TYPE(s) != T_INT64 || SI_GET_NUMERIC(s) < 0) { - ErrorCtx_SetError("Skip operates only on non-negative integers"); + ErrorCtx_SetError(EMSG_OPERATE_ON_NON_NEGATIVE_INT, "Skip"); } op->skip = SI_GET_NUMERIC(s); diff --git a/src/execution_plan/ops/op_skip.h b/src/execution_plan/ops/op_skip.h index ba906fa05b..2adfe9d84b 100644 --- a/src/execution_plan/ops/op_skip.h +++ b/src/execution_plan/ops/op_skip.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_sort.c b/src/execution_plan/ops/op_sort.c index 2e67561f00..460c34a69f 100644 --- a/src/execution_plan/ops/op_sort.c +++ b/src/execution_plan/ops/op_sort.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_sort.h" #include "op_project.h" @@ -27,6 +30,8 @@ static int _record_cmp Record b, OpSort *op ) { + ASSERT(a->owner == b->owner); + uint comparison_count = array_len(op->record_offsets); for(uint i = 0; i < comparison_count; i++) { SIValue aVal = Record_Get(a, op->record_offsets[i]); @@ -90,28 +95,20 @@ OpBase *NewSortOp ) { OpSort *op = rm_malloc(sizeof(OpSort)); - op->exps = exps; - op->heap = NULL; - op->skip = 0; - op->first = true; - op->limit = UNLIMITED; - op->buffer = NULL; - op->record_idx = 0; - op->directions = directions; + op->exps = exps; + op->heap = NULL; + op->skip = 0; + op->first = true; + op->limit = UNLIMITED; + op->buffer = NULL; + op->record_idx = 0; + op->directions = directions; + op->record_offsets = NULL; // set our Op operations OpBase_Init((OpBase *)op, OPType_SORT, "Sort", SortInit, SortConsume, SortReset, NULL, SortClone, SortFree, false, plan); - uint comparison_count = array_len(exps); - op->record_offsets = array_new(uint, comparison_count); - for(uint i = 0; i < comparison_count; i ++) { - int record_idx; - bool aware = OpBase_Aware((OpBase *)op, exps[i]->resolved_name, &record_idx); - ASSERT(aware); - array_append(op->record_offsets, record_idx); - } - return (OpBase *)op; } @@ -131,6 +128,16 @@ static OpResult SortInit(OpBase *opBase) { op->buffer = array_new(Record, 32); } + uint comparison_count = array_len(op->exps); + op->record_offsets = array_new(uint, comparison_count); + for(uint i = 0; i < comparison_count; i ++) { + int record_idx; + bool aware = OpBase_Aware((OpBase *)op, op->exps[i]->resolved_name, + &record_idx); + ASSERT(aware); + array_append(op->record_offsets, record_idx); + } + return OP_OK; } @@ -248,4 +255,3 @@ static void SortFree(OpBase *ctx) { op->exps = NULL; } } - diff --git a/src/execution_plan/ops/op_sort.h b/src/execution_plan/ops/op_sort.h index 1e7547fd96..cbd54157aa 100644 --- a/src/execution_plan/ops/op_sort.h +++ b/src/execution_plan/ops/op_sort.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -19,11 +22,10 @@ typedef struct { uint skip; // Total number of records to skip uint record_idx; // index of current record to return uint limit; // Total number of records to produce - uint *record_offsets; // All Record offsets containing values to sort by. - int *directions; // Array of sort directions(ascending / desending) for each item. + uint *record_offsets; // All Record offsets containing values to sort by + int *directions; // Array of sort directions(ascending / descending) AR_ExpNode **exps; // Projected expressons. } OpSort; /* Creates a new Sort operation */ OpBase *NewSortOp(const ExecutionPlan *plan, AR_ExpNode **exps, int *directions); - diff --git a/src/execution_plan/ops/op_unwind.c b/src/execution_plan/ops/op_unwind.c index 94ebd3641f..46bf052f7b 100644 --- a/src/execution_plan/ops/op_unwind.c +++ b/src/execution_plan/ops/op_unwind.c @@ -1,12 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_unwind.h" -#include "../../errors.h" #include "../../query_ctx.h" +#include "../../errors/errors.h" #include "../../datatypes/array.h" #include "../../arithmetic/arithmetic_expression.h" #include "limits.h" @@ -148,8 +151,10 @@ static OpResult UnwindReset ) { OpUnwind *op = (OpUnwind *)ctx; - // reset index to 0 op->listIdx = 0; + SIValue_Free(op->list); + op->list = SI_NullVal(); + op->listLen = 0; return OP_OK; } @@ -180,6 +185,7 @@ static void UnwindFree if(op->currentRecord != NULL) { OpBase_DeleteRecord(op->currentRecord); + op->currentRecord = NULL; } op->currentRecord = NULL; diff --git a/src/execution_plan/ops/op_unwind.h b/src/execution_plan/ops/op_unwind.h index 42ddc5af13..feb9a3d2b5 100644 --- a/src/execution_plan/ops/op_unwind.h +++ b/src/execution_plan/ops/op_unwind.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/op_update.c b/src/execution_plan/ops/op_update.c index 3fa316bbc3..3eb8a34575 100644 --- a/src/execution_plan/ops/op_update.c +++ b/src/execution_plan/ops/op_update.c @@ -1,20 +1,22 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_update.h" #include "RG.h" -#include "../../errors.h" #include "../../query_ctx.h" #include "../../util/arr.h" #include "../../util/rmalloc.h" +#include "../../errors/errors.h" #include "../../util/rax_extensions.h" #include "../../arithmetic/arithmetic_expression.h" -/* Forward declarations. */ -static OpResult UpdateInit(OpBase *opBase); +// forward declarations static Record UpdateConsume(OpBase *opBase); static OpResult UpdateReset(OpBase *opBase); static OpBase *UpdateClone(const ExecutionPlan *plan, const OpBase *opBase); @@ -28,17 +30,39 @@ static Record _handoff(OpUpdate *op) { return NULL; } +// fake hash function +// hash of key is simply key +static uint64_t _id_hash +( + const void *key +) { + return ((uint64_t)key); +} + +// hashtable entry free callback +static void freeCallback +( + dict *d, + void *val +) { + PendingUpdateCtx_Free((PendingUpdateCtx*)val); +} + +// hashtable callbacks +static dictType _dt = { _id_hash, NULL, NULL, NULL, NULL, freeCallback, NULL, + NULL, NULL, NULL}; + OpBase *NewUpdateOp(const ExecutionPlan *plan, rax *update_exps) { OpUpdate *op = rm_calloc(1, sizeof(OpUpdate)); - op->records = NULL; - op->node_updates = NULL; - op->edge_updates = NULL; - op->updates_committed = false; - op->update_ctxs = update_exps; - op->gc = QueryCtx_GetGraphCtx(); + op->gc = QueryCtx_GetGraphCtx(); + op->records = array_new(Record, 64); + op->update_ctxs = update_exps; + op->node_updates = HashTableCreate(&_dt); + op->edge_updates = HashTableCreate(&_dt); + op->updates_committed = false; // set our op operations - OpBase_Init((OpBase *)op, OPType_UPDATE, "Update", UpdateInit, UpdateConsume, + OpBase_Init((OpBase *)op, OPType_UPDATE, "Update", NULL, UpdateConsume, UpdateReset, NULL, UpdateClone, UpdateFree, true, plan); // iterate over all update expressions @@ -53,18 +77,10 @@ OpBase *NewUpdateOp(const ExecutionPlan *plan, rax *update_exps) { return (OpBase *)op; } -static OpResult UpdateInit(OpBase *opBase) { - OpUpdate *op = (OpUpdate *)opBase; - - op->stats = QueryCtx_GetResultSetStatistics(); - op->records = array_new(Record, 64); - op->node_updates = array_new(PendingUpdateCtx, raxSize(op->update_ctxs)); - op->edge_updates = array_new(PendingUpdateCtx, raxSize(op->update_ctxs)); - - return OP_OK; -} - -static Record UpdateConsume(OpBase *opBase) { +static Record UpdateConsume +( + OpBase *opBase +) { OpUpdate *op = (OpUpdate *)opBase; OpBase *child = op->op.children[0]; Record r; @@ -79,14 +95,14 @@ static Record UpdateConsume(OpBase *opBase) { raxSeek(&op->it, "^", NULL, 0); while(raxNext(&op->it)) { EntityUpdateEvalCtx *ctx = op->it.data; - EvalEntityUpdates(op->gc, &op->node_updates, &op->edge_updates, r, ctx, true); + EvalEntityUpdates(op->gc, op->node_updates, op->edge_updates, r, ctx, true); } array_append(op->records, r); } - uint node_updates_count = array_len(op->node_updates); - uint edge_updates_count = array_len(op->edge_updates); + uint node_updates_count = HashTableElemCount(op->node_updates); + uint edge_updates_count = HashTableElemCount(op->edge_updates); if(node_updates_count > 0 || edge_updates_count > 0) { // done reading; we're not going to call Consume any longer @@ -97,22 +113,12 @@ static Record UpdateConsume(OpBase *opBase) { // lock everything QueryCtx_LockForCommit(); - CommitUpdates(op->gc, op->stats, op->node_updates, ENTITY_NODE); - CommitUpdates(op->gc, op->stats, op->edge_updates, ENTITY_EDGE); - } - - for(uint i = 0; i < node_updates_count; i ++) { - PendingUpdateCtx *pending_update = op->node_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - - for(uint i = 0; i < edge_updates_count; i ++) { - PendingUpdateCtx *pending_update = op->edge_updates + i; - AttributeSet_Free(&pending_update->attributes); + CommitUpdates(op->gc, op->node_updates, ENTITY_NODE); + CommitUpdates(op->gc, op->edge_updates, ENTITY_EDGE); } - array_clear(op->node_updates); - array_clear(op->edge_updates); + HashTableEmpty(op->node_updates, NULL); + HashTableEmpty(op->edge_updates, NULL); op->updates_committed = true; @@ -130,19 +136,8 @@ static OpBase *UpdateClone(const ExecutionPlan *plan, const OpBase *opBase) { static OpResult UpdateReset(OpBase *ctx) { OpUpdate *op = (OpUpdate *)ctx; - uint node_updates_count = array_len(op->node_updates); - for(uint i = 0; i < node_updates_count; i ++) { - PendingUpdateCtx *pending_update = op->node_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - array_clear(op->node_updates); - - uint edge_updates_count = array_len(op->edge_updates); - for(uint i = 0; i < edge_updates_count; i ++) { - PendingUpdateCtx *pending_update = op->edge_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - array_clear(op->edge_updates); + HashTableEmpty(op->node_updates, NULL); + HashTableEmpty(op->edge_updates, NULL); op->updates_committed = false; return OP_OK; @@ -152,22 +147,12 @@ static void UpdateFree(OpBase *ctx) { OpUpdate *op = (OpUpdate *)ctx; if(op->node_updates) { - uint node_updates_count = array_len(op->node_updates); - for(uint i = 0; i < node_updates_count; i ++) { - PendingUpdateCtx *pending_update = op->node_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - array_free(op->node_updates); + HashTableRelease(op->node_updates); op->node_updates = NULL; } if(op->edge_updates) { - uint edge_updates_count = array_len(op->edge_updates); - for(uint i = 0; i < edge_updates_count; i ++) { - PendingUpdateCtx *pending_update = op->edge_updates + i; - AttributeSet_Free(&pending_update->attributes); - } - array_free(op->edge_updates); + HashTableRelease(op->edge_updates); op->edge_updates = NULL; } diff --git a/src/execution_plan/ops/op_update.h b/src/execution_plan/ops/op_update.h index 8f4f3dbd18..2e9a9d5250 100644 --- a/src/execution_plan/ops/op_update.h +++ b/src/execution_plan/ops/op_update.h @@ -1,12 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "op.h" +#include "../../util/dict.h" #include "../execution_plan.h" #include "shared/update_functions.h" #include "../../resultset/resultset_statistics.h" @@ -18,9 +22,8 @@ typedef struct { GraphContext *gc; rax *update_ctxs; // Entities to update and their expressions bool updates_committed; // True if we've already committed updates and are now in handoff mode. - PendingUpdateCtx *node_updates; // Enqueued node updates - PendingUpdateCtx *edge_updates; // Enqueued edge updates - ResultSetStatistics *stats; + dict *node_updates; // Enqueued node updates + dict *edge_updates; // Enqueued edge updates } OpUpdate; OpBase *NewUpdateOp(const ExecutionPlan *plan, rax *update_exps); diff --git a/src/execution_plan/ops/op_value_hash_join.c b/src/execution_plan/ops/op_value_hash_join.c index 2d5b722250..ebecb4baee 100644 --- a/src/execution_plan/ops/op_value_hash_join.c +++ b/src/execution_plan/ops/op_value_hash_join.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "op_value_hash_join.h" #include "../../value.h" diff --git a/src/execution_plan/ops/op_value_hash_join.h b/src/execution_plan/ops/op_value_hash_join.h index 308e9bc74b..32223fbd93 100644 --- a/src/execution_plan/ops/op_value_hash_join.h +++ b/src/execution_plan/ops/op_value_hash_join.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/ops.h b/src/execution_plan/ops/ops.h index d8663cfa5f..5704ef59ef 100644 --- a/src/execution_plan/ops/ops.h +++ b/src/execution_plan/ops/ops.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -30,6 +33,7 @@ #include "op_merge_create.h" #include "op_argument_list.h" #include "op_all_node_scan.h" +#include "op_call_subquery.h" #include "op_procedure_call.h" #include "op_node_by_id_seek.h" #include "op_value_hash_join.h" diff --git a/src/execution_plan/ops/shared/create_functions.c b/src/execution_plan/ops/shared/create_functions.c index 9d60f4a4a1..88297d196a 100644 --- a/src/execution_plan/ops/shared/create_functions.c +++ b/src/execution_plan/ops/shared/create_functions.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "create_functions.h" #include "RG.h" -#include "../../../errors.h" #include "../../../query_ctx.h" +#include "../../../errors/errors.h" #include "../../../ast/ast_shared.h" #include "../../../datatypes/array.h" #include "../../../graph/graph_hub.h" @@ -37,8 +40,8 @@ static void _CommitNodesBlueprint Schema *s = GraphContext_GetSchema(gc, label, SCHEMA_NODE); if(s == NULL) { - s = AddSchema(gc, label, SCHEMA_NODE); - pending->stats->labels_added++; + s = AddSchema(gc, label, SCHEMA_NODE, true); + QueryCtx_GetResultSetStatistics()->labels_added++; } node_ctx->labelsId[j] = s->id; @@ -74,8 +77,7 @@ static void _CommitNodes uint label_count = array_len(labels); // introduce node into graph - pending->stats->properties_set += CreateNode(gc, n, labels, label_count, - attr); + CreateNode(gc, n, labels, label_count, attr, true); //---------------------------------------------------------------------- // enforce constraints @@ -119,7 +121,7 @@ static void _CommitEdgesBlueprint const char *relation = edge_ctx->relation; Schema *s = GraphContext_GetSchema(gc, relation, SCHEMA_EDGE); - if(s == NULL) s = AddSchema(gc, relation, SCHEMA_EDGE); + if(s == NULL) s = AddSchema(gc, relation, SCHEMA_EDGE, true); // calling Graph_GetRelationMatrix will make sure relationship matrix // is of the right dimensions @@ -146,27 +148,17 @@ static void _CommitEdges ASSERT(Graph_GetMatrixPolicy(g) == SYNC_POLICY_NOP); for(int i = 0; i < edge_count; i++) { - NodeID srcNodeID; - NodeID destNodeID; e = pending->created_edges[i]; + NodeID src_id = Edge_GetSrcNodeID(e); + NodeID dest_id = Edge_GetDestNodeID(e); AttributeSet attr = pending->edge_attributes[i]; - // nodes which already existed prior to this query would - // have their ID set under e->srcNodeID and e->destNodeID - // Nodes which are created as part of this query would be - // saved under edge src/dest pointer - if(e->srcNodeID != INVALID_ENTITY_ID) srcNodeID = e->srcNodeID; - else srcNodeID = ENTITY_GET_ID(Edge_GetSrcNode(e)); - if(e->destNodeID != INVALID_ENTITY_ID) destNodeID = e->destNodeID; - else destNodeID = ENTITY_GET_ID(Edge_GetDestNode(e)); - Schema *s = GraphContext_GetSchema(gc, e->relationship, SCHEMA_EDGE); // all schemas have been created in the edge blueprint loop or earlier ASSERT(s != NULL); int relation_id = Schema_GetID(s); - pending->stats->properties_set += CreateEdge(gc, e, srcNodeID, - destNodeID, relation_id, attr); + CreateEdge(gc, e, src_id, dest_id, relation_id, attr, true); //---------------------------------------------------------------------- // enforce constraints @@ -201,7 +193,6 @@ void NewPendingCreationsContainer pending->created_edges = array_new(Edge *, 0); pending->node_attributes = array_new(AttributeSet, 0); pending->edge_attributes = array_new(AttributeSet, 0); - pending->stats = NULL; } // Lock the graph and commit all changes introduced by the operation. @@ -214,10 +205,6 @@ void CommitNewEntities uint node_count = array_len(pending->created_nodes); uint edge_count = array_len(pending->created_edges); - if(!pending->stats) { - pending->stats = QueryCtx_GetResultSetStatistics(); - } - // lock everything QueryCtx_LockForCommit(); @@ -244,9 +231,6 @@ void CommitNewEntities if(unlikely(ErrorCtx_EncounteredError())) { goto cleanup; } - - // update statistics - pending->stats->nodes_created += node_count; } //-------------------------------------------------------------------------- @@ -272,9 +256,6 @@ void CommitNewEntities if(unlikely(ErrorCtx_EncounteredError())) { goto cleanup; } - - // update statistics - pending->stats->relationships_created += edge_count; } cleanup: @@ -293,6 +274,9 @@ void ConvertPropertyMap bool fail_on_null ) { uint property_count = array_len(map->keys); + SIValue vals[property_count]; + Attribute_ID ids[property_count]; + uint attrs_count = 0; for(int i = 0; i < property_count; i++) { // note that AR_EXP_Evaluate may raise a run-time exception // in which case the allocations in this function will leak @@ -304,7 +288,9 @@ void ConvertPropertyMap if(!SIValue_IsNull(val)) { // if the value was a complex type, emit an exception SIValue_Free(val); - AttributeSet_Free(attributes); + for(int j = 0; j < i; j++) { + SIValue_Free(vals[j]); + } Error_InvalidPropertyValue(); ErrorCtx_RaiseRuntimeException(NULL); } @@ -313,7 +299,9 @@ void ConvertPropertyMap // otherwise skip this value if(fail_on_null) { // emit an error and exit - AttributeSet_Free(attributes); + for(int j = 0; j < i; j++) { + SIValue_Free(vals[j]); + } ErrorCtx_RaiseRuntimeException("Cannot merge node using null property value"); } @@ -329,17 +317,20 @@ void ConvertPropertyMap if(res) { // validation failed SIValue_Free(val); - AttributeSet_Free(attributes); + for(int j = 0; j < i; j++) { + SIValue_Free(vals[j]); + } Error_InvalidPropertyValue(); ErrorCtx_RaiseRuntimeException(NULL); } } // set the converted attribute - Attribute_ID attribute_id = FindOrAddAttribute(gc, map->keys[i]); - AttributeSet_Add(attributes, attribute_id, val); + ids[attrs_count] = FindOrAddAttribute(gc, map->keys[i], true); + vals[attrs_count++] = SI_CloneValue(val); SIValue_Free(val); } + AttributeSet_AddNoClone(attributes, ids, vals, attrs_count, false); } // free all data associated with a completed create operation diff --git a/src/execution_plan/ops/shared/create_functions.h b/src/execution_plan/ops/shared/create_functions.h index f95bd3f0f0..15902dd534 100644 --- a/src/execution_plan/ops/shared/create_functions.h +++ b/src/execution_plan/ops/shared/create_functions.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -20,7 +23,6 @@ typedef struct { int **node_labels; Node **created_nodes; Edge **created_edges; - ResultSetStatistics *stats; } PendingCreations; // initialize all variables for storing pending creations diff --git a/src/execution_plan/ops/shared/print_functions.c b/src/execution_plan/ops/shared/print_functions.c index d21f5acda9..e3aff30f90 100644 --- a/src/execution_plan/ops/shared/print_functions.c +++ b/src/execution_plan/ops/shared/print_functions.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "print_functions.h" #include "../../execution_plan.h" diff --git a/src/execution_plan/ops/shared/print_functions.h b/src/execution_plan/ops/shared/print_functions.h index 1e0bbdc9ee..06d246f356 100644 --- a/src/execution_plan/ops/shared/print_functions.h +++ b/src/execution_plan/ops/shared/print_functions.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/shared/scan_functions.c b/src/execution_plan/ops/shared/scan_functions.c new file mode 100644 index 0000000000..5cd1319f17 --- /dev/null +++ b/src/execution_plan/ops/shared/scan_functions.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include "scan_functions.h" +#include "../../../util/rmalloc.h" +#include "../../../graph/entities/qg_node.h" + +// allocates and returns a new context +NodeScanCtx *NodeScanCtx_New +( + char *alias, // alias + char *label, // label + LabelID label_id, // label id + const QGNode *n // node +) { + NodeScanCtx *ctx = rm_malloc(sizeof(NodeScanCtx)); + ctx->alias = alias; + ctx->label = label; + ctx->label_id = label_id; + ctx->n = QGNode_Clone(n); + + return ctx; +} + +// clones a context +NodeScanCtx *NodeScanCtx_Clone +( + const NodeScanCtx *ctx // context +) { + ASSERT(ctx != NULL); + ASSERT(ctx->n != NULL); + + NodeScanCtx *clone = rm_malloc(sizeof(NodeScanCtx)); + memcpy(clone, ctx, sizeof(NodeScanCtx)); + clone->n = QGNode_Clone(ctx->n); + + return clone; +} + +// frees a context +void NodeScanCtx_Free +( + NodeScanCtx *ctx // context +) { + ASSERT(ctx != NULL); + ASSERT(ctx->n != NULL); + + QGNode_Free(ctx->n); + + rm_free(ctx); +} diff --git a/src/execution_plan/ops/shared/scan_functions.h b/src/execution_plan/ops/shared/scan_functions.h index a64dd3ad6a..c6301c2282 100644 --- a/src/execution_plan/ops/shared/scan_functions.h +++ b/src/execution_plan/ops/shared/scan_functions.h @@ -1,23 +1,42 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once +#include "../../../graph/entities/node.h" +#include "../../../graph/entities/qg_node.h" + // Storage struct for label data in node and index scans. typedef struct { - const char *alias; // Alias of the node being traversed. - const char *label; // Label of the node being traversed. - int label_id; // Label ID of the node being traversed. + QGNode *n; // node to scan (might hold multiple labels) + LabelID label_id; // label ID of the node being traversed + const char *alias; // alias of the node being traversed + const char *label; // label of the node being traversed } NodeScanCtx; -// Instantiate a new labeled node context. -#define NODE_CTX_NEW(_alias, _label, _label_id) \ -(NodeScanCtx) { \ - .alias = (_alias), \ - .label = (_label), \ - .label_id = (_label_id) \ -} +// allocates and returns a new context +NodeScanCtx *NodeScanCtx_New +( + char *alias, // alias + char *label, // label + LabelID label_id, // label id + const QGNode *n // node +); + +// clones a context +NodeScanCtx *NodeScanCtx_Clone +( + const NodeScanCtx *ctx // context +); +// frees a context +void NodeScanCtx_Free +( + NodeScanCtx *ctx // context +); diff --git a/src/execution_plan/ops/shared/traverse_functions.c b/src/execution_plan/ops/shared/traverse_functions.c index 3f9f4e77eb..3a16c289d1 100644 --- a/src/execution_plan/ops/shared/traverse_functions.c +++ b/src/execution_plan/ops/shared/traverse_functions.c @@ -1,8 +1,12 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #include "traverse_functions.h" #include "../../../query_ctx.h" diff --git a/src/execution_plan/ops/shared/traverse_functions.h b/src/execution_plan/ops/shared/traverse_functions.h index f156707d4d..dbcb503269 100644 --- a/src/execution_plan/ops/shared/traverse_functions.h +++ b/src/execution_plan/ops/shared/traverse_functions.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/ops/shared/update_functions.c b/src/execution_plan/ops/shared/update_functions.c index 34b6840119..58012ff670 100644 --- a/src/execution_plan/ops/shared/update_functions.c +++ b/src/execution_plan/ops/shared/update_functions.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "update_functions.h" -#include "../../../errors.h" #include "../../../query_ctx.h" #include "../../../datatypes/map.h" +#include "../../../errors/errors.h" #include "../../../datatypes/array.h" #include "../../../graph/graph_hub.h" #include "../../../graph/entities/node.h" @@ -42,50 +45,43 @@ static bool _ValidateAttrType void CommitUpdates ( GraphContext *gc, - ResultSetStatistics *stats, - PendingUpdateCtx *updates, + dict *updates, EntityType type ) { ASSERT(gc != NULL); - ASSERT(stats != NULL); ASSERT(updates != NULL); ASSERT(type != ENTITY_UNKNOWN); - uint update_count = array_len(updates); - uint labels_added = 0; - uint labels_removed = 0; - uint properties_set = 0; - uint properties_removed = 0; + uint update_count = HashTableElemCount(updates); bool constraint_violation = false; // return early if no updates are enqueued if(update_count == 0) return; - for(uint i = 0; i < update_count; i++) { - PendingUpdateCtx *update = updates + i; + dictEntry *entry; + dictIterator *it = HashTableGetIterator(updates); + MATRIX_POLICY policy = Graph_GetMatrixPolicy(gc->g); + Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_NOP); + + while((entry = HashTableNext(it)) != NULL) { + PendingUpdateCtx *update = HashTableGetVal(entry); // if entity has been deleted, perform no updates if(GraphEntity_IsDeleted(update->ge)) continue; - uint _labels_added = 0; - uint _labels_removed = 0; - uint _props_set = 0; - uint _props_removed = 0; + AttributeSet_PersistValues(update->attributes); + // update the attributes on the graph entity UpdateEntityProperties(gc, update->ge, update->attributes, - type == ENTITY_NODE ? GETYPE_NODE : GETYPE_EDGE, &_props_set, - &_props_removed); + type == ENTITY_NODE ? GETYPE_NODE : GETYPE_EDGE, true); + update->attributes = NULL; if(type == ENTITY_NODE) { UpdateNodeLabels(gc, (Node*)update->ge, update->add_labels, - update->remove_labels, &_labels_added, &_labels_removed); + update->remove_labels, array_len(update->add_labels), + array_len(update->remove_labels), true); } - labels_added += _labels_added; - labels_removed += _labels_removed; - properties_set += _props_set; - properties_removed += _props_removed; - //---------------------------------------------------------------------- // enforce constraints //---------------------------------------------------------------------- @@ -101,7 +97,7 @@ void CommitUpdates label_count = Graph_GetNodeLabels(gc->g, (Node*)update->ge, labels, label_count); } else { - labels[0] = EDGE_GET_RELATION_ID((Edge*)update->ge, gc->g); + labels[0] = Edge_GetRelationID((Edge*)update->ge); } SchemaType stype = type == ENTITY_NODE ? SCHEMA_NODE : SCHEMA_EDGE; @@ -120,13 +116,8 @@ void CommitUpdates } } } - - if(stats) { - stats->labels_added += labels_added; - stats->labels_removed += labels_removed; - stats->properties_set += properties_set; - stats->properties_removed += properties_removed; - } + Graph_SetMatrixPolicy(gc->g, policy); + HashTableReleaseIterator(it); } // build pending updates in the 'updates' array to match all @@ -135,8 +126,8 @@ void CommitUpdates void EvalEntityUpdates ( GraphContext *gc, - PendingUpdateCtx **node_updates, - PendingUpdateCtx **edge_updates, + dict *node_updates, + dict *edge_updates, const Record r, const EntityUpdateEvalCtx *ctx, bool allow_null @@ -150,36 +141,75 @@ void EvalEntityUpdates // get the type of the entity to update // if the expected entity was not found, make no updates but do not error RecordEntryType t = Record_GetType(r, ctx->record_idx); - if(t == REC_TYPE_UNKNOWN) { + if(unlikely(t == REC_TYPE_UNKNOWN)) { return; } // make sure we're updating either a node or an edge - if(t != REC_TYPE_NODE && t != REC_TYPE_EDGE) { + if(unlikely(t != REC_TYPE_NODE && t != REC_TYPE_EDGE)) { ErrorCtx_RaiseRuntimeException( "Update error: alias '%s' did not resolve to a graph entity", ctx->alias); } // label(s) update can only be performed on nodes - if((ctx->add_labels != NULL || ctx->remove_labels != NULL) && - t != REC_TYPE_NODE) { + if(unlikely((ctx->add_labels != NULL || ctx->remove_labels != NULL) && + t != REC_TYPE_NODE)) { ErrorCtx_RaiseRuntimeException( "Type mismatch: expected Node but was Relationship"); } - PendingUpdateCtx **updates = (t == REC_TYPE_NODE) - ? node_updates - : edge_updates; - GraphEntity *entity = Record_GetGraphEntity(r, ctx->record_idx); - PendingUpdateCtx update = {0}; + // if the entity is marked as deleted, make no updates but do not error + if(unlikely(Graph_EntityIsDeleted(entity))) { + return; + } - update.ge = entity; - update.attributes = NULL; - update.add_labels = ctx->add_labels; - update.remove_labels = ctx->remove_labels; + dict *updates; + GraphEntityType entity_type; + if(t == REC_TYPE_NODE) { + updates = node_updates; + entity_type = GETYPE_NODE; + } else { + updates = edge_updates; + entity_type = GETYPE_EDGE; + } + + PendingUpdateCtx *update; + dictEntry *entry = HashTableFind(updates, (void *)ENTITY_GET_ID(entity)); + if(entry == NULL) { + // create a new update context + update = rm_malloc(sizeof(PendingUpdateCtx)); + update->ge = entity; + update->attributes = AttributeSet_ShallowClone(*entity->attributes); + update->add_labels = NULL; + update->remove_labels = NULL; + // add update context to updates dictionary + HashTableAdd(updates, (void *)ENTITY_GET_ID(entity), update); + } else { + // update context already exists + update = (PendingUpdateCtx *)HashTableGetVal(entry); + } + + if(array_len(ctx->add_labels) > 0 && update->add_labels == NULL) { + update->add_labels = array_new(const char *, array_len(ctx->add_labels)); + } + + if(array_len(ctx->remove_labels) > 0 && update->remove_labels == NULL) { + update->remove_labels = array_new(const char *, array_len(ctx->remove_labels)); + } + + array_union(update->add_labels, ctx->add_labels, strcmp); + array_union(update->remove_labels, ctx->remove_labels, strcmp); + + AttributeSet *old_attrs = entity->attributes; + entity->attributes = &update->attributes; + if(t == REC_TYPE_NODE) { + Record_AddNode(r, ctx->record_idx, *(Node *)entity); + } else { + Record_AddEdge(r, ctx->record_idx, *(Edge *)entity); + } // if we're converting a SET clause, NULL is acceptable // as it indicates a deletion @@ -190,6 +220,7 @@ void EvalEntityUpdates bool error = false; uint exp_count = array_len(ctx->properties); + EffectsBuffer *eb = QueryCtx_GetEffectsBuffer(); // evaluate each assigned expression // e.g. n.v = n.a + 2 @@ -199,7 +230,7 @@ void EvalEntityUpdates // // collect all updates into a single attribute-set // - + QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); for(uint i = 0; i < exp_count && !error; i++) { PropertySetCtx *property = ctx->properties + i; @@ -221,8 +252,32 @@ void EvalEntityUpdates break; } - Attribute_ID attr_id = FindOrAddAttribute(gc, attribute); - AttributeSet_Set_Allow_Null(&update.attributes, attr_id, v); + Attribute_ID attr_id = FindOrAddAttribute(gc, attribute, true); + + switch (AttributeSet_Set_Allow_Null(entity->attributes, attr_id, v)) + { + case CT_DEL: + // attribute removed + EffectsBuffer_AddEntityRemoveAttributeEffect(eb, entity, + attr_id, entity_type); + continue; + case CT_ADD: + // attribute added + EffectsBuffer_AddEntityAddAttributeEffect(eb, entity, + attr_id, v, entity_type); + break; + case CT_UPDATE: + // attribute update + EffectsBuffer_AddEntityUpdateAttributeEffect(eb, entity, + attr_id, v, entity_type); + break; + case CT_NONE: + // no change + break; + default: + assert("unknown change type value" && false); + break; + } SIValue_Free(v); continue; } @@ -241,8 +296,9 @@ void EvalEntityUpdates if(mode == UPDATE_REPLACE) { // if this update replaces all existing properties // enqueue a 'clear' update to do so - AttributeSet_Set_Allow_Null(&update.attributes, ATTRIBUTE_ID_ALL, - SI_NullVal()); + EffectsBuffer_AddEntityRemoveAttributeEffect(eb, entity, + ATTRIBUTE_ID_ALL, entity_type); + AttributeSet_Free(entity->attributes); } //---------------------------------------------------------------------- @@ -265,8 +321,32 @@ void EvalEntityUpdates break; } - Attribute_ID attr_id = FindOrAddAttribute(gc, key.stringval); - AttributeSet_Set_Allow_Null(&update.attributes, attr_id, value); + Attribute_ID attr_id = FindOrAddAttribute(gc, key.stringval, true); + // TODO: would have been nice we just sent n = {v:2} + switch (AttributeSet_Set_Allow_Null(entity->attributes, attr_id, value)) + { + case CT_DEL: + // attribute removed + EffectsBuffer_AddEntityRemoveAttributeEffect(eb, entity, + attr_id, entity_type); + break; + case CT_ADD: + // attribute added + EffectsBuffer_AddEntityAddAttributeEffect(eb, entity, + attr_id, value, entity_type); + break; + case CT_UPDATE: + // attribute update + EffectsBuffer_AddEntityUpdateAttributeEffect(eb, entity, + attr_id, value, entity_type); + break; + case CT_NONE: + // no change + break; + default: + assert("unknown change type value" && false); + break; + } } // free map @@ -286,16 +366,46 @@ void EvalEntityUpdates // iterate over all entity properties to build updates const AttributeSet set = GraphEntity_GetAttributes(ge); - for(uint j = 0; j < ATTRIBUTE_SET_COUNT(set); j++) { + for(uint j = 0; j < AttributeSet_Count(set); j++) { Attribute_ID attr_id; SIValue v = AttributeSet_GetIdx(set, j, &attr_id); - // simple assignment, no need to value validation - AttributeSet_Set_Allow_Null(&update.attributes, attr_id, v); + // simple assignment, no need to validate value + switch (AttributeSet_Set_Allow_Null(entity->attributes, attr_id, v)) + { + case CT_ADD: + // attribute added + EffectsBuffer_AddEntityAddAttributeEffect(eb, entity, + attr_id, v, entity_type); + break; + case CT_UPDATE: + // attribute update + EffectsBuffer_AddEntityUpdateAttributeEffect(eb, entity, + attr_id, v, entity_type); + break; + default: + break; + } } } // for loop end - // enqueue the current update - array_append(*updates, update); + // restore original attribute-set + // changes should not be visible prior to the commit phase + update->attributes = *entity->attributes; + entity->attributes = old_attrs; + if(t == REC_TYPE_NODE) { + Record_AddNode(r, ctx->record_idx, *(Node *)entity); + } else { + Record_AddEdge(r, ctx->record_idx, *(Edge *)entity); + } } +void PendingUpdateCtx_Free +( + PendingUpdateCtx *ctx +) { + AttributeSet_Free(&ctx->attributes); + array_free(ctx->add_labels); + array_free(ctx->remove_labels); + rm_free(ctx); +} diff --git a/src/execution_plan/ops/shared/update_functions.h b/src/execution_plan/ops/shared/update_functions.h index a1414ef4d3..44c471ccbe 100644 --- a/src/execution_plan/ops/shared/update_functions.h +++ b/src/execution_plan/ops/shared/update_functions.h @@ -1,12 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "../../execution_plan.h" +#include "../../../util/dict.h" // context representing a single update to perform on an entity typedef struct { @@ -20,8 +24,7 @@ typedef struct { void CommitUpdates ( GraphContext *gc, - ResultSetStatistics *stats, - PendingUpdateCtx *updates, + dict *updates, EntityType type ); @@ -31,10 +34,15 @@ void CommitUpdates void EvalEntityUpdates ( GraphContext *gc, - PendingUpdateCtx **node_updates, - PendingUpdateCtx **edge_updates, + dict *node_updates, + dict *edge_updates, const Record r, const EntityUpdateEvalCtx *ctx, bool allow_null ); +void PendingUpdateCtx_Free +( + PendingUpdateCtx *ctx +); + diff --git a/src/execution_plan/optimizations/apply_join.c b/src/execution_plan/optimizations/apply_join.c index 5a1259ffad..f3b5cb6ca6 100644 --- a/src/execution_plan/optimizations/apply_join.c +++ b/src/execution_plan/optimizations/apply_join.c @@ -1,14 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../../util/arr.h" #include "../ops/op_filter.h" #include "../ops/op_value_hash_join.h" #include "../../util/rax_extensions.h" #include "../ops/op_cartesian_product.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" #define NOT_RESOLVED -1 @@ -107,7 +111,8 @@ static void _reduce_cp_to_hashjoin(ExecutionPlan *plan, OpBase *cp) { rax *stream_entities[stream_count]; for(int j = 0; j < stream_count; j ++) { stream_entities[j] = raxNew(); - ExecutionPlan_BoundVariables(cp->children[j], stream_entities[j]); + ExecutionPlan_BoundVariables(cp->children[j], stream_entities[j], + cp->children[j]->plan); } for(uint i = 0; i < filter_count; i ++) { @@ -177,7 +182,8 @@ static void _reduce_cp_to_hashjoin(ExecutionPlan *plan, OpBase *cp) { stream_count = cp->childCount; for(int j = 0; j < stream_count; j ++) { stream_entities[j] = raxNew(); - ExecutionPlan_BoundVariables(cp->children[j], stream_entities[j]); + ExecutionPlan_BoundVariables(cp->children[j], + stream_entities[j], cp->children[j]->plan); } } } diff --git a/src/execution_plan/optimizations/apply_limit.c b/src/execution_plan/optimizations/apply_limit.c index 2a254d1388..a891479059 100644 --- a/src/execution_plan/optimizations/apply_limit.c +++ b/src/execution_plan/optimizations/apply_limit.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../ops/op.h" #include "../ops/op_sort.h" diff --git a/src/execution_plan/optimizations/apply_skip.c b/src/execution_plan/optimizations/apply_skip.c index 0a66e4ae07..8a7d4475e7 100644 --- a/src/execution_plan/optimizations/apply_skip.c +++ b/src/execution_plan/optimizations/apply_skip.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../ops/op.h" #include "../ops/op_sort.h" diff --git a/src/execution_plan/optimizations/compact_filters.c b/src/execution_plan/optimizations/compact_filters.c index da993be1fd..cc0abad14f 100644 --- a/src/execution_plan/optimizations/compact_filters.c +++ b/src/execution_plan/optimizations/compact_filters.c @@ -1,13 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../../RG.h" -#include "../../errors.h" #include "../../query_ctx.h" #include "../ops/op_filter.h" +#include "../../errors/errors.h" #include "../../filter_tree/filter_tree.h" #include "../execution_plan_build/execution_plan_modify.h" diff --git a/src/execution_plan/optimizations/filter_variable_length_edges.c b/src/execution_plan/optimizations/filter_variable_length_edges.c index 59aa0b68ca..2c833958a9 100644 --- a/src/execution_plan/optimizations/filter_variable_length_edges.c +++ b/src/execution_plan/optimizations/filter_variable_length_edges.c @@ -1,12 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../../util/arr.h" #include "../ops/op_filter.h" #include "../ops/op_cond_var_len_traverse.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" /* The filterVariableLengthEdges optimization finds variable-length traversal ops @@ -108,7 +112,7 @@ void filterVariableLengthEdges(ExecutionPlan *plan) { OPType_CONDITIONAL_VAR_LEN_TRAVERSE_EXPAND_INTO }; - var_len_traverse_ops = ExecutionPlan_CollectOpsMatchingType(plan->root, + var_len_traverse_ops = ExecutionPlan_CollectOpsMatchingTypes(plan->root, types, 2); uint count = array_len(var_len_traverse_ops); diff --git a/src/execution_plan/optimizations/optimizations.h b/src/execution_plan/optimizations/optimizations.h index af5d98ef05..c0d16f8631 100644 --- a/src/execution_plan/optimizations/optimizations.h +++ b/src/execution_plan/optimizations/optimizations.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/optimizations/optimize_cartesian_product.c b/src/execution_plan/optimizations/optimize_cartesian_product.c index 129c39c754..d89153ea7e 100644 --- a/src/execution_plan/optimizations/optimize_cartesian_product.c +++ b/src/execution_plan/optimizations/optimize_cartesian_product.c @@ -1,14 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" -#include "../../errors.h" #include "../ops/op_filter.h" +#include "../../errors/errors.h" #include "../ops/op_cartesian_product.h" #include "../../util/rax_extensions.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" #include "../execution_plan_build/execution_plan_construct.h" @@ -90,12 +94,13 @@ static FilterCtx *_locate_filters_and_entities static OpBase **_find_entities_solving_branches(rax *entities, OpBase *cp) { int entities_count = raxSize(entities); if(entities_count == 0) return NULL; // No dependencies in filters. + OpBase **solving_branches = array_new(OpBase *, 1); // Iterate over all the children or until all the entities are resolved. for(int i = 0; i < cp->childCount && entities_count > 0; i++) { OpBase *branch = cp->children[i]; // Don't recurse into previous scopes when trying to resolve references. - OpBase *recurse_limit = ExecutionPlan_LocateOpMatchingType(branch, PROJECT_OPS, PROJECT_OP_COUNT); + OpBase *recurse_limit = ExecutionPlan_LocateOpMatchingTypes(branch, PROJECT_OPS, PROJECT_OP_COUNT); /* Locate references reduces the amount of entities upon each call * that partially solves the references. */ ExecutionPlan_LocateReferences(branch, recurse_limit, entities); @@ -107,6 +112,7 @@ static OpBase **_find_entities_solving_branches(rax *entities, OpBase *cp) { array_append(solving_branches, branch); } } + if(entities_count != 0) { Error_InvalidFilterPlacement(entities); array_free(solving_branches); diff --git a/src/execution_plan/optimizations/optimize_label_scan.c b/src/execution_plan/optimizations/optimize_label_scan.c index 977b878a5c..2d39b529e5 100644 --- a/src/execution_plan/optimizations/optimize_label_scan.c +++ b/src/execution_plan/optimizations/optimize_label_scan.c @@ -1,13 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../../query_ctx.h" #include "../ops/op_node_by_label_scan.h" #include "../ops/op_conditional_traverse.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" #include "../../arithmetic/algebraic_expression/utils.h" @@ -35,41 +39,46 @@ static void _optimizeLabelScan(NodeByLabelScan *scan) { ASSERT(scan != NULL); - OpBase *op = (OpBase*)scan; - Graph *g = QueryCtx_GetGraph(); - QueryGraph *qg = op->plan->query_graph; + Graph *g = QueryCtx_GetGraph(); + OpBase *op = (OpBase*)scan; + QueryGraph *qg = op->plan->query_graph; + NodeScanCtx *n_ctx = scan->n; // see if scanned node has multiple labels - const char *node_alias = scan->n.alias; - QGNode *qn = QueryGraph_GetNodeByAlias(qg, node_alias); - ASSERT(qn != NULL); + const char *node_alias = n_ctx->alias; + + QGNode *n = n_ctx->n; // return if node has only one label - uint label_count = QGNode_LabelCount(qn); + uint label_count = QGNode_LabelCount(n); ASSERT(label_count >= 1); - if(label_count == 1) return; + if(label_count == 1) { + return; + } // node has multiple labels // find label with minimum entities - uint64_t min_nnz = UINT64_MAX; // tracks min entries - int min_label_id = 0; // tracks min label ID - const char *min_label_str = NULL; // tracks min label name + int min_label_id = n_ctx->label_id; + const char *min_label_str = n_ctx->label; + uint64_t min_nnz =(uint64_t) Graph_LabeledNodeCount(g, n_ctx->label_id); for(uint i = 0; i < label_count; i++) { uint64_t nnz; - int label_id = QGNode_GetLabelID(qn, i); + int label_id = QGNode_GetLabelID(n, i); nnz = Graph_LabeledNodeCount(g, label_id); if(min_nnz > nnz) { // update minimum - min_nnz = nnz; - min_label_id = label_id; - min_label_str = QGNode_GetLabel(qn, i); + min_nnz = nnz; + min_label_id = label_id; + min_label_str = QGNode_GetLabel(n, i); } } // scanned label has the minimum number of entries // no switching required - if(min_label_id == scan->n.label_id) return; + if(min_label_id == n_ctx->label_id) { + return; + } // patch following traversal, skip filters OpBase *parent = op->parent; @@ -80,8 +89,8 @@ static void _optimizeLabelScan(NodeByLabelScan *scan) { AlgebraicExpression *ae = op_traverse->ae; AlgebraicExpression *operand; - const char *row_domain = scan->n.alias; - const char *column_domain = scan->n.alias; + const char *row_domain = n_ctx->alias; + const char *column_domain = n_ctx->alias; // locate the operand corresponding to the about to be replaced label // in the parent operation (conditional traverse) @@ -92,11 +101,11 @@ static void _optimizeLabelScan(NodeByLabelScan *scan) { // create a replacement operand for the migrated label matrix AlgebraicExpression *replacement = AlgebraicExpression_NewOperand(NULL, true, AlgebraicExpression_Src(operand), - AlgebraicExpression_Dest(operand), NULL, scan->n.label); + AlgebraicExpression_Dest(operand), NULL, n_ctx->label); // swap current label with minimum label - scan->n.label = min_label_str; - scan->n.label_id = min_label_id; + n_ctx->label = min_label_str; + n_ctx->label_id = min_label_id; _AlgebraicExpression_InplaceRepurpose(operand, replacement); } @@ -106,7 +115,7 @@ void optimizeLabelScan(ExecutionPlan *plan) { // collect all label scan operations OPType t = OPType_NODE_BY_LABEL_SCAN; - OpBase **label_scan_ops = ExecutionPlan_CollectOpsMatchingType(plan->root, + OpBase **label_scan_ops = ExecutionPlan_CollectOpsMatchingTypes(plan->root, &t ,1); // for each label scan operation try to optimize scanned label @@ -117,4 +126,3 @@ void optimizeLabelScan(ExecutionPlan *plan) { } array_free(label_scan_ops); } - diff --git a/src/execution_plan/optimizations/optimizer.c b/src/execution_plan/optimizations/optimizer.c index 4d5e1d931d..3e9f0b3ca2 100644 --- a/src/execution_plan/optimizations/optimizer.c +++ b/src/execution_plan/optimizations/optimizer.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./optimizer.h" #include "./optimizations.h" diff --git a/src/execution_plan/optimizations/optimizer.h b/src/execution_plan/optimizations/optimizer.h index 232ba64c1f..5084256291 100644 --- a/src/execution_plan/optimizations/optimizer.h +++ b/src/execution_plan/optimizations/optimizer.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/optimizations/reduce_count.c b/src/execution_plan/optimizations/reduce_count.c index 1ff1eded82..6a90381d7c 100644 --- a/src/execution_plan/optimizations/reduce_count.c +++ b/src/execution_plan/optimizations/reduce_count.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../ops/ops.h" #include "../../util/arr.h" @@ -70,7 +73,7 @@ static int _identifyNodeCountPattern(OpBase *root, OpResult **opResult, OpAggreg *opScan = op; if(op->type == OPType_NODE_BY_LABEL_SCAN) { NodeByLabelScan *labelScan = (NodeByLabelScan *)op; - *label = labelScan->n.label; + *label = labelScan->n->label; } return 1; diff --git a/src/execution_plan/optimizations/reduce_distinct.c b/src/execution_plan/optimizations/reduce_distinct.c index 6de53b70b4..0d7dee813f 100644 --- a/src/execution_plan/optimizations/reduce_distinct.c +++ b/src/execution_plan/optimizations/reduce_distinct.c @@ -1,11 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../execution_plan.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" /* A distinct operation following an aggregation operation diff --git a/src/execution_plan/optimizations/reduce_filters.c b/src/execution_plan/optimizations/reduce_filters.c index 71bc25b053..f2746de192 100644 --- a/src/execution_plan/optimizations/reduce_filters.c +++ b/src/execution_plan/optimizations/reduce_filters.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../ops/op_filter.h" #include "../../filter_tree/filter_tree.h" diff --git a/src/execution_plan/optimizations/reduce_scans.c b/src/execution_plan/optimizations/reduce_scans.c index 3eb5fefa1e..8479f0af05 100644 --- a/src/execution_plan/optimizations/reduce_scans.c +++ b/src/execution_plan/optimizations/reduce_scans.c @@ -1,15 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" +#include "../../util/arr.h" +#include "../../query_ctx.h" #include "../ops/op_filter.h" #include "../ops/op_node_by_label_scan.h" #include "../ops/op_conditional_traverse.h" -#include "../../util/arr.h" -#include "../../query_ctx.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" /* The reduce scans optimizer searches the execution plans for @@ -19,9 +23,9 @@ static OpBase *_LabelScanToConditionalTraverse(NodeByLabelScan *op) { Graph *g = QueryCtx_GetGraph(); - const char *alias = op->n.alias; + const char *alias = op->n->alias; AlgebraicExpression *ae = AlgebraicExpression_NewOperand(GrB_NULL, true, alias, alias, NULL, - op->n.label); + op->n->label); return NewCondTraverseOp(op->op.plan, g, ae); } @@ -36,7 +40,8 @@ static void _reduceScans(ExecutionPlan *plan, OpBase *scan) { // Collect variables bound before this operation. rax *bound_vars = raxNew(); for(int i = 0; i < scan->childCount; i ++) { - ExecutionPlan_BoundVariables(scan->children[i], bound_vars); + ExecutionPlan_BoundVariables(scan->children[i], bound_vars, + scan->children[i]->plan); } if(raxFind(bound_vars, (unsigned char *)scanned_alias, strlen(scanned_alias)) != raxNotFound) { @@ -56,7 +61,7 @@ static void _reduceScans(ExecutionPlan *plan, OpBase *scan) { void reduceScans(ExecutionPlan *plan) { // Collect all SCAN operations within the execution plan. - OpBase **scans = ExecutionPlan_CollectOpsMatchingType(plan->root, SCAN_OPS, SCAN_OP_COUNT); + OpBase **scans = ExecutionPlan_CollectOpsMatchingTypes(plan->root, SCAN_OPS, SCAN_OP_COUNT); uint scan_count = array_len(scans); for(uint i = 0; i < scan_count; i++) { _reduceScans(plan, scans[i]); diff --git a/src/execution_plan/optimizations/reduce_traversal.c b/src/execution_plan/optimizations/reduce_traversal.c index 2fe1e64f28..5c0b2f3976 100644 --- a/src/execution_plan/optimizations/reduce_traversal.c +++ b/src/execution_plan/optimizations/reduce_traversal.c @@ -1,14 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../../util/arr.h" #include "../ops/op_expand_into.h" #include "../ops/op_conditional_traverse.h" #include "../ops/op_cond_var_len_traverse.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" /* Reduce traversal searches for traversal operations where @@ -44,7 +48,7 @@ static void _removeRedundantTraversal(ExecutionPlan *plan, OpCondTraverse *trave * are already resolved, in which case replace traversal operation * with expand-into op. */ void reduceTraversal(ExecutionPlan *plan) { - OpBase **traversals = ExecutionPlan_CollectOpsMatchingType(plan->root, TRAVERSE_OPS, + OpBase **traversals = ExecutionPlan_CollectOpsMatchingTypes(plan->root, TRAVERSE_OPS, TRAVERSE_OP_COUNT); uint traversals_count = array_len(traversals); @@ -80,7 +84,8 @@ void reduceTraversal(ExecutionPlan *plan) { // Collect variables bound before this op. rax *bound_vars = raxNew(); for(int i = 0; i < op->childCount; i ++) { - ExecutionPlan_BoundVariables(op->children[i], bound_vars); + ExecutionPlan_BoundVariables(op->children[i], bound_vars, + op->children[i]->plan); } const char *dest = AlgebraicExpression_Dest(ae); diff --git a/src/execution_plan/optimizations/seek_by_id.c b/src/execution_plan/optimizations/seek_by_id.c index dcf4ac4c2b..d9d38f0ff2 100644 --- a/src/execution_plan/optimizations/seek_by_id.c +++ b/src/execution_plan/optimizations/seek_by_id.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../../util/arr.h" #include "../ops/op_filter.h" @@ -11,6 +14,7 @@ #include "../ops/op_node_by_label_scan.h" #include "../../util/range/numeric_range.h" #include "../../arithmetic/arithmetic_op.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" /* The seek by ID optimization searches for a SCAN operation on which @@ -107,7 +111,7 @@ void seekByID(ExecutionPlan *plan) { ASSERT(plan != NULL); const OPType types[] = {OPType_ALL_NODE_SCAN, OPType_NODE_BY_LABEL_SCAN}; - OpBase **scan_ops = ExecutionPlan_CollectOpsMatchingType(plan->root, types, 2); + OpBase **scan_ops = ExecutionPlan_CollectOpsMatchingTypes(plan->root, types, 2); for(int i = 0; i < array_len(scan_ops); i++) { _UseIdOptimization(plan, scan_ops[i]); diff --git a/src/execution_plan/optimizations/traverse_order.c b/src/execution_plan/optimizations/traverse_order.c index 09d44e1fc8..50c4d55b22 100644 --- a/src/execution_plan/optimizations/traverse_order.c +++ b/src/execution_plan/optimizations/traverse_order.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../../util/arr.h" diff --git a/src/execution_plan/optimizations/traverse_order_utils.c b/src/execution_plan/optimizations/traverse_order_utils.c index 8dac70fbc3..50f7472274 100644 --- a/src/execution_plan/optimizations/traverse_order_utils.c +++ b/src/execution_plan/optimizations/traverse_order_utils.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../../util/arr.h" diff --git a/src/execution_plan/optimizations/traverse_order_utils.h b/src/execution_plan/optimizations/traverse_order_utils.h index 5391f087ab..26b3831516 100644 --- a/src/execution_plan/optimizations/traverse_order_utils.h +++ b/src/execution_plan/optimizations/traverse_order_utils.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/execution_plan/optimizations/utilize_indices.c b/src/execution_plan/optimizations/utilize_indices.c index e3f33cd37d..bcc2d0a623 100644 --- a/src/execution_plan/optimizations/utilize_indices.c +++ b/src/execution_plan/optimizations/utilize_indices.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../../value.h" @@ -22,6 +25,7 @@ #include "../../filter_tree/filter_tree_utils.h" #include "../../arithmetic/algebraic_expression.h" #include "../../arithmetic/algebraic_expression/utils.h" +#include "../execution_plan_build/execution_plan_util.h" #include "../execution_plan_build/execution_plan_modify.h" //------------------------------------------------------------------------------ @@ -308,7 +312,7 @@ void reduce_scan_op const char *min_label_str = NULL; // tracks min label name // see if scanned node has multiple labels - const char *node_alias = scan->n.alias; + const char *node_alias = scan->n->alias; QGNode *qn = QueryGraph_GetNodeByAlias(qg, node_alias); ASSERT(qn != NULL); @@ -331,7 +335,7 @@ void reduce_scan_op ASSERT(Index_Enabled(idx)); // TODO switch to reusable array - OpFilter **cur_filters = _applicableFilters((OpBase *)scan, scan->n.alias, idx); + OpFilter **cur_filters = _applicableFilters((OpBase *)scan, scan->n->alias, idx); // TODO consider heuristic which combines max // number / restrictiveness of applicable filters @@ -365,7 +369,7 @@ void reduce_scan_op if(rs_idx == NULL) goto cleanup; // did we found a better label to utilize? if so swap - if(scan->n.label_id != min_label_id) { + if(scan->n->label_id != min_label_id) { // the scanned label does not match the one we will build an // index scan over, update the traversal expression to // remove the indexed label and insert the previously-scanned label @@ -377,8 +381,8 @@ void reduce_scan_op AlgebraicExpression *ae = op_traverse->ae; AlgebraicExpression *operand; - const char *row_domain = scan->n.alias; - const char *column_domain = scan->n.alias; + const char *row_domain = scan->n->alias; + const char *column_domain = scan->n->alias; bool found = AlgebraicExpression_LocateOperand(ae, &operand, NULL, row_domain, column_domain, NULL, min_label_str); @@ -386,18 +390,19 @@ void reduce_scan_op AlgebraicExpression *replacement = AlgebraicExpression_NewOperand(NULL, true, AlgebraicExpression_Src(operand), - AlgebraicExpression_Dest(operand), NULL, scan->n.label); + AlgebraicExpression_Dest(operand), NULL, scan->n->label); _AlgebraicExpression_InplaceRepurpose(operand, replacement); } - scan->n.label = min_label_str; - scan->n.label_id = min_label_id; + scan->n->label = min_label_str; + scan->n->label_id = min_label_id; } FT_FilterNode *root = _Concat_Filters(filters); OpBase *indexOp = NewIndexScanOp(scan->op.plan, scan->g, scan->n, rs_idx, root); + scan->n = NULL; // replace the redundant scan op with the newly-constructed Index Scan ExecutionPlan_ReplaceOp(plan, (OpBase *)scan, indexOp); diff --git a/src/execution_plan/record.c b/src/execution_plan/record.c index 7c0b1a4b47..1f0d330e78 100644 --- a/src/execution_plan/record.c +++ b/src/execution_plan/record.c @@ -1,12 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "record.h" -#include "../errors.h" +#include "../errors/errors.h" #include "../util/rmalloc.h" // migrate the entry at the given index in the source Record to the same index diff --git a/src/execution_plan/record.h b/src/execution_plan/record.h index ec8d1a0119..8e43d58340 100644 --- a/src/execution_plan/record.h +++ b/src/execution_plan/record.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/filter_tree/filter_tree.c b/src/filter_tree/filter_tree.c index 8002cf8a2f..e8ade0cc63 100644 --- a/src/filter_tree/filter_tree.c +++ b/src/filter_tree/filter_tree.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "filter_tree.h" #include "RG.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../ast/ast_shared.h" #include "../datatypes/array.h" @@ -660,7 +663,7 @@ static inline bool _FilterTree_ValidExpressionNode const FT_FilterNode *root ) { bool valid = AR_EXP_ReturnsBoolean(root->exp.exp); - if(!valid) ErrorCtx_SetError("Expected boolean predicate."); + if(!valid) ErrorCtx_SetError(EMSG_EXPECTED_BOOLEAN_PREDICATE); return valid; } @@ -678,7 +681,7 @@ bool FilterTree_Valid case FT_N_PRED: // Empty or semi empty predicate, invalid structure. if((!root->pred.lhs || !root->pred.rhs)) { - ErrorCtx_SetError("Filter predicate did not compare two expressions."); + ErrorCtx_SetError(EMSG_FILTER_INVALID_COMPARISON); return false; } break; @@ -687,11 +690,11 @@ bool FilterTree_Valid // OR, AND should utilize both left and right children // NOT utilize only the left child. if(!root->cond.left && !root->cond.right) { - ErrorCtx_SetError("Empty filter condition."); + ErrorCtx_SetError(EMSG_EMPTY_FILTER); return false; } if(root->cond.op == OP_NOT && root->cond.right) { - ErrorCtx_SetError("Invalid usage of 'NOT' filter."); + ErrorCtx_SetError(EMSG_INVALID_NOT_USAGE); return false; } if(!FilterTree_Valid(root->cond.left)) return false; diff --git a/src/filter_tree/filter_tree.h b/src/filter_tree/filter_tree.h index fa09e33cf6..65b7fb3ca5 100644 --- a/src/filter_tree/filter_tree.h +++ b/src/filter_tree/filter_tree.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/filter_tree/filter_tree_utils.c b/src/filter_tree/filter_tree_utils.c index b0260de8c5..86575ccd04 100644 --- a/src/filter_tree/filter_tree_utils.c +++ b/src/filter_tree/filter_tree_utils.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "filter_tree_utils.h" #include "RG.h" diff --git a/src/filter_tree/filter_tree_utils.h b/src/filter_tree/filter_tree_utils.h index dffaa3cf10..89c6e365d5 100644 --- a/src/filter_tree/filter_tree_utils.h +++ b/src/filter_tree/filter_tree_utils.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/filter_tree/ft_to_rsq.c b/src/filter_tree/ft_to_rsq.c index 4ebdbedf6e..2c5f727a4c 100644 --- a/src/filter_tree/ft_to_rsq.c +++ b/src/filter_tree/ft_to_rsq.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "ft_to_rsq.h" #include "RG.h" diff --git a/src/filter_tree/ft_to_rsq.h b/src/filter_tree/ft_to_rsq.h index eed43c4042..e7e41fa842 100644 --- a/src/filter_tree/ft_to_rsq.h +++ b/src/filter_tree/ft_to_rsq.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/globals.c b/src/globals.c new file mode 100644 index 0000000000..5eef70b708 --- /dev/null +++ b/src/globals.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "globals.h" +#include "util/thpool/pools.h" + +struct Globals { + pthread_rwlock_t lock; // READ/WRITE lock + bool process_is_child; // running process is a child process + CommandCtx **command_ctxs; // list of CommandCtxs + GraphContext **graphs_in_keyspace; // list of graphs in keyspace +}; + +struct Globals _globals = {0}; + +// initialize global variables +void Globals_Init(void) { + // expecting Global_Init to be called only once + ASSERT(_globals.graphs_in_keyspace == NULL); + + // initialize + _globals.process_is_child = false; + _globals.graphs_in_keyspace = array_new(GraphContext*, 1); + _globals.command_ctxs = rm_calloc(ThreadPools_ThreadCount() + 1, + sizeof(CommandCtx *)); + + int res = pthread_rwlock_init(&_globals.lock, NULL); + ASSERT(res == 0); +} + +// read global variable 'process_is_child' +bool Globals_Get_ProcessIsChild(void) { + bool process_is_child = false; + + pthread_rwlock_rdlock(&_globals.lock); + + process_is_child = _globals.process_is_child; + + pthread_rwlock_unlock(&_globals.lock); + + return process_is_child; +} + +// set global variable 'process_is_child' +void Globals_Set_ProcessIsChild +( + bool process_is_child +) { + pthread_rwlock_wrlock(&_globals.lock); + + _globals.process_is_child = process_is_child; + + pthread_rwlock_unlock(&_globals.lock); +} + +// return number of graphs in keyspace +int Globals_GetGraphCount(void) { + // acuire read lock + pthread_rwlock_rdlock(&_globals.lock); + + // get number of graphs + int n = array_len(_globals.graphs_in_keyspace); + + // unlock + pthread_rwlock_unlock(&_globals.lock); + + return n; +} + +// get direct access to 'graphs_in_keyspace' +GraphContext **Globals_Get_GraphsInKeyspace(void) { + return _globals.graphs_in_keyspace; +} + +// add graph to global tracker +void Globals_AddGraph +( + GraphContext *gc // graph to add +) { + ASSERT(gc != NULL); + + // increase ref count regardless if 'gc' is already tracked + GraphContext_IncreaseRefCount(gc); + + // acuire write lock + pthread_rwlock_wrlock(&_globals.lock); + + bool registered = false; + uint n = array_len(_globals.graphs_in_keyspace); + for(uint i = 0; i < n; i++) { + if(_globals.graphs_in_keyspace[i] == gc) { + registered = true; + break; + } + } + + if(registered == false) { + // append graph + array_append(_globals.graphs_in_keyspace, gc); + } + + // release lock + pthread_rwlock_unlock(&_globals.lock); +} + +// remove graph from global tracker +void Globals_RemoveGraph +( + GraphContext *gc // graph to remove +) { + ASSERT(gc != NULL); + + uint64_t i = 0; + uint64_t n = array_len(_globals.graphs_in_keyspace); + if(n == 0) return; + + // acuire write lock + pthread_rwlock_wrlock(&_globals.lock); + + // search for graph + for(; i < n; i++) { + if(_globals.graphs_in_keyspace[i] == gc) { + break; + } + } + + // graph must be found + ASSERT(i != n); + + // graph located, remove it + array_del_fast(_globals.graphs_in_keyspace, i); + + // release lock + pthread_rwlock_unlock(&_globals.lock); +} + +// remove a graph by its name +void Globals_RemoveGraphByName +( + const char *name // graph name to remove +) { + ASSERT(name != NULL); + + // acuire write lock + pthread_rwlock_wrlock(&_globals.lock); + + // search for graph + uint64_t i = 0; + uint64_t n = array_len(_globals.graphs_in_keyspace); + for(; i < n; i++) { + GraphContext *gc = _globals.graphs_in_keyspace[i]; + if(strcmp(name, GraphContext_GetName(gc)) == 0) { + break; + } + } + + if(i != n) { + // graph located, remove it + array_del_fast(_globals.graphs_in_keyspace, i); + } + + // release lock + pthread_rwlock_unlock(&_globals.lock); +} + +// clear all tracked graphs +void Globals_ClearGraphs +( + RedisModuleCtx *ctx +) { + // acquire write lock + pthread_rwlock_wrlock(&_globals.lock); + + for(uint i = 0; i < array_len(_globals.graphs_in_keyspace); i++) { + GraphContext *gc = _globals.graphs_in_keyspace[i]; + if(gc->telemetry_stream != NULL) { + RedisModule_FreeString(ctx, gc->telemetry_stream); + gc->telemetry_stream = NULL; + } + } + + // clear graph tracking + array_clear(_globals.graphs_in_keyspace); + + // release lock + pthread_rwlock_unlock(&_globals.lock); +} + +//------------------------------------------------------------------------------ +// Command context tracking +//------------------------------------------------------------------------------ + +// track CommandCtx +void Globals_TrackCommandCtx +( + CommandCtx *ctx // CommandCtx to track +) { + ASSERT(ctx != NULL); + ASSERT(_globals.command_ctxs != NULL); + + int tid = ThreadPools_GetThreadID(); + + // acuire read lock + pthread_rwlock_rdlock(&_globals.lock); + + // expecting slot to be empty + ASSERT(_globals.command_ctxs[tid] == NULL); + + // set ctx at the current thread entry + _globals.command_ctxs[tid] = ctx; + + // release lock + pthread_rwlock_unlock(&_globals.lock); + + // reset thread memory consumption to 0 (no memory consumed) + rm_reset_n_alloced(); +} + +// untrack CommandCtx +void Globals_UntrackCommandCtx +( + const CommandCtx *ctx // CommandCtx to untrack +) { + ASSERT(ctx != NULL); + ASSERT(_globals.command_ctxs != NULL); + + int tid = ThreadPools_GetThreadID(); + + // acuire read lock + pthread_rwlock_rdlock(&_globals.lock); + + ASSERT(_globals.command_ctxs[tid] == ctx); + + // clear ctx at the current thread entry + // CommandCtx_Free will free it eventually + _globals.command_ctxs[tid] = NULL; + + // release lock + pthread_rwlock_unlock(&_globals.lock); +} + +// get all currently tracked CommandCtxs +void Globals_GetCommandCtxs +( + CommandCtx **commands, // array to populate + uint32_t *count // [input/output] number of entries in 'commands' +) { + ASSERT(count != NULL); + ASSERT(commands != NULL); + ASSERT(_globals.command_ctxs != NULL); + + // make a copy of the command contexts + uint32_t nthreads = ThreadPools_ThreadCount() + 1; + uint32_t cap = *count; // capacity of 'commands' + uint32_t found = 0; // number of command contexts found + + // acquire write lock + pthread_rwlock_wrlock(&_globals.lock); + + // increase ref count of each CommandCtx + for(uint32_t i = 0; i < nthreads && found < cap; i++) { + CommandCtx *cmd = _globals.command_ctxs[i]; + if(cmd != NULL) { + CommandCtx_Incref(cmd); + commands[found++] = cmd; + } + } + + // release lock + pthread_rwlock_unlock(&_globals.lock); + + // update number of command contexts found + *count = found; +} + +// free globals +void Globals_Free(void) { + rm_free(_globals.command_ctxs); + array_free(_globals.graphs_in_keyspace); + pthread_rwlock_destroy(&_globals.lock); +} + +//------------------------------------------------------------------------------ +// graphs in keyspace iterator +//------------------------------------------------------------------------------ + +// initialize iterator over graphs in keyspace +void Globals_ScanGraphs +( + KeySpaceGraphIterator *it +) { + ASSERT(it != NULL); + it->idx = 0; +} + +// seek iterator to index +void GraphIterator_Seek +( + KeySpaceGraphIterator *it, // iterator + uint64_t idx // index to seek to +) { + ASSERT(it != NULL); + it->idx = idx; +} + +// advance iterator +// returns graph object in case iterator isn't depleted, otherwise returns NULL +GraphContext *GraphIterator_Next +( + KeySpaceGraphIterator *it // iterator to advance +) { + ASSERT(it != NULL); + + GraphContext *gc = NULL; + + pthread_rwlock_rdlock(&_globals.lock); + + if(it->idx < array_len(_globals.graphs_in_keyspace)) { + // prepare next call + gc = _globals.graphs_in_keyspace[it->idx++]; + GraphContext_IncreaseRefCount(gc); + } + + pthread_rwlock_unlock(&_globals.lock); + + return gc; +} + diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 0000000000..c2d0becb30 --- /dev/null +++ b/src/globals.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "graph/graphcontext.h" +#include "commands/cmd_context.h" + +// initialize global variables +void Globals_Init(void); + +// read global variable 'process_is_child' +bool Globals_Get_ProcessIsChild(void); + +// set global variable 'process_is_child' +void Globals_Set_ProcessIsChild +( + bool process_is_child +); + +// return number of graphs in keyspace +int Globals_GetGraphCount(void); + +// get direct access to 'graphs_in_keyspace' +GraphContext **Globals_Get_GraphsInKeyspace(void); + +// add graph to global tracker +void Globals_AddGraph +( + GraphContext *gc // graph to add +); + +// get graph by name +GraphContext Globals_GetGraph +( + const char *name // name of graph to retrieve +); + +// remove graph from global tracker +void Globals_RemoveGraph +( + GraphContext *gc // graph to remove +); + +// remove a graph by its name +void Globals_RemoveGraphByName +( + const char *name // graph name to remove +); + +// clear all tracked graphs +void Globals_ClearGraphs( + RedisModuleCtx *ctx +); + +//------------------------------------------------------------------------------ +// Command context tracking +//------------------------------------------------------------------------------ + +// track CommandCtx +void Globals_TrackCommandCtx +( + CommandCtx *ctx // CommandCtx to track +); + +// untrack CommandCtx +void Globals_UntrackCommandCtx +( + const CommandCtx *ctx // CommandCtx to untrack +); + +// get all currently tracked CommandCtxs +void Globals_GetCommandCtxs +( + CommandCtx **commands, // array to populate + uint32_t *count // [input/output] number of entries in 'commands' +); + +// free globals +void Globals_Free(void); + +//------------------------------------------------------------------------------ +// Graphs iterator +//------------------------------------------------------------------------------ + +// graphs_in_keyspace iterator +typedef struct KeySpaceGraphIterator { + uint64_t idx; // current graph index +} KeySpaceGraphIterator; + +// initialize iterator over graphs in keyspace +void Globals_ScanGraphs(KeySpaceGraphIterator *it); + +// seek iterator to index +void GraphIterator_Seek +( + KeySpaceGraphIterator *it, // iterator + uint64_t idx // index to seek to +); + +// advance iterator +// returns graph object in case iterator isn't depleted +// otherwise returns NULL +// NOTICE: +// if caller doesn't hold the GIL thoughout the iterator scan +// it is possible for the scanning thread to miss keys which are deleted +// consider the iterator is at position 4 and graph at position 0 is deleted +// in which case array_del_fast will move the last graph (say index 9) to +// index 0. in this case the iterator will miss that migrated graph +GraphContext *GraphIterator_Next +( + KeySpaceGraphIterator *it // iterator to advance +); + diff --git a/src/graph/entities/attribute_set.c b/src/graph/entities/attribute_set.c index d1e1fda0c1..614b59dd81 100644 --- a/src/graph/entities/attribute_set.c +++ b/src/graph/entities/attribute_set.c @@ -1,20 +1,26 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include "RG.h" #include "attribute_set.h" #include "../../util/rmalloc.h" +#include "../../errors/errors.h" // compute size of attribute set in bytes -#define ATTRIBUTESET_BYTE_SIZE(set) ((set) == NULL ? sizeof(_AttributeSet) : sizeof(_AttributeSet) + sizeof(Attribute) * (set)->attr_count) +#define ATTRIBUTESET_BYTE_SIZE(set) ((set) == NULL ? \ + sizeof(_AttributeSet) : \ + sizeof(_AttributeSet) + sizeof(Attribute) * (set)->attr_count) -// determine if set is empty -#define ATTRIBUTESET_EMPTY(set) (set) == NULL +// mark attribute-set as mutable +#define ATTRIBUTE_SET_CLEAR_MSB(set) (CLEAR_MSB((intptr_t)set)) // returned value for a missing attribute SIValue *ATTRIBUTE_NOTFOUND = &(SIValue) { @@ -30,6 +36,9 @@ static bool _AttributeSet_Remove AttributeSet _set = *set; const uint16_t attr_count = _set->attr_count; + // attribute-set can't be read-only + ASSERT(ATTRIBUTE_SET_IS_READONLY(_set) == false); + // locate attribute position for (uint16_t i = 0; i < attr_count; ++i) { if(attr_id != _set->attributes[i].id) { @@ -65,24 +74,42 @@ static bool _AttributeSet_Remove return false; } +// returns number of attributes within the set +uint16_t AttributeSet_Count +( + const AttributeSet set // set to query +) { + // in case attribute-set is marked as read-only, clear marker + AttributeSet _set = (AttributeSet)ATTRIBUTE_SET_CLEAR_MSB(set); + + return (_set == NULL) ? 0 : _set->attr_count; +} + // retrieves a value from set // NOTE: if the key does not exist -// we return the special constant value ATTRIBUTE_NOTFOUND +// we return the special constant value ATTRIBUTE_NOTFOUND SIValue *AttributeSet_Get ( const AttributeSet set, // set to retieve attribute from Attribute_ID attr_id // attribute identifier ) { - if(set == NULL) return ATTRIBUTE_NOTFOUND; + // in case attribute-set is marked as read-only, clear marker + AttributeSet _set = (AttributeSet)ATTRIBUTE_SET_CLEAR_MSB(set); - if(attr_id == ATTRIBUTE_ID_NONE) return ATTRIBUTE_NOTFOUND; + if(_set == NULL) { + return ATTRIBUTE_NOTFOUND; + } + + if(attr_id == ATTRIBUTE_ID_NONE) { + return ATTRIBUTE_NOTFOUND; + } // TODO: benchmark, consider alternatives: // sorted set // array divided in two: // [attr_id_0, attr_id_1, attr_id_2, value_0, value_1, value_2] - for (uint16_t i = 0; i < set->attr_count; ++i) { - Attribute *attr = set->attributes + i; + for (uint16_t i = 0; i < _set->attr_count; ++i) { + Attribute *attr = _set->attributes + i; if(attr_id == attr->id) { // note, unsafe as attribute-set can get reallocated // TODO: why do we return a pointer to value instead of a copy ? @@ -102,11 +129,16 @@ SIValue AttributeSet_GetIdx uint16_t i, // index of the property Attribute_ID *attr_id // attribute identifier ) { - ASSERT(set != NULL); - ASSERT(i < set->attr_count); ASSERT(attr_id != NULL); - Attribute *attr = set->attributes + i; + // in case attribute-set is marked as read-only, clear marker + AttributeSet _set = (AttributeSet)ATTRIBUTE_SET_CLEAR_MSB(set); + + ASSERT(_set != NULL); + + ASSERT(i < _set->attr_count); + + Attribute *attr = _set->attributes + i; *attr_id = attr->id; return attr->value; @@ -114,45 +146,71 @@ SIValue AttributeSet_GetIdx static AttributeSet AttributeSet_AddPrepare ( - AttributeSet *set, // set to update - Attribute_ID attr_id // attribute identifier + AttributeSet *set, // set to update + ushort n // number of attributes to add ) { ASSERT(set != NULL); - ASSERT(attr_id != ATTRIBUTE_ID_NONE); AttributeSet _set = *set; - // make sure attribute isn't already in set - ASSERT(AttributeSet_Get(_set, attr_id) == ATTRIBUTE_NOTFOUND); + // attribute-set can't be read-only + ASSERT(ATTRIBUTE_SET_IS_READONLY(_set) == false); // allocate room for new attribute if(_set == NULL) { - _set = rm_malloc(sizeof(_AttributeSet) + sizeof(Attribute)); - _set->attr_count = 1; + _set = rm_malloc(sizeof(_AttributeSet) + n * sizeof(Attribute)); + _set->attr_count = n; } else { - ++_set->attr_count; - size_t n = ATTRIBUTESET_BYTE_SIZE(_set); - _set = rm_realloc(_set, n); + _set->attr_count += n; + _set = rm_realloc(_set, ATTRIBUTESET_BYTE_SIZE(_set)); } + return _set; } // adds an attribute to the set without cloning the SIvalue void AttributeSet_AddNoClone ( - AttributeSet *set, // set to update - Attribute_ID attr_id, // attribute identifier - SIValue value // attribute value + AttributeSet *set, // set to update + Attribute_ID *ids, // identifiers + SIValue *values, // values + ushort n, // number of values to add + bool allowNull // accept NULLs ) { + ASSERT(set != NULL); + + // return if set is read-only + if(unlikely(ATTRIBUTE_SET_IS_READONLY(*set))) { + return; + } + // validate value type // value must be a valid property type - ASSERT(SI_TYPE(value) & SI_VALID_PROPERTY_VALUE); - AttributeSet _set = AttributeSet_AddPrepare(set, attr_id); +#ifdef RG_DEBUG + SIType t = SI_VALID_PROPERTY_VALUE; + if(allowNull == true) { + t |= T_NULL; + } - // set attribute - Attribute *attr = _set->attributes + _set->attr_count - 1; - attr->id = attr_id; - attr->value = value; + for(ushort i = 0; i < n; i++) { + ASSERT(SI_TYPE(values[i]) & t); + // make sure attribute isn't already in set + ASSERT(AttributeSet_Get(*set, ids[i]) == ATTRIBUTE_NOTFOUND); + // make sure value isn't volotile + ASSERT(SI_ALLOCATION(values + i) != M_VOLATILE); + } +#endif + + ushort prev_count = AttributeSet_Count(*set); + AttributeSet _set = AttributeSet_AddPrepare(set, n); + Attribute *attrs = _set->attributes + prev_count; + + // add attributes to set + for(ushort i = 0; i < n; i++) { + Attribute *attr = attrs + i; + attr->id = ids[i]; + attr->value = values[i]; + } // update pointer *set = _set; @@ -165,10 +223,21 @@ void AttributeSet_Add Attribute_ID attr_id, // attribute identifier SIValue value // attribute value ) { - // validate value type + ASSERT(set != NULL); + + // return if set is read-only + if(unlikely(ATTRIBUTE_SET_IS_READONLY(*set))) { + return; + } + +#ifdef RG_DEBUG // value must be a valid property type ASSERT(SI_TYPE(value) & SI_VALID_PROPERTY_VALUE); - AttributeSet _set = AttributeSet_AddPrepare(set, attr_id); + // make sure attribute isn't already in set + ASSERT(AttributeSet_Get(*set, attr_id) == ATTRIBUTE_NOTFOUND); +#endif + + AttributeSet _set = AttributeSet_AddPrepare(set, 1); // set attribute Attribute *attr = _set->attributes + _set->attr_count - 1; @@ -179,8 +248,10 @@ void AttributeSet_Add *set = _set; } -// adds or updates an attribute to the set null value allowed -void AttributeSet_Set_Allow_Null +// add, remove or update an attribute +// this function allows NULL value to be added to the set +// returns the type of change performed +AttributeSetChangeType AttributeSet_Set_Allow_Null ( AttributeSet *set, // set to update Attribute_ID attr_id, // attribute identifier @@ -191,20 +262,33 @@ void AttributeSet_Set_Allow_Null AttributeSet _set = *set; + // return if set is read-only + if(unlikely(ATTRIBUTE_SET_IS_READONLY(_set))) { + return CT_NONE; + } + // validate value type - // value must be a valid property type ASSERT(SI_TYPE(value) & (SI_VALID_PROPERTY_VALUE | T_NULL)); // update the attribute if it is already presented in the set if(AttributeSet_Get(_set, attr_id) != ATTRIBUTE_NOTFOUND) { - AttributeSet_Update(&_set, attr_id, value); - // update pointer - *set = _set; - return; + if(AttributeSet_Update(&_set, attr_id, value)) { + // update pointer + *set = _set; + // if value is NULL, indicate attribute removal + // otherwise indicate attribute update + return SIValue_IsNull(value) ? CT_DEL : CT_UPDATE; + } + + // value did not change, indicate no modification + return CT_NONE; } + // can't remove a none existing attribute, indicate no modification + if(SIValue_IsNull(value)) return CT_NONE; + // allocate room for new attribute - _set = AttributeSet_AddPrepare(set, attr_id); + _set = AttributeSet_AddPrepare(set, 1); // set attribute Attribute *attr = _set->attributes + _set->attr_count - 1; @@ -213,6 +297,9 @@ void AttributeSet_Set_Allow_Null // update pointer *set = _set; + + // new attribute added, indicate attribute addition + return CT_ADD; } // updates existing attribute, return true if attribute been updated @@ -225,6 +312,11 @@ bool AttributeSet_UpdateNoClone ASSERT(set != NULL); ASSERT(attr_id != ATTRIBUTE_ID_NONE); + // return if set is read-only + if(unlikely(ATTRIBUTE_SET_IS_READONLY(*set))) { + return false; + } + // setting an attribute value to NULL removes that attribute if(unlikely(SIValue_IsNull(value))) { return _AttributeSet_Remove(set, attr_id); @@ -251,12 +343,21 @@ bool AttributeSet_Update ASSERT(set != NULL); ASSERT(attr_id != ATTRIBUTE_ID_NONE); + AttributeSet _set = *set; + + // return if set is read-only + if(unlikely(ATTRIBUTE_SET_IS_READONLY(_set))) { + return false; + } + + ASSERT(_set != NULL); + // setting an attribute value to NULL removes that attribute if(unlikely(SIValue_IsNull(value))) { return _AttributeSet_Remove(set, attr_id); } - SIValue *current = AttributeSet_Get(*set, attr_id); + SIValue *current = AttributeSet_Get(_set, attr_id); ASSERT(current != ATTRIBUTE_NOTFOUND); // compare current value to new value, only update if current != new @@ -271,28 +372,48 @@ bool AttributeSet_Update return true; } -// clones attribute set -AttributeSet AttributeSet_Clone +// clones attribute-set without SI values +AttributeSet AttributeSet_ShallowClone ( const AttributeSet set // set to clone ) { - if(set == NULL) return NULL; + // in case attribute-set is marked as read-only, clear marker + AttributeSet _set = (AttributeSet)ATTRIBUTE_SET_CLEAR_MSB(set); + + if(_set == NULL) return NULL; size_t n = ATTRIBUTESET_BYTE_SIZE(set); - AttributeSet clone = rm_malloc(n); - clone->attr_count = set->attr_count; + AttributeSet clone = rm_malloc(n); + clone->attr_count = _set->attr_count; - for (uint16_t i = 0; i < set->attr_count; ++i) { - Attribute *attr = set->attributes + i; - Attribute *clone_attr = clone->attributes + i; + for(uint16_t i = 0; i < _set->attr_count; ++i) { + Attribute *attr = _set->attributes + i; + Attribute *clone_attr = clone->attributes + i; clone_attr->id = attr->id; - clone_attr->value = SI_CloneValue(attr->value); + clone_attr->value = SI_ShareValue(attr->value); } return clone; } +// persists all attributes within given set +void AttributeSet_PersistValues +( + const AttributeSet set // set to persist +) { + // return if set is read-only + ASSERT(ATTRIBUTE_SET_IS_READONLY(set) == false); + + if(set == NULL) return; + + for (uint16_t i = 0; i < set->attr_count; ++i) { + Attribute *attr = set->attributes + i; + + SIValue_Persist(&attr->value); + } +} + // free attribute set void AttributeSet_Free ( @@ -302,7 +423,15 @@ void AttributeSet_Free AttributeSet _set = *set; - if(_set == NULL) return; + // return if set is read-only + if(unlikely(ATTRIBUTE_SET_IS_READONLY(_set))) { + return; + } + + // return if set is NULL + if(_set == NULL) { + return; + } // free all allocated properties for(uint16_t i = 0; i < _set->attr_count; ++i) { diff --git a/src/graph/entities/attribute_set.h b/src/graph/entities/attribute_set.h index 3794295cda..f4e8e9c277 100644 --- a/src/graph/entities/attribute_set.h +++ b/src/graph/entities/attribute_set.h @@ -1,11 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once +#include "RG.h" #include "../../value.h" // indicates a none existing attribute ID @@ -14,11 +18,22 @@ // indicates all attributes for SET clauses that replace a property map #define ATTRIBUTE_ID_ALL USHRT_MAX - 1 -// returns number of attribute within the set -#define ATTRIBUTE_SET_COUNT(attributes) (attributes == NULL ? 0 : ((attributes)->attr_count)) +// mark attribute-set as read-only +#define ATTRIBUTE_SET_MARK_READONLY(set) ((intptr_t)SET_MSB((intptr_t)(set))) + +// check if attribute-set is read-only +#define ATTRIBUTE_SET_IS_READONLY(set) ((intptr_t)(set) & MSB_MASK) typedef unsigned short Attribute_ID; +// type of change performed on the attribute-set +typedef enum { + CT_NONE, // no change + CT_ADD, // attribute been added + CT_UPDATE, // attribute been updated + CT_DEL // attribute been deleted +} AttributeSetChangeType; + typedef struct { Attribute_ID id; // attribute identifier SIValue value; // attribute value @@ -31,6 +46,12 @@ typedef struct { typedef _AttributeSet* AttributeSet; +// returns number of attributes within the set +uint16_t AttributeSet_Count +( + const AttributeSet set // set to query +); + // retrieves a value from set // NOTE: if the key does not exist // we return the special constant value ATTRIBUTE_NOTFOUND @@ -51,12 +72,14 @@ SIValue AttributeSet_GetIdx // adds an attribute to the set without cloning the SIValue void AttributeSet_AddNoClone ( - AttributeSet *set, // set to update - Attribute_ID attr_id, // attribute identifier - SIValue value // attribute value + AttributeSet *set, // set to update + Attribute_ID *ids, // identifiers + SIValue *values, // values + ushort n, // number of values to add + bool allowNull // accept NULLs ); -// adds an attribute to the set (clones the SIValue) +// adds an attribute to the set (clones the value) void AttributeSet_Add ( AttributeSet *set, // set to update @@ -64,16 +87,18 @@ void AttributeSet_Add SIValue value // attribute value ); -// add or update an attribute, this function allows NULL value to be added to the set -void AttributeSet_Set_Allow_Null +// add, remove or update an attribute +// this function allows NULL value to be added to the set +// returns the type of change performed +AttributeSetChangeType AttributeSet_Set_Allow_Null ( AttributeSet *set, // set to update Attribute_ID attr_id, // attribute identifier SIValue value // attribute value ); -// updates existing attribute (without cloning), return true if attribute been updated -// otherwise false +// updates existing attribute (without cloning) +// return true if attribute been updated bool AttributeSet_UpdateNoClone ( AttributeSet *set, // set to update @@ -81,8 +106,8 @@ bool AttributeSet_UpdateNoClone SIValue value // new value ); -// updates existing attribute, return true if attribute been updated -// otherwise false +// updates existing attribute +// return true if attribute been updated bool AttributeSet_Update ( AttributeSet *set, // set to update @@ -90,12 +115,18 @@ bool AttributeSet_Update SIValue value // new value ); -// clones attribute set -AttributeSet AttributeSet_Clone +// clones attribute set without si values +AttributeSet AttributeSet_ShallowClone ( const AttributeSet set // set to clone ); +// persists all attributes within given set +void AttributeSet_PersistValues +( + const AttributeSet set // set to persist +); + // free attribute set void AttributeSet_Free ( diff --git a/src/graph/entities/edge.c b/src/graph/entities/edge.c index 91ef5e45e4..bb3028927a 100644 --- a/src/graph/entities/edge.c +++ b/src/graph/entities/edge.c @@ -1,23 +1,26 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include +#include "RG.h" #include "edge.h" +#include "../graph.h" #include "graph_entity.h" -#include "../graphcontext.h" -#include "../../query_ctx.h" NodeID Edge_GetSrcNodeID ( const Edge *edge ) { ASSERT(edge); - return edge->srcNodeID; + return edge->src_id; } NodeID Edge_GetDestNodeID @@ -25,7 +28,7 @@ NodeID Edge_GetDestNodeID const Edge *edge ) { ASSERT(edge); - return edge->destNodeID; + return edge->dest_id; } int Edge_GetRelationID @@ -33,49 +36,33 @@ int Edge_GetRelationID const Edge *edge ) { ASSERT(edge); + ASSERT(edge->relationID != GRAPH_NO_RELATION); + ASSERT(edge->relationID != GRAPH_UNKNOWN_RELATION); return edge->relationID; } -Node *Edge_GetSrcNode -( - Edge *e -) { - ASSERT(e); - return e->src; -} - -Node *Edge_GetDestNode -( - Edge *e -) { - ASSERT(e); - return e->dest; -} - -void Edge_SetSrcNode +void Edge_SetSrcNodeID ( Edge *e, - Node *src + NodeID id ) { - ASSERT(e && src); - e->src = src; - e->srcNodeID = ENTITY_GET_ID(src); + ASSERT(e); + e->src_id = id; } -void Edge_SetDestNode +void Edge_SetDestNodeID ( Edge *e, - Node *dest + NodeID id ) { - ASSERT(e && dest); - e->dest = dest; - e->destNodeID = ENTITY_GET_ID(dest); + ASSERT(e); + e->dest_id = id; } void Edge_SetRelationID ( Edge *e, - int relationID + RelationID relationID ) { ASSERT(e); e->relationID = relationID; diff --git a/src/graph/entities/edge.h b/src/graph/entities/edge.h index 9985ace156..772750f4ff 100644 --- a/src/graph/entities/edge.h +++ b/src/graph/entities/edge.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -10,55 +13,29 @@ #include "../../value.h" #include "graph_entity.h" +typedef int RelationID; + #define EDGE_LENGTH_INF UINT_MAX - 2 -// instantiate a new unpopulated edge -#define GE_NEW_EDGE() \ -(Edge) { \ - .entity = NULL, \ - .id = INVALID_ENTITY_ID, \ - .relationship = NULL, \ - .relationID = GRAPH_NO_RELATION, \ - .src = NULL, \ - .dest = NULL, \ - .srcNodeID = INVALID_ENTITY_ID, \ - .destNodeID = INVALID_ENTITY_ID \ -} // instantiate a new edge with relation data #define GE_NEW_LABELED_EDGE(r_str, r_id) \ (Edge) { \ - .attributes = NULL, \ - .id = INVALID_ENTITY_ID, \ + .attributes = NULL, \ + .id = INVALID_ENTITY_ID, \ .relationship = (r_str), \ - .relationID = (r_id), \ - .src = NULL, \ - .dest = NULL, \ - .srcNodeID = INVALID_ENTITY_ID, \ - .destNodeID = INVALID_ENTITY_ID \ + .relationID = (r_id), \ + .src_id = INVALID_ENTITY_ID, \ + .dest_id = INVALID_ENTITY_ID \ } -// resolves to relationship-type ID of the given edge -// we first attempt to retrieve it from the given entity -// then check the graph if relationship-type isn't set -#define EDGE_GET_RELATION_ID(e, g) \ -__extension__({ \ - if ((e)->relationID == GRAPH_UNKNOWN_RELATION || (e)->relationID == GRAPH_NO_RELATION) \ - (e)->relationID = Graph_GetEdgeRelation((g), (e)); \ - (e)->relationID; \ -}) - -/* TODO: note it is possible to get into an inconsistency - * if we set src and srcNodeID to different nodes. */ struct Edge { AttributeSet *attributes; // MUST be the first member EntityID id; // Unique id, MUST be the second member const char *relationship; // Label attached to edge - int relationID; // Relation ID - Node *src; // Pointer to source node - Node *dest; // Pointer to destination node - NodeID srcNodeID; // Source node ID - NodeID destNodeID; // Destination node ID + RelationID relationID; // Relation ID + NodeID src_id; // Source node ID + NodeID dest_id; // Destination node ID }; typedef struct Edge Edge; @@ -81,37 +58,25 @@ int Edge_GetRelationID const Edge *edge ); -// retrieve edge source node -Node *Edge_GetSrcNode -( - Edge *e -); - -// retrieve edge destination node -Node *Edge_GetDestNode -( - Edge *e -); - // sets edge source node -void Edge_SetSrcNode +void Edge_SetSrcNodeID ( Edge *e, - Node *src + NodeID id ); // sets edge destination node -void Edge_SetDestNode +void Edge_SetDestNodeID ( Edge *e, - Node *dest + NodeID id ); // sets edge relation type void Edge_SetRelationID ( Edge *e, - int relationID + RelationID relationID ); // constructs a string representation of edge diff --git a/src/graph/entities/graph_entity.c b/src/graph/entities/graph_entity.c index 055978d044..5389ca74fa 100644 --- a/src/graph/entities/graph_entity.c +++ b/src/graph/entities/graph_entity.c @@ -1,14 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "graph_entity.h" -#include "../../errors.h" #include "../../query_ctx.h" #include "../graphcontext.h" #include "../../util/rmalloc.h" +#include "../../errors/errors.h" #include "../../datatypes/map.h" #include "../../datatypes/array.h" @@ -37,25 +40,13 @@ SIValue *GraphEntity_GetProperty // one which didn't had its attribute-set allocated within the graph datablock. if(e->attributes == NULL) { // note that this exception may cause memory to be leaked in the caller - ErrorCtx_SetError("Attempted to access undefined attribute"); + ErrorCtx_SetError(EMSG_ACCESS_UNDEFINED_ATTRIBUTE); return ATTRIBUTE_NOTFOUND; } return AttributeSet_Get(*e->attributes, attr_id); } -// updates existing property value -bool GraphEntity_SetProperty -( - const GraphEntity *e, - Attribute_ID attr_id, - SIValue value -) { - ASSERT(e); - - return AttributeSet_Update(e->attributes, attr_id, value); -} - // returns an SIArray of all keys in graph entity properties SIValue GraphEntity_Keys ( @@ -63,7 +54,7 @@ SIValue GraphEntity_Keys ) { GraphContext *gc = QueryCtx_GetGraphCtx(); const AttributeSet set = GraphEntity_GetAttributes(e); - int prop_count = ATTRIBUTE_SET_COUNT(set); + int prop_count = AttributeSet_Count(set); SIValue keys = SIArray_New(prop_count); for(int i = 0; i < prop_count; i++) { Attribute_ID attr_id; @@ -81,7 +72,7 @@ SIValue GraphEntity_Properties ) { GraphContext *gc = QueryCtx_GetGraphCtx(); const AttributeSet set = GraphEntity_GetAttributes(e); - int propCount = ATTRIBUTE_SET_COUNT(set); + int propCount = AttributeSet_Count(set); SIValue map = SI_Map(propCount); for(int i = 0; i < propCount; i++) { Attribute_ID attr_id; @@ -109,7 +100,7 @@ size_t GraphEntity_PropertiesToString *bytesWritten += snprintf(*buffer, *bufferLen, "{"); GraphContext *gc = QueryCtx_GetGraphCtx(); const AttributeSet set = GraphEntity_GetAttributes(e); - int propCount = ATTRIBUTE_SET_COUNT(set); + int propCount = AttributeSet_Count(set); for(int i = 0; i < propCount; i++) { Attribute_ID attr_id; SIValue value = AttributeSet_GetIdx(set, i, &attr_id); @@ -234,7 +225,7 @@ inline bool GraphEntity_IsDeleted return Graph_EntityIsDeleted(e); } -inline const AttributeSet GraphEntity_GetAttributes +inline AttributeSet GraphEntity_GetAttributes ( const GraphEntity *e ) { @@ -249,7 +240,7 @@ inline int GraphEntity_ClearAttributes ) { ASSERT(e != NULL); - int count = ATTRIBUTE_SET_COUNT(*e->attributes); + int count = AttributeSet_Count(*e->attributes); AttributeSet_Free(e->attributes); diff --git a/src/graph/entities/graph_entity.h b/src/graph/entities/graph_entity.h index fd05d27c05..00f5eff91e 100644 --- a/src/graph/entities/graph_entity.h +++ b/src/graph/entities/graph_entity.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -62,14 +65,6 @@ SIValue *GraphEntity_GetProperty Attribute_ID attr_id ); -// updates existing attribute value, return true if property been updated -bool GraphEntity_SetProperty -( - const GraphEntity *e, - Attribute_ID attr_id, - SIValue value -); - // returns an SIArray of all keys in graph entity properties SIValue GraphEntity_Keys ( @@ -102,7 +97,7 @@ bool GraphEntity_IsDeleted ); // returns attribute-set of entity -const AttributeSet GraphEntity_GetAttributes +AttributeSet GraphEntity_GetAttributes ( const GraphEntity *e ); diff --git a/src/graph/entities/node.c b/src/graph/entities/node.c index 1e3ed9248d..a8f9306c93 100644 --- a/src/graph/entities/node.c +++ b/src/graph/entities/node.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "node.h" diff --git a/src/graph/entities/node.h b/src/graph/entities/node.h index 392702d8be..fc38d1895f 100644 --- a/src/graph/entities/node.h +++ b/src/graph/entities/node.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/graph/entities/qg_edge.c b/src/graph/entities/qg_edge.c index abfe424243..ca15cedd23 100644 --- a/src/graph/entities/qg_edge.c +++ b/src/graph/entities/qg_edge.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "qg_edge.h" #include "qg_node.h" diff --git a/src/graph/entities/qg_edge.h b/src/graph/entities/qg_edge.h index cc34fbc9f7..cdc980a580 100644 --- a/src/graph/entities/qg_edge.h +++ b/src/graph/entities/qg_edge.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/graph/entities/qg_node.c b/src/graph/entities/qg_node.c index 6f42d1f7b8..7ce92b9ea3 100644 --- a/src/graph/entities/qg_node.c +++ b/src/graph/entities/qg_node.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "qg_node.h" diff --git a/src/graph/entities/qg_node.h b/src/graph/entities/qg_node.h index dcc17ca28b..24dcc42912 100644 --- a/src/graph/entities/qg_node.h +++ b/src/graph/entities/qg_node.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/graph/graph.c b/src/graph/graph.c index f9d175a48a..b158a43c9d 100644 --- a/src/graph/graph.c +++ b/src/graph/graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "graph.h" @@ -100,15 +103,15 @@ static void _CollectEdgesFromEntry const Graph *g, NodeID src, NodeID dest, - int r, + RelationID r, EdgeID edgeId, Edge **edges ) { Edge e = {0}; - e.relationID = r; - e.srcNodeID = src; - e.destNodeID = dest; + e.src_id = src; + e.dest_id = dest; + e.relationID = r; if(SINGLE_EDGE(edgeId)) { e.id = edgeId; @@ -280,11 +283,13 @@ MATRIX_POLICY Graph_GetMatrixPolicy } // define the current behavior for matrix creations and retrievals on this graph -void Graph_SetMatrixPolicy +MATRIX_POLICY Graph_SetMatrixPolicy ( Graph *g, MATRIX_POLICY policy ) { + MATRIX_POLICY prev_policy = Graph_GetMatrixPolicy(g); + switch(policy) { case SYNC_POLICY_FLUSH_RESIZE: // Default behavior; forces execution of pending GraphBLAS operations @@ -303,6 +308,8 @@ void Graph_SetMatrixPolicy default: ASSERT(false); } + + return prev_policy; } // synchronize and resize all matrices in graph @@ -316,11 +323,8 @@ void Graph_ApplyAllPending uint n = 0; RG_Matrix M = NULL; - // backup previous sync policy - MATRIX_POLICY policy = Graph_GetMatrixPolicy(g); - - // set matrix sync policy - Graph_SetMatrixPolicy(g, SYNC_POLICY_FLUSH_RESIZE); + // set matrix sync policy, backup previous sync policy + MATRIX_POLICY policy = Graph_SetMatrixPolicy(g, SYNC_POLICY_FLUSH_RESIZE); //-------------------------------------------------------------------------- // sync every matrix @@ -446,10 +450,10 @@ Graph *Graph_New fpDestructor cb = (fpDestructor)AttributeSet_Free; Graph *g = rm_calloc(1, sizeof(Graph)); - g->nodes = DataBlock_New(node_cap, node_cap, sizeof(AttributeSet), cb); - g->edges = DataBlock_New(edge_cap, edge_cap, sizeof(AttributeSet), cb); - g->labels = array_new(RG_Matrix, GRAPH_DEFAULT_LABEL_CAP); - g->relations = array_new(RG_Matrix, GRAPH_DEFAULT_RELATION_TYPE_CAP); + g->nodes = DataBlock_New(node_cap, node_cap, sizeof(AttributeSet), cb); + g->edges = DataBlock_New(edge_cap, edge_cap, sizeof(AttributeSet), cb); + g->labels = array_new(RG_Matrix, GRAPH_DEFAULT_LABEL_CAP); + g->relations = array_new(RG_Matrix, GRAPH_DEFAULT_RELATION_TYPE_CAP); GrB_Info info; UNUSED(info); @@ -468,7 +472,7 @@ Graph *Graph_New g->_writelocked = false; // force GraphBLAS updates and resize matrices to node count by default - Graph_SetMatrixPolicy(g, SYNC_POLICY_FLUSH_RESIZE); + g->SynchronizeMatrix = _MatrixSynchronize; return g; } @@ -496,9 +500,9 @@ size_t Graph_UncompactedNodeCount(const Graph *g) { uint64_t Graph_LabeledNodeCount ( const Graph *g, - int label_idx + LabelID label ) { - return GraphStatistics_NodeCount(&g->stats, label_idx); + return GraphStatistics_NodeCount(&g->stats, label); } size_t Graph_EdgeCount(const Graph *g) { @@ -506,8 +510,12 @@ size_t Graph_EdgeCount(const Graph *g) { return g->edges->itemCount; } -uint64_t Graph_RelationEdgeCount(const Graph *g, int relation_idx) { - return GraphStatistics_EdgeCount(&g->stats, relation_idx); +uint64_t Graph_RelationEdgeCount +( + const Graph *g, + RelationID relation +) { + return GraphStatistics_EdgeCount(&g->stats, relation); } uint Graph_DeletedEdgeCount(const Graph *g) { @@ -564,7 +572,7 @@ bool Graph_GetEdge return (e->attributes != NULL); } -int Graph_GetEdgeRelation +RelationID Graph_GetEdgeRelation ( const Graph *g, Edge *e @@ -573,18 +581,17 @@ int Graph_GetEdgeRelation ASSERT(e); GrB_Info info; - int rel = GRAPH_NO_RELATION; - EdgeID id = ENTITY_GET_ID(e); - NodeID srcNodeID = Edge_GetSrcNodeID(e); - NodeID destNodeID = Edge_GetDestNodeID(e); + RelationID rel = GRAPH_NO_RELATION; + EdgeID id = ENTITY_GET_ID(e); + NodeID src_id = Edge_GetSrcNodeID(e); + NodeID dest_id = Edge_GetDestNodeID(e); // search for relation mapping matrix M, where M[dest,src] == edge ID uint n = array_len(g->relations); for(uint i = 0; i < n; i++) { EdgeID edgeId = 0; RG_Matrix M = Graph_GetRelationMatrix(g, i, false); - info = RG_Matrix_extractElement_UINT64(&edgeId, M, srcNodeID, - destNodeID); + info = RG_Matrix_extractElement_UINT64(&edgeId, M, src_id, dest_id); if(info != GrB_SUCCESS) continue; if(SINGLE_EDGE(edgeId)) { @@ -619,7 +626,7 @@ void Graph_GetEdgesConnectingNodes const Graph *g, NodeID srcID, NodeID destID, - int r, + RelationID r, Edge **edges ) { ASSERT(g); @@ -649,6 +656,32 @@ void Graph_GetEdgesConnectingNodes } } +void Graph_ResetReservedNode +( + Graph *g +) { + ASSERT(g != NULL); + g->reserved_node_count = 0; +} + +Node Graph_ReserveNode +( + Graph *g // graph for which nodes will be added +) { + ASSERT(g != NULL); + + // reserve node ID + NodeID id = DataBlock_GetReservedIdx(g->nodes, g->reserved_node_count); + + // increment reserved node count + g->reserved_node_count++; + + // create node + Node n = (Node) { .attributes = NULL, .id = id }; + + return n; +} + void Graph_CreateNode ( Graph *g, @@ -660,12 +693,16 @@ void Graph_CreateNode ASSERT(n != NULL); ASSERT(label_count == 0 || (label_count > 0 && labels != NULL)); - NodeID id; - AttributeSet *set = DataBlock_AllocateItem(g->nodes, &id); - *set = NULL; + NodeID id = n->id; // save node ID + n->attributes = DataBlock_AllocateItem(g->nodes, &n->id); + *n->attributes = NULL; // initialize attributes to NULL - n->id = id; - n->attributes = set; + // node ID was reserved, make reserved ID was assigned + if(id != INVALID_ENTITY_ID) { + ASSERT(id == n->id); + g->reserved_node_count--; + ASSERT(g->reserved_node_count >= 0); + } if(label_count > 0) { Graph_LabelNode(g, ENTITY_GET_ID(n), labels, label_count); @@ -794,7 +831,7 @@ void Graph_CreateEdge Graph *g, NodeID src, NodeID dest, - int r, + RelationID r, Edge *e ) { ASSERT(g != NULL); @@ -812,9 +849,9 @@ void Graph_CreateEdge *set = NULL; e->id = id; + e->src_id = src; + e->dest_id = dest; e->attributes = set; - e->srcNodeID = src; - e->destNodeID = dest; e->relationID = r; Graph_FormConnection(g, src, dest, id, r); @@ -824,11 +861,11 @@ void Graph_CreateEdge // to/from given node N, depending on given direction void Graph_GetNodeEdges ( - const Graph *g, // graph to collect edges from - const Node *n, // either source or destination node - GRAPH_EDGE_DIR dir, // edge direction ->, <-, <-> - int edgeType, // relationship type - Edge **edges // [output] array of edges + const Graph *g, // graph to collect edges from + const Node *n, // either source or destination node + GRAPH_EDGE_DIR dir, // edge direction ->, <-, <-> + RelationID edgeType, // relationship type + Edge **edges // [output] array of edges ) { ASSERT(g); ASSERT(n); @@ -914,7 +951,7 @@ uint64_t Graph_GetNodeDegree const Graph *g, // graph to inquery const Node *n, // node to get degree of GRAPH_EDGE_DIR dir, // incoming/outgoing/both - int edgeType // relation type + RelationID edgeType // relation type ) { ASSERT(g != NULL); ASSERT(n != NULL); @@ -1057,10 +1094,10 @@ void Graph_DeleteEdges ( Graph *g, Edge *edges, - uint64_t count + uint64_t n ) { ASSERT(g != NULL); - ASSERT(count > 0); + ASSERT(n > 0); ASSERT(edges != NULL); uint64_t x; @@ -1069,10 +1106,9 @@ void Graph_DeleteEdges GrB_Info info; bool entry_deleted; - MATRIX_POLICY policy = Graph_GetMatrixPolicy(g); - Graph_SetMatrixPolicy(g, SYNC_POLICY_NOP); + MATRIX_POLICY policy = Graph_SetMatrixPolicy(g, SYNC_POLICY_NOP); - for (uint i = 0; i < count; i++) { + for (uint i = 0; i < n; i++) { Edge *e = edges + i; int r = Edge_GetRelationID(e); NodeID src_id = Edge_GetSrcNodeID(e); @@ -1126,6 +1162,11 @@ inline bool Graph_EntityIsDeleted ( const GraphEntity *e ) { + if(e->attributes == NULL) { + // most likely an entity which wasn't created just yet (reserved) + return false; + } + return DataBlock_ItemIsDeleted(e->attributes); } @@ -1137,39 +1178,6 @@ static void _Graph_FreeRelationMatrices for(uint i = 0; i < relationCount; i++) RG_Matrix_free(&g->relations[i]); } -// update entity's attribute with given value -int Graph_UpdateEntity -( - GraphEntity *ge, // entity to update - Attribute_ID attr_id, // attribute to update - SIValue value, // value to be set - GraphEntityType entity_type // type of the entity node/edge -) { - ASSERT(ge != NULL); - - int res = 0; - - // handle the case in which we are deleting all attributes - if(attr_id == ATTRIBUTE_ID_ALL) { - return GraphEntity_ClearAttributes(ge); - } - - // try to get current attribute value - SIValue *old_value = GraphEntity_GetProperty(ge, attr_id); - - if(old_value == ATTRIBUTE_NOTFOUND) { - // adding a new attribute; do nothing if its value is NULL - if(SI_TYPE(value) != T_NULL) { - res = GraphEntity_AddProperty(ge, attr_id, value); - } - } else { - // update attribute - res = GraphEntity_SetProperty(ge, attr_id, value); - } - - return res; -} - DataBlockIterator *Graph_ScanNodes(const Graph *g) { ASSERT(g); return DataBlock_Scan(g->nodes); @@ -1180,7 +1188,7 @@ DataBlockIterator *Graph_ScanEdges(const Graph *g) { return DataBlock_Scan(g->edges); } -int Graph_AddLabel +LabelID Graph_AddLabel ( Graph *g ) { @@ -1196,29 +1204,30 @@ int Graph_AddLabel // adding a new label, update the stats structures to support it GraphStatistics_IntroduceLabel(&g->stats); - int labelID = Graph_LabelTypeCount(g) - 1; - return labelID; + LabelID l = Graph_LabelTypeCount(g) - 1; + return l; } void Graph_RemoveLabel ( Graph *g, - int label_id + LabelID label_id ) { ASSERT(g != NULL); ASSERT(label_id == Graph_LabelTypeCount(g) - 1); + #ifdef RG_DEBUG GrB_Index nvals; GrB_Info info = RG_Matrix_nvals(&nvals, g->labels[label_id]); ASSERT(info == GrB_SUCCESS); ASSERT(nvals == 0); #endif + RG_Matrix_free(&g->labels[label_id]); g->labels = array_del(g->labels, label_id); } - -int Graph_AddRelationType +RelationID Graph_AddRelationType ( Graph *g ) { @@ -1234,7 +1243,7 @@ int Graph_AddRelationType // adding a new relationship type, update the stats structures to support it GraphStatistics_IntroduceRelationship(&g->stats); - int relationID = Graph_RelationTypeCount(g) - 1; + RelationID relationID = Graph_RelationTypeCount(g) - 1; return relationID; } @@ -1258,23 +1267,24 @@ void Graph_RemoveRelation RG_Matrix Graph_GetLabelMatrix ( const Graph *g, - int label_idx + LabelID label_idx ) { ASSERT(g != NULL); - ASSERT(label_idx < (int)array_len(g->labels)); + ASSERT(label_idx < Graph_LabelTypeCount(g)); // return zero matrix if label_idx is out of range if(label_idx < 0) return Graph_GetZeroMatrix(g); RG_Matrix m = g->labels[label_idx]; g->SynchronizeMatrix(g, m); + return m; } RG_Matrix Graph_GetRelationMatrix ( const Graph *g, - int relation_idx, + RelationID relation_idx, bool transposed ) { ASSERT(g); @@ -1309,7 +1319,7 @@ RG_Matrix Graph_GetAdjacencyMatrix bool Graph_RelationshipContainsMultiEdge ( const Graph *g, - int r, + RelationID r, bool transpose ) { ASSERT(Graph_RelationTypeCount(g) > r); diff --git a/src/graph/graph.h b/src/graph/graph.h index 494a78a4ef..c973c47ad9 100644 --- a/src/graph/graph.h +++ b/src/graph/graph.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -18,12 +21,12 @@ #include "../util/datablock/datablock_iterator.h" #include "../../deps/GraphBLAS/Include/GraphBLAS.h" -#define GRAPH_DEFAULT_RELATION_TYPE_CAP 16 // Default number of different relationship types a graph can hold before resizing. -#define GRAPH_DEFAULT_LABEL_CAP 16 // Default number of different labels a graph can hold before resizing. -#define GRAPH_NO_LABEL -1 // Labels are numbered [0-N], -1 represents no label. -#define GRAPH_UNKNOWN_LABEL -2 // Labels are numbered [0-N], -2 represents an unknown relation. -#define GRAPH_NO_RELATION -1 // Relations are numbered [0-N], -1 represents no relation. -#define GRAPH_UNKNOWN_RELATION -2 // Relations are numbered [0-N], -2 represents an unknown relation. +#define GRAPH_DEFAULT_RELATION_TYPE_CAP 16 // default number of different relationship types a graph can hold before resizing. +#define GRAPH_DEFAULT_LABEL_CAP 16 // default number of different labels a graph can hold before resizing. +#define GRAPH_NO_LABEL -1 // labels are numbered [0-N], -1 represents no label. +#define GRAPH_UNKNOWN_LABEL -2 // labels are numbered [0-N], -2 represents an unknown relation. +#define GRAPH_NO_RELATION -1 // relations are numbered [0-N], -1 represents no relation. +#define GRAPH_UNKNOWN_RELATION -2 // relations are numbered [0-N], -2 represents an unknown relation. typedef enum { GRAPH_EDGE_DIR_INCOMING, @@ -44,17 +47,18 @@ typedef struct Graph Graph; typedef void (*SyncMatrixFunc)(const Graph *, RG_Matrix); struct Graph { - DataBlock *nodes; // graph nodes stored in blocks - DataBlock *edges; // graph edges stored in blocks - RG_Matrix adjacency_matrix; // adjacency matrix, holds all graph connections - RG_Matrix *labels; // label matrices - RG_Matrix node_labels; // mapping of all node IDs to all labels possessed by each node - RG_Matrix *relations; // relation matrices - RG_Matrix _zero_matrix; // zero matrix - pthread_rwlock_t _rwlock; // read-write lock scoped to this specific graph - bool _writelocked; // true if the read-write lock was acquired by a writer - SyncMatrixFunc SynchronizeMatrix; // function pointer to matrix synchronization routine - GraphStatistics stats; // graph related statistics + int reserved_node_count; // number of nodes not commited yet + DataBlock *nodes; // graph nodes stored in blocks + DataBlock *edges; // graph edges stored in blocks + RG_Matrix adjacency_matrix; // adjacency matrix, holds all graph connections + RG_Matrix *labels; // label matrices + RG_Matrix node_labels; // mapping of all node IDs to all labels possessed by each node + RG_Matrix *relations; // relation matrices + RG_Matrix _zero_matrix; // zero matrix + pthread_rwlock_t _rwlock; // read-write lock scoped to this specific graph + bool _writelocked; // true if the read-write lock was acquired by a writer + SyncMatrixFunc SynchronizeMatrix; // function pointer to matrix synchronization routine + GraphStatistics stats; // graph related statistics }; // graph synchronization functions @@ -78,13 +82,6 @@ void Graph_ReleaseLock Graph *g ); -// choose the current matrix synchronization policy -void Graph_SetMatrixPolicy -( - Graph *g, - MATRIX_POLICY policy -); - // synchronize and resize all matrices in graph void Graph_ApplyAllPending ( @@ -99,7 +96,7 @@ MATRIX_POLICY Graph_GetMatrixPolicy ); // choose the current matrix synchronization policy -void Graph_SetMatrixPolicy +MATRIX_POLICY Graph_SetMatrixPolicy ( Graph *g, MATRIX_POLICY policy @@ -119,7 +116,7 @@ Graph *Graph_New ); // creates a new label matrix, returns id given to label -int Graph_AddLabel +LabelID Graph_AddLabel ( Graph *g ); @@ -128,7 +125,7 @@ int Graph_AddLabel void Graph_RemoveLabel ( Graph *g, - int label_id + LabelID label_id ); // label node with each label in 'lbls' @@ -158,7 +155,7 @@ bool Graph_IsNodeLabeled ); // creates a new relation matrix, returns id given to relation -int Graph_AddRelationType +RelationID Graph_AddRelationType ( Graph *g ); @@ -184,6 +181,16 @@ void Graph_AllocateEdges size_t n // number of edges to create ); +void Graph_ResetReservedNode +( + Graph *g +); + +Node Graph_ReserveNode +( + Graph *g // graph for which nodes will be added +); + // Create a single node and labels it accordingly. // Return newly created node. void Graph_CreateNode @@ -201,7 +208,7 @@ void Graph_CreateEdge Graph *g, // graph on which to operate NodeID src, // source node ID NodeID dest, // destination node ID - int r, // edge type + RelationID r, // edge type Edge *e ); @@ -218,16 +225,7 @@ void Graph_DeleteEdges ( Graph *g, Edge *edges, - uint64_t count -); - -// update entity attribute with new value -int Graph_UpdateEntity -( - GraphEntity *ge, // entity yo update - Attribute_ID attr_id, // attribute to update - SIValue value, // value to be set - GraphEntityType entity_type // type of the entity node/edge + uint64_t n ); // returns true if the given entity has been deleted @@ -317,9 +315,9 @@ int Graph_LabelTypeCount // false otherwise bool Graph_RelationshipContainsMultiEdge ( - const Graph *g, // Graph containing matrix to inspect - int r, // Relationship ID - bool transpose // false for R, true for transpose R + const Graph *g, // Graph containing matrix to inspect + RelationID r, // Relationship ID + bool transpose // false for R, true for transpose R ); // retrieves node with given id from graph, @@ -342,7 +340,7 @@ bool Graph_GetEdge // retrieves edge relation type // returns GRAPH_NO_RELATION if edge has no relation type -int Graph_GetEdgeRelation +RelationID Graph_GetEdgeRelation ( const Graph *g, Edge *e @@ -356,7 +354,7 @@ void Graph_GetEdgesConnectingNodes const Graph *g, // Graph to get edges from. NodeID srcID, // Source node of edge NodeID destID, // Destination node of edge - int r, // Edge type. + RelationID r, // Edge type. Edge **edges // array_t of edges connecting src to dest of type r. ); @@ -366,7 +364,7 @@ void Graph_GetNodeEdges const Graph *g, // graph to get edges from const Node *n, // node to extract edges from GRAPH_EDGE_DIR dir, // edge direction - int edgeType, // relation type + RelationID edgeType, // relation type Edge **edges // array_t incoming/outgoing edges ); @@ -376,7 +374,7 @@ uint64_t Graph_GetNodeDegree const Graph *g, // graph to inquery const Node *n, // node to get degree of GRAPH_EDGE_DIR dir, // incoming/outgoing/both - int edgeType // relation type + RelationID edgeType // relation type ); // populate array of node's label IDs, return number of labels on node. diff --git a/src/graph/graph_delete_nodes.c b/src/graph/graph_delete_nodes.c index bfea685b80..a0aecec7a6 100644 --- a/src/graph/graph_delete_nodes.c +++ b/src/graph/graph_delete_nodes.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "graph.h" @@ -44,14 +47,14 @@ void Graph_DeleteNodes Graph_SetMatrixPolicy(g, SYNC_POLICY_NOP); #if RG_DEBUG + Edge *es = array_new(Edge, 0); for(uint i = 0; i < count; i++) { Node *n = nodes + i; // validate assumption - Edge *es = array_new(Edge, 0); Graph_GetNodeEdges(g, n, GRAPH_EDGE_DIR_BOTH, GRAPH_NO_RELATION, &es); ASSERT(array_len(es) == 0); - array_free(es); } + array_free(es); #endif //-------------------------------------------------------------------------- @@ -131,7 +134,8 @@ void Graph_DeleteNodes GrB_ALL, ncols, GrB_DESC_S); ASSERT(info == GrB_SUCCESS); - info = GrB_Matrix_assign(DM, lbls_mask, NULL, M, GrB_ALL, nrows, GrB_ALL, nrows, GrB_DESC_S); + info = GrB_Matrix_assign(DM, lbls_mask, NULL, M, GrB_ALL, nrows, GrB_ALL, + ncols, GrB_DESC_S); ASSERT(info == GrB_SUCCESS); // mark labels matrix as dirty diff --git a/src/graph/graph_hub.c b/src/graph/graph_hub.c index db0ca33b9a..7f99008167 100644 --- a/src/graph/graph_hub.c +++ b/src/graph/graph_hub.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "graph_hub.h" #include "../query_ctx.h" @@ -43,7 +46,7 @@ static void _DeleteEdgeFromIndices Schema *s = NULL; Graph *g = gc->g; - int relation_id = EDGE_GET_RELATION_ID(e, g); + int relation_id = Edge_GetRelationID(e); s = GraphContext_GetSchemaByID(gc, relation_id, SCHEMA_EDGE); @@ -81,22 +84,25 @@ static void _AddEdgeToIndices(GraphContext *gc, Edge *e) { Schema *s = NULL; Graph *g = gc->g; - int relation_id = EDGE_GET_RELATION_ID(e, g); + int relation_id = Edge_GetRelationID(e); s = GraphContext_GetSchemaByID(gc, relation_id, SCHEMA_EDGE); + ASSERT(s != NULL); + Schema_AddEdgeToIndices(s, e); } -uint CreateNode +void CreateNode ( GraphContext *gc, Node *n, LabelID *labels, uint label_count, - AttributeSet set + AttributeSet set, + bool log ) { + ASSERT(n != NULL); ASSERT(gc != NULL); - ASSERT(n != NULL); Graph_CreateNode(gc->g, n, labels, label_count); *n->attributes = set; @@ -109,135 +115,110 @@ uint CreateNode } // add node creation operation to undo log - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); - UndoLog_CreateNode(&query_ctx->undo_log, n); - - return ATTRIBUTE_SET_COUNT(set); + if(log == true) { + UndoLog undo_log = QueryCtx_GetUndoLog(); + UndoLog_CreateNode(undo_log, n); + EffectsBuffer *eb = QueryCtx_GetEffectsBuffer(); + EffectsBuffer_AddCreateNodeEffect(eb, n, labels, label_count); + } } -uint CreateEdge +void CreateEdge ( GraphContext *gc, Edge *e, NodeID src, NodeID dst, - int r, - AttributeSet set + RelationID r, + AttributeSet set, + bool log ) { + ASSERT(e != NULL); ASSERT(gc != NULL); - ASSERT(e != NULL); Graph_CreateEdge(gc->g, src, dst, r, e); *e->attributes = set; - Schema *s = GraphContext_GetSchema(gc, e->relationship, SCHEMA_EDGE); + Schema *s = GraphContext_GetSchemaByID(gc, r, SCHEMA_EDGE); // all schemas have been created in the edge blueprint loop or earlier ASSERT(s != NULL); Schema_AddEdgeToIndices(s, e); // add edge creation operation to undo log - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); - UndoLog_CreateEdge(&query_ctx->undo_log, e); - - return ATTRIBUTE_SET_COUNT(set); + if(log == true) { + UndoLog undo_log = QueryCtx_GetUndoLog(); + UndoLog_CreateEdge(undo_log, e); + EffectsBuffer *eb = QueryCtx_GetEffectsBuffer(); + EffectsBuffer_AddCreateEdgeEffect(eb, e); + } } +// delete a node +// remove the node from the relevant indexes +// add node deletion operation to undo-log +// return 1 on success, 0 otherwise void DeleteNodes ( GraphContext *gc, Node *nodes, - uint count + uint n, + bool log ) { ASSERT(gc != NULL); ASSERT(nodes != NULL); - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); bool has_indices = GraphContext_HasIndices(gc); - for(uint i = 0; i < count; i++) { + UndoLog undo_log = (log) ? QueryCtx_GetUndoLog() : NULL; + EffectsBuffer *eb = (log) ? QueryCtx_GetEffectsBuffer() : NULL; + for(uint i = 0; i < n; i++) { Node *n = nodes + i; - // add node deletion operation to undo log - UndoLog_DeleteNode(&query_ctx->undo_log, n); + + if(log) { + // add node deletion operation to undo log + UndoLog_DeleteNode(undo_log, n); + EffectsBuffer_AddDeleteNodeEffect(eb, n); + } if(has_indices) { _DeleteNodeFromIndices(gc, n); } } - Graph_DeleteNodes(gc->g, nodes, count); + Graph_DeleteNodes(gc->g, nodes, n); } void DeleteEdges ( GraphContext *gc, Edge *edges, - uint64_t count + uint64_t n, + bool log ) { ASSERT(gc != NULL); - ASSERT(count > 0); + ASSERT(n > 0); ASSERT(edges != NULL); // add edge deletion operation to undo log bool has_indecise = GraphContext_HasIndices(gc); - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); - for (uint i = 0; i < count; i++) { - UndoLog_DeleteEdge(&query_ctx->undo_log, edges + i); - if(has_indecise) { - _DeleteEdgeFromIndices(gc, edges + i); - } - } + UndoLog undo_log = (log == true) ? QueryCtx_GetUndoLog() : NULL; + EffectsBuffer *eb = (log == true) ? QueryCtx_GetEffectsBuffer() : NULL; - Graph_DeleteEdges(gc->g, edges, count); -} + if(has_indecise == true || log == true) { + for (uint i = 0; i < n; i++) { + if(log == true) { + UndoLog_DeleteEdge(undo_log, edges + i); + EffectsBuffer_AddDeleteEdgeEffect(eb, edges + i); + } -// update entity attributes and update undo log -// in case attr_id is ATTRIBUTE_ID_ALL clear all attributes values -static void _Update_Entity_Property -( - GraphContext *gc, - GraphEntity *ge, - Attribute_ID attr_id, - SIValue new_value, - GraphEntityType entity_type, - uint *props_set_count, - uint *props_removed_count -) { - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); - if(attr_id == ATTRIBUTE_ID_ALL) { - // we're requested to clear entitiy's attribute-set - // backup entity's attributes in case we'll need to roolback - const AttributeSet set = GraphEntity_GetAttributes(ge); - for(int i = 0; i < ATTRIBUTE_SET_COUNT(set); i++) { - Attribute_ID id; - // add entity update operation to undo log - SIValue value = AttributeSet_GetIdx(set, i, &id); - UndoLog_UpdateEntity(&query_ctx->undo_log, ge, id, value, - entity_type); + if(has_indecise == true) { + _DeleteEdgeFromIndices(gc, edges + i); + } } - } else { - SIValue *orig_value = GraphEntity_GetProperty(ge, attr_id); - // add entity update operation to undo log - UndoLog_UpdateEntity(&query_ctx->undo_log, ge, attr_id, *orig_value, - entity_type); } - // update the property and set the appropriate counter. - SIValue *old_value = GraphEntity_GetProperty(ge, attr_id); - int updates = Graph_UpdateEntity(ge, attr_id, new_value, entity_type); - - if(SIValue_IsNull(new_value)) { - // removal of an attribute. In case the attribute is not present, - // the update will not be counted (Graph_UpdateEntity logic). - *props_removed_count = updates; - } else { - // addition of an attribte - *props_set_count = updates; - // overwrite exiting attribute is considered a removal - if(old_value != ATTRIBUTE_NOTFOUND) { - *props_removed_count = updates; - } - } + Graph_DeleteEdges(gc->g, edges, n); } // updates a graph entity attribute set. Returns as out params the number @@ -248,37 +229,97 @@ void UpdateEntityProperties GraphEntity *ge, // updated entity const AttributeSet set, // new attributes GraphEntityType entity_type, // entity type - uint *props_set_count, // number of attributes set - uint *props_removed_count // number of attributes removed + bool log // log update in undo-log ) { ASSERT(gc != NULL); ASSERT(ge != NULL); - ASSERT(props_set_count != NULL); - ASSERT(props_removed_count != NULL); - - int set_props = 0; - int removed_props = 0; - for (uint i = 0; i < ATTRIBUTE_SET_COUNT(set); i++) { - Attribute *prop = set->attributes + i; - uint _set_props = 0; - uint _removed_props = 0; + AttributeSet old_set = GraphEntity_GetAttributes(ge); - _Update_Entity_Property(gc, ge, prop->id, prop->value, entity_type, - &_set_props, &_removed_props); - - set_props += _set_props; - removed_props += _removed_props; + if(log == true) { + UndoLog log = QueryCtx_GetUndoLog(); + UndoLog_UpdateEntity(log, ge, old_set, entity_type); } + *ge->attributes = set; + if(entity_type == GETYPE_NODE) { _AddNodeToIndices(gc, (Node *)ge); } else { _AddEdgeToIndices(gc, (Edge *)ge); } +} + +void UpdateNodeProperty +( + GraphContext *gc, // graph context + NodeID id, // node ID + Attribute_ID attr_id, // attribute ID + SIValue v // new attribute value +) { + Node n; + int res = Graph_GetNode(gc->g, id, &n); + + // make sure entity was found + UNUSED(res); + ASSERT(res == true); + + if(attr_id == ATTRIBUTE_ID_ALL) { + AttributeSet_Free(n.attributes); + } else if(GraphEntity_GetProperty((GraphEntity *)&n, attr_id) == ATTRIBUTE_NOTFOUND) { + AttributeSet_AddNoClone(n.attributes, &attr_id, &v, 1, true); + } else { + AttributeSet_UpdateNoClone(n.attributes, attr_id, v); + } + + // retrieve node labels + uint label_count; + NODE_GET_LABELS(gc->g, &n, label_count); + + Schema *s; + for(uint i = 0; i < label_count; i++) { + int label_id = labels[i]; + s = GraphContext_GetSchemaByID(gc, label_id, SCHEMA_NODE); + ASSERT(s != NULL); + Schema_AddNodeToIndices(s, &n); + } +} - *props_set_count = set_props; - *props_removed_count = removed_props; +void UpdateEdgeProperty +( + GraphContext *gc, // graph context + EdgeID id, // edge ID + RelationID r_id, // relation ID + NodeID src_id, // source node ID + NodeID dest_id, // destination node ID + Attribute_ID attr_id, // attribute ID + SIValue v // new attribute value +) { + Edge e; // edge to delete + + // get src node, dest node and edge from the graph + int res; + UNUSED(res); + + res = Graph_GetEdge(gc->g, id, &e); + ASSERT(res != 0); + + // set edge relation, src and destination node + Edge_SetSrcNodeID(&e, src_id); + Edge_SetDestNodeID(&e, dest_id); + Edge_SetRelationID(&e, r_id); + + if(attr_id == ATTRIBUTE_ID_ALL) { + AttributeSet_Free(e.attributes); + } else if(GraphEntity_GetProperty((GraphEntity *)&e, attr_id) == ATTRIBUTE_NOTFOUND) { + AttributeSet_AddNoClone(e.attributes, &attr_id, &v, 1, true); + } else { + AttributeSet_UpdateNoClone(e.attributes, attr_id, v); + } + + Schema *schema = GraphContext_GetSchemaByID(gc, r_id, SCHEMA_EDGE); + ASSERT(schema != NULL); + Schema_AddEdgeToIndices(schema, &e); } void UpdateNodeLabels @@ -287,8 +328,9 @@ void UpdateNodeLabels Node *node, // the node to be updated const char **add_labels, // labels to add to the node const char **remove_labels, // labels to add to the node - uint *labels_added_count, // number of labels added (out param) - uint *labels_removed_count // number of labels removed (out param) + uint n_add_labels, // number of labels to add + uint n_remove_labels, // number of labels to remove + bool log // log this operation in undo-log ) { ASSERT(gc != NULL); ASSERT(node != NULL); @@ -298,28 +340,43 @@ void UpdateNodeLabels return; } - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); + // if add_labels is specified its count must be > 0 + ASSERT((add_labels != NULL && n_add_labels > 0) || + (add_labels == NULL && n_add_labels == 0)); + + // if remove_labels is specified its count must be > 0 + ASSERT((remove_labels != NULL && n_remove_labels > 0) || + (remove_labels == NULL && n_remove_labels == 0)); + + EffectsBuffer *eb = NULL; + UndoLog undo_log = NULL; + + if(log == true) { + eb = QueryCtx_GetEffectsBuffer(); + undo_log = QueryCtx_GetUndoLog(); + } if(add_labels != NULL) { - uint label_count = array_len(add_labels); - int add_labels_ids[label_count]; + int add_labels_ids[n_add_labels]; uint add_labels_index = 0; - for (uint i = 0; i < label_count; i++) { + for (uint i = 0; i < n_add_labels; i++) { const char *label = add_labels[i]; // get or create label matrix const Schema *s = GraphContext_GetSchema(gc, label, SCHEMA_NODE); bool schema_created = false; if(s == NULL) { - s = AddSchema(gc, label, SCHEMA_NODE); + s = AddSchema(gc, label, SCHEMA_NODE, log); schema_created = true; } int schema_id = Schema_GetID(s); - bool node_labeled = Graph_IsNodeLabeled(gc->g, node->id, schema_id); + bool node_labeled = Graph_IsNodeLabeled(gc->g, ENTITY_GET_ID(node), + schema_id); if(!node_labeled) { - // sync matrix, make sure label matrix is of the right dimensions + // sync matrix + // make sure label matrix is of the right dimensions if(schema_created) { RG_Matrix m = Graph_GetLabelMatrix(gc->g, schema_id); } @@ -331,20 +388,23 @@ void UpdateNodeLabels } if(add_labels_index > 0) { - *labels_added_count = add_labels_index; - // update node's labels - Graph_LabelNode(gc->g, node->id ,add_labels_ids, add_labels_index); - UndoLog_AddLabels(&query_ctx->undo_log, node, add_labels_ids, add_labels_index); + Graph_LabelNode(gc->g, ENTITY_GET_ID(node), add_labels_ids, + add_labels_index); + if(log == true) { + UndoLog_AddLabels(undo_log, node, add_labels_ids, + add_labels_index); + EffectsBuffer_AddLabelsEffect(eb, node, add_labels_ids, + add_labels_index); + } } } if(remove_labels != NULL) { - uint label_count = array_len(remove_labels); - int remove_labels_ids[label_count]; + int remove_labels_ids[n_remove_labels]; uint remove_labels_index = 0; - for (uint i = 0; i < label_count; i++) { + for (uint i = 0; i < n_remove_labels; i++) { const char *label = remove_labels[i]; // label removal @@ -355,6 +415,11 @@ void UpdateNodeLabels continue; } + if(!Graph_IsNodeLabeled(gc->g, ENTITY_GET_ID(node), Schema_GetID(s))) { + // skip removal of none existing label + continue; + } + // append label id remove_labels_ids[remove_labels_index++] = Schema_GetID(s); // remove node from index @@ -362,46 +427,61 @@ void UpdateNodeLabels } if(remove_labels_index > 0) { - *labels_removed_count = remove_labels_index; - // update node's labels - Graph_RemoveNodeLabels(gc->g, ENTITY_GET_ID(node), remove_labels_ids, - remove_labels_index); - UndoLog_RemoveLabels(&query_ctx->undo_log, node, remove_labels_ids, remove_labels_index); + Graph_RemoveNodeLabels(gc->g, ENTITY_GET_ID(node), + remove_labels_ids, remove_labels_index); + if(log == true) { + UndoLog_RemoveLabels(undo_log, node, remove_labels_ids, + remove_labels_index); + EffectsBuffer_AddRemoveLabelsEffect(eb, node, remove_labels_ids, + remove_labels_index); + } } } } - Schema *AddSchema ( - GraphContext *gc, // graph context to add the schema - const char *label, // schema label - SchemaType t // schema type (node/edge) + GraphContext *gc, // graph context to add the schema + const char *label, // schema label + SchemaType t, // schema type (node/edge) + bool log // should operation be logged in the undo-log ) { ASSERT(gc != NULL); ASSERT(label != NULL); - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); Schema *s = GraphContext_AddSchema(gc, label, t); - UndoLog_AddSchema(&query_ctx->undo_log, s->id, s->type); + + if(log == true) { + UndoLog undo_log = QueryCtx_GetUndoLog(); + UndoLog_AddSchema(undo_log, s->id, s->type); + EffectsBuffer *eb = QueryCtx_GetEffectsBuffer(); + EffectsBuffer_AddNewSchemaEffect(eb, Schema_GetName(s), s->type); + } + return s; } Attribute_ID FindOrAddAttribute ( - GraphContext *gc, // graph context to add the attribute - const char *attribute // attribute name + GraphContext *gc, // graph context to add the attribute + const char *attribute, // attribute name + bool log // should operation be logged in the undo-log ) { ASSERT(gc != NULL); ASSERT(attribute != NULL); bool created; - Attribute_ID attr_id = GraphContext_FindOrAddAttribute(gc, attribute, &created); - // In case there was an append, the latest id should be tracked - if(created) { - QueryCtx *query_ctx = QueryCtx_GetQueryCtx(); - UndoLog_AddAttribute(&query_ctx->undo_log, attr_id); + Attribute_ID attr_id = GraphContext_FindOrAddAttribute(gc, attribute, + &created); + + // in case there was an append, the latest id should be tracked + if(created == true && log == true) { + UndoLog undo_log = QueryCtx_GetUndoLog(); + UndoLog_AddAttribute(undo_log, attr_id); + EffectsBuffer *eb = QueryCtx_GetEffectsBuffer(); + EffectsBuffer_AddNewAttributeEffect(eb, attribute); } + return attr_id; } diff --git a/src/graph/graph_hub.h b/src/graph/graph_hub.h index e06122ecfc..693f36b3bd 100644 --- a/src/graph/graph_hub.h +++ b/src/graph/graph_hub.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -15,29 +18,29 @@ // set the node labels and attributes // add the node to the relevant indexes // add node creation operation to undo-log -// return the # of attributes set -uint CreateNode +void CreateNode ( - GraphContext *gc, // graph context to create the node - Node *n, // output node created - LabelID *labels, // node labels - uint label_count, // labels count - AttributeSet set // node attributes + GraphContext *gc, // graph context to create the node + Node *n, // output node created + LabelID *labels, // node labels + uint label_count, // labels count + AttributeSet set, // node attributes + bool log // log operation in undo-log ); // create an edge // set the edge src, dst endpoints and attributes // add the edge to the relevant indexes // add edge creation operation to undo-log -// return the # of attributes set -uint CreateEdge +void CreateEdge ( - GraphContext *gc, // graph context to create the edge - Edge *e, // output edge created - NodeID src, // edge source - NodeID dst, // edge destination - int r, // edge relation type - AttributeSet set // edge attributes + GraphContext *gc, // graph context to create the edge + Edge *e, // output edge created + NodeID src, // edge source + NodeID dst, // edge destination + RelationID r, // edge relation type + AttributeSet set, // edge attributes + bool log // log operation in undo-log ); // delete nodes @@ -47,7 +50,8 @@ void DeleteNodes ( GraphContext *gc, // graph context to delete the node Node *nodes, // nodes to be deleted - uint count // number of nodes to delete + uint n, // number of nodes to delete + bool log // log operations in undo-log ); // delete an edge @@ -58,7 +62,8 @@ void DeleteEdges ( GraphContext *gc, // graph context to delete the edge Edge *edges, // the edge to be deleted - uint64_t count // number of edges to delete + uint64_t n, // number of edges to delete + bool log // log operations in undo-log ); // update an entity(node/edge) @@ -71,10 +76,35 @@ void UpdateEntityProperties GraphEntity *ge, // the entity to be updated const AttributeSet set, // attributes to update GraphEntityType entity_type, // the entity type (node/edge) - uint *props_set_count, // number of properties set (out param) - uint *props_removed_count // number of properties removed (out param) + bool log // log this operation in undo-log ); +// update a node +// update the node attributes +// update the relevant indexes of the node +// used from effects +void UpdateNodeProperty +( + GraphContext *gc, // graph context + NodeID id, // node ID + Attribute_ID attr_id, // attribute ID + SIValue v // new attribute value +); + +// update an edge +// update the edge attributes +// update the relevant indexes of the edge +// used from effects +void UpdateEdgeProperty +( + GraphContext *gc, // graph context + EdgeID id, // edge ID + RelationID r_id, // relation ID + NodeID src_id, // source node ID + NodeID dest_id, // destination node ID + Attribute_ID attr_id, // attribute ID + SIValue v // new attribute value +); // this function sets the labels given in the rax "labels" to the given node // creates the label matrix if not exists @@ -86,23 +116,27 @@ void UpdateNodeLabels Node *node, // the node to be updated const char **add_labels, // labels to add to the node const char **remove_labels, // labels to add to the node - uint *labels_added_count, // number of labels added (out param) - uint *labels_removed_count // number of labels removed (out param) + uint n_add_labels, // number of labels to add + uint n_remove_labels, // number of labels to remove + bool log // log this operation in undo-log ); // Adds a schema to the graph. The schema is tracked by the undo log // so in case of error it will be deleted. Schema *AddSchema ( - GraphContext *gc, // graph context to add the schema - const char *label, // schema label - SchemaType t // schema type (node/edge) + GraphContext *gc, // graph context to add the schema + const char *label, // schema label + SchemaType t, // schema type (node/edge) + bool log // should operation be logged in the undo-log ); // Find or adding attribute. If there is a need to add an attribute to the graph // the attribute is tracked by the undo log so in case of error it will be deleted. Attribute_ID FindOrAddAttribute ( - GraphContext *gc, // graph context to add the attribute - const char *attribute // attribute name + GraphContext *gc, // graph context to add the attribute + const char *attribute, // attribute name + bool log // should operation be logged in the undo-log ); + diff --git a/src/graph/graph_statistics.c b/src/graph/graph_statistics.c index b6a551b61f..84212c4337 100644 --- a/src/graph/graph_statistics.c +++ b/src/graph/graph_statistics.c @@ -1,45 +1,74 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "graph_statistics.h" // Initialize the node_count and edge_count arrays -void GraphStatistics_init(GraphStatistics *stats) { +void GraphStatistics_init +( + GraphStatistics *stats +) { ASSERT(stats); stats->node_count = array_new(uint64_t, 0); stats->edge_count = array_new(uint64_t, 0); } -void GraphStatistics_IntroduceRelationship(GraphStatistics *stats) { +void GraphStatistics_IntroduceRelationship +( + GraphStatistics *stats +) { ASSERT(stats && stats->edge_count); array_append(stats->edge_count, 0); } -void GraphStatistics_IntroduceLabel(GraphStatistics *stats) { +void GraphStatistics_IntroduceLabel +( + GraphStatistics *stats +) { ASSERT(stats && stats->node_count); array_append(stats->node_count, 0); } -uint64_t GraphStatistics_EdgeCount(const GraphStatistics *stats, - int relation_idx) { - ASSERT(stats); - ASSERT(relation_idx < array_len(stats->edge_count)); - return stats->edge_count[relation_idx]; +uint64_t GraphStatistics_EdgeCount +( + const GraphStatistics *stats, + RelationID r +) { + ASSERT(stats != NULL); + ASSERT(r < ((RelationID)array_len(stats->edge_count))); + + if(r < 0) { + return 0; + } + + return stats->edge_count[r]; } -uint64_t GraphStatistics_NodeCount(const GraphStatistics *stats, - int label_idx) { - ASSERT(stats); - ASSERT(label_idx < (int)array_len(stats->node_count)); +uint64_t GraphStatistics_NodeCount +( + const GraphStatistics *stats, + LabelID l +) { + ASSERT(stats != NULL); + ASSERT(l < ((LabelID)array_len(stats->node_count))); + + if(l < 0) { + return 0; + } - if(label_idx < 0) return 0; - return stats->node_count[label_idx]; + return stats->node_count[l]; } -void GraphStatistics_FreeInternals(GraphStatistics *stats) { +void GraphStatistics_FreeInternals +( + GraphStatistics *stats +) { ASSERT(stats); if(stats->node_count) array_free(stats->node_count); if(stats->edge_count) array_free(stats->edge_count); diff --git a/src/graph/graph_statistics.h b/src/graph/graph_statistics.h index 9e6b1263f8..38260339f2 100644 --- a/src/graph/graph_statistics.h +++ b/src/graph/graph_statistics.h @@ -1,68 +1,105 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include #include "../util/arr.h" +#include "entities/node.h" +#include "entities/edge.h" -// Graph related statistics +// graph related statistics typedef struct { - uint64_t *node_count; // Array of node count per label matrix - uint64_t *edge_count; // Array of edge count per relationship matrix + uint64_t *node_count; // array of node count per label matrix + uint64_t *edge_count; // array of edge count per relationship matrix } GraphStatistics; -// Initialize the node_count and edge_count arrays -void GraphStatistics_init(GraphStatistics *stats); +// initialize the node_count and edge_count arrays +void GraphStatistics_init +( + GraphStatistics *stats +); -// New relationship is added, resize the edge_count array. -void GraphStatistics_IntroduceRelationship(GraphStatistics *stats); +// new relationship is added, resize the edge_count array +void GraphStatistics_IntroduceRelationship +( + GraphStatistics *stats +); -// New label is added, resize the node_count array. -void GraphStatistics_IntroduceLabel(GraphStatistics *stats); +// new label is added, resize the node_count array +void GraphStatistics_IntroduceLabel +( + GraphStatistics *stats +); -// Increment the edge counter by amount -static inline void GraphStatistics_IncEdgeCount(GraphStatistics *stats, - int relation_idx, uint64_t amount) { - ASSERT(relation_idx < array_len(stats->edge_count)); - stats->edge_count[relation_idx] += amount; +// increment the edge counter by amount +static inline void GraphStatistics_IncEdgeCount +( + GraphStatistics *stats, + RelationID r, + uint64_t amount +) { + ASSERT(r < array_len(stats->edge_count)); + stats->edge_count[r] += amount; } -// Decrement the edge counter by amount -static inline void GraphStatistics_DecEdgeCount(GraphStatistics *stats, - int relation_idx, uint64_t amount) { - ASSERT(relation_idx < array_len(stats->edge_count) && - stats->edge_count[relation_idx] >= amount); - stats->edge_count[relation_idx] -= amount; +// decrement the edge counter by amount +static inline void GraphStatistics_DecEdgeCount +( + GraphStatistics *stats, + RelationID r, + uint64_t amount +) { + ASSERT(r < array_len(stats->edge_count) && stats->edge_count[r] >= amount); + stats->edge_count[r] -= amount; } -// Increment the node counter by amount -static inline void GraphStatistics_IncNodeCount(GraphStatistics *stats, - int label_idx, uint64_t amount) { - ASSERT(label_idx < array_len(stats->node_count)); - stats->node_count[label_idx] += amount; +// increment the node counter by amount +static inline void GraphStatistics_IncNodeCount +( + GraphStatistics *stats, + LabelID l, + uint64_t amount +) { + ASSERT(l < array_len(stats->node_count)); + stats->node_count[l] += amount; } -// Decrement the node counter by amount -static inline void GraphStatistics_DecNodeCount(GraphStatistics *stats, - int label_idx, uint64_t amount) { - ASSERT(label_idx < array_len(stats->node_count) && - stats->node_count[label_idx] >= amount); - stats->node_count[label_idx] -= amount; +// decrement the node counter by amount +static inline void GraphStatistics_DecNodeCount +( + GraphStatistics *stats, + int l, + uint64_t amount +) { + ASSERT(l < array_len(stats->node_count) && stats->node_count[l] >= amount); + stats->node_count[l] -= amount; } -// Retrieves edge count for given relationship type -uint64_t GraphStatistics_EdgeCount(const GraphStatistics *stats, - int relation_idx); +// retrieves edge count for given relationship type +uint64_t GraphStatistics_EdgeCount +( + const GraphStatistics *stats, + RelationID r +); -// Retrieves node count for given label -uint64_t GraphStatistics_NodeCount(const GraphStatistics *stats, - int label_idx); +// retrieves node count for given label +uint64_t GraphStatistics_NodeCount +( + const GraphStatistics *stats, + LabelID l +); -// Free the internal structures. -void GraphStatistics_FreeInternals(GraphStatistics *stats); +// free the internal structures +void GraphStatistics_FreeInternals +( + GraphStatistics *stats +); diff --git a/src/graph/graphcontext.c b/src/graph/graphcontext.c index b72eb625b4..a650c48b7f 100644 --- a/src/graph/graphcontext.c +++ b/src/graph/graphcontext.c @@ -1,13 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ -#include -#include -#include "graphcontext.h" #include "../RG.h" +#include "globals.h" +#include "graphcontext.h" #include "../util/arr.h" #include "../util/uuid.h" #include "../query_ctx.h" @@ -18,8 +20,12 @@ #include "../serializers/graphcontext_type.h" #include "../commands/execution_ctx.h" -// Global array tracking all extant GraphContexts (defined in module.c) -extern GraphContext **graphs_in_keyspace; +#include +#include + +// telemetry stream format +#define TELEMETRY_FORMAT "telemetry{%s}" + extern uint aux_field_counter; // GraphContext type as it is registered at Redis. extern RedisModuleType *GraphContextRedisModuleType; @@ -27,6 +33,7 @@ extern RedisModuleType *GraphContextRedisModuleType; // Forward declarations. static void _GraphContext_Free(void *arg); static void _GraphContext_UpdateVersion(GraphContext *gc, const char *str); +static void _DeleteTelemetryStream(RedisModuleCtx *ctx, const GraphContext *gc); static uint64_t _count_indices_from_schemas(const Schema** schemas) { ASSERT(schemas); @@ -42,22 +49,12 @@ static uint64_t _count_indices_from_schemas(const Schema** schemas) { return count; } -// delete a GraphContext reference from the `graphs_in_keyspace` global array -void _GraphContext_RemoveFromRegistry(GraphContext *gc) { - uint graph_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graph_count; i ++) { - if(graphs_in_keyspace[i] == gc) { - graphs_in_keyspace = array_del_fast(graphs_in_keyspace, i); - break; - } - } -} - // increase graph context ref count by 1 inline void GraphContext_IncreaseRefCount ( GraphContext *gc ) { + ASSERT(gc != NULL); __atomic_fetch_add(&gc->ref_count, 1, __ATOMIC_RELAXED); } @@ -66,6 +63,8 @@ inline void GraphContext_DecreaseRefCount ( GraphContext *gc ) { + ASSERT(gc != NULL); + // if the reference count is 0 // the graph has been marked for deletion and no queries are active // free the graph @@ -73,9 +72,6 @@ inline void GraphContext_DecreaseRefCount bool async_delete; Config_Option_get(Config_ASYNC_DELETE, &async_delete); - // remove graph context from global `graphs_in_keyspace` array - _GraphContext_RemoveFromRegistry(gc); - if(async_delete) { // Async delete // add deletion task to pool using force mode @@ -101,6 +97,7 @@ GraphContext *GraphContext_New gc->version = 0; // initial graph version gc->slowlog = SlowLog_New(); + gc->queries_log = QueriesLog_New(); gc->ref_count = 0; // no refences gc->attributes = raxNew(); gc->index_count = 0; // no indicies @@ -120,6 +117,8 @@ GraphContext *GraphContext_New gc->g = Graph_New(node_cap, edge_cap); gc->graph_name = rm_strdup(graph_name); + gc->telemetry_stream = RedisModule_CreateStringPrintf(NULL, + TELEMETRY_FORMAT, gc->graph_name); // allocate the default space for schemas and indices gc->node_schemas = array_new(Schema *, GRAPH_DEFAULT_LABEL_CAP); @@ -140,17 +139,19 @@ GraphContext *GraphContext_New return gc; } -/* _GraphContext_Create tries to get a graph context, and if it does not exists, create a new one. - * The try-get-create flow is done when module global lock is acquired, to enforce consistency - * while BGSave is called. */ +// _GraphContext_Create tries to get a graph context +// and if it does not exists, create a new one +// the try-get-create flow is done when module global lock is acquired +// to enforce consistency while BGSave is called static GraphContext *_GraphContext_Create ( RedisModuleCtx *ctx, const char *graph_name ) { - // Create and initialize a graph context. + // create and initialize a graph context GraphContext *gc = GraphContext_New(graph_name); - RedisModuleString *graphID = RedisModule_CreateString(ctx, graph_name, strlen(graph_name)); + RedisModuleString *graphID = RedisModule_CreateString(ctx, graph_name, + strlen(graph_name)); RedisModuleKey *key = RedisModule_OpenKey(ctx, graphID, REDISMODULE_WRITE); @@ -162,6 +163,7 @@ static GraphContext *_GraphContext_Create RedisModule_FreeString(ctx, graphID); RedisModule_CloseKey(key); + return gc; } @@ -222,14 +224,66 @@ void GraphContext_MarkWriter(RedisModuleCtx *ctx, GraphContext *gc) { RedisModule_FreeString(ctx, graphID); } -const char *GraphContext_GetName(const GraphContext *gc) { +void GraphContext_LockForCommit +( + RedisModuleCtx *ctx, + GraphContext *gc +) { + // aquire GIL + RedisModule_ThreadSafeContextLock(ctx); + + // acquire graph write lock + Graph_AcquireWriteLock(gc->g); +} + +void GraphContext_UnlockCommit +( + RedisModuleCtx *ctx, + GraphContext *gc +) { + // release graph R/W lock + Graph_ReleaseLock(gc->g); + + // unlock GIL + RedisModule_ThreadSafeContextUnlock(ctx); +} + +const char *GraphContext_GetName +( + const GraphContext *gc +) { ASSERT(gc != NULL); return gc->graph_name; } -void GraphContext_Rename(GraphContext *gc, const char *name) { +// get graph context's telemetry stream name +const RedisModuleString *GraphContext_GetTelemetryStreamName +( + const GraphContext *gc +) { + ASSERT(gc != NULL); + ASSERT(gc->telemetry_stream != NULL); + + return gc->telemetry_stream; +} + +// rename a graph context +void GraphContext_Rename +( + RedisModuleCtx *ctx, // redis module context + GraphContext *gc, // graph context to rename + const char *name // new name +) { rm_free(gc->graph_name); gc->graph_name = rm_strdup(name); + + // drop old telemetry stream + _DeleteTelemetryStream(ctx, gc); + + // recreate telemetry stream name + RedisModule_FreeString(ctx, gc->telemetry_stream); + gc->telemetry_stream = RedisModule_CreateStringPrintf(NULL, + TELEMETRY_FORMAT, gc->graph_name); } XXH32_hash_t GraphContext_GetVersion(const GraphContext *gc) { @@ -289,22 +343,6 @@ unsigned short GraphContext_SchemaCount(const GraphContext *gc, SchemaType t) { else return array_len(gc->relation_schemas); } -void GraphContext_ActivateAllConstraints(const GraphContext *gc) { - for(uint i = 0; i < array_len(gc->node_schemas); i ++) { - Schema *s = gc->node_schemas[i]; - for(uint j = 0; j < array_len(s->constraints); j ++) { - Constraint_SetStatus(s->constraints[j], CT_ACTIVE); - } - } - - for(uint i = 0; i < array_len(gc->relation_schemas); i ++) { - Schema *s = gc->relation_schemas[i]; - for(uint j = 0; j < array_len(s->constraints); j ++) { - Constraint_SetStatus(s->constraints[j], CT_ACTIVE); - } - } -} - // enable all constraints void GraphContext_EnableConstrains ( @@ -351,7 +389,12 @@ Schema *GraphContext_GetSchemaByID(const GraphContext *gc, int id, SchemaType t) return schemas[id]; } -Schema *GraphContext_GetSchema(const GraphContext *gc, const char *label, SchemaType t) { +Schema *GraphContext_GetSchema +( + const GraphContext *gc, + const char *label, + SchemaType t +) { int id = _GraphContext_GetLabelID(gc, label, t); return GraphContext_GetSchemaByID(gc, id, t); } @@ -394,7 +437,7 @@ void GraphContext_RemoveSchema(GraphContext *gc, int schema_id, SchemaType t) { } const char *GraphContext_GetEdgeRelationType(const GraphContext *gc, Edge *e) { - int reltype_id = Graph_GetEdgeRelation(gc->g, e); + int reltype_id = Edge_GetRelationID(e); ASSERT(reltype_id != GRAPH_NO_RELATION); return gc->relation_schemas[reltype_id]->name; } @@ -458,9 +501,15 @@ Attribute_ID GraphContext_FindOrAddAttribute return (uintptr_t)attribute_id; } -const char *GraphContext_GetAttributeString(GraphContext *gc, Attribute_ID id) { +const char *GraphContext_GetAttributeString +( + GraphContext *gc, + Attribute_ID id +) { + ASSERT(gc != NULL); + ASSERT(id >= 0 && id < array_len(gc->string_mapping)); + pthread_rwlock_rdlock(&gc->_attribute_rwlock); - ASSERT(id < array_len(gc->string_mapping)); const char *name = gc->string_mapping[id]; pthread_rwlock_unlock(&gc->_attribute_rwlock); return name; @@ -505,7 +554,10 @@ void GraphContext_RemoveAttribute bool GraphContext_HasIndices(GraphContext *gc) { ASSERT(gc != NULL); - return GraphContext_NodeIndexCount(gc) || GraphContext_EdgeIndexCount(gc); + const bool has_node_indices = GraphContext_NodeIndexCount(gc); + const bool has_edge_indices = GraphContext_EdgeIndexCount(gc); + + return has_node_indices || has_edge_indices; } uint64_t GraphContext_NodeIndexCount @@ -719,28 +771,34 @@ int GraphContext_DeleteIndex //------------------------------------------------------------------------------ // register a new GraphContext for module-level tracking -void GraphContext_RegisterWithModule(GraphContext *gc) { - - // increase graph context ref count - GraphContext_IncreaseRefCount(gc); - - // See if the graph context is not already in the keyspace. - uint graph_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graph_count; i ++) { - if(graphs_in_keyspace[i] == gc) return; - } - array_append(graphs_in_keyspace, gc); +void GraphContext_RegisterWithModule +( + GraphContext *gc +) { + Globals_AddGraph(gc); } -GraphContext *GraphContext_GetRegisteredGraphContext(const char *graph_name) { +// retrive GraphContext from the global array +// graph isn't registered, NULL is returned +// graph's references count isn't increased! +// this is OK as long as only a single thread has access to the graph +GraphContext *GraphContext_UnsafeGetGraphContext +( + const char *graph_name +) { + KeySpaceGraphIterator it; + Globals_ScanGraphs(&it); + GraphContext *gc = NULL; - uint graph_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graph_count; i ++) { - if(strcmp(graphs_in_keyspace[i]->graph_name, graph_name) == 0) { - gc = graphs_in_keyspace[i]; + + while((gc = GraphIterator_Next(&it)) != NULL) { + bool match = (strcmp(gc->graph_name, graph_name) == 0); + GraphContext_DecreaseRefCount(gc); + if(match == true) { break; } } + return gc; } @@ -754,6 +812,31 @@ SlowLog *GraphContext_GetSlowLog(const GraphContext *gc) { return gc->slowlog; } +//------------------------------------------------------------------------------ +// Queries API +//------------------------------------------------------------------------------ + +void GraphContext_LogQuery +( + const GraphContext *gc, // graph context + uint64_t received, // query received timestamp + double wait_duration, // waiting time + double execution_duration, // executing time + double report_duration, // reporting time + bool parameterized, // uses parameters + bool utilized_cache, // utilized cache + bool write, // write query + bool timeout, // timeout query + const char *query // query string +) { + ASSERT(gc != NULL); + ASSERT(query != NULL); + + QueriesLog_AddQuery(gc->queries_log, received, wait_duration, + execution_duration, report_duration, parameterized, utilized_cache, + write, timeout, query); +} + //------------------------------------------------------------------------------ // Cache API //------------------------------------------------------------------------------ @@ -768,28 +851,66 @@ Cache *GraphContext_GetCache(const GraphContext *gc) { // Free routine //------------------------------------------------------------------------------ +// delete graph's telemetry stream +static void _DeleteTelemetryStream +( + RedisModuleCtx *ctx, // redis module context + const GraphContext *gc // graph context +) { + ASSERT(gc != NULL); + ASSERT(ctx != NULL); + + RedisModuleKey *key = RedisModule_OpenKey(ctx, gc->telemetry_stream, + REDISMODULE_WRITE); + RedisModule_DeleteKey(key); + RedisModule_CloseKey(key); +} + // Free all data associated with graph static void _GraphContext_Free(void *arg) { GraphContext *gc = (GraphContext *)arg; uint len; - // Disable matrix synchronization for graph deletion. + // disable matrix synchronization for graph deletion Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_NOP); - if(gc->decoding_context == NULL || GraphDecodeContext_Finished(gc->decoding_context)) Graph_Free(gc->g); - else Graph_PartialFree(gc->g); - bool async_delete; - Config_Option_get(Config_ASYNC_DELETE, &async_delete); + if(gc->decoding_context == NULL || + GraphDecodeContext_Finished(gc->decoding_context)) { + Graph_Free(gc->g); + } else { + Graph_PartialFree(gc->g); + } + // Redis main thread is 0 RedisModuleCtx *ctx = NULL; - if(async_delete) { + bool main_thread = ThreadPools_GetThreadID() == 0; + bool should_lock = !main_thread && RedisModule_GetThreadSafeContext != NULL; + + if(should_lock) { ctx = RedisModule_GetThreadSafeContext(NULL); - // GIL need to be acquire because RediSearch change Redis global data structure + // GIL need to be acquire because RediSearch change Redis data structure RedisModule_ThreadSafeContextLock(ctx); } //-------------------------------------------------------------------------- - // Free node schemas + // delete graph telemetry stream + //-------------------------------------------------------------------------- + + if(gc->telemetry_stream != NULL) { + bool should_create = (ctx == NULL); + if(should_create) { + ctx = RedisModule_GetThreadSafeContext(NULL); + } + _DeleteTelemetryStream(ctx, gc); + RedisModule_FreeString(ctx, gc->telemetry_stream); + if (should_create) { + RedisModule_FreeThreadSafeContext(ctx); + ctx = NULL; + } + } + + //-------------------------------------------------------------------------- + // free node schemas //-------------------------------------------------------------------------- if(gc->node_schemas) { @@ -801,7 +922,7 @@ static void _GraphContext_Free(void *arg) { } //-------------------------------------------------------------------------- - // Free relation schemas + // free relation schemas //-------------------------------------------------------------------------- if(gc->relation_schemas) { @@ -812,13 +933,19 @@ static void _GraphContext_Free(void *arg) { array_free(gc->relation_schemas); } - if(async_delete) { + if(should_lock) { RedisModule_ThreadSafeContextUnlock(ctx); RedisModule_FreeThreadSafeContext(ctx); } //-------------------------------------------------------------------------- - // Free attribute mappings + // free queries log + //-------------------------------------------------------------------------- + + QueriesLog_Free(gc->queries_log); + + //-------------------------------------------------------------------------- + // free attribute mappings //-------------------------------------------------------------------------- if(gc->attributes) raxFree(gc->attributes); @@ -837,7 +964,7 @@ static void _GraphContext_Free(void *arg) { if(gc->slowlog) SlowLog_Free(gc->slowlog); //-------------------------------------------------------------------------- - // Clear cache + // clear cache //-------------------------------------------------------------------------- if(gc->cache) Cache_Free(gc->cache); @@ -848,26 +975,3 @@ static void _GraphContext_Free(void *arg) { rm_free(gc); } -void GraphContext_LockForCommit -( - RedisModuleCtx *ctx, - GraphContext *gc -) { - // aquire GIL - RedisModule_ThreadSafeContextLock(ctx); - - // acquire graph write lock - Graph_AcquireWriteLock(gc->g); -} - -void GraphContext_UnlockCommit -( - RedisModuleCtx *ctx, - GraphContext *gc -) { - // release graph R/W lock - Graph_ReleaseLock(gc->g); - - // unlock GIL - RedisModule_ThreadSafeContextUnlock(ctx); -} diff --git a/src/graph/graphcontext.h b/src/graph/graphcontext.h index 74f1ceab5c..9a41356bd5 100644 --- a/src/graph/graphcontext.h +++ b/src/graph/graphcontext.h @@ -1,19 +1,23 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once +#include "graph.h" #include "../redismodule.h" #include "../index/index.h" #include "../schema/schema.h" -#include "graph.h" +#include "../util/cache/cache.h" #include "../slow_log/slow_log.h" +#include "../queries_log/queries_log.h" #include "../serializers/encode_context.h" #include "../serializers/decode_context.h" -#include "../util/cache/cache.h" // GraphContext holds refrences to various elements of a graph object // It is the value sitting behind a Redis graph key @@ -26,20 +30,22 @@ // and take action accordingly typedef struct { - Graph *g; // container for all matrices and entity properties - int ref_count; // number of active references - rax *attributes; // from strings to attribute IDs - pthread_rwlock_t _attribute_rwlock; // read-write lock to protect access to the attribute maps - char *graph_name; // string associated with graph - char **string_mapping; // from attribute IDs to strings - Schema **node_schemas; // array of schemas for each node label - Schema **relation_schemas; // array of schemas for each relation type - unsigned short index_count; // number of indicies - SlowLog *slowlog; // slowlog associated with graph - GraphEncodeContext *encoding_context; // encode context of the graph - GraphDecodeContext *decoding_context; // decode context of the graph - Cache *cache; // global cache of execution plans - XXH32_hash_t version; // graph version + Graph *g; // container for all matrices and entity properties + int ref_count; // number of active references + rax *attributes; // from strings to attribute IDs + pthread_rwlock_t _attribute_rwlock; // read-write lock to protect access to the attribute maps + char *graph_name; // string associated with graph + char **string_mapping; // from attribute IDs to strings + Schema **node_schemas; // array of schemas for each node label + Schema **relation_schemas; // array of schemas for each relation type + unsigned short index_count; // number of indicies + SlowLog *slowlog; // slowlog associated with graph + QueriesLog queries_log; // log last x executed queries + GraphEncodeContext *encoding_context; // encode context of the graph + GraphDecodeContext *decoding_context; // decode context of the graph + Cache *cache; // global cache of execution plans + XXH32_hash_t version; // graph version + RedisModuleString *telemetry_stream; // telemetry stream name } GraphContext; //------------------------------------------------------------------------------ @@ -81,17 +87,36 @@ void GraphContext_MarkWriter GraphContext *gc ); +void GraphContext_LockForCommit +( + RedisModuleCtx *ctx, + GraphContext *gc +); + +void GraphContext_UnlockCommit +( + RedisModuleCtx *ctx, + GraphContext *gc +); + // get graph name out of graph context const char *GraphContext_GetName ( const GraphContext *gc ); +// get graph context's telemetry stream name +const RedisModuleString *GraphContext_GetTelemetryStreamName +( + const GraphContext *gc +); + // rename a graph context void GraphContext_Rename ( - GraphContext *gc, - const char *name + RedisModuleCtx *ctx, // redis module context + GraphContext *gc, // graph context to rename + const char *name // new name ); // Get graph context version @@ -117,12 +142,6 @@ unsigned short GraphContext_SchemaCount SchemaType t ); -// activate all constraints for a given graph context -void GraphContext_ActivateAllConstraints -( - const GraphContext *gc -); - // enable all constraints void GraphContext_EnableConstrains ( @@ -318,11 +337,13 @@ void GraphContext_RegisterWithModule GraphContext *gc ); -// retrive GraphContext from the global array, by name -// if no such graph is registered, NULL is returned -GraphContext *GraphContext_GetRegisteredGraphContext +// retrive GraphContext from the global array +// graph isn't registered, NULL is returned +// graph's references count isn't increased! +// this is OK as long as only a single thread has access to the graph +GraphContext *GraphContext_UnsafeGetGraphContext ( - const char *graph_name + const char *graph_name // graph name ); //------------------------------------------------------------------------------ @@ -334,6 +355,24 @@ SlowLog *GraphContext_GetSlowLog const GraphContext *gc ); +//------------------------------------------------------------------------------ +// Queries API +//------------------------------------------------------------------------------ + +void GraphContext_LogQuery +( + const GraphContext *gc, // graph context + uint64_t received, // query received timestamp + double wait_duration, // waiting time + double execution_duration, // executing time + double report_duration, // reporting time + bool parameterized, // uses parameters + bool utilized_cache, // utilized cache + bool write, // write query + bool timeout, // timeout query + const char *query // query string +); + //------------------------------------------------------------------------------ // Cache API //------------------------------------------------------------------------------ @@ -344,14 +383,3 @@ Cache *GraphContext_GetCache const GraphContext *gc ); -void GraphContext_LockForCommit -( - RedisModuleCtx *ctx, - GraphContext *gc -); - -void GraphContext_UnlockCommit -( - RedisModuleCtx *ctx, - GraphContext *gc -); diff --git a/src/graph/query_graph.c b/src/graph/query_graph.c index 9cb4390cf6..412246f078 100644 --- a/src/graph/query_graph.c +++ b/src/graph/query_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "query_graph.h" #include "RG.h" @@ -405,7 +408,7 @@ QueryGraph *BuildQueryGraph uint path_count = array_len(paths); uint shortest_path_count = array_len(shortest_paths); bool only_shortest[path_count]; - memset(only_shortest, 0, path_count); + memset(only_shortest, 0, path_count*sizeof(bool)); uint l = 0; // index to paths array uint k = 0; // index to shortest paths array diff --git a/src/graph/query_graph.h b/src/graph/query_graph.h index c1b229e1ea..200149ccb9 100644 --- a/src/graph/query_graph.h +++ b/src/graph/query_graph.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/graph/rg_matrix/rg_add.c b/src/graph/rg_matrix/rg_add.c index b1d9b00135..dc84c20f5e 100644 --- a/src/graph/rg_matrix/rg_add.c +++ b/src/graph/rg_matrix/rg_add.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_copy.c b/src/graph/rg_matrix/rg_copy.c index d182b597b8..7b65b6900e 100644 --- a/src/graph/rg_matrix/rg_copy.c +++ b/src/graph/rg_matrix/rg_copy.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_utils.h" diff --git a/src/graph/rg_matrix/rg_export.c b/src/graph/rg_matrix/rg_export.c index dec65a4e74..90603675f8 100644 --- a/src/graph/rg_matrix/rg_export.c +++ b/src/graph/rg_matrix/rg_export.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_extract.c b/src/graph/rg_matrix/rg_extract.c index 665dc93551..fd22fb5075 100644 --- a/src/graph/rg_matrix/rg_extract.c +++ b/src/graph/rg_matrix/rg_extract.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_free.c b/src/graph/rg_matrix/rg_free.c index 6d240b2335..d251de7fa0 100644 --- a/src/graph/rg_matrix/rg_free.c +++ b/src/graph/rg_matrix/rg_free.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_matrix.c b/src/graph/rg_matrix/rg_matrix.c index 2caa878110..3131813db9 100644 --- a/src/graph/rg_matrix/rg_matrix.c +++ b/src/graph/rg_matrix/rg_matrix.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_matrix.h b/src/graph/rg_matrix/rg_matrix.h index 7b95dbf4f8..b12aded85a 100644 --- a/src/graph/rg_matrix/rg_matrix.h +++ b/src/graph/rg_matrix/rg_matrix.h @@ -1,26 +1,23 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once +#include "RG.h" +#include "GraphBLAS.h" + #include -#include "../../deps/GraphBLAS/Include/GraphBLAS.h" // forward declaration of RG_Matrix type typedef struct _RG_Matrix _RG_Matrix; typedef _RG_Matrix *RG_Matrix; -// Mask with most significant bit on 10000... -#define MSB_MASK (1UL << (sizeof(uint64_t) * 8 - 1)) -// Mask complement 01111... -#define MSB_MASK_CMP ~MSB_MASK -// Set X's most significant bit on. -#define SET_MSB(x) (x) | MSB_MASK -// Clear X's most significant bit. -#define CLEAR_MSB(x) (x) & MSB_MASK_CMP // Checks if X represents edge ID. #define SINGLE_EDGE(x) !((x) & MSB_MASK) diff --git a/src/graph/rg_matrix/rg_matrix_iter.c b/src/graph/rg_matrix/rg_matrix_iter.c index a316b5b308..1d62bd7bae 100644 --- a/src/graph/rg_matrix/rg_matrix_iter.c +++ b/src/graph/rg_matrix/rg_matrix_iter.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "./rg_matrix_iter.h" @@ -55,9 +58,9 @@ static inline void _init_iter GrB_Index max_row, bool *depleted ) { - ASSERT(it != NULL) ; - ASSERT(m != NULL) ; - ASSERT(min_row <= max_row) ; + ASSERT(it != NULL) ; + ASSERT(m != NULL) ; + ASSERT(min_row <= max_row) ; ASSERT(depleted != NULL) ; *depleted = true ; // default @@ -302,7 +305,7 @@ bool RG_MatrixTupleIter_is_attached // update iterator to scan given matrix GrB_Info RG_MatrixTupleIter_attach ( - RG_MatrixTupleIter *iter, // iterator to update + RG_MatrixTupleIter *iter, // iterator to update const RG_Matrix A // matrix to scan ) { return RG_MatrixTupleIter_AttachRange(iter, A, RG_ITER_MIN_ROW, diff --git a/src/graph/rg_matrix/rg_matrix_iter.h b/src/graph/rg_matrix/rg_matrix_iter.h index 81b10ba03b..0144e8c742 100644 --- a/src/graph/rg_matrix/rg_matrix_iter.h +++ b/src/graph/rg_matrix/rg_matrix_iter.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/graph/rg_matrix/rg_mxm.c b/src/graph/rg_matrix/rg_mxm.c index 549f669511..8edf2aaa4a 100644 --- a/src/graph/rg_matrix/rg_mxm.c +++ b/src/graph/rg_matrix/rg_mxm.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_new.c b/src/graph/rg_matrix/rg_new.c index 2f95213d2d..65a08d39c0 100644 --- a/src/graph/rg_matrix/rg_new.c +++ b/src/graph/rg_matrix/rg_new.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_pending.c b/src/graph/rg_matrix/rg_pending.c index cfb112dcb4..f347e7e299 100644 --- a/src/graph/rg_matrix/rg_pending.c +++ b/src/graph/rg_matrix/rg_pending.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_remove_element.c b/src/graph/rg_matrix/rg_remove_element.c index 1b66e6d6eb..71dff4b46f 100644 --- a/src/graph/rg_matrix/rg_remove_element.c +++ b/src/graph/rg_matrix/rg_remove_element.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_remove_entry.c b/src/graph/rg_matrix/rg_remove_entry.c index a30d9ccaea..90ecba2aa4 100644 --- a/src/graph/rg_matrix/rg_remove_entry.c +++ b/src/graph/rg_matrix/rg_remove_entry.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_utils.h" diff --git a/src/graph/rg_matrix/rg_resize.c b/src/graph/rg_matrix/rg_resize.c index cab625c09a..9ceca0eb5a 100644 --- a/src/graph/rg_matrix/rg_resize.c +++ b/src/graph/rg_matrix/rg_resize.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_set_element_bool.c b/src/graph/rg_matrix/rg_set_element_bool.c index 3c1a996e3c..3595770c7c 100644 --- a/src/graph/rg_matrix/rg_set_element_bool.c +++ b/src/graph/rg_matrix/rg_set_element_bool.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_utils.h" diff --git a/src/graph/rg_matrix/rg_set_element_uint64.c b/src/graph/rg_matrix/rg_set_element_uint64.c index 37f61da5b0..b8f9552976 100644 --- a/src/graph/rg_matrix/rg_set_element_uint64.c +++ b/src/graph/rg_matrix/rg_set_element_uint64.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_utils.h" diff --git a/src/graph/rg_matrix/rg_utils.c b/src/graph/rg_matrix/rg_utils.c index 1e1366f990..d2f18f0535 100644 --- a/src/graph/rg_matrix/rg_utils.c +++ b/src/graph/rg_matrix/rg_utils.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" diff --git a/src/graph/rg_matrix/rg_utils.h b/src/graph/rg_matrix/rg_utils.h index 2c3b30b065..68787ff831 100644 --- a/src/graph/rg_matrix/rg_utils.h +++ b/src/graph/rg_matrix/rg_utils.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/graph/rg_matrix/rg_wait.c b/src/graph/rg_matrix/rg_wait.c index c16d4deef0..96a304a8a4 100644 --- a/src/graph/rg_matrix/rg_wait.c +++ b/src/graph/rg_matrix/rg_wait.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rg_matrix.h" @@ -22,76 +25,97 @@ static inline void _SetUndirty } } -static GrB_Info RG_Matrix_sync +static void RG_Matrix_sync_deletions ( RG_Matrix C ) { ASSERT(C != NULL); - GrB_Matrix m = RG_MATRIX_M(C); - GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - GrB_Descriptor desc = GrB_NULL; - GrB_Matrix mask = GrB_NULL; + GrB_Matrix m = RG_MATRIX_M(C); + GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); GrB_Info info; - GrB_Index dp_nvals; - GrB_Index dm_nvals; - //-------------------------------------------------------------------------- - // determin change set - //-------------------------------------------------------------------------- + info = GrB_transpose(m, dm, GrB_NULL, m, GrB_DESC_RSCT0); + ASSERT(info == GrB_SUCCESS); - GrB_Matrix_nvals(&dp_nvals, dp); - GrB_Matrix_nvals(&dm_nvals, dm); + // clear delta minus + info = GrB_Matrix_clear(dm); + ASSERT(info == GrB_SUCCESS); +} - bool additions = dp_nvals > 0; - bool deletions = dm_nvals > 0; +static void RG_Matrix_sync_additions +( + RG_Matrix C +) { + ASSERT(C != NULL); - //-------------------------------------------------------------------------- - // perform deletions - //-------------------------------------------------------------------------- + GrB_Matrix m = RG_MATRIX_M(C); + GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); - if(deletions) { - info = GrB_transpose(m, dm, GrB_NULL, m, GrB_DESC_RSCT0); - ASSERT(info == GrB_SUCCESS); + GrB_Info info; + GrB_Index nrows; + GrB_Index ncols; - // clear delta minus - info = GrB_Matrix_clear(dm); - ASSERT(info == GrB_SUCCESS); - } + info = GrB_Matrix_nrows(&nrows, m); + ASSERT(info == GrB_SUCCESS); + info = GrB_Matrix_ncols(&ncols, m); + ASSERT(info == GrB_SUCCESS); + + info = GrB_Matrix_assign(m, dp, NULL, dp, GrB_ALL, nrows, GrB_ALL, ncols, + GrB_DESC_S); + ASSERT(info == GrB_SUCCESS); + + // clear delta plus + info = GrB_Matrix_clear(dp); + ASSERT(info == GrB_SUCCESS); +} + +static void RG_Matrix_sync +( + RG_Matrix C, + bool force_sync, + uint64_t delta_max_pending_changes +) { + ASSERT(C != NULL); + + GrB_Matrix m = RG_MATRIX_M(C); + GrB_Matrix dp = RG_MATRIX_DELTA_PLUS(C); + GrB_Matrix dm = RG_MATRIX_DELTA_MINUS(C); - //-------------------------------------------------------------------------- - // perform additions - //-------------------------------------------------------------------------- + if(force_sync) { + RG_Matrix_sync_deletions(C); + RG_Matrix_sync_additions(C); + } else { + GrB_Index dp_nvals; + GrB_Index dm_nvals; - if(additions) { - GrB_Type t; - GrB_Semiring s; - info = GxB_Matrix_type(&t, m); - ASSERT(info == GrB_SUCCESS); + //---------------------------------------------------------------------- + // determin change set + //---------------------------------------------------------------------- - s = (t == GrB_BOOL) ? GxB_ANY_PAIR_BOOL : GxB_ANY_PAIR_UINT64; - info = GrB_Matrix_eWiseAdd_Semiring(m, NULL, NULL, s, m, dp, NULL); - ASSERT(info == GrB_SUCCESS); + GrB_Matrix_nvals(&dp_nvals, dp); + GrB_Matrix_nvals(&dm_nvals, dm); - // clear delta plus - info = GrB_Matrix_clear(dp); - ASSERT(info == GrB_SUCCESS); - } + //---------------------------------------------------------------------- + // perform deletions + //---------------------------------------------------------------------- - //-------------------------------------------------------------------------- - // validate that both delta-plus and delta-minus are cleared - //-------------------------------------------------------------------------- + if(dm_nvals >= delta_max_pending_changes) { + RG_Matrix_sync_deletions(C); + } - GrB_Index nvals; - GrB_Matrix_nvals(&nvals, dp); - ASSERT(nvals == 0); - GrB_Matrix_nvals(&nvals, dm); - ASSERT(nvals == 0); + //---------------------------------------------------------------------- + // perform additions + //---------------------------------------------------------------------- + + if(dp_nvals >= delta_max_pending_changes) { + RG_Matrix_sync_additions(C); + } + } // wait on all 3 matrices - info = GrB_wait(m, GrB_MATERIALIZE); + GrB_Info info = GrB_wait(m, GrB_MATERIALIZE); ASSERT(info == GrB_SUCCESS); info = GrB_wait(dm, GrB_MATERIALIZE); @@ -99,8 +123,6 @@ static GrB_Info RG_Matrix_sync info = GrB_wait(dp, GrB_MATERIALIZE); ASSERT(info == GrB_SUCCESS); - - return info; } GrB_Info RG_Matrix_wait @@ -112,40 +134,15 @@ GrB_Info RG_Matrix_wait if(RG_MATRIX_MAINTAIN_TRANSPOSE(A)) { RG_Matrix_wait(A->transposed, force_sync); } - - GrB_Info info = GrB_SUCCESS; - GrB_Matrix m = RG_MATRIX_M(A); - GrB_Matrix delta_plus = RG_MATRIX_DELTA_PLUS(A); - GrB_Matrix delta_minus = RG_MATRIX_DELTA_MINUS(A); - - // check if merge is required - GrB_Index delta_plus_nvals; - GrB_Index delta_minus_nvals; - GrB_Matrix_nvals(&delta_plus_nvals, delta_plus); - GrB_Matrix_nvals(&delta_minus_nvals, delta_minus); uint64_t delta_max_pending_changes; Config_Option_get(Config_DELTA_MAX_PENDING_CHANGES, &delta_max_pending_changes); - if(force_sync || - delta_plus_nvals + delta_minus_nvals >= delta_max_pending_changes) { - info = RG_Matrix_sync(A); - } else { - // wait on 'm', in most cases 'm' won't contain any pending work - // but it might need to build its internal hyper-hash - info = GrB_wait(m, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - - info = GrB_wait(delta_plus, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - - info = GrB_wait(delta_minus, GrB_MATERIALIZE); - ASSERT(info == GrB_SUCCESS); - } + RG_Matrix_sync(A, force_sync, delta_max_pending_changes); _SetUndirty(A); - return info; + return GrB_SUCCESS; } diff --git a/src/grouping/group.c b/src/grouping/group.c index 18aaed2149..2bfc4ff207 100644 --- a/src/grouping/group.c +++ b/src/grouping/group.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include "group.h" diff --git a/src/grouping/group.h b/src/grouping/group.h index 4a5d01198a..11501b0a5c 100644 --- a/src/grouping/group.h +++ b/src/grouping/group.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/index/index.c b/src/index/index.c index e1798ca0a6..9e2824fbd8 100644 --- a/src/index/index.c +++ b/src/index/index.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "index.h" diff --git a/src/index/index.h b/src/index/index.h index f775cb3bee..16e34faf72 100644 --- a/src/index/index.h +++ b/src/index/index.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/index/index_construct.c b/src/index/index_construct.c index 14038cbf4c..955e1b2154 100644 --- a/src/index/index_construct.c +++ b/src/index/index_construct.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "index.h" @@ -175,8 +178,8 @@ static void _Index_PopulateEdgeIndex do { Edge e; - e.srcNodeID = src_id; - e.destNodeID = dest_id; + e.src_id = src_id; + e.dest_id = dest_id; e.relationID = Index_GetLabelID(idx); if(SINGLE_EDGE(edge_id)) { diff --git a/src/index/index_edge.c b/src/index/index_edge.c index 979fade215..4d66aea5fb 100644 --- a/src/index/index_edge.c +++ b/src/index/index_edge.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "index.h" diff --git a/src/index/index_node.c b/src/index/index_node.c index 07b46994e2..223e68d82a 100644 --- a/src/index/index_node.c +++ b/src/index/index_node.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "index.h" diff --git a/src/index/indexer.c b/src/index/indexer.c index bdad5ac540..127f70e60e 100644 --- a/src/index/indexer.c +++ b/src/index/indexer.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "indexer.h" #include "../redismodule.h" @@ -139,12 +142,32 @@ static void _indexer_enforce_constraint } } + // try to enforce constraint on all relevent entities if(Constraint_GetEntityType(c) == GETYPE_NODE) { Constraint_EnforceNodes(c, g); } else { Constraint_EnforceEdges(c, g); } + // replicate constraint if active + // upon constraint creation + // it is possible for the primary shard to replicate the constraint via RDB + // in which case the constraint wouldn't be included + // as only active constraints are encoded within RDBs + // to make sure the constraint is introduced to the replica we re-issue it + // once the constraint becomes active + if(Constraint_GetStatus(c) == CT_ACTIVE) { + // lock before calling replicate + RedisModuleCtx *rm_ctx = RedisModule_GetThreadSafeContext(NULL); + RedisModule_ThreadSafeContextLock(rm_ctx); + + Constraint_Replicate(rm_ctx, c, (const struct GraphContext*)gc); + + // unlock and free + RedisModule_ThreadSafeContextUnlock(rm_ctx); + RedisModule_FreeThreadSafeContext(rm_ctx); + } + // decrease number of pending changes Constraint_DecPendingChanges(c); @@ -271,8 +294,8 @@ static void _indexer_PopTask ASSERT(res == 0); } - res = CircularBuffer_Remove(indexer->q, task); - ASSERT(res == 1); + void *read = CircularBuffer_Read(indexer->q, task); + ASSERT(read != NULL); // unlock res = pthread_mutex_unlock(&indexer->m); @@ -348,7 +371,7 @@ bool Indexer_Init(void) { } if(indexer->q != NULL) { - CircularBuffer_Free(&indexer->q); + CircularBuffer_Free(indexer->q); } rm_free(indexer); diff --git a/src/index/indexer.h b/src/index/indexer.h index 5d9badb13d..9928f954ac 100644 --- a/src/index/indexer.h +++ b/src/index/indexer.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/module.c b/src/module.c index 23b84ea0f2..eecef0b904 100644 --- a/src/module.c +++ b/src/module.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include @@ -10,8 +13,9 @@ #include "debug.h" #include "errors.h" #include "version.h" +#include "globals.h" #include "util/arr.h" -#include "util/cron.h" +#include "cron/cron.h" #include "query_ctx.h" #include "index/indexer.h" #include "redisearch_api.h" @@ -29,21 +33,11 @@ #include "serializers/graphcontext_type.h" #include "arithmetic/arithmetic_expression.h" -//------------------------------------------------------------------------------ -// Minimal supported Redis version -//------------------------------------------------------------------------------ +// minimal supported Redis version #define MIN_REDIS_VERION_MAJOR 6 -#define MIN_REDIS_VERION_MINOR 0 +#define MIN_REDIS_VERION_MINOR 2 #define MIN_REDIS_VERION_PATCH 0 -//------------------------------------------------------------------------------ -// Module-level global variables -//------------------------------------------------------------------------------ -GraphContext **graphs_in_keyspace; // Global array tracking all extant GraphContexts. -bool process_is_child; // Flag indicating whether the running process is a child. - -extern CommandCtx **command_ctxs; - static int _RegisterDataTypes(RedisModuleCtx *ctx) { if(GraphContextType_Register(ctx) == REDISMODULE_ERR) { printf("Failed to register GraphContext type\n"); @@ -57,9 +51,34 @@ static int _RegisterDataTypes(RedisModuleCtx *ctx) { return REDISMODULE_OK; } -static void _PrepareModuleGlobals(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { - graphs_in_keyspace = array_new(GraphContext *, 1); - process_is_child = false; +// starts cron and register recurring tasks +static bool _Cron_Start(void) { + // start CRON + bool res = Cron_Start(); + + // register recurring tasks + Cron_AddRecurringTasks(); + + return res; +} + +// print RedisGraph configuration +static void _Print_Config +( + RedisModuleCtx *ctx +) { + // TODO: consider adding Config_Print + + int ompThreadCount; + Config_Option_get(Config_OPENMP_NTHREAD, &ompThreadCount); + RedisModule_Log(ctx, "notice", "Maximum number of OpenMP threads set to %d", ompThreadCount); + + bool cmd_info_enabled = false; + if(Config_Option_get(Config_CMD_INFO, &cmd_info_enabled) && cmd_info_enabled) { + uint32_t info_max_query_count = 0; + Config_Option_get(Config_CMD_INFO_MAX_QUERY_COUNT, &info_max_query_count); + RedisModule_Log(ctx, "notice", "Query backlog size: %u", info_max_query_count); + } } static int GraphBLAS_Init(RedisModuleCtx *ctx) { @@ -102,11 +121,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) RedisModule_Log(ctx, "notice", "Starting up RedisGraph version %d.%d.%d.", REDISGRAPH_VERSION_MAJOR, REDISGRAPH_VERSION_MINOR, REDISGRAPH_VERSION_PATCH); - Proc_Register(); // Register procedures. - AR_RegisterFuncs(); // Register arithmetic functions. - Cron_Start(); // Start CRON - // Set up global lock and variables scoped to the entire module. - _PrepareModuleGlobals(ctx, argv, argc); + Proc_Register(); // register procedures + AR_RegisterFuncs(); // register arithmetic functions // set up the module's configurable variables, // using user-defined values where provided @@ -117,6 +133,7 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) RegisterEventHandlers(ctx); // create thread local storage keys for query and error contexts + if(!_Cron_Start()) return REDISMODULE_ERR; if(!QueryCtx_Init()) return REDISMODULE_ERR; if(!ErrorCtx_Init()) return REDISMODULE_ERR; if(!ThreadPools_Init()) return REDISMODULE_ERR; @@ -133,10 +150,9 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) RedisModule_Log(ctx, "warning", "Failed to set OpenMP thread count to %d", ompThreadCount); return REDISMODULE_ERR; } - RedisModule_Log(ctx, "notice", "Maximum number of OpenMP threads set to %d", ompThreadCount); - // initialize array of command contexts - command_ctxs = calloc(ThreadPools_ThreadCount() + 1, sizeof(CommandCtx *)); + // log configuration + _Print_Config(ctx); if(_RegisterDataTypes(ctx) != REDISMODULE_OK) return REDISMODULE_ERR; @@ -195,11 +211,19 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) return REDISMODULE_ERR; } - if (RedisModule_CreateCommand(ctx, "graph.INFO", Graph_Info, "readonly", 1, 1, - 1) == REDISMODULE_ERR) { + if(RedisModule_CreateCommand(ctx, "graph.INFO", Graph_Info, "readonly", 1, 1, + 1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } + if(RedisModule_CreateCommand(ctx, "graph.EFFECT", Graph_Effect, "write", 1, + 1, 1) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } + + // set up global variables scoped to the entire module + Globals_Init(); + setupCrashHandlers(ctx); return REDISMODULE_OK; diff --git a/src/module_event_handlers.c b/src/module_event_handlers.c index 9c378d9cd1..3d51dba82b 100644 --- a/src/module_event_handlers.c +++ b/src/module_event_handlers.c @@ -1,14 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "module_event_handlers.h" #include "RG.h" #include #include +#include "globals.h" #include "util/uuid.h" +#include "cron/cron.h" #include "util/thpool/pools.h" #include "util/redis_version.h" #include "graph/graphcontext.h" @@ -19,10 +24,6 @@ // indicates the possibility of half-baked graphs in the keyspace #define INTERMEDIATE_GRAPHS (aux_field_counter > 0) -// global array tracking all extant GraphContexts -extern GraphContext **graphs_in_keyspace; -// flag indicating whether the running process is a child -extern bool process_is_child; // graphContext type as it is registered at Redis extern RedisModuleType *GraphContextRedisModuleType; // graph meta keys type as it is registered at Redis @@ -40,24 +41,44 @@ uint aux_field_counter = 0 ; // holds the id of the Redis Main thread in order to figure out the context the fork is running on static pthread_t redis_main_thread_id; -// this callback invokes once rename for a graph is done. Since the key value is a graph context -// which saves the name of the graph for later key accesses, this data must be consistent with the key name, -// otherwise, the graph context will remain with the previous graph name, and a key access to this name might -// yield an empty key or wrong value. This method changes the graph name value at the graph context to be +// this callback invokes once rename for a graph is done +// since the key value is a graph context +// which saves the name of the graph for later key accesses +// this data must be consistent with the key name +// otherwise the graph context will remain with the previous graph name +// and a key access to this name might yield an empty key or wrong value +// this method changes the graph name value at the graph context to be // consistent with the key name -static int _RenameGraphHandler(RedisModuleCtx *ctx, int type, const char *event, - RedisModuleString *key_name) { - if(type != REDISMODULE_NOTIFY_GENERIC) return REDISMODULE_OK; +static int _GenericKeyspaceHandler +( + RedisModuleCtx *ctx, + int type, + const char *event, + RedisModuleString *key_name +) { + if(type != REDISMODULE_NOTIFY_GENERIC) { + return REDISMODULE_OK; + } + if(strcasecmp(event, "RENAME_TO") == 0) { - RedisModuleKey *key = RedisModule_OpenKey(ctx, key_name, REDISMODULE_WRITE); + RedisModuleKey *key = RedisModule_OpenKey(ctx, key_name, + REDISMODULE_WRITE); if(RedisModule_ModuleTypeGetType(key) == GraphContextRedisModuleType) { GraphContext *gc = RedisModule_ModuleTypeGetValue(key); size_t len; const char *new_name = RedisModule_StringPtrLen(key_name, &len); - GraphContext_Rename(gc, new_name); + GraphContext_Rename(ctx, gc, new_name); } RedisModule_CloseKey(key); } + + else if(strcasecmp(event, "DEL") == 0) { + // TODO: in Redis 7.2 we could use REDISMODULE_EVENT_KEY to register + // for a more convenient key event notification + const char *graph_name = RedisModule_StringPtrLen(key_name, NULL); + Globals_RemoveGraphByName(graph_name); + } + return REDISMODULE_OK; } @@ -94,37 +115,43 @@ static uint64_t _GraphContext_RequiredMetaKeys(const GraphContext *gc) { return MAX(key_count, 0); } -static void _CreateGraphMetaKeys(RedisModuleCtx *ctx, GraphContext *gc) { +static void _CreateGraphMetaKeys +( + RedisModuleCtx *ctx, + GraphContext *gc +) { uint meta_key_count = _GraphContext_RequiredMetaKeys(gc); bool graph_name_contains_tag = _GraphContext_NameContainsTag(gc); for(uint i = 1; i <= meta_key_count; i++) { char *uuid = UUID_New(); RedisModuleString *meta_rm_string; - /* Meta keys need to be in the exact shard/slot as the graph context key - * to avoid graph sharding at the target db - * we want to save all the graph keys on the same shard. - * For that, we need to that them In so their tag hash value will be - * the same as the graph context key hash value. - * If the graph name already contains a tag, we can duplicate - * the graph name completely for each meta key. - * If not, the meta keys tag will be the graph name, so - * when hashing the graphcontext key name (graph name) - * and the graph meta key tag (graph name) - * the hash values will be the same. */ + // meta keys need to be in the exact shard/slot as the graph context key + // to avoid graph sharding at the target db + // we want to save all the graph keys on the same shard + // for that, we need to that them In so their tag hash value will be + // the same as the graph context key hash value + // if the graph name already contains a tag, we can duplicate + // the graph name completely for each meta key + // if not, the meta keys tag will be the graph name, so + // when hashing the graphcontext key name (graph name) + // and the graph meta key tag (graph name) + // the hash values will be the same if(graph_name_contains_tag) { - // Graph already has a tag, create a meta key of "graph_name_uuid" - meta_rm_string = RedisModule_CreateStringPrintf(ctx, "%s_%s", gc->graph_name, uuid); + // graph already has a tag, create a meta key of "graph_name_uuid" + meta_rm_string = RedisModule_CreateStringPrintf(ctx, "%s_%s", + gc->graph_name, uuid); } else { - // Graph is untagged, one must be introduced to ensure that - // keys are propagated to the same node. - // Create a meta key of "{graph_name}graph_name_i" - meta_rm_string = RedisModule_CreateStringPrintf(ctx, "{%s}%s_%s", gc->graph_name, - gc->graph_name, uuid); + // graph is untagged, one must be introduced to ensure that + // keys are propagated to the same node + // create a meta key of "{graph_name}graph_name_i" + meta_rm_string = RedisModule_CreateStringPrintf(ctx, "{%s}%s_%s", + gc->graph_name, gc->graph_name, uuid); } const char *key_name = RedisModule_StringPtrLen(meta_rm_string, NULL); GraphEncodeContext_AddMetaKey(gc->encoding_context, key_name); - RedisModuleKey *key = RedisModule_OpenKey(ctx, meta_rm_string, REDISMODULE_WRITE); + RedisModuleKey *key = RedisModule_OpenKey(ctx, meta_rm_string, + REDISMODULE_WRITE); // set value in key RedisModule_ModuleTypeSetValue(key, GraphMetaRedisModuleType, gc); @@ -140,53 +167,100 @@ static void _CreateGraphMetaKeys(RedisModuleCtx *ctx, GraphContext *gc) { meta_key_count, gc->graph_name); } -// Delete meta keys, upon RDB encode or decode finished event triggering. -// The decode flag represent the event. -static void _DeleteGraphMetaKeys(RedisModuleCtx *ctx, GraphContext *gc, bool decode) { - unsigned char **keys; +// delete meta keys, upon RDB encode or decode finished event triggering +// the decode flag represent the event +static void _DeleteGraphMetaKeys +( + RedisModuleCtx *ctx, + GraphContext *gc, + bool decode +) { uint key_count; - // Get the meta keys required, according to the "decode" flag. - if(decode) keys = GraphDecodeContext_GetMetaKeys(gc->decoding_context); - else keys = GraphEncodeContext_GetMetaKeys(gc->encoding_context); + unsigned char **keys; + + // get the meta keys required, according to the "decode" flag. + if(decode) { + keys = GraphDecodeContext_GetMetaKeys(gc->decoding_context); + } else { + keys = GraphEncodeContext_GetMetaKeys(gc->encoding_context); + } + key_count = array_len(keys); for(uint i = 0; i < key_count; i++) { - RedisModuleString *meta_rm_string = RedisModule_CreateStringPrintf(ctx, "%s", keys[i]); - RedisModuleKey *key = RedisModule_OpenKey(ctx, meta_rm_string, REDISMODULE_WRITE); + RedisModuleString *meta_rm_string = + RedisModule_CreateStringPrintf(ctx, "%s", keys[i]); + + RedisModuleKey *key = + RedisModule_OpenKey(ctx, meta_rm_string, REDISMODULE_WRITE); + RedisModule_DeleteKey(key); RedisModule_CloseKey(key); RedisModule_FreeString(ctx, meta_rm_string); + rm_free(keys[i]); } + array_free(keys); - // Clear the relevant context meta keys as they are no longer valid. - if(decode) GraphDecodeContext_ClearMetaKeys(gc->decoding_context); - else GraphEncodeContext_ClearMetaKeys(gc->encoding_context); - RedisModule_Log(ctx, "notice", "Deleted %d virtual keys for graph %s", key_count, gc->graph_name); + + // clear the relevant context meta keys as they are no longer valid + if(decode) { + GraphDecodeContext_ClearMetaKeys(gc->decoding_context); + } else { + GraphEncodeContext_ClearMetaKeys(gc->encoding_context); + } + + RedisModule_Log(ctx, "notice", "Deleted %d virtual keys for graph %s", + key_count, gc->graph_name); } // create the meta keys for each graph in the keyspace // used on RDB start event -static void _CreateKeySpaceMetaKeys(RedisModuleCtx *ctx) { - uint graphs_in_keyspace_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graphs_in_keyspace_count; i ++) { - _CreateGraphMetaKeys(ctx, graphs_in_keyspace[i]); +static void _CreateKeySpaceMetaKeys +( + RedisModuleCtx *ctx +) { + KeySpaceGraphIterator it; + GraphContext *gc = NULL; + Globals_ScanGraphs(&it); + + while((gc = GraphIterator_Next(&it)) != NULL) { + _CreateGraphMetaKeys(ctx, gc); + GraphContext_DecreaseRefCount(gc); } } -/* Delete the meta keys for each graph in the key space - used on RDB finish (save/load/fail) event. - * The decode flag represent if the graph is after encodeing or decodeing. */ -static void _ClearKeySpaceMetaKeys(RedisModuleCtx *ctx, bool decode) { - uint graphs_in_keyspace_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graphs_in_keyspace_count; i ++) { - _DeleteGraphMetaKeys(ctx, graphs_in_keyspace[i], decode); +// delete the meta keys for each graph in the keyspace +// used on RDB finish (save/load/fail) event +// the decode flag represent if the graph is after encodeing or decodeing +static void _ClearKeySpaceMetaKeys +( + RedisModuleCtx *ctx, + bool decode +) { + KeySpaceGraphIterator it; + GraphContext *gc = NULL; + Globals_ScanGraphs(&it); + + while((gc = GraphIterator_Next(&it)) != NULL) { + _DeleteGraphMetaKeys(ctx, gc, decode); + GraphContext_DecreaseRefCount(gc); } } -static void _FlushDBHandler(RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, - void *data) { - // reset `aux_field_counter` upon handeling FLUSH-ALL - if(eid.id == REDISMODULE_EVENT_FLUSHDB && - subevent == REDISMODULE_SUBEVENT_FLUSHDB_START) { +static void _FlushDBHandler +( + RedisModuleCtx *ctx, + RedisModuleEvent eid, + uint64_t subevent, + void *data +) { + ASSERT(eid.id == REDISMODULE_EVENT_FLUSHDB); + + if(subevent == REDISMODULE_SUBEVENT_FLUSHDB_START) { + // clear global graphs tracking + Globals_ClearGraphs(ctx); + + // reset `aux_field_counter` aux_field_counter = 0; } } @@ -216,18 +290,20 @@ static void _ReplicationRoleChangedEventHandler uint64_t subevent, void *data ) { - uint n = array_len(graphs_in_keyspace); + KeySpaceGraphIterator it; + GraphContext *gc = NULL; + Globals_ScanGraphs(&it); if(subevent == REDISMODULE_EVENT_REPLROLECHANGED_NOW_MASTER) { // now master enable constraints - for(uint i = 0; i < n; i++) { - GraphContext *g = graphs_in_keyspace[i]; - GraphContext_EnableConstrains(g); + while((gc = GraphIterator_Next(&it)) != NULL) { + GraphContext_EnableConstrains(gc); + GraphContext_DecreaseRefCount(gc); } } else if (subevent == REDISMODULE_EVENT_REPLROLECHANGED_NOW_REPLICA) { // now slave disable constraints - for(uint i = 0; i < n; i++) { - GraphContext *g = graphs_in_keyspace[i]; - GraphContext_DisableConstrains(g); + while((gc = GraphIterator_Next(&it)) != NULL) { + GraphContext_DisableConstrains(gc); + GraphContext_DecreaseRefCount(gc); } } } @@ -241,7 +317,7 @@ static void _PersistenceEventHandler(RedisModuleCtx *ctx, RedisModuleEvent eid, // in such case we do not want to either perform backup nor do we want to // synchronize our replica, as such we're aborting by existing // assuming we're running on a fork process - if(process_is_child) { + if(Globals_Get_ProcessIsChild()) { // intermediate graph(s) detected, exit! RedisModule_Log(NULL, REDISMODULE_LOGLEVEL_WARNING, "RedisGraph - aborting BGSAVE, detected intermediate graph(s)"); @@ -261,37 +337,82 @@ static void _PersistenceEventHandler(RedisModuleCtx *ctx, RedisModuleEvent eid, } // Perform clean-up upon server shutdown. -static void _ShutdownEventHandler(RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, - void *data) { +static void _ShutdownEventHandler +( + RedisModuleCtx *ctx, + RedisModuleEvent eid, + uint64_t subevent, + void *data +) { void RediSearch_CleanupModule(); if (!getenv("RS_GLOBAL_DTORS")) { // used only with sanitizer or valgrind return; } - // Stop threads before finalize GraphBLAS. + + // stop cron + Cron_Stop(); + + // stop threads before finalize GraphBLAS ThreadPools_Destroy(); - // Server is shutting down, finalize GraphBLAS. + + // server is shutting down, finalize GraphBLAS GrB_finalize(); RedisModule_Log(ctx, "notice", "%s", "Clearing RediSearch resources on shutdown"); RediSearch_CleanupModule(); + + // free global variables + Globals_Free(); +} + +static void _ModuleLoadedHandler +( + RedisModuleCtx *ctx, + RedisModuleEvent eid, + uint64_t subevent, + void *data +) { + if(subevent == REDISMODULE_SUBEVENT_MODULE_LOADED) { + // see which module been loaded + RedisModuleModuleChange *pdata = (RedisModuleModuleChange*)data; + if(strcmp(pdata->module_name, "graph") == 0) { + Cron_Start(); + Cron_AddRecurringTasks(); + } + } } static void _RegisterServerEvents(RedisModuleCtx *ctx) { - RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_FlushDB, + int res; + res = RedisModule_SubscribeToServerEvent(ctx, + RedisModuleEvent_FlushDB, _FlushDBHandler); + ASSERT(res == REDISMODULE_OK); - RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_Shutdown, + res = RedisModule_SubscribeToServerEvent(ctx, + RedisModuleEvent_Shutdown, _ShutdownEventHandler); + ASSERT(res == REDISMODULE_OK); - RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_GENERIC, - _RenameGraphHandler); - - RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_Persistence, + res = RedisModule_SubscribeToServerEvent(ctx, + RedisModuleEvent_Persistence, _PersistenceEventHandler); + ASSERT(res == REDISMODULE_OK); + + // TODO: try to use RedisModuleEvent_ModuleChange to start cron + //res = RedisModule_SubscribeToServerEvent(ctx, + // RedisModuleEvent_ModuleChange, + // _ModuleLoadedHandler); + //ASSERT(res == REDISMODULE_OK); + + // RedisModule_SubscribeToServerEvent(ctx, + // RedisModuleEvent_ReplicationRoleChanged, + // _ReplicationRoleChangedEventHandler); + + RedisModule_SubscribeToKeyspaceEvents(ctx, + REDISMODULE_NOTIFY_GENERIC, + _GenericKeyspaceHandler); -// RedisModule_SubscribeToServerEvent(ctx, -// RedisModuleEvent_ReplicationRoleChanged, -// _ReplicationRoleChangedEventHandler); } //------------------------------------------------------------------------------ @@ -318,10 +439,12 @@ static void RG_ForkPrepare() { // return if we have half-baked graphs if(INTERMEDIATE_GRAPHS) return; - uint graph_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graph_count; i++) { + KeySpaceGraphIterator it; + GraphContext *gc = NULL; + Globals_ScanGraphs(&it); + while((gc = GraphIterator_Next(&it)) != NULL) { // acquire read lock, guarantee graph isn't modified - Graph *g = graphs_in_keyspace[i]->g; + Graph *g = gc->g; Graph_AcquireReadLock(g); // set matrix synchronization policy to default @@ -330,6 +453,8 @@ static void RG_ForkPrepare() { // synchronize all matrices, make sure they're in a consistent state // do not force-flush as this can take awhile Graph_ApplyAllPending(g, false); + + GraphContext_DecreaseRefCount(gc); } } @@ -342,9 +467,13 @@ static void RG_AfterForkParent() { if(INTERMEDIATE_GRAPHS) return; // the child process forked, release all acquired locks - uint graph_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graph_count; i++) { - Graph_ReleaseLock(graphs_in_keyspace[i]->g); + KeySpaceGraphIterator it; + GraphContext *gc = NULL; + Globals_ScanGraphs(&it); + + while((gc = GraphIterator_Next(&it)) != NULL) { + Graph_ReleaseLock(gc->g); + GraphContext_DecreaseRefCount(gc); } } @@ -352,7 +481,7 @@ static void RG_AfterForkParent() { static void RG_AfterForkChild() { // mark that the child is a forked process so that it doesn't // attempt invalid accesses of POSIX primitives it doesn't own - process_is_child = true; + Globals_Set_ProcessIsChild(true); // restrict GraphBLAS to use a single thread this is done for 2 reasons: // 1. save resources @@ -360,10 +489,10 @@ static void RG_AfterForkChild() { // in forked process GxB_set(GxB_NTHREADS, 1); - uint graph_count = array_len(graphs_in_keyspace); - for(uint i = 0; i < graph_count; i++) { - Graph *g = graphs_in_keyspace[i]->g; - + GraphContext **graphs = Globals_Get_GraphsInKeyspace(); + uint32_t n = array_len(graphs); + for(uint32_t i = 0; i < n; i++) { + Graph *g = graphs[i]->g; // all matrices should be synced, set synchronization policy to NOP Graph_SetMatrixPolicy(g, SYNC_POLICY_NOP); } @@ -372,7 +501,7 @@ static void RG_AfterForkChild() { static void _RegisterForkHooks() { redis_main_thread_id = pthread_self(); // This function is being called on the main thread context. - /* Register handlers to control the behavior of fork calls. */ + // register handlers to control the behavior of fork calls int res = pthread_atfork(RG_ForkPrepare, RG_AfterForkParent, RG_AfterForkChild); ASSERT(res == 0); } @@ -404,7 +533,7 @@ void ModuleEventHandler_AUXAfterKeyspaceEvent(void) { } void RegisterEventHandlers(RedisModuleCtx *ctx) { - _RegisterForkHooks(); // Set up hooks for forking logic to prevent bgsave deadlocks. - _RegisterServerEvents(ctx); // Set up hooks for rename and server events on Redis 6 and up. + _RegisterForkHooks(); // set up hooks for forking logic to prevent bgsave deadlocks + _RegisterServerEvents(ctx); // set up hooks for del/rename and server events } diff --git a/src/module_event_handlers.h b/src/module_event_handlers.h index 4130ac9c63..8c9e9d0d7a 100644 --- a/src/module_event_handlers.h +++ b/src/module_event_handlers.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_bfs.c b/src/procedures/proc_bfs.c index a8fcd2bc90..2da88fd1b7 100644 --- a/src/procedures/proc_bfs.c +++ b/src/procedures/proc_bfs.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "proc_bfs.h" diff --git a/src/procedures/proc_bfs.h b/src/procedures/proc_bfs.h index 9cdeaa4ec8..ec6f4dddbc 100644 --- a/src/procedures/proc_bfs.h +++ b/src/procedures/proc_bfs.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_ctx.h b/src/procedures/proc_ctx.h index fd5b48bd58..537fccea1e 100644 --- a/src/procedures/proc_ctx.h +++ b/src/procedures/proc_ctx.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_fulltext_create_index.c b/src/procedures/proc_fulltext_create_index.c index 04b3ad9104..b0ba284f43 100644 --- a/src/procedures/proc_fulltext_create_index.c +++ b/src/procedures/proc_fulltext_create_index.c @@ -1,15 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_fulltext_create_index.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../index/index.h" +#include "../errors/errors.h" #include "../index/indexer.h" #include "../util/rmalloc.h" #include "../graph/graphcontext.h" @@ -38,7 +41,7 @@ static ProcedureResult _validateIndexConfigMap bool stopword_exists = MAP_GET(config, "stopwords", sw); if(!label_exists) { - ErrorCtx_SetError("Label is missing"); + ErrorCtx_SetError(EMSG_IS_MISSING, "Label"); return PROCEDURE_ERR; } @@ -47,7 +50,7 @@ static ProcedureResult _validateIndexConfigMap Index idx = GraphContext_GetIndex(gc, label.stringval, NULL, 0, IDX_FULLTEXT, SCHEMA_NODE); if(idx != NULL) { - ErrorCtx_SetError("Index already exists configuration can't be changed"); + ErrorCtx_SetError(EMSG_INDEX_ALREADY_EXISTS); return PROCEDURE_ERR; } } @@ -62,12 +65,12 @@ static ProcedureResult _validateIndexConfigMap for (uint i = 0; i < stopwords_count; i++) { SIValue stopword = SIArray_Get(sw, i); if(SI_TYPE(stopword) != T_STRING) { - ErrorCtx_SetError("Stopword must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "Stopword", "string"); return PROCEDURE_ERR; } } } else { - ErrorCtx_SetError("Stopwords must be array"); + ErrorCtx_SetError(EMSG_MUST_BE, "Stopwords", "array"); return PROCEDURE_ERR; } } @@ -78,11 +81,11 @@ static ProcedureResult _validateIndexConfigMap if(lang_exists) { if(SI_TYPE(lang) != T_STRING) { - ErrorCtx_SetError("Language must be string"); + ErrorCtx_SetError(EMSG_MUST_BE, "Language", "string"); return PROCEDURE_ERR; } if(RediSearch_ValidateLanguage(lang.stringval)) { - ErrorCtx_SetError("Language is not supported"); + ErrorCtx_SetError(EMSG_NOT_SUPPORTED, "Language"); return PROCEDURE_ERR; } } @@ -114,32 +117,32 @@ static ProcedureResult _validateFieldConfigMap // field name is mandatory if(!field_exists) { - ErrorCtx_SetError("Field is missing"); + ErrorCtx_SetError(EMSG_IS_MISSING, "Field"); return PROCEDURE_ERR; } if((SI_TYPE(field) & T_STRING) == 0) { - ErrorCtx_SetError("Field must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "Field", "string"); return PROCEDURE_ERR; } if(weight_exists) { if((SI_TYPE(weight) & SI_NUMERIC) == 0) { - ErrorCtx_SetError("Weight must be numeric"); + ErrorCtx_SetError(EMSG_MUST_BE, "Weight", "numeric"); return PROCEDURE_ERR; } } if(nostem_exists) { if(SI_TYPE(nostem) != T_BOOL) { - ErrorCtx_SetError("Nostem must be bool"); + ErrorCtx_SetError(EMSG_MUST_BE, "Nostem", "bool"); return PROCEDURE_ERR; } } if(phonetic_exists) { if(SI_TYPE(phonetic) != T_STRING) { - ErrorCtx_SetError("Phonetic must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "Phonetic", "string"); return PROCEDURE_ERR; } } @@ -153,7 +156,7 @@ static ProcedureResult _validateFieldConfigMap Index idx = GraphContext_GetIndex(gc, label, &fieldID, 1, IDX_FULLTEXT, SCHEMA_NODE); if(idx != NULL) { - ErrorCtx_SetError("Index already exists configuration can't be changed"); + ErrorCtx_SetError(EMSG_INDEX_ALREADY_EXISTS); return PROCEDURE_ERR; } } @@ -173,13 +176,13 @@ ProcedureResult Proc_FulltextCreateNodeIdxInvoke ) { uint arg_count = array_len((SIValue *)args); if(arg_count < 2) { - ErrorCtx_SetError("Minimum number of arguments is 2"); + ErrorCtx_SetError(EMSG_FULLTEXT_MIN_ARGS); return PROCEDURE_ERR; } // label argument should be of type string or map if(!(SI_TYPE(args[0]) & (T_STRING | T_MAP))) { - ErrorCtx_SetError("Label argument can be string or map"); + ErrorCtx_SetError(EMSG_FULLTEXT_LABEL_TYPE); return PROCEDURE_ERR; } if(SI_TYPE(args[0]) == T_MAP && @@ -201,7 +204,7 @@ ProcedureResult Proc_FulltextCreateNodeIdxInvoke // validation, fields arguments should be of type string or map for(uint i = 1; i < arg_count; i++) { if(!(SI_TYPE(args[i]) & (T_STRING | T_MAP))) { - ErrorCtx_SetError("Field argument must be string or map"); + ErrorCtx_SetError(EMSG_FULLTEXT_FIELD_TYPE); return PROCEDURE_ERR; } if(SI_TYPE(args[i]) == T_MAP && diff --git a/src/procedures/proc_fulltext_create_index.h b/src/procedures/proc_fulltext_create_index.h index 4768daceb0..3da4f72b69 100644 --- a/src/procedures/proc_fulltext_create_index.h +++ b/src/procedures/proc_fulltext_create_index.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_fulltext_drop_index.c b/src/procedures/proc_fulltext_drop_index.c index 1406410477..fcb989bf42 100644 --- a/src/procedures/proc_fulltext_drop_index.c +++ b/src/procedures/proc_fulltext_drop_index.c @@ -1,15 +1,18 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_fulltext_drop_index.h" #include "../query_ctx.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../index/indexer.h" #include "../graph/graphcontext.h" @@ -41,7 +44,7 @@ ProcedureResult Proc_FulltextDropIndexInvoke int res = GraphContext_DeleteIndex(gc, SCHEMA_NODE, l, NULL, IDX_FULLTEXT); if(res != INDEX_OK) { - ErrorCtx_SetError("ERR Unable to drop index on :%s: no such index.", l); + ErrorCtx_SetError(EMSG_FULLTEXT_DROP_INDEX, l); } return PROCEDURE_OK; diff --git a/src/procedures/proc_fulltext_drop_index.h b/src/procedures/proc_fulltext_drop_index.h index ce5bfa1cb3..43e27ada75 100644 --- a/src/procedures/proc_fulltext_drop_index.h +++ b/src/procedures/proc_fulltext_drop_index.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_fulltext_query.c b/src/procedures/proc_fulltext_query.c index 8f70098900..f9dbf48c8b 100644 --- a/src/procedures/proc_fulltext_query.c +++ b/src/procedures/proc_fulltext_query.c @@ -1,17 +1,20 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_fulltext_query.h" #include "RG.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../index/index.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../graph/graphcontext.h" //------------------------------------------------------------------------------ @@ -94,7 +97,7 @@ ProcedureResult Proc_FulltextQueryNodeInvoke // RediSearch error message is allocated using `rm_strdup` // QueryCtx is expecting to free `error` using `free` // in which case we have no option but to clone error - ErrorCtx_SetError("RediSearch: %s", err); + ErrorCtx_SetError(EMSG_REDISEARCH, err); rm_free(err); // raise the exception, we expect an exception handler to be set // as procedure invocation is done at runtime diff --git a/src/procedures/proc_fulltext_query.h b/src/procedures/proc_fulltext_query.h index 623ef8609f..26746e40b7 100644 --- a/src/procedures/proc_fulltext_query.h +++ b/src/procedures/proc_fulltext_query.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_labels.c b/src/procedures/proc_labels.c index 5e7608546e..8250a0c411 100644 --- a/src/procedures/proc_labels.c +++ b/src/procedures/proc_labels.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_labels.h" #include "RG.h" diff --git a/src/procedures/proc_labels.h b/src/procedures/proc_labels.h index 45fd0c2f14..d01c9706da 100644 --- a/src/procedures/proc_labels.h +++ b/src/procedures/proc_labels.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_list_constraints.c b/src/procedures/proc_list_constraints.c index 88749d0d9c..a8727f9d25 100644 --- a/src/procedures/proc_list_constraints.c +++ b/src/procedures/proc_list_constraints.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_list_constraints.h" #include "RG.h" diff --git a/src/procedures/proc_list_constraints.h b/src/procedures/proc_list_constraints.h index 93d31e5ae2..ce75a6dfe4 100644 --- a/src/procedures/proc_list_constraints.h +++ b/src/procedures/proc_list_constraints.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_list_indexes.c b/src/procedures/proc_list_indexes.c index 8db521ba18..ecd993dc4a 100644 --- a/src/procedures/proc_list_indexes.c +++ b/src/procedures/proc_list_indexes.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_list_indexes.h" #include "RG.h" @@ -165,7 +168,7 @@ static bool _EmitIndex //-------------------------------------------------------------------------- if(ctx->yield_entity_type != NULL) { - if(Index_GraphEntityType(idx) == SCHEMA_NODE) { + if(Index_GraphEntityType(idx) == GETYPE_NODE) { *ctx->yield_entity_type = SI_ConstStringVal("NODE"); } else { *ctx->yield_entity_type = SI_ConstStringVal("RELATIONSHIP"); diff --git a/src/procedures/proc_list_indexes.h b/src/procedures/proc_list_indexes.h index bbefb929d1..8deb1ae4fb 100644 --- a/src/procedures/proc_list_indexes.h +++ b/src/procedures/proc_list_indexes.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_pagerank.c b/src/procedures/proc_pagerank.c index 92c0406ec4..e7bea78302 100644 --- a/src/procedures/proc_pagerank.c +++ b/src/procedures/proc_pagerank.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_pagerank.h" #include "../RG.h" diff --git a/src/procedures/proc_pagerank.h b/src/procedures/proc_pagerank.h index 992d06a5d2..f5e54034f9 100644 --- a/src/procedures/proc_pagerank.h +++ b/src/procedures/proc_pagerank.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_procedures.c b/src/procedures/proc_procedures.c index 44442440b9..12ddfce1e7 100644 --- a/src/procedures/proc_procedures.c +++ b/src/procedures/proc_procedures.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "../util/arr.h" #include "rax.h" diff --git a/src/procedures/proc_procedures.h b/src/procedures/proc_procedures.h index d436a88bc4..6a3b8d1ce6 100644 --- a/src/procedures/proc_procedures.h +++ b/src/procedures/proc_procedures.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_property_keys.c b/src/procedures/proc_property_keys.c index 318daa11c4..6a5889b9e8 100644 --- a/src/procedures/proc_property_keys.c +++ b/src/procedures/proc_property_keys.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_property_keys.h" #include "RG.h" diff --git a/src/procedures/proc_property_keys.h b/src/procedures/proc_property_keys.h index 8d7b6bcc8e..c97672aca0 100644 --- a/src/procedures/proc_property_keys.h +++ b/src/procedures/proc_property_keys.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_relations.c b/src/procedures/proc_relations.c index cc515916f2..1ca4e88f55 100644 --- a/src/procedures/proc_relations.c +++ b/src/procedures/proc_relations.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "proc_labels.h" #include "RG.h" diff --git a/src/procedures/proc_relations.h b/src/procedures/proc_relations.h index f53aefa615..03d8b24ed6 100644 --- a/src/procedures/proc_relations.h +++ b/src/procedures/proc_relations.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_sp_paths.c b/src/procedures/proc_sp_paths.c index 2b144dc404..0ffc3dc2ef 100644 --- a/src/procedures/proc_sp_paths.c +++ b/src/procedures/proc_sp_paths.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "proc_sp_paths.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../graph/graphcontext.h" #include "../datatypes/datatypes.h" @@ -207,18 +210,18 @@ static ProcedureResult validate_config if(!start_exists || !end_exists) { - ErrorCtx_SetError("sourceNode and targetNode are required"); + ErrorCtx_SetError(EMSG_SPPATH_REQUIRED); return false; } if(SI_TYPE(start) != T_NODE || SI_TYPE(end) != T_NODE) { - ErrorCtx_SetError("sourceNode and targetNode must be of type Node"); + ErrorCtx_SetError(EMSG_SPPATH_INVALID_TYPE); return false; } GRAPH_EDGE_DIR direction = GRAPH_EDGE_DIR_OUTGOING; if(dir_exists) { if(SI_TYPE(dir) != T_STRING) { - ErrorCtx_SetError("relDirection values must be 'incoming', 'outgoing' or 'both'"); + ErrorCtx_SetError(EMSG_REL_DIRECTION); return false; } if(strcasecmp(dir.stringval, "incoming") == 0) { @@ -228,7 +231,7 @@ static ProcedureResult validate_config } else if(strcasecmp(dir.stringval, "both") == 0) { direction = GRAPH_EDGE_DIR_BOTH; } else { - ErrorCtx_SetError("relDirection values must be 'incoming', 'outgoing' or 'both'"); + ErrorCtx_SetError(EMSG_REL_DIRECTION); return false; } } @@ -236,7 +239,7 @@ static ProcedureResult validate_config int64_t max_length_val = LONG_MAX - 1; if(max_length_exists) { if(SI_TYPE(max_length) != T_INT64) { - ErrorCtx_SetError("maxLen must be integer"); + ErrorCtx_SetError(EMSG_MUST_BE, "maxLen", "integer"); return false; } max_length_val = SI_GET_NUMERIC(max_length); @@ -249,7 +252,7 @@ static ProcedureResult validate_config if(relationships_exists) { if(SI_TYPE(relationships) != T_ARRAY || !SIArray_AllOfType(relationships, T_STRING)) { - ErrorCtx_SetError("relTypes must be array of strings"); + ErrorCtx_SetError(EMSG_MUST_BE, "relTypes", "array of strings"); return false; } types_count = SIArray_Length(relationships); @@ -280,7 +283,7 @@ static ProcedureResult validate_config if(weight_prop_exists) { if(SI_TYPE(weight_prop) != T_STRING) { - ErrorCtx_SetError("weightProp must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "weightProp", "string"); return false; } ctx->weight_prop = GraphContext_GetAttributeID(gc, weight_prop.stringval); @@ -288,7 +291,7 @@ static ProcedureResult validate_config if(cost_prop_exists) { if(SI_TYPE(cost_prop) != T_STRING) { - ErrorCtx_SetError("costProp must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "costProp", "string"); return false; } ctx->cost_prop = GraphContext_GetAttributeID(gc, cost_prop.stringval); @@ -296,7 +299,7 @@ static ProcedureResult validate_config if(max_cost_exists) { if(SI_TYPE(max_cost) != T_INT64 && SI_TYPE(max_cost) != T_DOUBLE) { - ErrorCtx_SetError("maxCost must be numeric"); + ErrorCtx_SetError(EMSG_MUST_BE, "maxCost", "numeric"); return false; } ctx->max_cost = SI_GET_NUMERIC(max_cost); @@ -304,11 +307,11 @@ static ProcedureResult validate_config if(path_count_exists) { if(SI_TYPE(path_count) != T_INT64) { - ErrorCtx_SetError("pathCount must be integer"); + ErrorCtx_SetError(EMSG_MUST_BE, "pathCount", "integer"); return false; } if(path_count.longval < 0) { - ErrorCtx_SetError("pathCount must be greater than or equal to 0"); + ErrorCtx_SetError(EMSG_MUST_BE_NON_NEGATIVE, "pathCount"); return false; } ctx->path_count = SI_GET_NUMERIC(path_count); diff --git a/src/procedures/proc_sp_paths.h b/src/procedures/proc_sp_paths.h index a6cb233252..3e908876f8 100644 --- a/src/procedures/proc_sp_paths.h +++ b/src/procedures/proc_sp_paths.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/proc_ss_paths.c b/src/procedures/proc_ss_paths.c index 4f0554191c..2b60768a5c 100644 --- a/src/procedures/proc_ss_paths.c +++ b/src/procedures/proc_ss_paths.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "proc_ss_paths.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../graph/graphcontext.h" #include "../datatypes/datatypes.h" @@ -202,18 +205,18 @@ static ProcedureResult validate_config if(!start_exists) { - ErrorCtx_SetError("sourceNode is required"); + ErrorCtx_SetError(EMSG_SSPATH_REQUIRED); return false; } if(SI_TYPE(start) != T_NODE) { - ErrorCtx_SetError("sourceNode must be of type Node"); + ErrorCtx_SetError(EMSG_SSPATH_INVALID_TYPE); return false; } GRAPH_EDGE_DIR direction = GRAPH_EDGE_DIR_OUTGOING; if(dir_exists) { if(SI_TYPE(dir) != T_STRING) { - ErrorCtx_SetError("relDirection values must be 'incoming', 'outgoing' or 'both'"); + ErrorCtx_SetError(EMSG_REL_DIRECTION); return false; } if(strcasecmp(dir.stringval, "incoming") == 0) { @@ -223,7 +226,7 @@ static ProcedureResult validate_config } else if(strcasecmp(dir.stringval, "both") == 0) { direction = GRAPH_EDGE_DIR_BOTH; } else { - ErrorCtx_SetError("relDirection values must be 'incoming', 'outgoing' or 'both'"); + ErrorCtx_SetError(EMSG_REL_DIRECTION); return false; } } @@ -231,7 +234,7 @@ static ProcedureResult validate_config int64_t max_length_val = LONG_MAX - 1; if(max_length_exists) { if(SI_TYPE(max_length) != T_INT64) { - ErrorCtx_SetError("maxLen must be integer"); + ErrorCtx_SetError(EMSG_MUST_BE, "maxLen", "integer"); return false; } max_length_val = SI_GET_NUMERIC(max_length); @@ -244,7 +247,7 @@ static ProcedureResult validate_config if(relationships_exists) { if(SI_TYPE(relationships) != T_ARRAY || !SIArray_AllOfType(relationships, T_STRING)) { - ErrorCtx_SetError("relTypes must be array of strings"); + ErrorCtx_SetError(EMSG_MUST_BE, "relTypes", "array of strings"); return false; } types_count = SIArray_Length(relationships); @@ -275,7 +278,7 @@ static ProcedureResult validate_config if(weight_prop_exists) { if(SI_TYPE(weight_prop) != T_STRING) { - ErrorCtx_SetError("weightProp must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "weightProp", "string"); return false; } ctx->weight_prop = GraphContext_GetAttributeID(gc, weight_prop.stringval); @@ -283,7 +286,7 @@ static ProcedureResult validate_config if(cost_prop_exists) { if(SI_TYPE(cost_prop) != T_STRING) { - ErrorCtx_SetError("costProp must be a string"); + ErrorCtx_SetError(EMSG_MUST_BE, "costProp", "string"); return false; } ctx->cost_prop = GraphContext_GetAttributeID(gc, cost_prop.stringval); @@ -291,7 +294,7 @@ static ProcedureResult validate_config if(max_cost_exists) { if(SI_TYPE(max_cost) != T_INT64 && SI_TYPE(max_cost) != T_DOUBLE) { - ErrorCtx_SetError("maxCost must be numeric"); + ErrorCtx_SetError(EMSG_MUST_BE, "maxCost", "numeric"); return false; } ctx->max_cost = SI_GET_NUMERIC(max_cost); @@ -299,11 +302,11 @@ static ProcedureResult validate_config if(path_count_exists) { if(SI_TYPE(path_count) != T_INT64) { - ErrorCtx_SetError("pathCount must be integer"); + ErrorCtx_SetError(EMSG_MUST_BE, "pathCount", "integer"); return false; } if(path_count.longval < 0) { - ErrorCtx_SetError("pathCount must be greater than or equal to 0"); + ErrorCtx_SetError(EMSG_MUST_BE_NON_NEGATIVE, "pathCount"); return false; } ctx->path_count = SI_GET_NUMERIC(path_count); diff --git a/src/procedures/proc_ss_paths.h b/src/procedures/proc_ss_paths.h index 43dc0f72a2..a6600c14d0 100644 --- a/src/procedures/proc_ss_paths.h +++ b/src/procedures/proc_ss_paths.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/procedure.c b/src/procedures/procedure.c index a8cdad98bd..a374a233db 100644 --- a/src/procedures/procedure.c +++ b/src/procedures/procedure.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "./procedure.h" #include "procedures.h" diff --git a/src/procedures/procedure.h b/src/procedures/procedure.h index 9644801215..5747c64fd1 100644 --- a/src/procedures/procedure.h +++ b/src/procedures/procedure.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/procedures/procedures.h b/src/procedures/procedures.h index d6da067aec..b7a31c4d75 100644 --- a/src/procedures/procedures.h +++ b/src/procedures/procedures.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/queries_log/queries_log.c b/src/queries_log/queries_log.c new file mode 100644 index 0000000000..8123bdab10 --- /dev/null +++ b/src/queries_log/queries_log.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include "queries_log.h" +#include "util/rmalloc.h" +#include "configuration/config.h" + +#include +#include + +// holds query statistics per graph +typedef struct QueriesCounters { + _Atomic uint64_t ro_succeeded_n; // # read-only queries succeeded + _Atomic uint64_t write_succeeded_n; // # write queries succeeded + _Atomic uint64_t ro_failed_n; // # RO queries failed + _Atomic uint64_t write_failed_n; // # write queries failed + _Atomic uint64_t ro_timedout_n; // # RO queries timed out + _Atomic uint64_t write_timedout_n; // # write queries timed out +} QueriesCounters; + +// QueriesLog +// maintains a log of queries +typedef struct _QueriesLog { + CircularBuffer queries; // buffer + CircularBuffer swap; // swap buffer + QueriesCounters counters; // counters with states + pthread_rwlock_t rwlock; // RWLock +} _QueriesLog; + +// create a new queries log structure +QueriesLog QueriesLog_New(void) { + QueriesLog log = rm_calloc(1, sizeof(struct _QueriesLog)); + + // initialize read/write lock + int res = pthread_rwlock_init(&log->rwlock, NULL); + ASSERT(res == 0); + + // create circular buffer + // read buffer capacity from configuration + uint32_t cap; + bool get = Config_Option_get(Config_CMD_INFO_MAX_QUERY_COUNT, &cap); + ASSERT(get == true); + + size_t item_size = sizeof(LoggedQuery); + log->swap = CircularBuffer_New(item_size, cap); + log->queries = CircularBuffer_New(item_size, cap); + + return log; +} + +// add query to buffer +void QueriesLog_AddQuery +( + QueriesLog log, // queries log + uint64_t received, // query received timestamp + double wait_duration, // waiting time + double execution_duration, // executing time + double report_duration, // reporting time + bool parameterized, // uses parameters + bool utilized_cache, // utilized cache + bool write, // write query + bool timeout, // timeout query + const char *query // query string +) { + // add query stats to buffer + // acquire READ lock, multiple threads can be populating the circular buffer + // simultaneously (the circular-buffer is lock-free) + + int res = pthread_rwlock_rdlock(&log->rwlock); + ASSERT(res == 0); + + // get a slot within log's buffer + void *slot = CircularBuffer_Reserve(log->queries); + + // dump query to slot + LoggedQuery *q = (LoggedQuery*)(slot); + + if(q->query != NULL) { + rm_free(q->query); + } + + q->received = received; + q->wait_duration = wait_duration; + q->execution_duration = execution_duration; + q->report_duration = report_duration; + q->parameterized = parameterized; + q->write = write; + q->timeout = timeout; + q->utilized_cache = utilized_cache; + q->query = rm_strdup(query); + + res = pthread_rwlock_unlock(&log->rwlock); + ASSERT(res == 0); +} + +// returns number of queries in log +uint64_t QueriesLog_GetQueriesCount +( + QueriesLog log // queries log +) { + // acquire READ lock to buffer + pthread_rwlock_rdlock(&log->rwlock); + + // there's no harm in returning a lower count than actual + // inf favour of performance + uint64_t n = CircularBuffer_ItemCount(log->queries); + + // release lock + pthread_rwlock_unlock(&log->rwlock); + + return n; +} + +// reset queries buffer +// returns queries buffer prior to reset +CircularBuffer QueriesLog_ResetQueries +( + QueriesLog log // queries log +) { + ASSERT(log != NULL); + + //-------------------------------------------------------------------------- + // swap buffers + //-------------------------------------------------------------------------- + + // acquire WRITE lock, waiting for all readers to finish + int res = pthread_rwlock_wrlock(&log->rwlock); + ASSERT(res == 0); + + CircularBuffer prev = log->queries; + log->queries = log->swap; + log->swap = prev; + + // release lock + res = pthread_rwlock_unlock(&log->rwlock); + ASSERT(res == 0); + + return prev; +} + +// free the QueriesLog structure's content +void QueriesLog_Free +( + QueriesLog log // queries log +) { + ASSERT(log != NULL); + + LoggedQuery *q = NULL; + CircularBuffer_ResetReader(log->queries); + + while((q = CircularBuffer_Read(log->queries, NULL)) != NULL) { + // clean up + if(q->query != NULL) { + rm_free(q->query); + } + } + + CircularBuffer_Free(log->swap); + CircularBuffer_Free(log->queries); + + pthread_rwlock_destroy(&log->rwlock); + + rm_free(log); +} + diff --git a/src/queries_log/queries_log.h b/src/queries_log/queries_log.h new file mode 100644 index 0000000000..29492dafcb --- /dev/null +++ b/src/queries_log/queries_log.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +#include "../util/circular_buffer.h" + +// query statistics +typedef struct QueryStats { + uint64_t received; // query received timestamp + double wait_duration; // waiting time + double execution_duration; // executing time + double report_duration; // reporting time + bool parameterized; // uses parameters + bool utilized_cache; // utilized cache + bool write; // write query + bool timeout; // timeout query + char *query; // query string +} LoggedQuery; + +// forward declaration of opaque QueriesLog structure +typedef struct _QueriesLog *QueriesLog; + +// create a new queries log structure +QueriesLog QueriesLog_New(void); + +// add query to buffer +void QueriesLog_AddQuery +( + QueriesLog log, // queries log + uint64_t received, // query received timestamp + double wait_duration, // waiting time + double execution_duration, // executing time + double report_duration, // reporting time + bool parameterized, // uses parameters + bool utilized_cache, // utilized cache + bool write, // write query + bool timeout, // timeout query + const char *query // query string +); + +// returns number of queries in log +uint64_t QueriesLog_GetQueriesCount +( + QueriesLog log // queries log +); + +// reset queries buffer +// returns queries buffer prior to reset +CircularBuffer QueriesLog_ResetQueries +( + QueriesLog log // queries log +); + +// free the QueriesLog structure's content +void QueriesLog_Free +( + QueriesLog log // queries log +); + diff --git a/src/query_ctx.c b/src/query_ctx.c index 784c30538f..58939d851f 100644 --- a/src/query_ctx.c +++ b/src/query_ctx.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "query_ctx.h" #include "RG.h" @@ -12,20 +15,27 @@ #include "serializers/graphcontext_type.h" #include "undo_log/undo_log.h" -// GraphContext type as it is registered at Redis. +// GraphContext type as it is registered at Redis extern RedisModuleType *GraphContextRedisModuleType; -pthread_key_t _tlsQueryCtxKey; // Thread local storage query context key. +pthread_key_t _tlsQueryCtxKey; // thread local storage query context key // retrieve or instantiate new QueryCtx static inline QueryCtx *_QueryCtx_GetCreateCtx(void) { QueryCtx *ctx = pthread_getspecific(_tlsQueryCtxKey); - if(!ctx) { - // Set a new thread-local QueryCtx if one has not been created. + + if(ctx == NULL) { + // set a new thread-local QueryCtx if one has not been created ctx = rm_calloc(1, sizeof(QueryCtx)); - ctx->undo_log = UndoLog_New(); + + // created lazily only when needed + ctx->undo_log = NULL; + ctx->effects_buffer = NULL; + ctx->stage = QueryStage_WAITING; // initial query stage + pthread_setspecific(_tlsQueryCtxKey, ctx); } + return ctx; } @@ -46,95 +56,256 @@ bool QueryCtx_Init(void) { return (pthread_key_create(&_tlsQueryCtxKey, NULL) == 0); } -inline QueryCtx *QueryCtx_GetQueryCtx() { +inline QueryCtx *QueryCtx_GetQueryCtx(void) { return _QueryCtx_GetCreateCtx(); } -inline void QueryCtx_SetTLS(QueryCtx *query_ctx) { +inline void QueryCtx_SetTLS +( + QueryCtx *query_ctx +) { pthread_setspecific(_tlsQueryCtxKey, query_ctx); } -inline void QueryCtx_RemoveFromTLS() { +inline void QueryCtx_RemoveFromTLS(void) { pthread_setspecific(_tlsQueryCtxKey, NULL); } -void QueryCtx_BeginTimer(void) { - QueryCtx *ctx = _QueryCtx_GetCreateCtx(); // Attempt to retrieve the QueryCtx. - simple_tic(ctx->internal_exec_ctx.timer); // Start the execution timer. +//------------------------------------------------------------------------------ +// query statistics +//------------------------------------------------------------------------------ + +// returns the number of milliseconds the timer has counted +// this function reset the timer +static double _QueryCtx_GetCountedMilliseconds +( + QueryCtx *ctx +) { + ASSERT(ctx != NULL); + + double ms = TIMER_GET_ELAPSED_MILLISECONDS(ctx->stats.timer); + + // resets the stage timer + simple_tic(ctx->stats.timer); + + return ms; +} + +// reads the stage timer and updates the current stage duration +static void _QueryCtx_UpdateStageDuration +( + QueryCtx *ctx // query context +) { + ASSERT(ctx != NULL); + + // update stage duration + ctx->stats.durations[ctx->stage] += _QueryCtx_GetCountedMilliseconds(ctx); +} + +// advance query's stage +// waiting -> executing +// executing -> reporting +// reporting -> finished +void QueryCtx_AdvanceStage +( + QueryCtx *ctx // query context +) { + ASSERT(ctx != NULL); + + // validate query stage + ASSERT(ctx->stage >= QueryStage_WAITING); + ASSERT(ctx->stage <= QueryStage_REPORTING); + + // update stage duration + _QueryCtx_UpdateStageDuration(ctx); + + if(ctx->stage == QueryStage_REPORTING) { + // done reporting, log query + GraphContext_LogQuery(ctx->gc, + ctx->stats.received_ts, + ctx->stats.durations[QueryStage_WAITING], + ctx->stats.durations[QueryStage_EXECUTING], + ctx->stats.durations[QueryStage_REPORTING], + ctx->stats.parameterized, + ctx->stats.utilized_cache, + ctx->flags & QueryExecutionTypeFlag_WRITE, + ctx->status == QueryExecutionStatus_TIMEDOUT, + ctx->query_data.query); + } + + // advance to next stage + ctx->stage++; +} + +// regress query's stage +// waiting <- executing +void QueryCtx_ResetStage +( + QueryCtx *ctx // query context +) { + ASSERT(ctx != NULL); + + // a query can only transition back from executing to waiting + ASSERT(ctx->stage == QueryStage_EXECUTING); + + // update stage duration + _QueryCtx_UpdateStageDuration(ctx); + + // transition from executing to waiting + ctx->stage = QueryStage_WAITING; } -void QueryCtx_SetGlobalExecutionCtx(CommandCtx *cmd_ctx) { +// sets the "utilized_cache" flag of a QueryInfo +void QueryCtx_SetUtilizedCache +( + QueryCtx *ctx, // query context + bool utilized // cache utilized +) { + ASSERT(ctx != NULL); + + ctx->stats.utilized_cache = utilized; +} + +// sets the global execution context +void QueryCtx_SetGlobalExecutionCtx +( + CommandCtx *cmd_ctx +) { + ASSERT(cmd_ctx != NULL); + QueryCtx *ctx = _QueryCtx_GetCreateCtx(); - ctx->gc = CommandCtx_GetGraphContext(cmd_ctx); - ctx->query_data.query = CommandCtx_GetQuery(cmd_ctx); - ctx->global_exec_ctx.bc = CommandCtx_GetBlockingClient(cmd_ctx); - ctx->global_exec_ctx.redis_ctx = CommandCtx_GetRedisCtx(cmd_ctx); + + ctx->gc = CommandCtx_GetGraphContext(cmd_ctx); + ctx->query_data.query = CommandCtx_GetQuery(cmd_ctx); + ctx->global_exec_ctx.bc = CommandCtx_GetBlockingClient(cmd_ctx); + ctx->global_exec_ctx.redis_ctx = CommandCtx_GetRedisCtx(cmd_ctx); ctx->global_exec_ctx.command_name = CommandCtx_GetCommandName(cmd_ctx); + + // copy command's timer + simple_timer_copy(cmd_ctx->timer, ctx->stats.timer); + + // received timestamp (epoch time) + ctx->stats.received_ts = cmd_ctx->received_ts; } -void QueryCtx_SetAST(AST *ast) { +// set the provided AST for access through the QueryCtx +void QueryCtx_SetAST +( + AST *ast +) { QueryCtx *ctx = _QueryCtx_GetCreateCtx(); ctx->query_data.ast = ast; } -void QueryCtx_SetGraphCtx(GraphContext *gc) { +// set the provided GraphCtx for access through the QueryCtx +void QueryCtx_SetGraphCtx +( + GraphContext *gc +) { + ASSERT(gc != NULL); QueryCtx *ctx = _QueryCtx_GetCreateCtx(); ctx->gc = gc; } -void QueryCtx_SetResultSet(ResultSet *result_set) { +// set the resultset +void QueryCtx_SetResultSet +( + ResultSet *result_set +) { + ASSERT(result_set != NULL); + QueryCtx *ctx = _QueryCtx_GetCreateCtx(); ctx->internal_exec_ctx.result_set = result_set; } -void QueryCtx_SetParams(rax *params) { +// set the parameters map +void QueryCtx_SetParams +( + rax *params +) { ASSERT(params != NULL); + QueryCtx *ctx = _QueryCtx_GetCreateCtx(); ctx->query_data.params = params; } +// retrieve the AST AST *QueryCtx_GetAST(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx != NULL); return ctx->query_data.ast; } +// retrieve the query parameters values map rax *QueryCtx_GetParams(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx != NULL); return ctx->query_data.params; } +// retrieve the GraphCtx GraphContext *QueryCtx_GetGraphCtx(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx && ctx->gc); return ctx->gc; } +// retrieve the Graph object Graph *QueryCtx_GetGraph(void) { GraphContext *gc = QueryCtx_GetGraphCtx(); return gc->g; } +// retrieve undo log UndoLog QueryCtx_GetUndoLog(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); - ASSERT(ctx && ctx->undo_log); + ASSERT(ctx != NULL); + if(ctx->undo_log == NULL) { + ctx->undo_log = UndoLog_New(); + } return ctx->undo_log; } +// rollback the current command +void QueryCtx_Rollback(void) { + QueryCtx *ctx = _QueryCtx_GetCtx(); + ASSERT(ctx != NULL); + + Graph_ResetReservedNode(ctx->gc->g); + + if(ctx->undo_log == NULL) return; + + UndoLog_Rollback(&ctx->undo_log); +} + +// retrieve effects-buffer +EffectsBuffer *QueryCtx_GetEffectsBuffer(void) { + QueryCtx *ctx = _QueryCtx_GetCtx(); + ASSERT(ctx != NULL); + + if(ctx->effects_buffer == NULL) { + ctx->effects_buffer = EffectsBuffer_New(); + } + + return ctx->effects_buffer; +} + +// retrieve the Redis module context RedisModuleCtx *QueryCtx_GetRedisModuleCtx(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx != NULL); return ctx->global_exec_ctx.redis_ctx; } +// retrive the resultset ResultSet *QueryCtx_GetResultSet(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx != NULL); return ctx->internal_exec_ctx.result_set; } +// retrive the resultset statistics ResultSetStatistics *QueryCtx_GetResultSetStatistics(void) { ResultSetStatistics *stats = NULL; ResultSet *result_set = QueryCtx_GetResultSet(); @@ -142,21 +313,38 @@ ResultSetStatistics *QueryCtx_GetResultSetStatistics(void) { return stats; } +// print the current query void QueryCtx_PrintQuery(void) { QueryCtx *ctx = _QueryCtx_GetCreateCtx(); printf("%s\n", ctx->query_data.query); } -static void _QueryCtx_ThreadSafeContextLock(QueryCtx *ctx) { +static void _QueryCtx_ThreadSafeContextLock +( + QueryCtx *ctx +) { if(ctx->global_exec_ctx.bc) { RedisModule_ThreadSafeContextLock(ctx->global_exec_ctx.redis_ctx); } } -static void _QueryCtx_ThreadSafeContextUnlock(QueryCtx *ctx) { +static void _QueryCtx_ThreadSafeContextUnlock +( + QueryCtx *ctx +) { if(ctx->global_exec_ctx.bc) RedisModule_ThreadSafeContextUnlock(ctx->global_exec_ctx.redis_ctx); } +// starts a locking flow before commiting changes +// Locking flow: +// 1. lock GIL +// 2. open key with `write` flag +// 3. graph R/W lock with write flag +// since 2PL protocal is implemented, the method returns true if +// it managed to achieve locks in this call or a previous call +// in case that the locks are already locked, there will be no attempt to lock +// them again this method returns false if the key has changed +// from the current graph, and sets the relevant error message bool QueryCtx_LockForCommit(void) { QueryCtx *ctx = _QueryCtx_GetCreateCtx(); if(ctx->internal_exec_ctx.locked_for_commit) return true; @@ -172,16 +360,16 @@ bool QueryCtx_LockForCommit(void) { RedisModuleKey *key = RedisModule_OpenKey(redis_ctx, graphID, REDISMODULE_WRITE); RedisModule_FreeString(redis_ctx, graphID); if(RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { - ErrorCtx_SetError("Encountered an empty key when opened key %s", ctx->gc->graph_name); + ErrorCtx_SetError(EMSG_EMPTY_KEY, ctx->gc->graph_name); goto clean_up; } if(RedisModule_ModuleTypeGetType(key) != GraphContextRedisModuleType) { - ErrorCtx_SetError("Encountered a non-graph value type when opened key %s", ctx->gc->graph_name); + ErrorCtx_SetError(EMSG_NON_GRAPH_KEY, ctx->gc->graph_name); goto clean_up; } if(gc != RedisModule_ModuleTypeGetValue(key)) { - ErrorCtx_SetError("Encountered different graph value when opened key %s", ctx->gc->graph_name); + ErrorCtx_SetError(EMSG_DIFFERENT_VALUE, ctx->gc->graph_name); goto clean_up; } ctx->internal_exec_ctx.key = key; @@ -204,7 +392,10 @@ bool QueryCtx_LockForCommit(void) { return false; } -static void _QueryCtx_UnlockCommit(QueryCtx *ctx) { +static void _QueryCtx_UnlockCommit +( + QueryCtx *ctx +) { GraphContext *gc = ctx->gc; ctx->internal_exec_ctx.locked_for_commit = false; @@ -218,7 +409,26 @@ static void _QueryCtx_UnlockCommit(QueryCtx *ctx) { _QueryCtx_ThreadSafeContextUnlock(ctx); } -// replicate command +// starts an ulocking flow and notifies Redis after commiting changes +// the only writer which allow to perform the unlock and commit (replicate) +// is the last_writer the method get an OpBase and compares it to +// the last writer, if they are equal then the commit and unlock flow will start +// Unlocking flow: +// 1. replicate +// 2. unlock graph R/W lock +// 3. close key +// 4. unlock GIL +void QueryCtx_UnlockCommit() { + QueryCtx *ctx = _QueryCtx_GetCtx(); + if(!ctx) return; + + // already unlocked? + if(!ctx->internal_exec_ctx.locked_for_commit) return; + + _QueryCtx_UnlockCommit(ctx); +} + +// replicate command to AOF/Replicas void QueryCtx_Replicate ( QueryCtx *ctx @@ -233,34 +443,31 @@ void QueryCtx_Replicate "cc!", gc->graph_name, ctx->query_data.query); } -void QueryCtx_UnlockCommit() { - QueryCtx *ctx = _QueryCtx_GetCtx(); - if(!ctx) return; - - // already unlocked? - if(!ctx->internal_exec_ctx.locked_for_commit) return; - - _QueryCtx_UnlockCommit(ctx); -} - -double QueryCtx_GetExecutionTime(void) { +// compute and return elapsed query execution time +double QueryCtx_GetRuntime(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx != NULL); - return simple_toc(ctx->internal_exec_ctx.timer) * 1000; + + return ctx->stats.durations[QueryStage_EXECUTING] + + ctx->stats.durations[QueryStage_REPORTING]; } +// free the allocations within the QueryCtx and reset it for the next query void QueryCtx_Free(void) { QueryCtx *ctx = _QueryCtx_GetCtx(); ASSERT(ctx != NULL); - UndoLog_Free(ctx->undo_log); + UndoLog_Free(&ctx->undo_log); + EffectsBuffer_Free(ctx->effects_buffer); - if(ctx->query_data.params) { + if(ctx->query_data.params != NULL) { raxFreeWithCallback(ctx->query_data.params, _ParameterFreeCallback); ctx->query_data.params = NULL; } rm_free(ctx); + // NULL-set the context for reuse the next time this thread receives a query QueryCtx_RemoveFromTLS(); } + diff --git a/src/query_ctx.h b/src/query_ctx.h index 4fe9cbd986..fcb1b68919 100644 --- a/src/query_ctx.h +++ b/src/query_ctx.h @@ -1,121 +1,231 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include "ast/ast.h" #include "redismodule.h" #include "util/rmalloc.h" +#include "util/simple_timer.h" +#include "undo_log/undo_log.h" #include "graph/graphcontext.h" -#include "commands/cmd_context.h" #include "resultset/resultset.h" +#include "commands/cmd_context.h" #include "execution_plan/ops/op.h" #include "undo_log/undo_log.h" +#include "effects/effects.h" #include extern pthread_key_t _tlsQueryCtxKey; // Thread local storage query context key. +// holds the execution type flags: certain traits of query regarding its +// execution +typedef enum QueryExecutionTypeFlag { + // indicates that this query is a read-only query + QueryExecutionTypeFlag_READ = 0, + // indicates that this query is a write query + QueryExecutionTypeFlag_WRITE = 1 << 0, + // whether or not we want to profile the query + QueryExecutionTypeFlag_PROFILE = 1 << 1, +} QueryExecutionTypeFlag; + +// holds the query execution status +typedef enum QueryExecutionStatus { + QueryExecutionStatus_SUCCESS = 0, + QueryExecutionStatus_FAILURE, + QueryExecutionStatus_TIMEDOUT, +} QueryExecutionStatus; + +// stages a query may be in +typedef enum QueryStage { + QueryStage_WAITING = 0, + QueryStage_EXECUTING = 1, + QueryStage_REPORTING = 2, + QueryStage_FINISHED = 3, +} QueryStage; + typedef struct { - AST *ast; // The scoped AST associated with this query. - rax *params; // Query parameters. - const char *query; // Query string. - const char *query_no_params; // Query string without parameters part. + AST *ast; // the scoped AST associated with this query + rax *params; // query parameters + const char *query; // query string + const char *query_no_params; // query string without parameters part } QueryCtx_QueryData; typedef struct { - double timer[2]; // Query execution time tracking. - RedisModuleKey *key; // Saves an open key value, for later extraction and closing. - ResultSet *result_set; // Save the execution result set. - bool locked_for_commit; // Indicates if a call for QueryCtx_LockForCommit issued before. + RedisModuleKey *key; // graph open key, for later extraction and closing + ResultSet *result_set; // execution result set + bool locked_for_commit; // indicates if QueryCtx_LockForCommit been called } QueryCtx_InternalExecCtx; typedef struct { - RedisModuleCtx *redis_ctx; // The Redis module context. - RedisModuleBlockedClient *bc; // Blocked client. - const char *command_name; // Command name. + RedisModuleCtx *redis_ctx; // the Redis module context + RedisModuleBlockedClient *bc; // blocked client + const char *command_name; // command name } QueryCtx_GlobalExecCtx; +// query statistics typedef struct { - QueryCtx_QueryData query_data; // The data related to the query syntax. - QueryCtx_InternalExecCtx internal_exec_ctx; // The data related to internal query execution. - QueryCtx_GlobalExecCtx global_exec_ctx; // The data rlated to global redis execution. - GraphContext *gc; // The GraphContext associated with this query's graph. - UndoLog undo_log; // Undo log for updates, used in the case of write query can fail and rollback is needed. + simple_timer_t timer; // stage timer + uint64_t received_ts; // query received timestamp + double durations[3]; // stage durations + bool parameterized; // uses parameters + bool utilized_cache; // utilized cache +} QueryStats; + +typedef struct QueryCtx { + QueryStats stats; // query statistics + GraphContext *gc; // GraphContext associated with this query's graph + UndoLog undo_log; // undo-log in case rollback is needed + QueryStage stage; // query execution stage + QueryExecutionStatus status; // query execution status + QueryExecutionTypeFlag flags; // execution flags + EffectsBuffer *effects_buffer; // effects-buffer for replication, used when write query succeed and replication is needed + QueryCtx_QueryData query_data; // data related to the query syntax + QueryCtx_GlobalExecCtx global_exec_ctx; // data related to global redis execution + QueryCtx_InternalExecCtx internal_exec_ctx; // data related to internal query execution } QueryCtx; -/* Instantiate the thread-local QueryCtx on module load. */ +// instantiate the thread-local QueryCtx on module load bool QueryCtx_Init(void); -/* Retrieve this thread's QueryCtx. */ -QueryCtx *QueryCtx_GetQueryCtx(); +// retrieve this thread's QueryCtx +QueryCtx *QueryCtx_GetQueryCtx(void); + +// set the provided QueryCtx in this thread's storage key +void QueryCtx_SetTLS +( + QueryCtx *query_ctx +); + +// Null-set this thread's storage key +void QueryCtx_RemoveFromTLS(void); + +//------------------------------------------------------------------------------ +// query statistics +//------------------------------------------------------------------------------ + +// advance query's stage +// waiting -> executing +// executing -> reporting +// reporting -> finished +void QueryCtx_AdvanceStage +( + QueryCtx *ctx // query context +); + +// reset query's stage +// waiting <- executing +void QueryCtx_ResetStage +( + QueryCtx *ctx // query context +); -/* Set the provided QueryCtx in this thread's storage key. */ -void QueryCtx_SetTLS(QueryCtx *query_ctx); +// sets the "utilized_cache" flag of a QueryInfo +void QueryCtx_SetUtilizedCache +( + QueryCtx *ctx, // query context + bool utilized // cache utilized +); -/* Null-set this thread's storage key. */ -void QueryCtx_RemoveFromTLS(); +//------------------------------------------------------------------------------ +// setters +//------------------------------------------------------------------------------ -/* Start timing query execution. */ -void QueryCtx_BeginTimer(void); +// sets the global execution context +void QueryCtx_SetGlobalExecutionCtx +( + CommandCtx *cmd_ctx +); -/* Setters */ -/* Sets the global execution context */ -void QueryCtx_SetGlobalExecutionCtx(CommandCtx *cmd_ctx); -/* Set the provided AST for access through the QueryCtx. */ -void QueryCtx_SetAST(AST *ast); -/* Set the provided GraphCtx for access through the QueryCtx. */ -void QueryCtx_SetGraphCtx(GraphContext *gc); -/* Set the resultset. */ -void QueryCtx_SetResultSet(ResultSet *result_set); -/* Set the parameters map. */ -void QueryCtx_SetParams(rax *params); +// set the provided AST for access through the QueryCtx +void QueryCtx_SetAST +( + AST *ast +); -/* Getters */ -/* Retrieve the AST. */ +// set the provided GraphCtx for access through the QueryCtx +void QueryCtx_SetGraphCtx +( + GraphContext *gc +); + +// set the resultset +void QueryCtx_SetResultSet +( + ResultSet *result_set +); + +// set the parameters map +void QueryCtx_SetParams +( + rax *params +); + +//------------------------------------------------------------------------------ +// getters +//------------------------------------------------------------------------------ + +// retrieve the AST AST *QueryCtx_GetAST(void); -/* Retrieve the query parameters values map. */ + +// retrieve the query parameters values map rax *QueryCtx_GetParams(void); -/* Retrieve the Graph object. */ + +// retrieve the GraphCtx +GraphContext *QueryCtx_GetGraphCtx(void); + +// retrieve the Graph object Graph *QueryCtx_GetGraph(void); -// Retrieve undo log + +// retrieve undo log UndoLog QueryCtx_GetUndoLog(void); -/* Retrieve the GraphCtx. */ -GraphContext *QueryCtx_GetGraphCtx(void); -/* Retrieve the Redis module context. */ + +// rollback the current command +void QueryCtx_Rollback(void); + +// retrieve effects-buffer +EffectsBuffer *QueryCtx_GetEffectsBuffer(void); + +// retrieve the Redis module context RedisModuleCtx *QueryCtx_GetRedisModuleCtx(void); -/* Retrive the resultset. */ + +// retrive the resultset ResultSet *QueryCtx_GetResultSet(void); -/* Retrive the resultset statistics. */ + +// retrive the resultset statistics ResultSetStatistics *QueryCtx_GetResultSetStatistics(void); // print the current query void QueryCtx_PrintQuery(void); -/* Starts a locking flow before commiting changes in the graph and Redis keyspace. - * Locking flow is: - * 1. LOCK GIL - * 2. Key open with `write` flag - * 3. Graph R/W lock with write flag - * Since 2PL protocal is implemented, the method returns true if the it managed to achieve - * locks in this call or a previous call. In case that the locks are already locked, there will - * be no attempt to lock them again. - * This method returns false if the key has changed from the current graph, - * and sets the relevant error message. */ +// starts a locking flow before commiting changes +// Locking flow: +// 1. lock GIL +// 2. open key with `write` flag +// 3. graph R/W lock with write flag +// since 2PL protocal is implemented, the method returns true if +// it managed to achieve locks in this call or a previous call +// in case that the locks are already locked, there will be no attempt to lock +// them again this method returns false if the key has changed +// from the current graph, and sets the relevant error message bool QueryCtx_LockForCommit(void); -/* Starts an ulocking flow and notifies Redis after commiting changes in the graph and Redis keyspace. - * The only writer which allow to perform the unlock and commit(replicate) is the last_writer. - * The method get an OpBase and compares it to the last writer, if they are equal then the commit - * and unlock flow will start. - * Unlocking flow is: - * 1. Replicate. - * 2. Unlock graph R/W lock - * 3. Close key - * 4. Unlock GIL */ -void QueryCtx_UnlockCommit(); +// starts an ulocking flow and notifies Redis after commiting changes +// the only writer which allow to perform the unlock and commit (replicate) +// is the last_writer the method get an OpBase and compares it to +// the last writer, if they are equal then the commit and unlock flow will start +// Unlocking flow: +// 1. replicate +// 2. unlock graph R/W lock +// 3. close key +// 4. unlock GIL +void QueryCtx_UnlockCommit(void); // replicate command to AOF/Replicas void QueryCtx_Replicate @@ -123,8 +233,9 @@ void QueryCtx_Replicate QueryCtx *ctx ); -/* Compute and return elapsed query execution time. */ -double QueryCtx_GetExecutionTime(void); +// compute and return elapsed query execution time +double QueryCtx_GetRuntime(void); -/* Free the allocations within the QueryCtx and reset it for the next query. */ +// free the allocations within the QueryCtx and reset it for the next query void QueryCtx_Free(void); + diff --git a/src/redismodule.h b/src/redismodule.h index c53e4f5aa6..34982e3c32 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #ifndef REDISMODULE_H #define REDISMODULE_H @@ -6,18 +15,44 @@ #include #include + +typedef struct RedisModuleString RedisModuleString; +typedef struct RedisModuleKey RedisModuleKey; + +/* -------------- Defines NOT common between core and modules ------------- */ + +#if defined REDISMODULE_CORE +/* Things only defined for the modules core (server), not exported to modules + * that include this file. */ + +#define RedisModuleString robj + +#endif /* defined REDISMODULE_CORE */ + +#if !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE +/* Things defined for modules, but not for core-modules. */ + +typedef long long mstime_t; +typedef long long ustime_t; + +#endif /* !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE */ + /* ---------------- Defines common between core and modules --------------- */ /* Error status return values. */ #define REDISMODULE_OK 0 #define REDISMODULE_ERR 1 +/* Module Based Authentication status return values. */ +#define REDISMODULE_AUTH_HANDLED 0 +#define REDISMODULE_AUTH_NOT_HANDLED 1 + /* API versions. */ #define REDISMODULE_APIVER_1 1 /* Version of the RedisModuleTypeMethods structure. Once the RedisModuleTypeMethods * structure is changed, this version number needs to be changed synchronistically. */ -#define REDISMODULE_TYPE_METHOD_VERSION 4 +#define REDISMODULE_TYPE_METHOD_VERSION 5 /* API flags and constants */ #define REDISMODULE_READ (1<<0) @@ -26,6 +61,18 @@ /* RedisModule_OpenKey extra flags for the 'mode' argument. * Avoid touching the LRU/LFU of the key when opened. */ #define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16) +/* Don't trigger keyspace event on key misses. */ +#define REDISMODULE_OPEN_KEY_NONOTIFY (1<<17) +/* Don't update keyspace hits/misses counters. */ +#define REDISMODULE_OPEN_KEY_NOSTATS (1<<18) +/* Avoid deleting lazy expired keys. */ +#define REDISMODULE_OPEN_KEY_NOEXPIRE (1<<19) +/* Avoid any effects from fetching the key */ +#define REDISMODULE_OPEN_KEY_NOEFFECTS (1<<20) +/* Mask of all REDISMODULE_OPEN_KEY_* values. Any new mode should be added to this list. + * Should not be used directly by the module, use RM_GetOpenKeyModesAll instead. + * Located here so when we will add new modes we will not forget to update it. */ +#define _REDISMODULE_OPEN_KEY_ALL REDISMODULE_READ | REDISMODULE_WRITE | REDISMODULE_OPEN_KEY_NOTOUCH | REDISMODULE_OPEN_KEY_NONOTIFY | REDISMODULE_OPEN_KEY_NOSTATS | REDISMODULE_OPEN_KEY_NOEXPIRE | REDISMODULE_OPEN_KEY_NOEFFECTS /* List push and pop */ #define REDISMODULE_LIST_HEAD 0 @@ -55,6 +102,7 @@ #define REDISMODULE_REPLY_BIG_NUMBER 9 #define REDISMODULE_REPLY_VERBATIM_STRING 10 #define REDISMODULE_REPLY_ATTRIBUTE 11 +#define REDISMODULE_REPLY_PROMISE 12 /* Postponed array length. */ #define REDISMODULE_POSTPONED_ARRAY_LEN -1 /* Deprecated, please use REDISMODULE_POSTPONED_LEN */ @@ -80,6 +128,16 @@ #define REDISMODULE_HASH_EXISTS (1<<3) #define REDISMODULE_HASH_COUNT_ALL (1<<4) +#define REDISMODULE_CONFIG_DEFAULT 0 /* This is the default for a module config. */ +#define REDISMODULE_CONFIG_IMMUTABLE (1ULL<<0) /* Can this value only be set at startup? */ +#define REDISMODULE_CONFIG_SENSITIVE (1ULL<<1) /* Does this value contain sensitive information */ +#define REDISMODULE_CONFIG_HIDDEN (1ULL<<4) /* This config is hidden in `config get ` (used for tests/debugging) */ +#define REDISMODULE_CONFIG_PROTECTED (1ULL<<5) /* Becomes immutable if enable-protected-configs is enabled. */ +#define REDISMODULE_CONFIG_DENY_LOADING (1ULL<<6) /* This config is forbidden during loading. */ + +#define REDISMODULE_CONFIG_MEMORY (1ULL<<7) /* Indicates if this value can be set as a memory value */ +#define REDISMODULE_CONFIG_BITFLAGS (1ULL<<8) /* Indicates if this value can be set as a multiple enum values */ + /* StreamID type. */ typedef struct RedisModuleStreamID { uint64_t ms; @@ -152,11 +210,13 @@ typedef struct RedisModuleStreamID { #define REDISMODULE_CTX_FLAGS_RESP3 (1<<22) /* Redis is currently async loading database for diskless replication. */ #define REDISMODULE_CTX_FLAGS_ASYNC_LOADING (1<<23) +/* Redis is starting. */ +#define REDISMODULE_CTX_FLAGS_SERVER_STARTUP (1<<24) /* Next context flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetContextFlagsAll instead. */ -#define _REDISMODULE_CTX_FLAGS_NEXT (1<<24) +#define _REDISMODULE_CTX_FLAGS_NEXT (1<<25) /* Keyspace changes notification classes. Every class is associated with a * character for configuration purposes. @@ -175,14 +235,17 @@ This flag should not be used directly by the module. #define REDISMODULE_NOTIFY_KEY_MISS (1<<11) /* m (Note: This one is excluded from REDISMODULE_NOTIFY_ALL on purpose) */ #define REDISMODULE_NOTIFY_LOADED (1<<12) /* module only key space notification, indicate a key loaded from rdb */ #define REDISMODULE_NOTIFY_MODULE (1<<13) /* d, module key space notification */ +#define REDISMODULE_NOTIFY_NEW (1<<14) /* n, new key notification */ /* Next notification flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetKeyspaceNotificationFlagsAll instead. */ -#define _REDISMODULE_NOTIFY_NEXT (1<<14) +#define _REDISMODULE_NOTIFY_NEXT (1<<15) #define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM | REDISMODULE_NOTIFY_MODULE) /* A */ +#define REDISMODULE_NOTIFY_TRIMMED (1<<30) /* trimmed by reshard trimming enterprise only event */ + /* A special pointer that we can use between the core and the module to signal * field deletion, and that is impossible to be a valid pointer. */ #define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1) @@ -222,6 +285,10 @@ This flag should not be used directly by the module. #define REDISMODULE_YIELD_FLAG_NONE (1<<0) #define REDISMODULE_YIELD_FLAG_CLIENTS (1<<1) +/* RM_BlockClientOnKeysWithFlags flags */ +#define REDISMODULE_BLOCK_UNBLOCK_DEFAULT (0) +#define REDISMODULE_BLOCK_UNBLOCK_DELETED (1<<0) + /* This type represents a timer handle, and is returned when a timer is * registered and used in order to invalidate a timer. It's just a 64 bit * number, because this is how each timer is represented inside the radix tree @@ -238,12 +305,21 @@ typedef uint64_t RedisModuleTimerID; /* When set, Redis will not call RedisModule_SignalModifiedKey(), implicitly in * RedisModule_CloseKey, and the module needs to do that when manually when keys - * are modified from the user's sperspective, to invalidate WATCH. */ + * are modified from the user's perspective, to invalidate WATCH. */ #define REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED (1<<1) /* Declare that the module can handle diskless async replication with RedisModule_SetModuleOptions. */ #define REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD (1<<2) +/* Declare that the module want to get nested key space notifications. + * If enabled, the module is responsible to break endless loop. */ +#define REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS (1<<3) + +/* Next option flag, must be updated when adding new module flags above! + * This flag should not be used directly by the module. + * Use RedisModule_GetModuleOptionsAll instead. */ +#define _REDISMODULE_OPTIONS_FLAGS_NEXT (1<<4) + /* Definitions for RedisModule_SetCommandInfo. */ typedef enum { @@ -313,7 +389,9 @@ typedef struct RedisModuleCommandArg { const char *summary; const char *since; int flags; /* The REDISMODULE_CMD_ARG_* macros. */ + const char *deprecated_since; struct RedisModuleCommandArg *subargs; + const char *display_text; } RedisModuleCommandArg; typedef struct { @@ -335,7 +413,7 @@ typedef struct { const char *keyword; /* An index in argv from which to start searching. * Can be negative, which means start search from the end, in reverse - * (Example: -2 means to start in reverse from the panultimate arg) */ + * (Example: -2 means to start in reverse from the penultimate arg) */ int startfrom; } keyword; } bs; @@ -429,7 +507,9 @@ typedef void (*RedisModuleEventLoopOneShotFunc)(void *user_data); #define REDISMODULE_EVENT_FORK_CHILD 13 #define REDISMODULE_EVENT_REPL_ASYNC_LOAD 14 #define REDISMODULE_EVENT_EVENTLOOP 15 -#define _REDISMODULE_EVENT_NEXT 16 /* Next event flag, should be updated if a new event added. */ +#define REDISMODULE_EVENT_CONFIG 16 +#define REDISMODULE_EVENT_KEY 17 +#define _REDISMODULE_EVENT_NEXT 18 /* Next event flag, should be updated if a new event added. */ typedef struct RedisModuleEvent { uint64_t id; /* REDISMODULE_EVENT_... defines. */ @@ -532,7 +612,15 @@ static const RedisModuleEvent RedisModuleEvent_EventLoop = { REDISMODULE_EVENT_EVENTLOOP, 1 -}; + }, + RedisModuleEvent_Config = { + REDISMODULE_EVENT_CONFIG, + 1 + }, + RedisModuleEvent_Key = { + REDISMODULE_EVENT_KEY, + 1 + }; /* Those are values that are used for the 'subevent' callback argument. */ #define REDISMODULE_SUBEVENT_PERSISTENCE_RDB_START 0 @@ -574,6 +662,9 @@ static const RedisModuleEvent #define REDISMODULE_SUBEVENT_MODULE_UNLOADED 1 #define _REDISMODULE_SUBEVENT_MODULE_NEXT 2 +#define REDISMODULE_SUBEVENT_CONFIG_CHANGE 0 +#define _REDISMODULE_SUBEVENT_CONFIG_NEXT 1 + #define REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB 0 #define REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF 1 #define _REDISMODULE_SUBEVENT_LOADING_PROGRESS_NEXT 2 @@ -597,6 +688,12 @@ static const RedisModuleEvent #define REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP 1 #define _REDISMODULE_SUBEVENT_EVENTLOOP_NEXT 2 +#define REDISMODULE_SUBEVENT_KEY_DELETED 0 +#define REDISMODULE_SUBEVENT_KEY_EXPIRED 1 +#define REDISMODULE_SUBEVENT_KEY_EVICTED 2 +#define REDISMODULE_SUBEVENT_KEY_OVERWRITTEN 3 +#define _REDISMODULE_SUBEVENT_KEY_NEXT 4 + #define _REDISMODULE_SUBEVENT_SHUTDOWN_NEXT 0 #define _REDISMODULE_SUBEVENT_CRON_LOOP_NEXT 0 #define _REDISMODULE_SUBEVENT_SWAPDB_NEXT 0 @@ -636,6 +733,8 @@ typedef struct RedisModuleClientInfo { #define RedisModuleClientInfo RedisModuleClientInfoV1 +#define REDISMODULE_CLIENTINFO_INITIALIZER_V1 { .version = 1 } + #define REDISMODULE_REPLICATIONINFO_VERSION 1 typedef struct RedisModuleReplicationInfo { uint64_t version; /* Not used since this structure is never passed @@ -674,6 +773,17 @@ typedef struct RedisModuleModuleChange { #define RedisModuleModuleChange RedisModuleModuleChangeV1 +#define REDISMODULE_CONFIGCHANGE_VERSION 1 +typedef struct RedisModuleConfigChange { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + uint32_t num_changes; /* how many redis config options were changed */ + const char **config_names; /* the config names that were changed */ +} RedisModuleConfigChangeV1; + +#define RedisModuleConfigChange RedisModuleConfigChangeV1 + #define REDISMODULE_CRON_LOOP_VERSION 1 typedef struct RedisModuleCronLoopInfo { uint64_t version; /* Not used since this structure is never passed @@ -707,11 +817,40 @@ typedef struct RedisModuleSwapDbInfo { #define RedisModuleSwapDbInfo RedisModuleSwapDbInfoV1 -/* ------------------------- End of common defines ------------------------ */ +#define REDISMODULE_KEYINFO_VERSION 1 +typedef struct RedisModuleKeyInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + RedisModuleKey *key; /* Opened key. */ +} RedisModuleKeyInfoV1; -#ifndef REDISMODULE_CORE +#define RedisModuleKeyInfo RedisModuleKeyInfoV1 -typedef long long mstime_t; +typedef enum { + REDISMODULE_ACL_LOG_AUTH = 0, /* Authentication failure */ + REDISMODULE_ACL_LOG_CMD, /* Command authorization failure */ + REDISMODULE_ACL_LOG_KEY, /* Key authorization failure */ + REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */ +} RedisModuleACLLogEntryReason; + +/* Incomplete structures needed by both the core and modules. */ +typedef struct RedisModuleIO RedisModuleIO; +typedef struct RedisModuleDigest RedisModuleDigest; +typedef struct RedisModuleInfoCtx RedisModuleInfoCtx; +typedef struct RedisModuleDefragCtx RedisModuleDefragCtx; + +/* Function pointers needed by both the core and modules, these needs to be + * exposed since you can't cast a function pointer to (void *). */ +typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report); +typedef void (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx); +typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata); + +/* ------------------------- End of common defines ------------------------ */ + +/* ----------- The rest of the defines are only for modules ----------------- */ +#if !defined REDISMODULE_CORE || defined REDISMODULE_CORE_MODULE +/* Things defined for modules and core-modules. */ /* Macro definitions specific to individual compilers */ #ifndef REDISMODULE_ATTR_UNUSED @@ -741,28 +880,24 @@ typedef long long mstime_t; /* Incomplete structures for compiler checks but opaque access. */ typedef struct RedisModuleCtx RedisModuleCtx; typedef struct RedisModuleCommand RedisModuleCommand; -typedef struct RedisModuleKey RedisModuleKey; -typedef struct RedisModuleString RedisModuleString; typedef struct RedisModuleCallReply RedisModuleCallReply; -typedef struct RedisModuleIO RedisModuleIO; typedef struct RedisModuleType RedisModuleType; -typedef struct RedisModuleDigest RedisModuleDigest; typedef struct RedisModuleBlockedClient RedisModuleBlockedClient; typedef struct RedisModuleClusterInfo RedisModuleClusterInfo; typedef struct RedisModuleDict RedisModuleDict; typedef struct RedisModuleDictIter RedisModuleDictIter; typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx; typedef struct RedisModuleCommandFilter RedisModuleCommandFilter; -typedef struct RedisModuleInfoCtx RedisModuleInfoCtx; typedef struct RedisModuleServerInfoData RedisModuleServerInfoData; typedef struct RedisModuleScanCursor RedisModuleScanCursor; -typedef struct RedisModuleDefragCtx RedisModuleDefragCtx; typedef struct RedisModuleUser RedisModuleUser; typedef struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx; +typedef struct RedisModuleRdbStream RedisModuleRdbStream; typedef int (*RedisModuleCmdFunc)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc); typedef int (*RedisModuleNotificationFunc)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key); +typedef void (*RedisModulePostNotificationJobFunc) (RedisModuleCtx *ctx, void *pd); typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver); typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value); typedef int (*RedisModuleTypeAuxLoadFunc)(RedisModuleIO *rdb, int encver, int when); @@ -783,11 +918,19 @@ typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const cha typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data); typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter); typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data); -typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report); typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata); typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata); -typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata); -typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx); +typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata); +typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigGetEnumFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigSetStringFunc)(const char *name, RedisModuleString *val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetNumericFunc)(const char *name, long long val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetBoolFunc)(const char *name, int val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetEnumFunc)(const char *name, int val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigApplyFunc)(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err); +typedef void (*RedisModuleOnUnblocked)(RedisModuleCtx *ctx, RedisModuleCallReply *reply, void *private_data); +typedef int (*RedisModuleAuthCallback)(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err); typedef struct RedisModuleTypeMethods { uint64_t version; @@ -808,6 +951,7 @@ typedef struct RedisModuleTypeMethods { RedisModuleTypeFreeEffortFunc2 free_effort2; RedisModuleTypeUnlinkFunc2 unlink2; RedisModuleTypeCopyFunc2 copy2; + RedisModuleTypeAuxSaveFunc aux_save2; } RedisModuleTypeMethods; #define REDISMODULE_GET_API(name) \ @@ -824,6 +968,7 @@ typedef struct RedisModuleTypeMethods { #endif REDISMODULE_API void * (*RedisModule_Alloc)(size_t bytes) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_TryAlloc)(size_t bytes) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_Realloc)(void *ptr, size_t bytes) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_Free)(void *ptr) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_Calloc)(size_t nmemb, size_t size) REDISMODULE_ATTR; @@ -833,6 +978,8 @@ REDISMODULE_API int (*RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char REDISMODULE_API RedisModuleCommand *(*RedisModule_GetCommand)(RedisModuleCtx *ctx, const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CreateSubcommand)(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SetCommandInfo)(RedisModuleCommand *command, const RedisModuleCommandInfo *info) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetCommandACLCategories)(RedisModuleCommand *command, const char *ctgrsflags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AddACLCategory)(RedisModuleCtx *ctx, const char *name) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsModuleNameBusy)(const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_WrongArity)(RedisModuleCtx *ctx) REDISMODULE_ATTR; @@ -840,7 +987,8 @@ REDISMODULE_API int (*RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long l REDISMODULE_API int (*RedisModule_GetSelectedDb)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname) REDISMODULE_ATTR; -REDISMODULE_API void * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleKey * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetOpenKeyModesAll)(void) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_CloseKey)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KeyType)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_ValueLength)(RedisModuleKey *kp) REDISMODULE_ATTR; @@ -862,11 +1010,14 @@ REDISMODULE_API const char* (*RedisModule_CallReplyVerbatim)(RedisModuleCallRepl REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplySetElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CallReplyMapElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CallReplyAttributeElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_CallReplyPromiseSetUnblockHandler)(RedisModuleCallReply *reply, RedisModuleOnUnblocked on_unblock, void *private_data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyPromiseAbort)(RedisModuleCallReply *reply, void **private_data) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyAttribute)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_CallReplyLength)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromULongLong)(RedisModuleCtx *ctx, unsigned long long ull) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongDouble)(RedisModuleCtx *ctx, long double ld, int humanfriendly) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str) REDISMODULE_ATTR; @@ -875,6 +1026,7 @@ REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringPrintf)(RedisModul REDISMODULE_API void (*RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API const char * (*RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithErrorFormat)(RedisModuleCtx *ctx, const char *fmt, ...) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithMap)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; @@ -900,6 +1052,7 @@ REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d REDISMODULE_API int (*RedisModule_ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToULongLong)(const RedisModuleString *str, unsigned long long *ull) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongDouble)(const RedisModuleString *str, long double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToStreamID)(const RedisModuleString *str, RedisModuleStreamID *id) REDISMODULE_ATTR; @@ -952,9 +1105,12 @@ REDISMODULE_API void (*RedisModule_ChannelAtPosWithFlags)(RedisModuleCtx *ctx, i REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientUserNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetClientNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetClientNameById)(uint64_t id, RedisModuleString *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_PublishMessageShard)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_AvoidReplicaTraffic)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AvoidReplicaTraffic)(void) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes) REDISMODULE_ATTR; REDISMODULE_API RedisModuleType * (*RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value) REDISMODULE_ATTR; @@ -990,7 +1146,7 @@ REDISMODULE_API int (*RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, Redis REDISMODULE_API void (*RedisModule_TrimStringAllocation)(RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_HoldString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringCompare)(const RedisModuleString *a, const RedisModuleString *b) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCtx * (*RedisModule_GetContextFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromModuleKey)(RedisModuleKey *key) REDISMODULE_ATTR; @@ -1000,8 +1156,10 @@ REDISMODULE_API int (*RedisModule_GetDbIdFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_API int (*RedisModule_GetToDbIdFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetToKeyNameFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API long long (*RedisModule_Milliseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API mstime_t (*RedisModule_Milliseconds)(void) REDISMODULE_ATTR; REDISMODULE_API uint64_t (*RedisModule_MonotonicMicroseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API ustime_t (*RedisModule_Microseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API ustime_t (*RedisModule_CachedMicroseconds)(void) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, const char *ele, size_t len) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestEndSequence)(RedisModuleDigest *md) REDISMODULE_ATTR; @@ -1030,6 +1188,7 @@ REDISMODULE_API RedisModuleString * (*RedisModule_DictPrev)(RedisModuleCtx *ctx, REDISMODULE_API int (*RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_RegisterInfoFunc)(RedisModuleCtx *ctx, RedisModuleInfoFunc cb) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_RegisterAuthCallback)(RedisModuleCtx *ctx, RedisModuleAuthCallback cb) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_InfoEndDictField)(RedisModuleInfoCtx *ctx) REDISMODULE_ATTR; @@ -1051,20 +1210,25 @@ REDISMODULE_API int (*RedisModule_GetLRU)(RedisModuleKey *key, mstime_t *lru_idl REDISMODULE_API int (*RedisModule_SetLFU)(RedisModuleKey *key, long long lfu_freq) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetLFU)(RedisModuleKey *key, long long *lfu_freq) REDISMODULE_ATTR; REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClientOnKeys)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClientOnKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata, int flags) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_SignalKeyAsReady)(RedisModuleCtx *ctx, RedisModuleString *key) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetBlockedClientReadyKey)(RedisModuleCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API RedisModuleScanCursor * (*RedisModule_ScanCursorCreate)() REDISMODULE_ATTR; +REDISMODULE_API RedisModuleScanCursor * (*RedisModule_ScanCursorCreate)(void) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_ScanCursorRestart)(RedisModuleScanCursor *cursor) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_ScanCursorDestroy)(RedisModuleScanCursor *cursor) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_Scan)(RedisModuleCtx *ctx, RedisModuleScanCursor *cursor, RedisModuleScanCB fn, void *privdata) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ScanKey)(RedisModuleKey *key, RedisModuleScanCursor *cursor, RedisModuleScanKeyCB fn, void *privdata) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_GetContextFlagsAll)() REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_GetKeyspaceNotificationFlagsAll)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetContextFlagsAll)(void) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetModuleOptionsAll)(void) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetKeyspaceNotificationFlagsAll)(void) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsSubEventSupported)(RedisModuleEvent event, uint64_t subevent) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_GetServerVersion)() REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_GetTypeMethodVersion)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetServerVersion)(void) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetTypeMethodVersion)(void) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_Yield)(RedisModuleCtx *ctx, int flags, const char *busy_reply) REDISMODULE_ATTR; REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_BlockClientGetPrivateData)(RedisModuleBlockedClient *blocked_client) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_BlockClientSetPrivateData)(RedisModuleBlockedClient *blocked_client, void *private_data) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClientOnAuth)(RedisModuleCtx *ctx, RedisModuleAuthCallback reply_callback, void (*free_privdata)(RedisModuleCtx*,void*)) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; @@ -1080,8 +1244,9 @@ REDISMODULE_API void (*RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx) R REDISMODULE_API int (*RedisModule_ThreadSafeContextTryLock)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AddPostNotificationJob)(RedisModuleCtx *ctx, RedisModulePostNotificationJobFunc callback, void *pd, void (*free_pd)(void*)) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_NotifyKeyspaceEvent)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_GetNotifyKeyspaceEvents)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetNotifyKeyspaceEvents)(void) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len) REDISMODULE_ATTR; @@ -1106,24 +1271,33 @@ REDISMODULE_API RedisModuleString * (*RedisModule_CommandFilterArgGet)(RedisModu REDISMODULE_API int (*RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API unsigned long long (*RedisModule_CommandFilterGetClientId)(RedisModuleCommandFilterCtx *fctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_Fork)(RedisModuleForkDoneHandler cb, void *user_data) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_SendChildHeartbeat)(double progress) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ExitFromChild)(int retcode) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KillForkChild)(int child_pid) REDISMODULE_ATTR; -REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)() REDISMODULE_ATTR; +REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)(void) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_MallocSize)(void* ptr) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocUsableSize)(void *ptr) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSizeString)(RedisModuleString* str) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSizeDict)(RedisModuleDict* dict) REDISMODULE_ATTR; REDISMODULE_API RedisModuleUser * (*RedisModule_CreateModuleUser)(const char *name) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeModuleUser)(RedisModuleUser *user) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SetContextUser)(RedisModuleCtx *ctx, const RedisModuleUser *user) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SetModuleUserACL)(RedisModuleUser *user, const char* acl) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetModuleUserACLString)(RedisModuleCtx * ctx, RedisModuleUser *user, const char* acl, RedisModuleString **error) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetModuleUserACLString)(RedisModuleUser *user) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetCurrentUserName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleUser * (*RedisModule_GetModuleUserFromUserName)(RedisModuleString *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ACLCheckCommandPermissions)(RedisModuleUser *user, RedisModuleString **argv, int argc) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ACLCheckKeyPermissions)(RedisModuleUser *user, RedisModuleString *key, int flags) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ACLCheckChannelPermissions)(RedisModuleUser *user, RedisModuleString *ch, int literal) REDISMODULE_ATTR; -REDISMODULE_API void (*RedisModule_ACLAddLogEntry)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ACLAddLogEntry)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ACLAddLogEntryByUserName)(RedisModuleCtx *ctx, RedisModuleString *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AuthenticateClientWithACLUser)(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RedactClientCommandArgument)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR; REDISMODULE_API int *(*RedisModule_GetCommandKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags) REDISMODULE_ATTR; @@ -1139,6 +1313,15 @@ REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromDefragCtx) REDISMODULE_API int (*RedisModule_EventLoopAdd)(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_EventLoopDel)(int fd, int mask) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_EventLoopAddOneShot)(RedisModuleEventLoopOneShotFunc func, void *user_data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterBoolConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterNumericConfig)(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterStringConfig)(RedisModuleCtx *ctx, const char *name, const char *default_val, unsigned int flags, RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterEnumConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, const char **enum_values, const int *int_values, int num_enum_vals, RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_LoadConfigs)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleRdbStream *(*RedisModule_RdbStreamCreateFromFile)(const char *filename) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_RdbStreamFree)(RedisModuleRdbStream *stream) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RdbLoad)(RedisModuleCtx *ctx, RedisModuleRdbStream *stream, int flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RdbSave)(RedisModuleCtx *ctx, RedisModuleRdbStream *stream, int flags) REDISMODULE_ATTR; // enterprise only REDISMODULE_API int (*RedisModule_ShardingGetKeySlot)(RedisModuleString *keyname) REDISMODULE_ATTR; @@ -1152,6 +1335,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int void *getapifuncptr = ((void**)ctx)[0]; RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr; REDISMODULE_GET_API(Alloc); + REDISMODULE_GET_API(TryAlloc); REDISMODULE_GET_API(Calloc); REDISMODULE_GET_API(Free); REDISMODULE_GET_API(Realloc); @@ -1160,11 +1344,14 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(GetCommand); REDISMODULE_GET_API(CreateSubcommand); REDISMODULE_GET_API(SetCommandInfo); + REDISMODULE_GET_API(SetCommandACLCategories); + REDISMODULE_GET_API(AddACLCategory); REDISMODULE_GET_API(SetModuleAttribs); REDISMODULE_GET_API(IsModuleNameBusy); REDISMODULE_GET_API(WrongArity); REDISMODULE_GET_API(ReplyWithLongLong); REDISMODULE_GET_API(ReplyWithError); + REDISMODULE_GET_API(ReplyWithErrorFormat); REDISMODULE_GET_API(ReplyWithSimpleString); REDISMODULE_GET_API(ReplyWithArray); REDISMODULE_GET_API(ReplyWithMap); @@ -1193,6 +1380,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(SelectDb); REDISMODULE_GET_API(KeyExists); REDISMODULE_GET_API(OpenKey); + REDISMODULE_GET_API(GetOpenKeyModesAll); REDISMODULE_GET_API(CloseKey); REDISMODULE_GET_API(KeyType); REDISMODULE_GET_API(ValueLength); @@ -1203,6 +1391,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ListInsert); REDISMODULE_GET_API(ListDelete); REDISMODULE_GET_API(StringToLongLong); + REDISMODULE_GET_API(StringToULongLong); REDISMODULE_GET_API(StringToDouble); REDISMODULE_GET_API(StringToLongDouble); REDISMODULE_GET_API(StringToStreamID); @@ -1217,6 +1406,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CallReplySetElement); REDISMODULE_GET_API(CallReplyMapElement); REDISMODULE_GET_API(CallReplyAttributeElement); + REDISMODULE_GET_API(CallReplyPromiseSetUnblockHandler); + REDISMODULE_GET_API(CallReplyPromiseAbort); REDISMODULE_GET_API(CallReplyAttribute); REDISMODULE_GET_API(CallReplyType); REDISMODULE_GET_API(CallReplyLength); @@ -1225,6 +1416,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CreateStringFromCallReply); REDISMODULE_GET_API(CreateString); REDISMODULE_GET_API(CreateStringFromLongLong); + REDISMODULE_GET_API(CreateStringFromULongLong); REDISMODULE_GET_API(CreateStringFromDouble); REDISMODULE_GET_API(CreateStringFromLongDouble); REDISMODULE_GET_API(CreateStringFromString); @@ -1327,6 +1519,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(GetToDbIdFromOptCtx); REDISMODULE_GET_API(Milliseconds); REDISMODULE_GET_API(MonotonicMicroseconds); + REDISMODULE_GET_API(Microseconds); + REDISMODULE_GET_API(CachedMicroseconds); REDISMODULE_GET_API(DigestAddStringBuffer); REDISMODULE_GET_API(DigestAddLongLong); REDISMODULE_GET_API(DigestEndSequence); @@ -1355,6 +1549,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(DictCompare); REDISMODULE_GET_API(DictCompareC); REDISMODULE_GET_API(RegisterInfoFunc); + REDISMODULE_GET_API(RegisterAuthCallback); REDISMODULE_GET_API(InfoAddSection); REDISMODULE_GET_API(InfoBeginDictField); REDISMODULE_GET_API(InfoEndDictField); @@ -1371,13 +1566,17 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ServerInfoGetFieldUnsigned); REDISMODULE_GET_API(ServerInfoGetFieldDouble); REDISMODULE_GET_API(GetClientInfoById); + REDISMODULE_GET_API(GetClientNameById); + REDISMODULE_GET_API(SetClientNameById); REDISMODULE_GET_API(PublishMessage); + REDISMODULE_GET_API(PublishMessageShard); REDISMODULE_GET_API(SubscribeToServerEvent); REDISMODULE_GET_API(SetLRU); REDISMODULE_GET_API(GetLRU); REDISMODULE_GET_API(SetLFU); REDISMODULE_GET_API(GetLFU); REDISMODULE_GET_API(BlockClientOnKeys); + REDISMODULE_GET_API(BlockClientOnKeysWithFlags); REDISMODULE_GET_API(SignalKeyAsReady); REDISMODULE_GET_API(GetBlockedClientReadyKey); REDISMODULE_GET_API(ScanCursorCreate); @@ -1386,6 +1585,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(Scan); REDISMODULE_GET_API(ScanKey); REDISMODULE_GET_API(GetContextFlagsAll); + REDISMODULE_GET_API(GetModuleOptionsAll); REDISMODULE_GET_API(GetKeyspaceNotificationFlagsAll); REDISMODULE_GET_API(IsSubEventSupported); REDISMODULE_GET_API(GetServerVersion); @@ -1398,6 +1598,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ThreadSafeContextTryLock); REDISMODULE_GET_API(ThreadSafeContextUnlock); REDISMODULE_GET_API(BlockClient); + REDISMODULE_GET_API(BlockClientGetPrivateData); + REDISMODULE_GET_API(BlockClientSetPrivateData); + REDISMODULE_GET_API(BlockClientOnAuth); REDISMODULE_GET_API(UnblockClient); REDISMODULE_GET_API(IsBlockedReplyRequest); REDISMODULE_GET_API(IsBlockedTimeoutRequest); @@ -1408,6 +1611,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(BlockedClientMeasureTimeEnd); REDISMODULE_GET_API(SetDisconnectCallback); REDISMODULE_GET_API(SubscribeToKeyspaceEvents); + REDISMODULE_GET_API(AddPostNotificationJob); REDISMODULE_GET_API(NotifyKeyspaceEvent); REDISMODULE_GET_API(GetNotifyKeyspaceEvents); REDISMODULE_GET_API(BlockedClientDisconnected); @@ -1433,24 +1637,33 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CommandFilterArgInsert); REDISMODULE_GET_API(CommandFilterArgReplace); REDISMODULE_GET_API(CommandFilterArgDelete); + REDISMODULE_GET_API(CommandFilterGetClientId); REDISMODULE_GET_API(Fork); REDISMODULE_GET_API(SendChildHeartbeat); REDISMODULE_GET_API(ExitFromChild); REDISMODULE_GET_API(KillForkChild); REDISMODULE_GET_API(GetUsedMemoryRatio); REDISMODULE_GET_API(MallocSize); + REDISMODULE_GET_API(MallocUsableSize); + REDISMODULE_GET_API(MallocSizeString); + REDISMODULE_GET_API(MallocSizeDict); REDISMODULE_GET_API(CreateModuleUser); REDISMODULE_GET_API(FreeModuleUser); + REDISMODULE_GET_API(SetContextUser); REDISMODULE_GET_API(SetModuleUserACL); + REDISMODULE_GET_API(SetModuleUserACLString); + REDISMODULE_GET_API(GetModuleUserACLString); REDISMODULE_GET_API(GetCurrentUserName); REDISMODULE_GET_API(GetModuleUserFromUserName); REDISMODULE_GET_API(ACLCheckCommandPermissions); REDISMODULE_GET_API(ACLCheckKeyPermissions); REDISMODULE_GET_API(ACLCheckChannelPermissions); REDISMODULE_GET_API(ACLAddLogEntry); + REDISMODULE_GET_API(ACLAddLogEntryByUserName); REDISMODULE_GET_API(DeauthenticateAndCloseClient); REDISMODULE_GET_API(AuthenticateClientWithACLUser); REDISMODULE_GET_API(AuthenticateClientWithUser); + REDISMODULE_GET_API(RedactClientCommandArgument); REDISMODULE_GET_API(GetClientCertificate); REDISMODULE_GET_API(GetCommandKeys); REDISMODULE_GET_API(GetCommandKeysWithFlags); @@ -1466,6 +1679,19 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(EventLoopAdd); REDISMODULE_GET_API(EventLoopDel); REDISMODULE_GET_API(EventLoopAddOneShot); + REDISMODULE_GET_API(RegisterBoolConfig); + REDISMODULE_GET_API(RegisterNumericConfig); + REDISMODULE_GET_API(RegisterStringConfig); + REDISMODULE_GET_API(RegisterEnumConfig); + REDISMODULE_GET_API(LoadConfigs); + REDISMODULE_GET_API(RdbStreamCreateFromFile); + REDISMODULE_GET_API(RdbStreamFree); + REDISMODULE_GET_API(RdbLoad); + REDISMODULE_GET_API(RdbSave); + + // enterprise only + REDISMODULE_GET_API(ShardingGetKeySlot); + REDISMODULE_GET_API(ShardingGetSlotRange); if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR; RedisModule_SetModuleAttribs(ctx,name,ver,apiver); @@ -1476,11 +1702,5 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int #define RMAPI_FUNC_SUPPORTED(func) (func != NULL) -#else - -/* Things only defined for the modules core, not exported to modules - * including this file. */ -#define RedisModuleString robj - #endif /* REDISMODULE_CORE */ -#endif /* REDISMODULE_H */ \ No newline at end of file +#endif /* REDISMODULE_H */ diff --git a/src/resultset/formatters/resultset_formatter.h b/src/resultset/formatters/resultset_formatter.h index d87b7adbbb..5f62eb01b9 100644 --- a/src/resultset/formatters/resultset_formatter.h +++ b/src/resultset/formatters/resultset_formatter.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/resultset/formatters/resultset_formatters.c b/src/resultset/formatters/resultset_formatters.c index 4e49eaa4de..17983330e8 100644 --- a/src/resultset/formatters/resultset_formatters.c +++ b/src/resultset/formatters/resultset_formatters.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "resultset_formatters.h" diff --git a/src/resultset/formatters/resultset_formatters.h b/src/resultset/formatters/resultset_formatters.h index 736b5f08cc..bd79df3c86 100644 --- a/src/resultset/formatters/resultset_formatters.h +++ b/src/resultset/formatters/resultset_formatters.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/resultset/formatters/resultset_replycompact.c b/src/resultset/formatters/resultset_replycompact.c index 91512879c5..ed7529bf51 100644 --- a/src/resultset/formatters/resultset_replycompact.c +++ b/src/resultset/formatters/resultset_replycompact.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "resultset_formatters.h" #include "RG.h" @@ -99,7 +102,7 @@ static void _ResultSet_CompactReplyWithSIValue(RedisModuleCtx *ctx, GraphContext static void _ResultSet_CompactReplyWithProperties(RedisModuleCtx *ctx, GraphContext *gc, const GraphEntity *e) { const AttributeSet set = GraphEntity_GetAttributes(e); - int prop_count = ATTRIBUTE_SET_COUNT(set); + int prop_count = AttributeSet_Count(set); RedisModule_ReplyWithArray(ctx, prop_count); // Iterate over all properties stored on entity for(int i = 0; i < prop_count; i ++) { @@ -160,7 +163,7 @@ static void _ResultSet_CompactReplyWithEdge(RedisModuleCtx *ctx, GraphContext *g RedisModule_ReplyWithLongLong(ctx, id); // reltype string index, retrieve reltype. - int reltype_id = Graph_GetEdgeRelation(gc->g, e); + int reltype_id = Edge_GetRelationID(e); ASSERT(reltype_id != GRAPH_NO_RELATION); RedisModule_ReplyWithLongLong(ctx, reltype_id); diff --git a/src/resultset/formatters/resultset_replycompact.h b/src/resultset/formatters/resultset_replycompact.h index 364567a844..0be9f849e1 100644 --- a/src/resultset/formatters/resultset_replycompact.h +++ b/src/resultset/formatters/resultset_replycompact.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/resultset/formatters/resultset_replynop.c b/src/resultset/formatters/resultset_replynop.c index 11ef3ef87a..1ae44e749a 100644 --- a/src/resultset/formatters/resultset_replynop.c +++ b/src/resultset/formatters/resultset_replynop.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "resultset_formatters.h" #include "../../util/arr.h" diff --git a/src/resultset/formatters/resultset_replynop.h b/src/resultset/formatters/resultset_replynop.h index 70d9d3fb5a..2a23b567e6 100644 --- a/src/resultset/formatters/resultset_replynop.h +++ b/src/resultset/formatters/resultset_replynop.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/resultset/formatters/resultset_replyverbose.c b/src/resultset/formatters/resultset_replyverbose.c index abcfe04f3f..c39798b8e8 100644 --- a/src/resultset/formatters/resultset_replyverbose.c +++ b/src/resultset/formatters/resultset_replyverbose.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "resultset_formatters.h" #include "../../util/arr.h" @@ -61,12 +64,16 @@ static void _ResultSet_VerboseReplyWithSIValue(RedisModuleCtx *ctx, GraphContext } } -static void _ResultSet_VerboseReplyWithProperties(RedisModuleCtx *ctx, GraphContext *gc, - const GraphEntity *e) { +static void _ResultSet_VerboseReplyWithProperties +( + RedisModuleCtx *ctx, + GraphContext *gc, + const GraphEntity *e +) { const AttributeSet set = GraphEntity_GetAttributes(e); - int prop_count = ATTRIBUTE_SET_COUNT(set); + int prop_count = AttributeSet_Count(set); RedisModule_ReplyWithArray(ctx, prop_count); - // Iterate over all properties stored on entity + // iterate over all properties stored on entity for(int i = 0; i < prop_count; i ++) { RedisModule_ReplyWithArray(ctx, 2); Attribute_ID attr_id; @@ -141,12 +148,12 @@ static void _ResultSet_VerboseReplyWithEdge(RedisModuleCtx *ctx, GraphContext *g const char *reltype = Schema_GetName(s); RedisModule_ReplyWithStringBuffer(ctx, reltype, strlen(reltype)); - // ["src_node", srcNodeID (integer)] + // ["src_node", src_id (integer)] RedisModule_ReplyWithArray(ctx, 2); RedisModule_ReplyWithStringBuffer(ctx, "src_node", 8); RedisModule_ReplyWithLongLong(ctx, Edge_GetSrcNodeID(e)); - // ["dest_node", destNodeID (integer)] + // ["dest_node", dest_id (integer)] RedisModule_ReplyWithArray(ctx, 2); RedisModule_ReplyWithStringBuffer(ctx, "dest_node", 9); RedisModule_ReplyWithLongLong(ctx, Edge_GetDestNodeID(e)); diff --git a/src/resultset/formatters/resultset_replyverbose.h b/src/resultset/formatters/resultset_replyverbose.h index 73c6335378..0320799195 100644 --- a/src/resultset/formatters/resultset_replyverbose.h +++ b/src/resultset/formatters/resultset_replyverbose.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/resultset/resultset.c b/src/resultset/resultset.c index 0c716a75e1..1ad1b0bca6 100644 --- a/src/resultset/resultset.c +++ b/src/resultset/resultset.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "resultset.h" #include "RG.h" #include "../value.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" static void _ResultSet_ReplyWithPreamble ( diff --git a/src/resultset/resultset.h b/src/resultset/resultset.h index 0bb06f400f..8f766cde7c 100644 --- a/src/resultset/resultset.h +++ b/src/resultset/resultset.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/resultset/resultset_statistics.c b/src/resultset/resultset_statistics.c index 9adcc853ed..a524c4395c 100644 --- a/src/resultset/resultset_statistics.c +++ b/src/resultset/resultset_statistics.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "../query_ctx.h" @@ -129,7 +132,7 @@ void ResultSetStat_emit RedisModule_ReplyWithStringBuffer(ctx, (const char *)buff, buflen); // emit query execution time - double t = QueryCtx_GetExecutionTime(); + double t = QueryCtx_GetRuntime(); buflen = sprintf(buff, "Query internal execution time: %.6f milliseconds", t); RedisModule_ReplyWithStringBuffer(ctx, buff, buflen); } diff --git a/src/resultset/resultset_statistics.h b/src/resultset/resultset_statistics.h index 302681b192..f9c6f81830 100644 --- a/src/resultset/resultset_statistics.h +++ b/src/resultset/resultset_statistics.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/schema/schema.c b/src/schema/schema.c index 3d4915e18a..50705b5131 100644 --- a/src/schema/schema.c +++ b/src/schema/schema.c @@ -1,14 +1,17 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "schema.h" -#include "../errors.h" #include "../util/arr.h" #include "../query_ctx.h" #include "../util/rmalloc.h" +#include "../errors/errors.h" #include "../index/indexer.h" #include "../graph/graphcontext.h" #include "../constraint/constraint.h" @@ -162,7 +165,7 @@ static int _Schema_RemoveExactMatchIndex if(Constraint_GetStatus(c) != CT_FAILED && Constraint_GetType(c) == CT_UNIQUE && Constraint_ContainsAttribute(c, attr_id)) { - ErrorCtx_SetError("Index supports constraint"); + ErrorCtx_SetError(EMSG_INDEX_SUPPORT_CONSTRAINTS); return INDEX_FAIL; } } diff --git a/src/schema/schema.h b/src/schema/schema.h index 88ed3c37bb..ee68bc3226 100644 --- a/src/schema/schema.h +++ b/src/schema/schema.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decode_context.c b/src/serializers/decode_context.c index d40ede8990..ebb9a2c0ab 100644 --- a/src/serializers/decode_context.c +++ b/src/serializers/decode_context.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_context.h" #include "../RG.h" diff --git a/src/serializers/decode_context.h b/src/serializers/decode_context.h index 202e2b1d99..3abb7d8017 100644 --- a/src/serializers/decode_context.h +++ b/src/serializers/decode_context.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/current/v13/decode_graph.c b/src/serializers/decoders/current/v13/decode_graph.c index ad1f2db6f0..2e4b393abf 100644 --- a/src/serializers/decoders/current/v13/decode_graph.c +++ b/src/serializers/decoders/current/v13/decode_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v13.h" #include "../../../../index/indexer.h" @@ -11,14 +14,17 @@ static GraphContext *_GetOrCreateGraphContext ( char *graph_name ) { - GraphContext *gc = GraphContext_GetRegisteredGraphContext(graph_name); - if(!gc) { - // New graph is being decoded. Inform the module and create new graph context. + GraphContext *gc = GraphContext_UnsafeGetGraphContext(graph_name); + if(gc == NULL) { + // new graph is being decoded + // inform the module and create new graph context gc = GraphContext_New(graph_name); - // While loading the graph, minimize matrix realloc and synchronization calls. + // while loading the graph + // minimize matrix realloc and synchronization calls Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); } - // Free the name string, as it either not in used or copied. + + // free the name string, as it either not in used or copied RedisModule_Free(graph_name); return gc; @@ -188,7 +194,6 @@ GraphContext *RdbLoadGraphContext_v13 } } - GraphContext_ActivateAllConstraints(gc); array_free(key_schema); // update decode context diff --git a/src/serializers/decoders/current/v13/decode_graph_entities.c b/src/serializers/decoders/current/v13/decode_graph_entities.c index a3dc334732..b7ff2f40b6 100644 --- a/src/serializers/decoders/current/v13/decode_graph_entities.c +++ b/src/serializers/decoders/current/v13/decode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v13.h" @@ -80,14 +83,16 @@ static void _RdbLoadEntity // #properties N // (name, value type, value) X N - uint64_t propCount = RedisModule_LoadUnsigned(rdb); + uint64_t n = RedisModule_LoadUnsigned(rdb); + SIValue vals[n]; + Attribute_ID ids[n]; - for(int i = 0; i < propCount; i++) { - Attribute_ID attr_id = RedisModule_LoadUnsigned(rdb); - SIValue attr_value = _RdbLoadSIValue(rdb); - GraphEntity_AddProperty(e, attr_id, attr_value); - SIValue_Free(attr_value); + for(int i = 0; i < n; i++) { + ids[i] = RedisModule_LoadUnsigned(rdb); + vals[i] = _RdbLoadSIValue(rdb); } + + AttributeSet_AddNoClone(e->attributes, ids, vals, n, false); } void RdbLoadNodes_v13 diff --git a/src/serializers/decoders/current/v13/decode_graph_schema.c b/src/serializers/decoders/current/v13/decode_graph_schema.c index 1155a25535..2129f41c6b 100644 --- a/src/serializers/decoders/current/v13/decode_graph_schema.c +++ b/src/serializers/decoders/current/v13/decode_graph_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v13.h" #include "../../../../schema/schema.h" diff --git a/src/serializers/decoders/current/v13/decode_v13.h b/src/serializers/decoders/current/v13/decode_v13.h index a21168915f..a144a32e89 100644 --- a/src/serializers/decoders/current/v13/decode_v13.h +++ b/src/serializers/decoders/current/v13/decode_v13.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/decode_graph.c b/src/serializers/decoders/decode_graph.c index 80e55a1ccb..aa08b2156a 100644 --- a/src/serializers/decoders/decode_graph.c +++ b/src/serializers/decoders/decode_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_graph.h" #include "current/v13/decode_v13.h" diff --git a/src/serializers/decoders/decode_graph.h b/src/serializers/decoders/decode_graph.h index 6e02508e08..f64f2867e8 100644 --- a/src/serializers/decoders/decode_graph.h +++ b/src/serializers/decoders/decode_graph.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/decode_previous.c b/src/serializers/decoders/decode_previous.c index 13efaaaf3b..9e1d6882b5 100644 --- a/src/serializers/decoders/decode_previous.c +++ b/src/serializers/decoders/decode_previous.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_previous.h" #include "prev/decoders.h" diff --git a/src/serializers/decoders/decode_previous.h b/src/serializers/decoders/decode_previous.h index a480cf2490..7b4130e778 100644 --- a/src/serializers/decoders/decode_previous.h +++ b/src/serializers/decoders/decode_previous.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/prev/decoders.h b/src/serializers/decoders/prev/decoders.h index eefa8a3216..94537ae5b2 100644 --- a/src/serializers/decoders/prev/decoders.h +++ b/src/serializers/decoders/prev/decoders.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "v8/decode_v8.h" #include "v9/decode_v9.h" diff --git a/src/serializers/decoders/prev/v10/decode_graph.c b/src/serializers/decoders/prev/v10/decode_graph.c index 7fe734bd73..1285ec327e 100644 --- a/src/serializers/decoders/prev/v10/decode_graph.c +++ b/src/serializers/decoders/prev/v10/decode_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v10.h" @@ -10,14 +13,16 @@ static GraphContext *_GetOrCreateGraphContext ( char *graph_name ) { - GraphContext *gc = GraphContext_GetRegisteredGraphContext(graph_name); + GraphContext *gc = GraphContext_UnsafeGetGraphContext(graph_name); if(!gc) { - // New graph is being decoded. Inform the module and create new graph context. + // new graph is being decoded + // inform the module and create new graph context gc = GraphContext_New(graph_name); - // While loading the graph, minimize matrix realloc and synchronization calls. + // while loading the graph + // minimize matrix realloc and synchronization calls Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); } - // Free the name string, as it either not in used or copied. + // free the name string, as it either not in used or copied RedisModule_Free(graph_name); return gc; diff --git a/src/serializers/decoders/prev/v10/decode_graph_entities.c b/src/serializers/decoders/prev/v10/decode_graph_entities.c index 041f5d770c..b925fd1845 100644 --- a/src/serializers/decoders/prev/v10/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v10/decode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v10.h" @@ -61,21 +64,27 @@ static SIValue _RdbLoadSIArray(RedisModuleIO *rdb) { return list; } -static void _RdbLoadEntity(RedisModuleIO *rdb, GraphContext *gc, GraphEntity *e) { +static void _RdbLoadEntity +( + RedisModuleIO *rdb, + GraphContext *gc, + GraphEntity *e +) { /* Format: * #properties N * (name, value type, value) X N */ - uint64_t propCount = RedisModule_LoadUnsigned(rdb); + uint64_t n = RedisModule_LoadUnsigned(rdb); + SIValue vals[n]; + Attribute_ID ids[n]; - for(int i = 0; i < propCount; i++) { - Attribute_ID attr_id = RedisModule_LoadUnsigned(rdb); - SIValue attr_value = _RdbLoadSIValue(rdb); - GraphEntity_AddProperty(e, attr_id, attr_value); - SIValue_Free(attr_value); + for(int i = 0; i < n; i++) { + ids[i] = RedisModule_LoadUnsigned(rdb); + vals[i] = _RdbLoadSIValue(rdb); } -} + AttributeSet_AddNoClone(e->attributes, ids, vals, n, false); +} void RdbLoadNodes_v10(RedisModuleIO *rdb, GraphContext *gc, uint64_t node_count) { /* Node Format: diff --git a/src/serializers/decoders/prev/v10/decode_graph_schema.c b/src/serializers/decoders/prev/v10/decode_graph_schema.c index 5df51dbb26..c14a3a0ca3 100644 --- a/src/serializers/decoders/prev/v10/decode_graph_schema.c +++ b/src/serializers/decoders/prev/v10/decode_graph_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v10.h" diff --git a/src/serializers/decoders/prev/v10/decode_v10.h b/src/serializers/decoders/prev/v10/decode_v10.h index c2604ee2fc..ff36053a7f 100644 --- a/src/serializers/decoders/prev/v10/decode_v10.h +++ b/src/serializers/decoders/prev/v10/decode_v10.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/prev/v11/decode_graph.c b/src/serializers/decoders/prev/v11/decode_graph.c index 39696761d0..3732dc9842 100644 --- a/src/serializers/decoders/prev/v11/decode_graph.c +++ b/src/serializers/decoders/prev/v11/decode_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v11.h" @@ -10,14 +13,16 @@ static GraphContext *_GetOrCreateGraphContext ( char *graph_name ) { - GraphContext *gc = GraphContext_GetRegisteredGraphContext(graph_name); + GraphContext *gc = GraphContext_UnsafeGetGraphContext(graph_name); if(!gc) { - // New graph is being decoded. Inform the module and create new graph context. + // new graph is being decoded + // inform the module and create new graph context gc = GraphContext_New(graph_name); - // While loading the graph, minimize matrix realloc and synchronization calls. + // while loading the graph + // minimize matrix realloc and synchronization calls Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); } - // Free the name string, as it either not in used or copied. + // free the name string, as it either not in used or copied RedisModule_Free(graph_name); return gc; diff --git a/src/serializers/decoders/prev/v11/decode_graph_entities.c b/src/serializers/decoders/prev/v11/decode_graph_entities.c index 2a508d9285..afad10c625 100644 --- a/src/serializers/decoders/prev/v11/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v11/decode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v11.h" @@ -80,14 +83,16 @@ static void _RdbLoadEntity // #properties N // (name, value type, value) X N - uint64_t propCount = RedisModule_LoadUnsigned(rdb); + uint64_t n = RedisModule_LoadUnsigned(rdb); + SIValue vals[n]; + Attribute_ID ids[n]; - for(int i = 0; i < propCount; i++) { - Attribute_ID attr_id = RedisModule_LoadUnsigned(rdb); - SIValue attr_value = _RdbLoadSIValue(rdb); - GraphEntity_AddProperty(e, attr_id, attr_value); - SIValue_Free(attr_value); + for(int i = 0; i < n; i++) { + ids[i] = RedisModule_LoadUnsigned(rdb); + vals[i] = _RdbLoadSIValue(rdb); } + + AttributeSet_AddNoClone(e->attributes, ids, vals, n, false); } void RdbLoadNodes_v11 diff --git a/src/serializers/decoders/prev/v11/decode_graph_schema.c b/src/serializers/decoders/prev/v11/decode_graph_schema.c index 1b171cd7cd..3f895e7240 100644 --- a/src/serializers/decoders/prev/v11/decode_graph_schema.c +++ b/src/serializers/decoders/prev/v11/decode_graph_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v11.h" diff --git a/src/serializers/decoders/prev/v11/decode_v11.h b/src/serializers/decoders/prev/v11/decode_v11.h index 4a77a789ec..9bd2cdc127 100644 --- a/src/serializers/decoders/prev/v11/decode_v11.h +++ b/src/serializers/decoders/prev/v11/decode_v11.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/prev/v12/decode_graph.c b/src/serializers/decoders/prev/v12/decode_graph.c index 84c47a3a8b..8e9c135884 100644 --- a/src/serializers/decoders/prev/v12/decode_graph.c +++ b/src/serializers/decoders/prev/v12/decode_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v12.h" @@ -10,14 +13,16 @@ static GraphContext *_GetOrCreateGraphContext ( char *graph_name ) { - GraphContext *gc = GraphContext_GetRegisteredGraphContext(graph_name); + GraphContext *gc = GraphContext_UnsafeGetGraphContext(graph_name); if(!gc) { - // New graph is being decoded. Inform the module and create new graph context. + // new graph is being decoded + // inform the module and create new graph context gc = GraphContext_New(graph_name); - // While loading the graph, minimize matrix realloc and synchronization calls. + // while loading the graph + // minimize matrix realloc and synchronization calls Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); } - // Free the name string, as it either not in used or copied. + // free the name string, as it either not in used or copied RedisModule_Free(graph_name); return gc; diff --git a/src/serializers/decoders/prev/v12/decode_graph_entities.c b/src/serializers/decoders/prev/v12/decode_graph_entities.c index 7ca7f98b66..02aa5e7a2d 100644 --- a/src/serializers/decoders/prev/v12/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v12/decode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v12.h" @@ -80,14 +83,16 @@ static void _RdbLoadEntity // #properties N // (name, value type, value) X N - uint64_t propCount = RedisModule_LoadUnsigned(rdb); + uint64_t n = RedisModule_LoadUnsigned(rdb); + SIValue vals[n]; + Attribute_ID ids[n]; - for(int i = 0; i < propCount; i++) { - Attribute_ID attr_id = RedisModule_LoadUnsigned(rdb); - SIValue attr_value = _RdbLoadSIValue(rdb); - GraphEntity_AddProperty(e, attr_id, attr_value); - SIValue_Free(attr_value); + for(int i = 0; i < n; i++) { + ids[i] = RedisModule_LoadUnsigned(rdb); + vals[i] = _RdbLoadSIValue(rdb); } + + AttributeSet_AddNoClone(e->attributes, ids, vals, n, false); } void RdbLoadNodes_v12 diff --git a/src/serializers/decoders/prev/v12/decode_graph_schema.c b/src/serializers/decoders/prev/v12/decode_graph_schema.c index d159bd580c..1ac9731e1c 100644 --- a/src/serializers/decoders/prev/v12/decode_graph_schema.c +++ b/src/serializers/decoders/prev/v12/decode_graph_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v12.h" diff --git a/src/serializers/decoders/prev/v12/decode_v12.h b/src/serializers/decoders/prev/v12/decode_v12.h index bf09b73bec..6fb2df109f 100644 --- a/src/serializers/decoders/prev/v12/decode_v12.h +++ b/src/serializers/decoders/prev/v12/decode_v12.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/prev/v8/decode_graph.c b/src/serializers/decoders/prev/v8/decode_graph.c index 2eb452313f..923dde08a3 100644 --- a/src/serializers/decoders/prev/v8/decode_graph.c +++ b/src/serializers/decoders/prev/v8/decode_graph.c @@ -1,20 +1,25 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v8.h" static GraphContext *_GetOrCreateGraphContext(char *graph_name) { - GraphContext *gc = GraphContext_GetRegisteredGraphContext(graph_name); + GraphContext *gc = GraphContext_UnsafeGetGraphContext(graph_name); if(!gc) { - // New graph is being decoded. Inform the module and create new graph context. + // new graph is being decoded + // inform the module and create new graph context gc = GraphContext_New(graph_name); - // While loading the graph, minimize matrix realloc and synchronization calls. + // while loading the graph + // minimize matrix realloc and synchronization calls Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); } - // Free the name string, as it either not in used or copied. + // free the name string, as it either not in used or copied RedisModule_Free(graph_name); return gc; diff --git a/src/serializers/decoders/prev/v8/decode_graph_entities.c b/src/serializers/decoders/prev/v8/decode_graph_entities.c index 3e5d3fa957..f53abfe950 100644 --- a/src/serializers/decoders/prev/v8/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v8/decode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v8.h" @@ -50,19 +53,26 @@ static SIValue _RdbLoadSIArray(RedisModuleIO *rdb) { return list; } -static void _RdbLoadEntity(RedisModuleIO *rdb, GraphContext *gc, GraphEntity *e) { +static void _RdbLoadEntity +( + RedisModuleIO *rdb, + GraphContext *gc, + GraphEntity *e +) { /* Format: * #properties N * (name, value type, value) X N */ - uint64_t propCount = RedisModule_LoadUnsigned(rdb); + uint64_t n = RedisModule_LoadUnsigned(rdb); + SIValue vals[n]; + Attribute_ID ids[n]; - for(int i = 0; i < propCount; i++) { - Attribute_ID attr_id = RedisModule_LoadUnsigned(rdb); - SIValue attr_value = _RdbLoadSIValue(rdb); - GraphEntity_AddProperty(e, attr_id, attr_value); - SIValue_Free(attr_value); + for(int i = 0; i < n; i++) { + ids[i] = RedisModule_LoadUnsigned(rdb); + vals[i] = _RdbLoadSIValue(rdb); } + + AttributeSet_AddNoClone(e->attributes, ids, vals, n, false); } void RdbLoadNodes_v8(RedisModuleIO *rdb, GraphContext *gc, uint64_t node_count) { diff --git a/src/serializers/decoders/prev/v8/decode_graph_schema.c b/src/serializers/decoders/prev/v8/decode_graph_schema.c index 9bf5743606..c368e50372 100644 --- a/src/serializers/decoders/prev/v8/decode_graph_schema.c +++ b/src/serializers/decoders/prev/v8/decode_graph_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v8.h" diff --git a/src/serializers/decoders/prev/v8/decode_v8.h b/src/serializers/decoders/prev/v8/decode_v8.h index cd8455ef19..920259347c 100644 --- a/src/serializers/decoders/prev/v8/decode_v8.h +++ b/src/serializers/decoders/prev/v8/decode_v8.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/decoders/prev/v9/decode_graph.c b/src/serializers/decoders/prev/v9/decode_graph.c index e231f2d42c..bdf981f86d 100644 --- a/src/serializers/decoders/prev/v9/decode_graph.c +++ b/src/serializers/decoders/prev/v9/decode_graph.c @@ -1,20 +1,25 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v9.h" static GraphContext *_GetOrCreateGraphContext(char *graph_name) { - GraphContext *gc = GraphContext_GetRegisteredGraphContext(graph_name); + GraphContext *gc = GraphContext_UnsafeGetGraphContext(graph_name); if(!gc) { - // New graph is being decoded. Inform the module and create new graph context. + // new graph is being decoded + // inform the module and create new graph context gc = GraphContext_New(graph_name); - // While loading the graph, minimize matrix realloc and synchronization calls. + // while loading the graph + // minimize matrix realloc and synchronization calls Graph_SetMatrixPolicy(gc->g, SYNC_POLICY_RESIZE); } - // Free the name string, as it either not in used or copied. + // free the name string, as it either not in used or copied RedisModule_Free(graph_name); return gc; diff --git a/src/serializers/decoders/prev/v9/decode_graph_entities.c b/src/serializers/decoders/prev/v9/decode_graph_entities.c index eaaefe0a18..661f2a2d21 100644 --- a/src/serializers/decoders/prev/v9/decode_graph_entities.c +++ b/src/serializers/decoders/prev/v9/decode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v9.h" @@ -61,19 +64,26 @@ static SIValue _RdbLoadSIArray(RedisModuleIO *rdb) { return list; } -static void _RdbLoadEntity(RedisModuleIO *rdb, GraphContext *gc, GraphEntity *e) { +static void _RdbLoadEntity +( + RedisModuleIO *rdb, + GraphContext *gc, + GraphEntity *e +) { /* Format: * #properties N * (name, value type, value) X N */ - uint64_t propCount = RedisModule_LoadUnsigned(rdb); + uint64_t n = RedisModule_LoadUnsigned(rdb); + SIValue vals[n]; + Attribute_ID ids[n]; - for(int i = 0; i < propCount; i++) { - Attribute_ID attr_id = RedisModule_LoadUnsigned(rdb); - SIValue attr_value = _RdbLoadSIValue(rdb); - GraphEntity_AddProperty(e, attr_id, attr_value); - SIValue_Free(attr_value); + for(int i = 0; i < n; i++) { + ids[i] = RedisModule_LoadUnsigned(rdb); + vals[i] = _RdbLoadSIValue(rdb); } + + AttributeSet_AddNoClone(e->attributes, ids, vals, n, false); } diff --git a/src/serializers/decoders/prev/v9/decode_graph_schema.c b/src/serializers/decoders/prev/v9/decode_graph_schema.c index 77baa520b8..30ac02750f 100644 --- a/src/serializers/decoders/prev/v9/decode_graph_schema.c +++ b/src/serializers/decoders/prev/v9/decode_graph_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "decode_v9.h" diff --git a/src/serializers/decoders/prev/v9/decode_v9.h b/src/serializers/decoders/prev/v9/decode_v9.h index 9248080eb8..c64e3020ea 100644 --- a/src/serializers/decoders/prev/v9/decode_v9.h +++ b/src/serializers/decoders/prev/v9/decode_v9.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/encode_context.c b/src/serializers/encode_context.c index b1f38fb2d8..edfdca50e0 100644 --- a/src/serializers/encode_context.c +++ b/src/serializers/encode_context.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "encode_context.h" #include "../RG.h" diff --git a/src/serializers/encode_context.h b/src/serializers/encode_context.h index aa0a55b454..4611832b32 100644 --- a/src/serializers/encode_context.h +++ b/src/serializers/encode_context.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/encoder/encode_graph.c b/src/serializers/encoder/encode_graph.c index 5737be1813..f13be5932e 100644 --- a/src/serializers/encoder/encode_graph.c +++ b/src/serializers/encoder/encode_graph.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "encode_graph.h" #include "v13/encode_v13.h" diff --git a/src/serializers/encoder/encode_graph.h b/src/serializers/encoder/encode_graph.h index 2edcb09668..176f996c05 100644 --- a/src/serializers/encoder/encode_graph.h +++ b/src/serializers/encoder/encode_graph.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/encoder/v13/encode_graph.c b/src/serializers/encoder/v13/encode_graph.c index 7a44cc0892..07ea87b7eb 100644 --- a/src/serializers/encoder/v13/encode_graph.c +++ b/src/serializers/encoder/v13/encode_graph.c @@ -1,17 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "encode_v13.h" - -extern bool process_is_child; // Global variable declared in module.c +#include "../../../globals.h" // Determine whether we are in the context of a bgsave, in which case -// the process is independent and should not acquire locks. +// the process is independent and should not acquire locks static inline bool _shouldAcquireLocks(void) { - return !process_is_child; + return !Globals_Get_ProcessIsChild(); } static void _RdbSaveHeader diff --git a/src/serializers/encoder/v13/encode_graph_entities.c b/src/serializers/encoder/v13/encode_graph_entities.c index e97676f5c8..455065d77e 100644 --- a/src/serializers/encoder/v13/encode_graph_entities.c +++ b/src/serializers/encoder/v13/encode_graph_entities.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "encode_v13.h" #include "../../../datatypes/datatypes.h" @@ -78,10 +81,11 @@ static void _RdbSaveEntity // (name, value type, value) X N const AttributeSet set = GraphEntity_GetAttributes(e); + uint16_t attr_count = AttributeSet_Count(set); - RedisModule_SaveUnsigned(rdb, ATTRIBUTE_SET_COUNT(set)); + RedisModule_SaveUnsigned(rdb, attr_count); - for(int i = 0; i < ATTRIBUTE_SET_COUNT(set); i++) { + for(int i = 0; i < attr_count; i++) { Attribute_ID attr_id; SIValue value = AttributeSet_GetIdx(set, i, &attr_id); RedisModule_SaveUnsigned(rdb, attr_id); @@ -264,8 +268,8 @@ static void _RdbSaveMultipleEdges while(i < edgeCount && encoded_edges_count < edges_to_encode) { Edge e; EdgeID edgeID = multiple_edges_array[i++]; - e.srcNodeID = src; - e.destNodeID = dest; + e.src_id = src; + e.dest_id = dest; Graph_GetEdge(gc->g, edgeID, &e); _RdbSaveEdge(rdb, gc->g, &e, r); encoded_edges_count++; @@ -366,8 +370,8 @@ void RdbSaveEdges_v13 ASSERT(info == GrB_SUCCESS); - e.srcNodeID = src; - e.destNodeID = dest; + e.src_id = src; + e.dest_id = dest; if(SINGLE_EDGE(edgeID)) { Graph_GetEdge(gc->g, edgeID, &e); _RdbSaveEdge(rdb, gc->g, &e, r); diff --git a/src/serializers/encoder/v13/encode_schema.c b/src/serializers/encoder/v13/encode_schema.c index 52eacbc998..4febed17af 100644 --- a/src/serializers/encoder/v13/encode_schema.c +++ b/src/serializers/encoder/v13/encode_schema.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "encode_v13.h" #include "../../../util/arr.h" diff --git a/src/serializers/encoder/v13/encode_v13.h b/src/serializers/encoder/v13/encode_v13.h index dc22ea0c94..28d25fe9f2 100644 --- a/src/serializers/encoder/v13/encode_v13.h +++ b/src/serializers/encoder/v13/encode_v13.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/encoding_version.h b/src/serializers/encoding_version.h index 864c270253..1a5699984a 100644 --- a/src/serializers/encoding_version.h +++ b/src/serializers/encoding_version.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/graph_extensions.c b/src/serializers/graph_extensions.c index 8534229f3b..87eff5fa19 100644 --- a/src/serializers/graph_extensions.c +++ b/src/serializers/graph_extensions.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "graph_extensions.h" #include "../RG.h" @@ -196,11 +199,11 @@ void Serializer_Graph_SetEdge AttributeSet *set = DataBlock_AllocateItemOutOfOrder(g->edges, edge_id); *set = NULL; - e->id = edge_id; - e->attributes = set; - e->relationID = r; - e->srcNodeID = src; - e->destNodeID = dest; + e->id = edge_id; + e->src_id = src; + e->dest_id = dest; + e->attributes = set; + e->relationID = r; if(multi_edge) { if(!Graph_FormConnection(g, src, dest, edge_id, r)) { diff --git a/src/serializers/graph_extensions.h b/src/serializers/graph_extensions.h index 2f6efbd074..7ef6325fee 100644 --- a/src/serializers/graph_extensions.h +++ b/src/serializers/graph_extensions.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/graphcontext_type.c b/src/serializers/graphcontext_type.c index c4195be103..f88dfe50d8 100644 --- a/src/serializers/graphcontext_type.c +++ b/src/serializers/graphcontext_type.c @@ -1,11 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "graphcontext_type.h" #include "../version.h" +#include "../globals.h" #include "encoding_version.h" #include "encoder/encode_graph.h" #include "decoders/decode_graph.h" @@ -19,27 +23,32 @@ void ModuleEventHandler_AUXAfterKeyspaceEvent(void); // declaration of the type for redis registration RedisModuleType *GraphContextRedisModuleType; -static void *_GraphContextType_RdbLoad(RedisModuleIO *rdb, int encver) { +static void *_GraphContextType_RdbLoad +( + RedisModuleIO *rdb, + int encver +) { GraphContext *gc = NULL; if(encver > GRAPH_ENCODING_VERSION_LATEST) { - // Not forward compatible. + // not forward compatible printf("Failed loading Graph, RedisGraph version (%d) is not forward compatible.\n", REDISGRAPH_MODULE_VERSION); return NULL; - // Not backward compatible. + // not backward compatible } else if(encver < GRAPHCONTEXT_TYPE_DECODE_MIN_V) { printf("Failed loading Graph, RedisGraph version (%d) is not backward compatible with encoder version %d.\n", REDISGRAPH_MODULE_VERSION, encver); return NULL; - // Previous version. + // previous version } else if(encver < GRAPH_ENCODING_VERSION_LATEST) { gc = Decode_Previous(rdb, encver); } else { - // Current version. + // current version gc = RdbLoadGraph(rdb); } - // Add GraphContext to global array of graphs. + + // add GraphContext to global array of graphs GraphContext_RegisterWithModule(gc); return gc; } @@ -50,10 +59,26 @@ static void _GraphContextType_RdbSave(RedisModuleIO *rdb, void *value) { } // save an unsigned placeholder before and after the keyspace encoding -static void _GraphContextType_AuxSave(RedisModuleIO *rdb, int when) { +static void _GraphContextType_AuxSave +( + RedisModuleIO *rdb, + int when +) { RedisModule_SaveUnsigned(rdb, 0); } +// save an unsigned placeholder before and after the keyspace encoding +static void _GraphContextType_AuxSave2 +( + RedisModuleIO *rdb, + int when +) { + // only write AUX field if there are graphs in the keyspace + if(Globals_GetGraphCount() > 0) { + RedisModule_SaveUnsigned(rdb, 0); + } +} + // decode the unsigned placeholders saved before and after the keyspace values // and call the module event handler static int _GraphContextType_AuxLoad(RedisModuleIO *rdb, int encver, int when) { @@ -65,6 +90,7 @@ static int _GraphContextType_AuxLoad(RedisModuleIO *rdb, int encver, int when) { static void _GraphContextType_Free(void *value) { GraphContext *gc = value; + Globals_RemoveGraph(gc); GraphContext_DecreaseRefCount(gc); } @@ -78,6 +104,14 @@ int GraphContextType_Register(RedisModuleCtx *ctx) { tm.aux_load = _GraphContextType_AuxLoad; tm.aux_save_triggers = REDISMODULE_AUX_BEFORE_RDB | REDISMODULE_AUX_AFTER_RDB; + // use aux_save2 if available + Redis_Version redis_version = RG_GetRedisVersion(); + if(redis_version.major > 7 || + (redis_version.major == 7 && redis_version.minor >= 2)) { + tm.aux_save = NULL; + tm.aux_save2 = _GraphContextType_AuxSave2; + } + GraphContextRedisModuleType = RedisModule_CreateDataType(ctx, "graphdata", GRAPH_ENCODING_VERSION_LATEST, &tm); diff --git a/src/serializers/graphcontext_type.h b/src/serializers/graphcontext_type.h index 473a233adc..f9bf630c5d 100644 --- a/src/serializers/graphcontext_type.h +++ b/src/serializers/graphcontext_type.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/graphmeta_type.c b/src/serializers/graphmeta_type.c index dc185c9e01..722a476416 100644 --- a/src/serializers/graphmeta_type.c +++ b/src/serializers/graphmeta_type.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "graphmeta_type.h" #include "../version.h" @@ -18,23 +21,24 @@ static void *_GraphMetaType_RdbLoad(RedisModuleIO *rdb, int encver) { GraphContext *gc = NULL; if(encver > GRAPH_ENCODING_VERSION_LATEST) { - // Not forward compatible. + // not forward compatible printf("Failed loading Graph, RedisGraph version (%d) is not forward compatible.\n", REDISGRAPH_MODULE_VERSION); return NULL; - // Not backward compatible. + // not backward compatible } else if(encver < GRAPHMETA_TYPE_DECODE_MIN_V) { printf("Failed loading Graph, RedisGraph version (%d) is not backward compatible with encoder version %d.\n", REDISGRAPH_MODULE_VERSION, encver); return NULL; - // Previous version. + // previous version } else if(encver < GRAPH_ENCODING_VERSION_LATEST) { gc = Decode_Previous(rdb, encver); } else { - // Current version. + // current version gc = RdbLoadGraph(rdb); } - // Add GraphContext to global array of graphs. + + // add GraphContext to global array of graphs GraphContext_RegisterWithModule(gc); return gc; } diff --git a/src/serializers/graphmeta_type.h b/src/serializers/graphmeta_type.h index 254ba4732d..3fe638051a 100644 --- a/src/serializers/graphmeta_type.h +++ b/src/serializers/graphmeta_type.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/serializers/serializers_include.h b/src/serializers/serializers_include.h index ec3f06a58f..331844a0ca 100644 --- a/src/serializers/serializers_include.h +++ b/src/serializers/serializers_include.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/slow_log/slow_log.c b/src/slow_log/slow_log.c index e47e3fdf51..1c946634aa 100644 --- a/src/slow_log/slow_log.c +++ b/src/slow_log/slow_log.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include diff --git a/src/slow_log/slow_log.h b/src/slow_log/slow_log.h index 406d432a1a..0180f82121 100644 --- a/src/slow_log/slow_log.h +++ b/src/slow_log/slow_log.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/undo_log/undo_log.c b/src/undo_log/undo_log.c index b4113d3198..0aaaa5aef7 100644 --- a/src/undo_log/undo_log.c +++ b/src/undo_log/undo_log.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "undo_log.h" @@ -11,6 +14,13 @@ #include "../execution_plan/ops/shared/create_functions.h" #include "../graph/entities/attribute_set.h" +// initial number of entries in undo-log +#define UNDOLOG_INIT_SIZE 32 + +#define UNDOLOG_GET_ITEM(log, i) DataBlock_GetItem(log, i) +#define UNDOLOG_ADD_OP(log, op) \ + *(UndoOp*)DataBlock_AllocateItem((log), NULL) = op; + static void _index_node ( QueryCtx *ctx, @@ -48,7 +58,7 @@ static void _index_edge QueryCtx *ctx, Edge *e ) { - Schema *s = GraphContext_GetSchemaByID(ctx->gc, e->relationID, SCHEMA_EDGE); + Schema *s = GraphContext_GetSchemaByID(ctx->gc, Edge_GetRelationID(e), SCHEMA_EDGE); ASSERT(s); if(Schema_HasIndices(s)) Schema_AddEdgeToIndices(s, e); @@ -91,7 +101,7 @@ static void _index_delete_edge QueryCtx *ctx, Edge *e ) { - Schema *s = GraphContext_GetSchemaByID(ctx->gc, e->relationID, SCHEMA_EDGE); + Schema *s = GraphContext_GetSchemaByID(ctx->gc, Edge_GetRelationID(e), SCHEMA_EDGE); ASSERT(s); // update any indices this entity is represented in @@ -110,7 +120,7 @@ static void _UndoLog_Restore_Entity_Property if(old_value == ATTRIBUTE_NOTFOUND) { // adding a new attribute; do nothing if its value is NULL if(SI_TYPE(value) != T_NULL) { - AttributeSet_AddNoClone(ge->attributes, attr_id, value); + AttributeSet_AddNoClone(ge->attributes, &attr_id, &value, 1, false); } } else { // update attribute @@ -125,19 +135,20 @@ static void _UndoLog_Rollback_Update_Entity int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { - UndoOp *op = undo_list + i; + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoUpdateOp *update_op = &op->update_op; // update indices if(update_op->entity_type == GETYPE_NODE) { - _UndoLog_Restore_Entity_Property((GraphEntity *)&update_op->n, update_op->attr_id, - update_op->orig_value); + // free current entity attribute-set + AttributeSet_Free(update_op->n.attributes); + // restore entity original attribute-set + *update_op->n.attributes = update_op->set; _index_node(ctx, &update_op->n); } else { - _UndoLog_Restore_Entity_Property((GraphEntity *)&update_op->e, update_op->attr_id, - update_op->orig_value); + AttributeSet_Free(update_op->e.attributes); + *update_op->e.attributes = update_op->set; _index_edge(ctx, &update_op->e); } } @@ -149,20 +160,19 @@ static void _UndoLog_Rollback_Set_Labels int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { Graph *g = QueryCtx_GetGraph(); - UndoOp *op = undo_list + i; + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoLabelsOp *update_labels_op = &(op->labels_op); uint labels_count = update_labels_op->labels_count; Graph_RemoveNodeLabels(g, update_labels_op->node.id, - update_labels_op->label_lds, labels_count); + update_labels_op->label_ids, labels_count); _index_delete_node_with_labels(ctx, &(update_labels_op->node), - update_labels_op->label_lds, labels_count); + update_labels_op->label_ids, labels_count); - array_free(update_labels_op->label_lds); + array_free(update_labels_op->label_ids); } } @@ -172,20 +182,19 @@ static void _UndoLog_Rollback_Remove_Labels int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { Graph *g = QueryCtx_GetGraph(); - UndoOp *op = undo_list + i; + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoLabelsOp *update_labels_op = &(op->labels_op); uint labels_count = update_labels_op->labels_count; Graph_LabelNode(g, update_labels_op->node.id, - update_labels_op->label_lds, labels_count); + update_labels_op->label_ids, labels_count); _index_node_with_labels(ctx, &(update_labels_op->node), - update_labels_op->label_lds, labels_count); + update_labels_op->label_ids, labels_count); - array_free(update_labels_op->label_lds); + array_free(update_labels_op->label_ids); } } @@ -199,13 +208,13 @@ static void _UndoLog_Rollback_Create_Node ASSERT(seq_start > seq_end); uint node_count = seq_start - seq_end; - UndoOp *undo_list = ctx->undo_log; Node *nodes = rm_malloc(sizeof(Node) * node_count); - for(int i = 0; i < node_count; i++) { - Node *n = &undo_list[seq_start - i].create_op.n; - nodes[i] = *n; + for(int i = seq_start; i > seq_end; --i) { + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); + Node *n = &op->create_op.n; + nodes[seq_start - i] = *n; _index_delete_node(ctx, n); } @@ -223,13 +232,13 @@ static void _UndoLog_Rollback_Create_Edge ASSERT(seq_start > seq_end); uint edge_count = seq_start - seq_end; - UndoOp *undo_list = ctx->undo_log; Edge *edges = rm_malloc(sizeof(Edge) * edge_count); - for(int i = 0; i < edge_count; i++) { - Edge *e = &undo_list[seq_start - i].create_op.e; - edges[i] = *e; + for(int i = seq_start; i > seq_end; --i) { + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); + Edge *e = &op->create_op.e; + edges[seq_start - i] = *e; _index_delete_edge(ctx, e); } @@ -244,10 +253,9 @@ static void _UndoLog_Rollback_Delete_Node int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { - Node n; - UndoOp *op = undo_list + i; + Node n = GE_NEW_NODE(); + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoDeleteNodeOp *delete_op = &(op->delete_node_op); Graph_CreateNode(ctx->gc->g, &n, delete_op->labels, @@ -256,7 +264,8 @@ static void _UndoLog_Rollback_Delete_Node // re-introduce node to indices _index_node(ctx, &n); - // Cleanup after undo rollback, as the op D'tor is not called. + + // cleanup after undo rollback, as the op D'tor is not called rm_free(delete_op->labels); } } @@ -268,13 +277,12 @@ static void _UndoLog_Rollback_Delete_Edge int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { Edge e; - UndoOp *op = undo_list + i; + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoDeleteEdgeOp delete_op = op->delete_edge_op; - Graph_CreateEdge(ctx->gc->g, delete_op.srcNodeID, delete_op.destNodeID, + Graph_CreateEdge(ctx->gc->g, delete_op.src_id, delete_op.dest_id, delete_op.relationID, &e); *e.attributes = delete_op.set; @@ -289,10 +297,9 @@ static void _UndoLog_Rollback_Add_Schema int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { Edge e; - UndoOp *op = undo_list + i; + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoAddSchemaOp schema_op = op->schema_op; int schema_id = schema_op.schema_id; int schema_count = GraphContext_SchemaCount(ctx->gc, schema_op.t); @@ -313,30 +320,29 @@ static void _UndoLog_Rollback_Add_Attribute int seq_start, int seq_end ) { - UndoOp *undo_list = ctx->undo_log; for(int i = seq_start; i > seq_end; --i) { - Edge e; - UndoOp *op = undo_list + i; + UndoOp *op = UNDOLOG_GET_ITEM(ctx->undo_log, i); UndoAddAttributeOp attribute_op = op->attribute_op; int attribute_id = attribute_op.attribute_id; GraphContext_RemoveAttribute(ctx->gc, attribute_id); } } -// add an operation to undo log -static inline void _UndoLog_AddOperation -( - UndoLog *log, // undo log - UndoOp *op // undo operation -) { - ASSERT(op != NULL); - ASSERT(log != NULL && *log != NULL); - - array_append(*log, *op); +UndoLog UndoLog_New(void) { + return (UndoLog)DataBlock_New( + UNDOLOG_INIT_SIZE, + UNDOLOG_INIT_SIZE, + sizeof(UndoOp), + NULL); } -UndoLog UndoLog_New(void) { - return (UndoLog)array_new(UndoOp, 0); +// returns number of entries in log +uint UndoLog_Length +( + const UndoLog log // log to query +) { + ASSERT(log != NULL); + return DataBlock_ItemCount(log); } //------------------------------------------------------------------------------ @@ -346,42 +352,42 @@ UndoLog UndoLog_New(void) { // undo node creation void UndoLog_CreateNode ( - UndoLog *log, + UndoLog log, // undo log Node *node // node created ) { - ASSERT(log != NULL && *log != NULL); + ASSERT(log != NULL); UndoOp op; op.type = UNDO_CREATE_NODE; op.create_op.n = *node; - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } // undo edge creation void UndoLog_CreateEdge ( - UndoLog *log, + UndoLog log, // undo log Edge *edge // edge created ) { - ASSERT(log != NULL && *log != NULL); + ASSERT(log != NULL); UndoOp op; op.type = UNDO_CREATE_EDGE; op.create_op.e = *edge; - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } // undo node deletion void UndoLog_DeleteNode ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node // node deleted ) { - ASSERT(log != NULL && *log != NULL); + ASSERT(log != NULL); ASSERT(node != NULL); UndoOp op; @@ -391,60 +397,66 @@ void UndoLog_DeleteNode // take ownership over node's attribute-set op.delete_node_op.set = *node->attributes; - *node->attributes = NULL; + + // mark node's attribute-set as read-only + *node->attributes = + (AttributeSet)ATTRIBUTE_SET_MARK_READONLY(*node->attributes); Graph *g = QueryCtx_GetGraph(); NODE_GET_LABELS(g, node, op.delete_node_op.label_count); - op.delete_node_op.labels = rm_malloc(sizeof(LabelID) * op.delete_node_op.label_count); - for (uint i = 0; i < op.delete_node_op.label_count; i++) { - op.delete_node_op.labels[i] = labels[i]; - } - _UndoLog_AddOperation(log, &op); + // save node's labels + op.delete_node_op.labels = + rm_malloc(sizeof(LabelID) * op.delete_node_op.label_count); + + memcpy(op.delete_node_op.labels, labels, + sizeof(LabelID) * op.delete_node_op.label_count); + + UNDOLOG_ADD_OP(log, op); } // undo edge deletion void UndoLog_DeleteEdge ( - UndoLog *log, // undo log + UndoLog log, // undo log Edge *edge // edge deleted ) { - ASSERT(log != NULL && *log != NULL); + ASSERT(log != NULL); ASSERT(edge != NULL); UndoOp op; op.type = UNDO_DELETE_EDGE; op.delete_edge_op.id = edge->id; - op.delete_edge_op.srcNodeID = edge->srcNodeID; - op.delete_edge_op.destNodeID = edge->destNodeID; - op.delete_edge_op.relationID = edge->relationID; + op.delete_edge_op.src_id = Edge_GetSrcNodeID(edge); + op.delete_edge_op.dest_id = Edge_GetDestNodeID(edge); + op.delete_edge_op.relationID = Edge_GetRelationID(edge); // take ownership over edge's attribute-set op.delete_edge_op.set = *edge->attributes; - *edge->attributes = NULL; - _UndoLog_AddOperation(log, &op); + // mark edge's attribute-set as read-only + *edge->attributes = + (AttributeSet)ATTRIBUTE_SET_MARK_READONLY(*edge->attributes); + + UNDOLOG_ADD_OP(log, op); } // undo entity update void UndoLog_UpdateEntity ( - UndoLog *log, // undo log + UndoLog log, // undo log GraphEntity *ge, // updated entity - Attribute_ID attr_id, // updated attribute ID - SIValue orig_value, // attribute original value + AttributeSet set, // old attribute set GraphEntityType entity_type // entity type ) { - ASSERT(log != NULL && *log != NULL); + ASSERT(log != NULL); ASSERT(ge != NULL); - ASSERT(attr_id != ATTRIBUTE_ID_NONE && attr_id != ATTRIBUTE_ID_ALL); UndoOp op; op.type = UNDO_UPDATE; - op.update_op.attr_id = attr_id; - op.update_op.orig_value = SI_CloneValue(orig_value); + op.update_op.set = set; op.update_op.entity_type = entity_type; if(entity_type == GETYPE_NODE) { @@ -453,15 +465,15 @@ void UndoLog_UpdateEntity op.update_op.e = *(Edge *)ge; } - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } // undo node add label void UndoLog_AddLabels ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node, // updated node - int *label_ids, // added labels + LabelID *label_ids, // added labels size_t labels_count // number of removed labels ) { ASSERT(node != NULL); @@ -471,18 +483,18 @@ void UndoLog_AddLabels op.type = UNDO_SET_LABELS; op.labels_op.node = *node; - op.labels_op.label_lds = array_new(int, labels_count); - memcpy(op.labels_op.label_lds, label_ids, sizeof(int)*labels_count); + op.labels_op.label_ids = array_new(LabelID, labels_count); + memcpy(op.labels_op.label_ids, label_ids, sizeof(LabelID)*labels_count); op.labels_op.labels_count = labels_count; - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } // undo node remove label void UndoLog_RemoveLabels ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node, // updated node - int *label_ids, // removed labels + LabelID *label_ids, // removed labels size_t labels_count // number of removed labels ) { ASSERT(node != NULL); @@ -492,16 +504,16 @@ void UndoLog_RemoveLabels op.type = UNDO_REMOVE_LABELS; op.labels_op.node = *node; - op.labels_op.label_lds = array_new(int, labels_count); - memcpy(op.labels_op.label_lds, label_ids, sizeof(int)*labels_count); + op.labels_op.label_ids = array_new(LabelID, labels_count); + memcpy(op.labels_op.label_ids, label_ids, sizeof(LabelID)*labels_count); op.labels_op.labels_count = labels_count; - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } // undo schema addition void UndoLog_AddSchema ( - UndoLog *log, // undo log + UndoLog log, // undo log int schema_id, // id of the schema SchemaType t // type of the schema ) { @@ -511,12 +523,12 @@ void UndoLog_AddSchema op.type = UNDO_ADD_SCHEMA; op.schema_op.schema_id = schema_id; op.schema_op.t = t; - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } void UndoLog_AddAttribute ( - UndoLog *log, // undo log + UndoLog log, // undo log Attribute_ID attribute_id // id of the attribute ) { ASSERT(log != NULL); @@ -524,33 +536,36 @@ void UndoLog_AddAttribute op.type = UNDO_ADD_ATTRIBUTE; op.attribute_op.attribute_id = attribute_id; - _UndoLog_AddOperation(log, &op); + UNDOLOG_ADD_OP(log, op); } - //------------------------------------------------------------------------------ // rollback //------------------------------------------------------------------------------ void UndoLog_Rollback ( - UndoLog log + UndoLog *log ) { ASSERT(log != NULL); - QueryCtx *ctx = QueryCtx_GetQueryCtx(); - uint64_t count = array_len(log); + UndoLog _log = *log; + if(_log == NULL) return; - if(count == 0) return; + QueryCtx *ctx = QueryCtx_GetQueryCtx(); + uint64_t count = DataBlock_ItemCount(_log); // apply undo operations in reverse order for rollback correctness // find sequences of the same operation and rollback them as a bulk int seq_end = count - 1; while (seq_end >= 0) { - UndoOpType cur_type = log[seq_end].type; + UndoOp *op = UNDOLOG_GET_ITEM(_log, seq_end); + UndoOpType cur_type = op->type; int seq_start = seq_end; seq_end--; - while(seq_end > 0 && log[seq_end].type == cur_type) { + while(seq_end >= 0) { + op = UNDOLOG_GET_ITEM(_log, seq_end); + if(op->type != cur_type) break; seq_end--; } @@ -587,43 +602,59 @@ void UndoLog_Rollback } } - array_clear(log); + DataBlock_Free(_log); + *log = NULL; } -void UndoLog_Free +static void UndoLog_FreeOp ( - UndoLog log + UndoOp *op ) { - // free each undo operation - uint count = array_len(log); - for (uint i = 0; i < count; i++) { - UndoOp *op = log + i; - switch(op->type) { - case UNDO_UPDATE: - SIValue_Free(op->update_op.orig_value); - break; - case UNDO_CREATE_NODE: - break; - case UNDO_CREATE_EDGE: - break; - case UNDO_DELETE_NODE: - rm_free(op->delete_node_op.labels); - AttributeSet_Free(&op->delete_node_op.set); - break; - case UNDO_DELETE_EDGE: - AttributeSet_Free(&op->delete_edge_op.set); - break; - case UNDO_SET_LABELS: - case UNDO_REMOVE_LABELS: - array_free(op->labels_op.label_lds); - break; - case UNDO_ADD_SCHEMA: - case UNDO_ADD_ATTRIBUTE: - break; - default: - ASSERT(false); - } + ASSERT(op != NULL); + + switch(op->type) { + case UNDO_UPDATE: + AttributeSet_Free(&op->update_op.set); + break; + case UNDO_CREATE_NODE: + break; + case UNDO_CREATE_EDGE: + break; + case UNDO_DELETE_NODE: + rm_free(op->delete_node_op.labels); + AttributeSet_Free(&op->delete_node_op.set); + break; + case UNDO_DELETE_EDGE: + AttributeSet_Free(&op->delete_edge_op.set); + break; + case UNDO_SET_LABELS: + case UNDO_REMOVE_LABELS: + array_free(op->labels_op.label_ids); + break; + case UNDO_ADD_SCHEMA: + case UNDO_ADD_ATTRIBUTE: + break; + default: + ASSERT(false); } +} + +void UndoLog_Free +( + UndoLog *log +) { + ASSERT(log != NULL); - array_free(log); + UndoLog _log = *log; + if(_log == NULL) return; + + DataBlockIterator *iter = DataBlock_Scan(_log); + UndoOp *op; + while((op = DataBlockIterator_Next(iter, NULL))) { + UndoLog_FreeOp(op); + } + DataBlockIterator_Free(iter); + DataBlock_Free(_log); + *log = NULL; } + diff --git a/src/undo_log/undo_log.h b/src/undo_log/undo_log.h index ad65cda3f4..c2decbfd96 100644 --- a/src/undo_log/undo_log.h +++ b/src/undo_log/undo_log.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -30,7 +33,7 @@ typedef enum { UNDO_SET_LABELS, // undo set labels UNDO_REMOVE_LABELS, // undo remove labels UNDO_ADD_SCHEMA, // undo schema addition - UNDO_ADD_ATTRIBUTE // undo property addition + UNDO_ADD_ATTRIBUTE // undo property addition } UndoOpType; //------------------------------------------------------------------------------ @@ -38,56 +41,61 @@ typedef enum { //------------------------------------------------------------------------------ // undo node/edge creation -typedef struct { +typedef struct UndoCreateOp UndoCreateOp; +struct UndoCreateOp { union { Node n; Edge e; }; -} UndoCreateOp; +}; // undo node deletion -typedef struct { +typedef struct UndoDeleteNodeOp UndoDeleteNodeOp; +struct UndoDeleteNodeOp { EntityID id; AttributeSet set; LabelID *labels; // labels attached to deleted entity uint label_count; // number of labels attached to deleted entity -} UndoDeleteNodeOp; +}; // undo edge deletion -typedef struct { +typedef struct UndoDeleteEdgeOp UndoDeleteEdgeOp; +struct UndoDeleteEdgeOp { EntityID id; - int relationID; // Relation ID - NodeID srcNodeID; // Source node ID - NodeID destNodeID; // Destination node ID + int relationID; // Relation ID + NodeID src_id; // Source node ID + NodeID dest_id; // Destination node ID AttributeSet set; -} UndoDeleteEdgeOp; +}; // undo graph entity update -typedef struct { +typedef struct UndoUpdateOp UndoUpdateOp; +struct UndoUpdateOp { union { Node n; Edge e; }; GraphEntityType entity_type; // node/edge - Attribute_ID attr_id; // attribute update - SIValue orig_value; // attribute original value -} UndoUpdateOp; + AttributeSet set; // old attribute set +}; -typedef struct { +typedef struct UndoLabelsOp UndoLabelsOp; +struct UndoLabelsOp { Node node; - int* label_lds; - size_t labels_count; -} UndoLabelsOp; - + LabelID* label_ids; + ushort labels_count; +}; -typedef struct { +typedef struct UndoAddSchemaOp UndoAddSchemaOp; +struct UndoAddSchemaOp { int schema_id; SchemaType t; -} UndoAddSchemaOp; +}; -typedef struct { +typedef struct UndoAddAttributeOp UndoAddAttributeOp; +struct UndoAddAttributeOp { Attribute_ID attribute_id; -} UndoAddAttributeOp; +}; // Undo operation typedef struct { @@ -104,11 +112,17 @@ typedef struct { } UndoOp; // container for undo_list -typedef UndoOp *UndoLog; +typedef DataBlock *UndoLog; // create a new undo-log UndoLog UndoLog_New(void); +// returns number of entries in log +uint UndoLog_Length +( + const UndoLog log // log to query +); + //------------------------------------------------------------------------------ // UndoLog add operations //------------------------------------------------------------------------------ @@ -116,63 +130,62 @@ UndoLog UndoLog_New(void); // undo node creation void UndoLog_CreateNode ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node // node created ); // undo edge creation void UndoLog_CreateEdge ( - UndoLog *log, // undo log + UndoLog log, // undo log Edge *edge // edge created ); // undo node deletion void UndoLog_DeleteNode ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node // node deleted ); // undo edge deletion void UndoLog_DeleteEdge ( - UndoLog *log, // undo log + UndoLog log, // undo log Edge *edge // edge deleted ); // undo entity update void UndoLog_UpdateEntity ( - UndoLog *log, // undo log + UndoLog log, // undo log GraphEntity *ge, // updated entity - Attribute_ID attr_id, // updated attribute ID - SIValue orig_value, // attribute original value + AttributeSet set, // old attribute set GraphEntityType entity_type // entity type ); // undo node add label void UndoLog_AddLabels ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node, // updated node - int *label_ids, // added labels + LabelID *label_ids, // added labels size_t labels_count // number of removed labels ); // undo node remove label void UndoLog_RemoveLabels ( - UndoLog *log, // undo log + UndoLog log, // undo log Node *node, // updated node - int *label_ids, // removed labels + LabelID *label_ids, // removed labels size_t labels_count // number of removed labels ); // undo schema addition void UndoLog_AddSchema ( - UndoLog *log, // undo log + UndoLog log, // undo log int schema_id, // id of the schema SchemaType t // type of the schema ); @@ -180,20 +193,19 @@ void UndoLog_AddSchema // undo attribute addition void UndoLog_AddAttribute ( - UndoLog *log, // undo log + UndoLog log, // undo log Attribute_ID attribute_id // id of the attribute ); - // rollback all modifications tracked by this undo log void UndoLog_Rollback ( - UndoLog log + UndoLog *log ); // free UndoLog void UndoLog_Free ( - UndoLog log + UndoLog *log ); diff --git a/src/util/arr.h b/src/util/arr.h index 175bd1c540..d39e1bff0d 100644 --- a/src/util/arr.h +++ b/src/util/arr.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #ifndef UTIL_ARR_H_ #define UTIL_ARR_H_ /* arr.h - simple, easy to use dynamic array with fat pointers, @@ -325,6 +334,29 @@ __extension__({ \ } \ }) \ +// dest = dest ∪ src +// treats both src and dest as sets +// [1,2,3] ∪ [2,4,4] = [1,2,3,4,4] +// TODO: if either src or dest are large and we're allowed to rearrange +// elements position then consider sorting +#define array_union(dest, src, cmp) \ + __extension__({ \ + uint32_t src_len = array_len((src)); \ + uint32_t dest_len = array_len((dest)); \ + for (uint i = 0; i < src_len; i++) { \ + bool found = false; \ + for(uint j = 0; j < dest_len; j++) { \ + if(cmp((dest)[j], (src)[i]) == 0) { \ + found = true; \ + break; \ + } \ + } \ + if(!found) { \ + array_append((dest), (src)[i]); \ + } \ + } \ +}) \ + #pragma GCC diagnostic pop #ifdef __cplusplus diff --git a/src/util/block.c b/src/util/block.c index 68be99c468..a5a6504b02 100644 --- a/src/util/block.c +++ b/src/util/block.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "block.h" #include "RG.h" diff --git a/src/util/block.h b/src/util/block.h index 8b15aca2b5..b01c8eb96c 100644 --- a/src/util/block.h +++ b/src/util/block.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/blocked_client.c b/src/util/blocked_client.c index 53222ff71e..4a09f63519 100644 --- a/src/util/blocked_client.c +++ b/src/util/blocked_client.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "blocked_client.h" diff --git a/src/util/blocked_client.h b/src/util/blocked_client.h index 3b95191ea2..85708e313f 100644 --- a/src/util/blocked_client.h +++ b/src/util/blocked_client.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" diff --git a/src/util/cache/cache.c b/src/util/cache/cache.c index ef784210e3..fe451a907a 100644 --- a/src/util/cache/cache.c +++ b/src/util/cache/cache.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "cache.h" #include "RG.h" diff --git a/src/util/cache/cache.h b/src/util/cache/cache.h index cecedffcc6..7ea3c528dc 100644 --- a/src/util/cache/cache.h +++ b/src/util/cache/cache.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/cache/cache_array.c b/src/util/cache/cache_array.c index ee8befa659..31296b805e 100644 --- a/src/util/cache/cache_array.c +++ b/src/util/cache/cache_array.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "cache_array.h" #include "../rmalloc.h" diff --git a/src/util/cache/cache_array.h b/src/util/cache/cache_array.h index 8bfd3fdb23..277a04155f 100644 --- a/src/util/cache/cache_array.h +++ b/src/util/cache/cache_array.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/circular_buffer.c b/src/util/circular_buffer.c index abd33bd0a9..907a6ef22c 100644 --- a/src/util/circular_buffer.c +++ b/src/util/circular_buffer.c @@ -1,24 +1,30 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "rmalloc.h" #include "circular_buffer.h" +#include "graph/graphcontext.h" + +#include // circular buffer structure // the buffer is of fixed size // items are removed by order of insertion, similar to a queue struct _CircularBuffer { - char *read; // read data from here - char *write; // write data to here - size_t item_size; // item size in bytes - _Atomic int item_count; // current number of items in buffer - int item_cap; // max number of items held by buffer - char *end_marker; // marks the end of the buffer - char data[]; // data + char *read; // read data from here + _Atomic uint64_t write; // write offset into data + size_t item_size; // item size in bytes + _Atomic uint64_t item_count; // current number of items in buffer + uint64_t item_cap; // max number of items held by buffer + char *end_marker; // marks the end of the buffer + char data[]; // data }; CircularBuffer CircularBuffer_New @@ -26,133 +32,258 @@ CircularBuffer CircularBuffer_New size_t item_size, // size of item in bytes uint cap // max number of items in buffer ) { - CircularBuffer cb = rm_malloc(sizeof(_CircularBuffer) + item_size * cap); + CircularBuffer cb = rm_calloc(1, sizeof(_CircularBuffer) + item_size * cap); - cb->read = cb->data; // read from begining of data - cb->write = cb->data; // write to begining of data - cb->item_cap = cap; // save cap - cb->item_size = item_size; // save item size - cb->item_count = 0; // no items in buffer - cb->end_marker = cb->data + (item_size * cap); + cb->read = cb->data; // initial read position + cb->write = ATOMIC_VAR_INIT(0); // write offset into data + cb->item_cap = cap; // buffer capacity + cb->item_size = item_size; // item size + cb->item_count = ATOMIC_VAR_INIT(0); // no items in buffer + cb->end_marker = cb->data + (item_size * cap); // end of data marker return cb; } +// returns number of items in buffer +uint64_t CircularBuffer_ItemCount +( + CircularBuffer cb // buffer to inspect +) { + ASSERT(cb != NULL); + + return cb->item_count; +} + +// returns buffer capacity +uint64_t CircularBuffer_Cap +( + CircularBuffer cb // buffer +) { + ASSERT(cb != NULL); + + return cb->item_cap; +} + +uint CircularBuffer_ItemSize +( + const CircularBuffer cb // buffer +) { + return cb->item_size; +} + +// return true if buffer is empty +inline bool CircularBuffer_Empty +( + const CircularBuffer cb // buffer +) { + ASSERT(cb != NULL); + + return cb->item_count == 0; +} + +// returns true if buffer is full +inline bool CircularBuffer_Full +( + const CircularBuffer cb // buffer +) { + ASSERT(cb != NULL); + + return cb->item_count == cb->item_cap; +} + +// sets the read pointer to the oldest item in buffer +// assuming the buffer looks like this: +// +// [., ., ., A, B, C, ., ., .] +// ^ +// W +// +// CircularBuffer_ResetReader will set 'read' to A +// +// [., ., ., A, B, C, ., ., .] +// ^ ^ +// R W +// +void CircularBuffer_ResetReader +( + CircularBuffer cb // circular buffer +) { + // compensate for circularity + uint64_t write = cb->write; + + // compute newest item index, e.g. newest item is at index k + uint idx = write / cb->item_size; + + // compute offset to oldest item + // oldest item is n elements before newest item + // + // example: + // + // [C, ., ., ., ., ., ., A, B] + // + // idx = 1, item_count = 3 + // offset is 1 - 3 = -2 + // + // [C, ., ., ., ., ., ., A, B] + // ^ ^ + // W R + + int offset = idx - cb->item_count; + offset *= cb->item_size; + + if(offset >= 0) { + // offset is positive, read from beginning of buffer + cb->read = cb->data + offset; + } else { + // offset is negative, read from end of buffer + cb->read = cb->end_marker + offset; + } +} + // adds an item to buffer // returns 1 on success, 0 otherwise +// this function is thread-safe and lock-free int CircularBuffer_Add ( - CircularBuffer cb, // buffer to populate + CircularBuffer cb, // buffer to populate void *item // item to add ) { - ASSERT(cb != NULL); + ASSERT(cb != NULL); ASSERT(item != NULL); + // atomic update buffer item count // do not add item if buffer is full - if(unlikely(CircularBuffer_Full(cb))) { + uint64_t item_count = atomic_fetch_add(&cb->item_count, 1); + if(unlikely(item_count >= cb->item_cap)) { + cb->item_count = cb->item_cap; return 0; } - // copy item into buffer - memcpy(cb->write, item, cb->item_size); + // determine current and next write position + uint64_t offset = atomic_fetch_add(&cb->write, cb->item_size); - // atomic update buffer item count - cb->item_count++; + // check for buffer overflow + if(unlikely(cb->data + offset >= cb->end_marker)) { + // write need to circle back + // [., ., ., ., ., ., A, B, C] + // ^ ^ + // W0 W1 + uint64_t overflow = offset + cb->item_size; - // advance write position - // circle back if write reached the end of the buffer - cb->write += cb->item_size; - if(unlikely(cb->write >= cb->end_marker)) { - cb->write = cb->data; + // adjust offset + // [., ., ., ., ., ., A, B, C] + // ^ ^ + // W0 W1 + offset -= cb->item_size * cb->item_cap; + + // update write position + // multiple threads "competing" to update write position + // only the thread with the largest offset will succeed + // for the above example, W1 will succeed + // + // [., ., ., ., ., ., A, B, C] + // ^ + // W + atomic_compare_exchange_weak(&cb->write, &overflow, offset + cb->item_size); } + // copy item into buffer + memcpy(cb->data + offset, item, cb->item_size); + // report success return 1; } -// removes oldest item from buffer -// returns 1 on success, 0 otherwise -int CircularBuffer_Remove +// reserve a slot within buffer +// returns a pointer to a 'item size' slot within the buffer +// this function is thread-safe and lock-free +void *CircularBuffer_Reserve ( - CircularBuffer cb, // buffer to remove item from - void *item // [output] pointer populated with removed item + CircularBuffer cb // buffer to populate ) { ASSERT(cb != NULL); - ASSERT(item != NULL); - // make sure there's data to return - if(unlikely(CircularBuffer_Empty(cb))) { - return 0; + // atomic update buffer item count + // an item will be overwritten if buffer is full + uint64_t item_count = atomic_fetch_add(&cb->item_count, 1); + if(unlikely(item_count >= cb->item_cap)) { + cb->item_count = cb->item_cap; } - // update buffer item count - cb->item_count--; + // determine current and next write position + uint64_t offset = atomic_fetch_add(&cb->write, cb->item_size); - // copy item from buffer to output - memcpy(item, cb->read, cb->item_size); + // check for buffer overflow + if(unlikely(cb->data + offset >= cb->end_marker)) { + // write need to circle back + // [., ., ., ., ., ., A, B, C] + // ^ ^ + // W0 W1 + uint64_t overflow = offset + cb->item_size; - // advance read position - // circle back if read reached the end of the buffer - cb->read += cb->item_size; - if(unlikely(cb->read >= cb->end_marker)) { - cb->read = cb->data; + // adjust offset + // [., ., ., ., ., ., A, B, C] + // ^ ^ + // W0 W1 + offset -= cb->item_size * cb->item_cap; + + // update write position + // multiple threads "competing" to update write position + // only the thread with the largest offset will succeed + // for the above example, W1 will succeed + // + // [., ., ., ., ., ., A, B, C] + // ^ + // W + atomic_compare_exchange_weak(&cb->write, &overflow, offset + cb->item_size); } - // report success - return 1; + // return slot pointer + return cb->data + offset; } -void *CircularBuffer_Current +// read oldest item from buffer +// note: this function is not thread-safe +void *CircularBuffer_Read ( - const CircularBuffer cb + CircularBuffer cb, // buffer to read item from + void *item // [optional] pointer populated with removed item ) { ASSERT(cb != NULL); - ASSERT(!CircularBuffer_Empty(cb)); - return cb->read; -} + // make sure there's data to return + if(unlikely(CircularBuffer_Empty(cb))) { + return NULL; + } -// returns number of items in buffer -int CircularBuffer_ItemCount -( - CircularBuffer cb // buffer to inspect -) { - ASSERT(cb != NULL); + void *read = cb->read; - return cb->item_count; -} - -// return true if buffer is empty -inline bool CircularBuffer_Empty -( - const CircularBuffer cb // buffer to inspect -) { - ASSERT(cb != NULL); + // update buffer item count + cb->item_count--; - return cb->item_count == 0; -} + // copy item from buffer to output + if(item != NULL) { + memcpy(item, cb->read, cb->item_size); + } -// returns true if buffer is full -inline bool CircularBuffer_Full -( - const CircularBuffer cb // buffer to inspect -) { - ASSERT(cb != NULL); + // advance read position + // circle back if read reached the end of the buffer + cb->read += cb->item_size; + if(unlikely(cb->read >= cb->end_marker)) { + cb->read = cb->data; + } - return cb->item_count == cb->item_cap; + // return original read position + return read; } -// free buffer +// free buffer (does not free its elements if its free callback is NULL) void CircularBuffer_Free ( - CircularBuffer *cb // buffer to free + CircularBuffer cb // buffer to free ) { - ASSERT(cb != NULL && *cb != NULL); + ASSERT(cb != NULL); - // note: if there are items in buffer that are heap allocated - // we don't free them, it is the caller responsibility to make sure - // items stored in the buffer do not leak - rm_free(*cb); - *cb = NULL; + rm_free(cb); } diff --git a/src/util/circular_buffer.h b/src/util/circular_buffer.h index 7b0c68fa59..8c2cbf4152 100644 --- a/src/util/circular_buffer.h +++ b/src/util/circular_buffer.h @@ -1,12 +1,16 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include +#include // forward declaration typedef struct _CircularBuffer _CircularBuffer; @@ -18,31 +22,21 @@ CircularBuffer CircularBuffer_New uint cap // max number of items in buffer ); -// adds an item to buffer -// returns 1 on success, 0 otherwise -int CircularBuffer_Add -( - CircularBuffer cb, // buffer to populate - void *item // item to add -); - -// removes oldest item from buffer -// returns 1 on success, 0 otherwise -int CircularBuffer_Remove +// returns number of items in buffer +uint64_t CircularBuffer_ItemCount ( - CircularBuffer cb, // buffer to remove item from - void *item // [output] pointer populated with removed item + CircularBuffer cb // buffer ); -void *CircularBuffer_Current +// returns buffer capacity +uint64_t CircularBuffer_Cap ( - const CircularBuffer cb + CircularBuffer cb // buffer ); -// returns number of items in buffer -int CircularBuffer_ItemCount +uint CircularBuffer_ItemSize ( - CircularBuffer cb // buffer to inspect + const CircularBuffer cb // buffer ); // return true if buffer is empty @@ -57,8 +51,38 @@ bool CircularBuffer_Full const CircularBuffer cb // buffer to inspect ); -// free buffer +// adds an item to buffer +// returns 1 on success, 0 otherwise +int CircularBuffer_Add +( + CircularBuffer cb, // buffer to populate + void *item // item to add +); + +// reserve a slot within buffer +// returns a pointer to a 'item size' slot within the buffer +// this function is thread-safe and lock-free +void *CircularBuffer_Reserve +( + CircularBuffer cb // buffer to populate +); + +// read oldest item from buffer +void *CircularBuffer_Read +( + CircularBuffer cb, // buffer to read item from + void *item // [optional] pointer populated with removed item +); + +// sets the read pointer to the beginning of the buffer +void CircularBuffer_ResetReader +( + CircularBuffer cb // circular buffer +); + +// free buffer (does not free its elements if its free callback is NULL) void CircularBuffer_Free ( - CircularBuffer *cb // buffer to free + CircularBuffer cb // buffer to free ); + diff --git a/src/util/cron.h b/src/util/cron.h deleted file mode 100644 index ed1fada141..0000000000 --- a/src/util/cron.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#pragma once - -#include "heap.h" -#include -#include -#include - -// CRON is a task scheduler -// a task is defined by: -// when it should run; delta in ms from the time it's introduced -// a callback to call when it is time to execute the task -// and an optional private data passed to the callback - -// task callback function -typedef void (*CronTaskCB)(void *pdata); -typedef uintptr_t CronTaskHandle; - -// start CRON, should be called once -void Cron_Start(void); - -// stop CRON -void Cron_Stop(void); - -// create a new CRON task -CronTaskHandle Cron_AddTask -( - uint when, // number of miliseconds until task invocation - CronTaskCB cb, // callback to call when task is due - void *pdata // private data to pass to callback -); - -// aborts the CRON task passed (if found). -// this function doesn't wait until the task is completed if it has -// already started at the moment of invocation. -void Cron_AbortTask -( - CronTaskHandle t -); diff --git a/src/util/datablock/datablock.c b/src/util/datablock/datablock.c index 73386e57f5..0199e6cdff 100644 --- a/src/util/datablock/datablock.c +++ b/src/util/datablock/datablock.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "RG.h" #include "datablock.h" @@ -165,6 +168,17 @@ void *DataBlock_GetItem(const DataBlock *dataBlock, uint64_t idx) { return ITEM_DATA(item_header); } +uint64_t DataBlock_GetReservedIdx(const DataBlock *dataBlock, uint64_t n) { + ASSERT(dataBlock != NULL); + + uint deleted = DataBlock_DeletedItemsCount(dataBlock); + if(n < deleted) { + return dataBlock->deletedIdx[deleted - n - 1]; + } + + return DataBlock_ItemCount(dataBlock) + n; +} + void *DataBlock_AllocateItem(DataBlock *dataBlock, uint64_t *idx) { // make sure we've got room for items if(dataBlock->itemCount >= dataBlock->itemCap) { diff --git a/src/util/datablock/datablock.h b/src/util/datablock/datablock.h index 266a11b1d4..7af0973480 100644 --- a/src/util/datablock/datablock.h +++ b/src/util/datablock/datablock.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -83,6 +86,9 @@ DataBlockIterator *DataBlock_FullScan(const DataBlock *dataBlock); // Get item at position idx void *DataBlock_GetItem(const DataBlock *dataBlock, uint64_t idx); +// Get reserved item id after 'n' items +uint64_t DataBlock_GetReservedIdx(const DataBlock *dataBlock, uint64_t n); + // Allocate a new item within given dataBlock, // if idx is not NULL, idx will contain item position // return a pointer to the newly allocated item. diff --git a/src/util/datablock/datablock_iterator.c b/src/util/datablock/datablock_iterator.c index 89a6c81029..b055765512 100644 --- a/src/util/datablock/datablock_iterator.c +++ b/src/util/datablock/datablock_iterator.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "datablock_iterator.h" #include "RG.h" diff --git a/src/util/datablock/datablock_iterator.h b/src/util/datablock/datablock_iterator.h index c14aca8003..46f74fd7d9 100644 --- a/src/util/datablock/datablock_iterator.h +++ b/src/util/datablock/datablock_iterator.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/datablock/oo_datablock.h b/src/util/datablock/oo_datablock.h index 4fdcbe72e5..1268402c2d 100644 --- a/src/util/datablock/oo_datablock.h +++ b/src/util/datablock/oo_datablock.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/dict.c b/src/util/dict.c index 63e4bd1fc5..8120fdb6f2 100644 --- a/src/util/dict.c +++ b/src/util/dict.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* Hash Tables Implementation. * * This file implements in memory hash tables with insert/del/replace/find/ @@ -77,10 +86,22 @@ struct dictEntry { static int _HashTableExpandIfNeeded(dict *d); static signed char _dictNextExp(unsigned long size); static long _dictKeyIndex(dict *d, const void *key, uint64_t hash, dictEntry **existing); -static int _dictInit(dict *d, dictType *type); +static int _dictInit(dict *d, const dictType *type); /* -------------------------- hash functions -------------------------------- */ +// identity hash function +static uint64_t _id_hash +( + const void *key +) { + return ((uint64_t)key); +} + +// hashtable callbacks +dictType def_dt = {_id_hash, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL}; + static uint8_t dict_hash_function_seed[16]; void HashTableSetHashFunctionSeed(uint8_t *seed) { @@ -122,16 +143,17 @@ static void _dictReset /* Create a new hash table */ dict *HashTableCreate ( - dictType *type -) -{ + const dictType *type +) { + assert(type != NULL); + size_t metasize = type->dictMetadataBytes ? type->dictMetadataBytes() : 0; dict *d = malloc(sizeof(*d) + metasize); if (metasize) { memset(HashTableMetadata(d), 0, metasize); } - _dictInit(d,type); + _dictInit(d, type); return d; } @@ -147,7 +169,7 @@ unsigned long HashTableElemCount int _dictInit ( dict *d, - dictType *type + const dictType *type ) { _dictReset(d, 0); _dictReset(d, 1); diff --git a/src/util/dict.h b/src/util/dict.h index c7ca8957f1..6570042203 100644 --- a/src/util/dict.h +++ b/src/util/dict.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* Hash Tables Implementation. * * This file implements in-memory hash tables with insert/del/replace/find/ @@ -67,8 +76,17 @@ typedef struct dictType { #define DICTHT_SIZE(exp) ((exp) == -1 ? 0 : (unsigned long)1<<(exp)) #define DICTHT_SIZE_MASK(exp) ((exp) == -1 ? 0 : (DICTHT_SIZE(exp))-1) +// fake hash function +// hash of key is simply key +static uint64_t nop_hash +( + const void *key +) { + return ((uint64_t)key); +} + struct dict { - dictType *type; + const dictType *type; dictEntry **ht_table[2]; unsigned long ht_used[2]; @@ -84,6 +102,9 @@ struct dict { * by dictType's dictEntryBytes. */ }; +// global default dictType with identity hash function +dictType def_dt; + /* If safe is set to 1 this is a safe iterator, that means, you can call * dictAdd, dictFind, and other functions against the dictionary even while * iterating. Otherwise it is a non safe iterator, and only dictNext() @@ -145,7 +166,7 @@ typedef enum { } HashTableResizeEnable; /* API */ -dict *HashTableCreate(dictType *type); +dict *HashTableCreate(const dictType *type); unsigned long HashTableElemCount(const dict *d); int HashTableExpand(dict *d, unsigned long size); void *HashTableMetadata(dict *d); diff --git a/src/util/heap.c b/src/util/heap.c index c88578db6e..9da63f59c5 100644 --- a/src/util/heap.c +++ b/src/util/heap.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #include #include #include diff --git a/src/util/heap.h b/src/util/heap.h index 9fdf8b6b93..8faab84c0f 100644 --- a/src/util/heap.h +++ b/src/util/heap.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #pragma once #include diff --git a/src/util/json_encoder.c b/src/util/json_encoder.c index b3e374d1c1..cd05f03b62 100644 --- a/src/util/json_encoder.c +++ b/src/util/json_encoder.c @@ -1,16 +1,19 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "json_encoder.h" #include "sds/sds.h" #include "rmalloc.h" #include "strutil.h" #include "../value.h" -#include "../errors.h" #include "../query_ctx.h" +#include "../errors/errors.h" #include "../graph/graphcontext.h" #include "../graph/entities/node.h" #include "../graph/entities/edge.h" @@ -26,7 +29,7 @@ static inline sds _JsonEncoder_String(SIValue v, sds s) { static sds _JsonEncoder_Properties(const GraphEntity *ge, sds s) { s = sdscat(s, "\"properties\": {"); const AttributeSet set = GraphEntity_GetAttributes(ge); - uint prop_count = ATTRIBUTE_SET_COUNT(set); + uint prop_count = AttributeSet_Count(set); GraphContext *gc = QueryCtx_GetGraphCtx(); for(uint i = 0; i < prop_count; i ++) { Attribute_ID attr_id; @@ -64,7 +67,7 @@ static sds _JsonEncoder_Edge(Edge *e, sds s) { s = sdscatfmt(s, "\"id\": %U", ENTITY_GET_ID(e)); GraphContext *gc = QueryCtx_GetGraphCtx(); // Retrieve reltype data. - int id = Graph_GetEdgeRelation(gc->g, e); + int id = Edge_GetRelationID(e); Schema *schema = GraphContext_GetSchemaByID(gc, id, SCHEMA_EDGE); ASSERT(schema); const char *relationship = Schema_GetName(schema); @@ -76,13 +79,13 @@ static sds _JsonEncoder_Edge(Edge *e, sds s) { s = sdscat(s, ", \"start\": {"); // Retrieve source node data. Node src; - Graph_GetNode(gc->g, e->srcNodeID, &src); + Graph_GetNode(gc->g, e->src_id, &src); s = _JsonEncoder_Node(&src, s); s = sdscat(s, "}, \"end\": {"); // Retrieve dest node data. Node dest; - Graph_GetNode(gc->g, e->destNodeID, &dest); + Graph_GetNode(gc->g, e->dest_id, &dest); s = _JsonEncoder_Node(&dest, s); s = sdscat(s, "}"); diff --git a/src/util/json_encoder.h b/src/util/json_encoder.h index a67ad38d65..bf4db36b75 100644 --- a/src/util/json_encoder.h +++ b/src/util/json_encoder.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/math_util.c b/src/util/math_util.c new file mode 100644 index 0000000000..69b3194057 --- /dev/null +++ b/src/util/math_util.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#include "RG.h" +#include + +// computes x + y +// returns to true if x+y overflowed +bool safe_add +( + int x, // x + int y, // y + int *z // x+y +) { + ASSERT(z != NULL); + return __builtin_add_overflow(x, y, z); +} + +// computes x * y +// returns to true if x*y overflowed +bool safe_mul +( + int x, // x + int y, // y + int *z // x*y +) { + ASSERT(z != NULL); + return __builtin_mul_overflow(x, y, z); +} + diff --git a/src/util/math_util.h b/src/util/math_util.h new file mode 100644 index 0000000000..487f74c89c --- /dev/null +++ b/src/util/math_util.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + +#pragma once + +// computes x + y +// returns to true if x+y overflowed +bool safe_add +( + int x, // x + int y, // y + int *z // x+y +); + +// computes x * y +// returns to true if x*y overflowed +bool safe_mul +( + int x, // x + int y, // y + int *z // x*y +); + diff --git a/src/util/mt19937-64.c b/src/util/mt19937-64.c index a0c897ff6d..c9a36c7445 100644 --- a/src/util/mt19937-64.c +++ b/src/util/mt19937-64.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* A C-program for MT19937-64 (2004/9/29 version). Coded by Takuji Nishimura and Makoto Matsumoto. diff --git a/src/util/mt19937-64.h b/src/util/mt19937-64.h index b98348fd4f..a336a67a59 100644 --- a/src/util/mt19937-64.h +++ b/src/util/mt19937-64.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* A C-program for MT19937-64 (2004/9/29 version). Coded by Takuji Nishimura and Makoto Matsumoto. diff --git a/src/util/num.c b/src/util/num.c deleted file mode 100644 index ba149457f1..0000000000 --- a/src/util/num.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "num.h" - -#if defined(__has_builtin) -#define ___has_builtin(X) __has_builtin(X) -#else -#define ___has_builtin(X) false -#endif - -#if ___has_builtin(__builtin_add_overflow) -#define CHECKED_ADD(prefix, type) \ - bool checked_add_##prefix(const type lhs, const type rhs, type *result) { \ -return !__builtin_add_overflow(lhs, rhs, result); \ -} -#else -#define CHECKED_ADD(prefix, type) \ -bool checked_add_##prefix \ -( \ - const type lhs, \ - const type rhs, \ - type *result \ -) { \ - if (!result) { \ - return false; \ - } \ - \ - *result = lhs + rhs; \ - if (*result < lhs || *result < rhs) { \ - return false; \ - } \ - \ - return true; \ -} -#endif // __builtin_add_overflow - -CHECKED_ADD(u8, uint8_t); -CHECKED_ADD(u16, uint16_t); -CHECKED_ADD(u32, uint32_t); -CHECKED_ADD(u64, uint64_t); diff --git a/src/util/num.h b/src/util/num.h deleted file mode 100644 index 924be61f18..0000000000 --- a/src/util/num.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -/** - * This file contains helpful functions to work with numbers, like - * checked addition for unsigned integers, among others. - * To support the "overload" for a single function using different arguments - * (except for the out parameter), all the arguments for addition are implicitly - * converted to the max-width type (uint64_t) and only then, inside the body, - * the checks are performed. -*/ - -#pragma once - -#include -#include - -// Checks whether the specified flag is set within the flag variable. -// Evaluates to true if set, to false otherwise. -#define CHECK_FLAG(flag_var, flag_value) \ - ((flag_var & flag_value) == flag_value) - -bool checked_add_u8(const uint8_t lhs, const uint8_t rhs, uint8_t *result); -bool checked_add_u16(const uint16_t lhs, const uint16_t rhs, uint16_t *result); -bool checked_add_u32(const uint32_t lhs, const uint32_t rhs, uint32_t *result); -bool checked_add_u64(const uint64_t lhs, const uint64_t rhs, uint64_t *result); diff --git a/src/util/object_pool/object_pool.c b/src/util/object_pool/object_pool.c index b5db93ba79..50f42afb01 100644 --- a/src/util/object_pool/object_pool.c +++ b/src/util/object_pool/object_pool.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "object_pool.h" #include "RG.h" diff --git a/src/util/object_pool/object_pool.h b/src/util/object_pool/object_pool.h index 41066d151a..4d6a36bb9b 100644 --- a/src/util/object_pool/object_pool.h +++ b/src/util/object_pool/object_pool.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/qsort.h b/src/util/qsort.h index e58313d8df..72a0307a0a 100644 --- a/src/util/qsort.h +++ b/src/util/qsort.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ // this is a modified version of Isaac Turner 29 April 2014 Public Domain // sort_r.h diff --git a/src/util/range/numeric_range.c b/src/util/range/numeric_range.c index cc71a724ab..a983df6c80 100644 --- a/src/util/range/numeric_range.c +++ b/src/util/range/numeric_range.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "numeric_range.h" #include "RG.h" diff --git a/src/util/range/numeric_range.h b/src/util/range/numeric_range.h index c58e089571..80a9263fde 100644 --- a/src/util/range/numeric_range.h +++ b/src/util/range/numeric_range.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/range/string_range.c b/src/util/range/string_range.c index 2f6d47f0d9..d8c126d218 100644 --- a/src/util/range/string_range.c +++ b/src/util/range/string_range.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "string_range.h" #include "RG.h" diff --git a/src/util/range/string_range.h b/src/util/range/string_range.h index d997a12552..0b67a2008e 100644 --- a/src/util/range/string_range.h +++ b/src/util/range/string_range.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/range/unsigned_range.c b/src/util/range/unsigned_range.c index 365258d30a..bf312a0905 100644 --- a/src/util/range/unsigned_range.c +++ b/src/util/range/unsigned_range.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "unsigned_range.h" #include "RG.h" @@ -12,25 +15,35 @@ UnsignedRange *UnsignedRange_New(void) { UnsignedRange *range = rm_malloc(sizeof(UnsignedRange)); - range->valid = true; - range->min = 0; - range->max = UINT64_MAX; + + range->min = 0; + range->max = UINT64_MAX; + range->valid = true; range->include_min = true; range->include_max = true; + return range; } -UnsignedRange *UnsignedRange_Clone(const UnsignedRange *range) { +UnsignedRange *UnsignedRange_Clone +( + const UnsignedRange *range +) { UnsignedRange *clone = rm_malloc(sizeof(UnsignedRange)); - clone->min = range->min; - clone->max = range->max; - clone->valid = range->valid; + + clone->min = range->min; + clone->max = range->max; + clone->valid = range->valid; clone->include_min = range->include_min; clone->include_max = range->include_max; + return clone; } -bool UnsignedRange_IsValid(const UnsignedRange *range) { +bool UnsignedRange_IsValid +( + const UnsignedRange *range +) { if(!range->valid) return false; if(range->include_min && range->include_max) { // X >= y AND X <= z @@ -43,7 +56,11 @@ bool UnsignedRange_IsValid(const UnsignedRange *range) { } } -bool UnsignedRange_ContainsValue(const UnsignedRange *range, uint64_t v) { +bool UnsignedRange_ContainsValue +( + const UnsignedRange *range, + uint64_t v +) { if(!range->valid) return false; // Make sure v is <= max. @@ -63,7 +80,12 @@ bool UnsignedRange_ContainsValue(const UnsignedRange *range, uint64_t v) { return true; } -void UnsignedRange_TightenRange(UnsignedRange *range, int op, uint64_t v) { +void UnsignedRange_TightenRange +( + UnsignedRange *range, + int op, + uint64_t v +) { if(!range->valid) return; switch(op) { @@ -108,11 +130,14 @@ void UnsignedRange_TightenRange(UnsignedRange *range, int op, uint64_t v) { break; } - // See if range is still valid. + // see if range is still valid range->valid = UnsignedRange_IsValid(range); } -void UnsignedRange_ToString(const UnsignedRange *range) { +void UnsignedRange_ToString +( + const UnsignedRange *range +) { ASSERT(range != NULL); int offset = 0; char buff[1024]; @@ -132,7 +157,10 @@ void UnsignedRange_ToString(const UnsignedRange *range) { printf("%s\n", buff); } -void UnsignedRange_Free(UnsignedRange *range) { +void UnsignedRange_Free +( + UnsignedRange *range +) { ASSERT(range != NULL); rm_free(range); } diff --git a/src/util/range/unsigned_range.h b/src/util/range/unsigned_range.h index b912d079a8..6a672644e1 100644 --- a/src/util/range/unsigned_range.h +++ b/src/util/range/unsigned_range.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/rax_extensions.c b/src/util/rax_extensions.c index f8bca9846a..4496612a04 100644 --- a/src/util/rax_extensions.c +++ b/src/util/rax_extensions.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "rax_extensions.h" #include "arr.h" diff --git a/src/util/rax_extensions.h b/src/util/rax_extensions.h index 9b6cd4cbd9..c88d6d0def 100644 --- a/src/util/rax_extensions.h +++ b/src/util/rax_extensions.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/redis_version.c b/src/util/redis_version.c index a26afcda25..2c76980a14 100644 --- a/src/util/redis_version.c +++ b/src/util/redis_version.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "redis_version.h" #include "../redismodule.h" diff --git a/src/util/redis_version.h b/src/util/redis_version.h index 9b2f947fb9..1d80295295 100644 --- a/src/util/redis_version.h +++ b/src/util/redis_version.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/rmalloc.c b/src/util/rmalloc.c index eaa763bfaf..88fb6b368d 100644 --- a/src/util/rmalloc.c +++ b/src/util/rmalloc.c @@ -1,11 +1,15 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "rmalloc.h" -#include "../errors.h" + +#include "../errors/errors.h" #ifdef REDIS_MODULE_TARGET /* Set this when compiling your code as a module */ @@ -43,10 +47,10 @@ static inline void _nmalloc_increment(int64_t n_bytes) { if(n_alloced > mem_capacity) { // set n_alloced to MIN to avoid further out of memory exceptions // TODO: consider switching to double -inf - n_alloced = INT64_MIN; + n_alloced = INT32_MIN; // throw exception cause memory limit exceeded - ErrorCtx_SetError("Query's mem consumption exceeded capacity"); + ErrorCtx_SetError(EMSG_QUERY_MEM_CONSUMPTION); } } diff --git a/src/util/rmalloc.h b/src/util/rmalloc.h index def29767a9..58662fd8c6 100644 --- a/src/util/rmalloc.h +++ b/src/util/rmalloc.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + #ifndef __REDISGRAPH_ALLOC__ #define __REDISGRAPH_ALLOC__ diff --git a/src/util/sds/sds.c b/src/util/sds/sds.c index 82347fbe5d..7efbcef8a6 100644 --- a/src/util/sds/sds.c +++ b/src/util/sds/sds.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + // clang-format off /* SDSLib 2.0 -- A C dynamic strings library diff --git a/src/util/sds/sds.h b/src/util/sds/sds.h index ab8731e5ef..9f61964f8f 100644 --- a/src/util/sds/sds.h +++ b/src/util/sds/sds.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* SDSLib 2.0 -- A C dynamic strings library * * Copyright (c) 2006-2015, Salvatore Sanfilippo diff --git a/src/util/sds/sdsalloc.h b/src/util/sds/sdsalloc.h index f547b4c09b..2b1d58beee 100644 --- a/src/util/sds/sdsalloc.h +++ b/src/util/sds/sdsalloc.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* SDSLib 2.0 -- A C dynamic strings library * * Copyright (c) 2006-2015, Salvatore Sanfilippo diff --git a/src/util/simple_timer.c b/src/util/simple_timer.c index 57f00cf1fa..df4845e406 100644 --- a/src/util/simple_timer.c +++ b/src/util/simple_timer.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + //------------------------------------------------------------------------------ // GraphBLAS/Demo/Source/simple_timer.c: a timer for performance measurements //------------------------------------------------------------------------------ @@ -10,6 +19,7 @@ // simple_timer: a portable timer for accurate performance measurements #include "simple_timer.h" +#include //------------------------------------------------------------------------------ // simple_tic: return the current wallclock time in high resolution @@ -76,3 +86,25 @@ double simple_toc // returns time since last simple_tic simple_tic (toc) ; return ((toc [0] - tic [0]) + 1e-9 * (toc [1] - tic [1])) ; } + +void simple_timer_copy // copies a simple time +( + const double tic [2], // tic from last call to simple_tic + double cpy [2] // pointer to recieve a copy of tic +) +{ + cpy[0] = tic[0]; + cpy[1] = tic[1]; +} + +uint64_t unix_timestamp // returns UNIX timestamp +( + void +) +{ + struct timespec timestamp; + assert(clock_gettime(CLOCK_REALTIME, ×tamp) == 0); + + return timestamp.tv_sec; +} + diff --git a/src/util/simple_timer.h b/src/util/simple_timer.h index 5fe63c3d58..105a0b0158 100644 --- a/src/util/simple_timer.h +++ b/src/util/simple_timer.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + //------------------------------------------------------------------------------ // GraphBLAS/Demo/Include/simple_timer.h: a timer for performance measurements //------------------------------------------------------------------------------ @@ -38,6 +47,7 @@ #define SIMPLE_TIMER_H #include +#include //------------------------------------------------------------------------------ // decide which timer to use @@ -66,6 +76,15 @@ #endif // #if defined(_OPENMP) +typedef double simple_timer_t[2]; + +// Determines how many milliseconds are in a second. +#define MILLISECONDS_IN_SECOND 1000 + +// An alias to return the time in milliseconds passed since the previous call. +#define TIMER_GET_ELAPSED_MILLISECONDS(timer) \ + (simple_toc(timer) * MILLISECONDS_IN_SECOND) + //------------------------------------------------------------------------------ void simple_tic // returns current time in seconds and nanoseconds @@ -78,4 +97,15 @@ double simple_toc // returns time since last simple_tic const double tic [2] // tic from last call to simple_tic ) ; +void simple_timer_copy // copies a simple time +( + const double tic [2], // tic from last call to simple_tic + double cpy [2] // pointer to recieve a copy of tic +) ; + +uint64_t unix_timestamp // returns UNIX timestamp +( + void +) ; + #endif // SIMPLE_TIMER_H diff --git a/src/util/strutil.c b/src/util/strutil.c index 97060cb451..99ef271bba 100644 --- a/src/util/strutil.c +++ b/src/util/strutil.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include diff --git a/src/util/strutil.h b/src/util/strutil.h index 4ea97c73a5..f5886b3c96 100644 --- a/src/util/strutil.h +++ b/src/util/strutil.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/util/thpool/pools.c b/src/util/thpool/pools.c index 563a6718d3..275d59eab3 100644 --- a/src/util/thpool/pools.c +++ b/src/util/thpool/pools.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include #include "RG.h" @@ -170,6 +173,42 @@ void ThreadPools_SetMaxPendingWork(uint64_t val) { if(_writers_thpool != NULL) thpool_set_jobqueue_cap(_writers_thpool, val); } +// returns a list of queued tasks that match the given handler +// caller must free the returned list +void **ThreadPools_GetTasksByHandler +( + void (*handler)(void *), // task handler to match + void (*match)(void *), // [optional] function to invoke on each match + uint32_t *n // number of tasks returned +) { + // validations + ASSERT(handler != NULL); + ASSERT(_readers_thpool != NULL); + ASSERT(_writers_thpool != NULL); + + // cap number of read tasks + uint32_t r_task_count = (thpool_get_jobqueue_len(_readers_thpool) > 1000) + ? 1000 + : thpool_get_jobqueue_len(_readers_thpool); + + // cap number of write tasks + uint32_t w_task_count = (thpool_get_jobqueue_len(_writers_thpool) > 1000) + ? 1000 + : thpool_get_jobqueue_len(_writers_thpool); + + void **tasks = malloc(sizeof(void *) * (r_task_count + w_task_count)); + + // collect tasks from readers and writers + thpool_get_tasks(_readers_thpool, tasks, &r_task_count, handler, match); + thpool_get_tasks(_writers_thpool, tasks + r_task_count, &w_task_count, + handler, match); + + // update number of tasks + *n = r_task_count + w_task_count; + + return tasks; +} + void ThreadPools_Destroy ( void @@ -180,3 +219,4 @@ void ThreadPools_Destroy thpool_destroy(_readers_thpool); thpool_destroy(_writers_thpool); } + diff --git a/src/util/thpool/pools.h b/src/util/thpool/pools.h index 3f4355c2a8..5487f867c9 100644 --- a/src/util/thpool/pools.h +++ b/src/util/thpool/pools.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once @@ -26,37 +29,22 @@ int ThreadPools_CreatePools ); // return number of threads in both the readers and writers pools -uint ThreadPools_ThreadCount -( - void -); +uint ThreadPools_ThreadCount(void); // return size of READERS thread-pool -uint ThreadPools_ReadersCount -( - void -); +uint ThreadPools_ReadersCount(void); // retrieve current thread id // 0 redis-main // 1..N + 1 readers // N + 2.. writers -int ThreadPools_GetThreadID -( - void -); +int ThreadPools_GetThreadID(void); // pause all thread pools -void ThreadPools_Pause -( - void -); +void ThreadPools_Pause(void); // resume all threads -void ThreadPools_Resume -( - void -); +void ThreadPools_Resume(void); // adds a read task int ThreadPools_AddWorkReader @@ -80,8 +68,18 @@ void ThreadPools_SetMaxPendingWork uint64_t val ); +// returns a list of queued tasks that match the given handler +// caller must free the returned list +void **ThreadPools_GetTasksByHandler +( + void (*handler)(void *), // task handler to match + void (*match)(void *), // [optional] function to invoke on each match + uint32_t *n // number of tasks returned +); + // destroies all threadpools, allows threads to exit gracefully void ThreadPools_Destroy ( void ); + diff --git a/src/util/thpool/thpool.c b/src/util/thpool/thpool.c index e837ef282a..fdcd161c37 100644 --- a/src/util/thpool/thpool.c +++ b/src/util/thpool/thpool.c @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /* ******************************** * Author: Johan Hanssen Seferidis * License: MIT @@ -211,7 +220,7 @@ void thpool_destroy(thpool_* thpool_p) { // Wake up the threads so that they exit and will become ready to be // destroyed. - while (thpool_p->num_threads_alive) { + while(thpool_p->num_threads_alive) { bsem_post_all(thpool_p->jobqueue.has_jobs); } @@ -277,11 +286,77 @@ bool thpool_queue_full(thpool_* thpool_p) { return (thpool_p->jobqueue.len >= thpool_p->jobqueue.cap); } -void thpool_set_jobqueue_cap(thpool_* thpool_p, uint64_t val) { +void thpool_set_jobqueue_cap +( + thpool_* thpool_p, + uint64_t val +) { ASSERT(thpool_p); thpool_p->jobqueue.cap = val; } +uint64_t thpool_get_jobqueue_cap +( + thpool_* thpool_p +) { + ASSERT(thpool_p); + return thpool_p->jobqueue.cap; +} + +uint64_t thpool_get_jobqueue_len +( + thpool_* thpool_p +) { + ASSERT(thpool_p); + return thpool_p->jobqueue.len; +} + +// collects tasks matching given handler +void thpool_get_tasks +( + threadpool thpool_p, // thread pool + void **tasks, // array of tasks + uint32_t *num_tasks, // number of tasks collected + void (*handler)(void *), // handler function + void (*match)(void*) // [optional] executed on every match task +) { + // validations + ASSERT(tasks != NULL); + ASSERT(handler != NULL); + ASSERT(thpool_p != NULL); + ASSERT(num_tasks != NULL); + + jobqueue *jobqueue_p = &thpool_p->jobqueue; + + // lock job queue + pthread_mutex_lock(&jobqueue_p->rwmutex); + + job *job = jobqueue_p->front; + + // iterate through job queue + uint32_t i = 0; + for(; i < jobqueue_p->len && i < *num_tasks; i++) { + // check if job matches given handler + if(job->function == handler) { + tasks[i] = job->arg; + + // execute match function if given + if(match != NULL) { + match(job->arg); + } + } + + // advance to next job + job = job->prev; + } + + // release lock + pthread_mutex_unlock(&jobqueue_p->rwmutex); + + // set number of tasks collected + *num_tasks = i; +} + /* ============================ THREAD ============================== */ /* Initialize a thread in the thread pool @@ -357,7 +432,6 @@ static void *thread_do(struct thread *thread_p) { bsem_wait(thpool_p->jobqueue.has_jobs); if(threads_keepalive) { - ++thpool_p->num_threads_working; /* Read job from queue and execute it */ diff --git a/src/util/thpool/thpool.h b/src/util/thpool/thpool.h index 1a6fa49ffd..fc0098bd46 100644 --- a/src/util/thpool/thpool.h +++ b/src/util/thpool/thpool.h @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ + /********************************** * @author Johan Hanssen Seferidis * License: MIT @@ -218,7 +227,41 @@ bool thpool_queue_full(threadpool); * @param threadpool the threadpool of interest * @param uint64_t capacity of the queue */ -void thpool_set_jobqueue_cap(threadpool, uint64_t); +void thpool_set_jobqueue_cap +( + threadpool, + uint64_t +); + +/** + * @brief Gets jobqueue capacity. + * + * @param threadpool the threadpool of interest + */ +uint64_t thpool_get_jobqueue_cap +( + threadpool +); + +/** + * @brief Gets jobqueue length. + * + * @param threadpool the threadpool of interest + */ +uint64_t thpool_get_jobqueue_len +( + threadpool +); + +// collects tasks matching given handler +void thpool_get_tasks +( + threadpool thpool_p, // thread pool + void **tasks, // array of tasks + uint32_t *num_tasks, // number of tasks collected + void (*handler)(void *), // handler function + void (*match)(void*) // [optional] executed on every match task +); #ifdef __cplusplus } diff --git a/src/util/time.c b/src/util/time.c deleted file mode 100644 index 9c40feb9fe..0000000000 --- a/src/util/time.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "time.h" -#include -#include - -uint64_t get_unix_timestamp_milliseconds(void) { - struct timeval tv = {}; - - gettimeofday(&tv, NULL); - - const uint64_t milliseconds_since_epoch = - (uint64_t)(tv.tv_sec) * 1000 + - (uint64_t)(tv.tv_usec) / 1000; - - return milliseconds_since_epoch; -} diff --git a/src/util/time.h b/src/util/time.h deleted file mode 100644 index 50505d50c4..0000000000 --- a/src/util/time.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#pragma once - -#include - -// Returns the milliseconds elapsed since the UNIX epoch. -uint64_t get_unix_timestamp_milliseconds(void); diff --git a/src/util/uuid.c b/src/util/uuid.c index a2df829bef..61cd6f8a3b 100644 --- a/src/util/uuid.c +++ b/src/util/uuid.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "rmalloc.h" #include "uuid.h" diff --git a/src/util/uuid.h b/src/util/uuid.h index fe93ca50c4..11e0abe713 100644 --- a/src/util/uuid.h +++ b/src/util/uuid.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once diff --git a/src/value.c b/src/value.c index 7aedaa1d05..e88cfabff2 100644 --- a/src/value.c +++ b/src/value.c @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #include "value.h" #include "RG.h" @@ -415,13 +418,13 @@ size_t SIValue_StringJoinLen(SIValue *strings, unsigned int string_count, const /* Compute length. */ for(int i = 0; i < string_count; i ++) { /* String elements representing bytes size strings, - * for all other SIValue types 32 bytes should be enough. */ - elem_len = (strings[i].type == T_STRING) ? strlen(strings[i].stringval) + delimiter_len : 32; + * for all other SIValue types 64 bytes should be enough. */ + elem_len = (strings[i].type == T_STRING) ? strlen(strings[i].stringval) + delimiter_len : 64; length += elem_len; } /* Account for NULL terminating byte. */ - length += string_count + 1; + length++; return length; } @@ -762,6 +765,69 @@ XXH64_hash_t SIValue_HashCode(SIValue v) { return XXH64_digest(&state); } +// reads SIValue off of binary stream +SIValue SIValue_FromBinary +( + FILE *stream // stream to read value from +) { + ASSERT(stream != NULL); + + // read value type + SIType t; + SIValue v; + size_t len; // string length + + bool b; + int64_t i; + double d; + Point p; + char *s; + struct SIValue *array; + + fread_assert(&t, sizeof(SIType), stream); + switch(t) { + case T_POINT: + // read point from stream + fread_assert(&p, sizeof(v.point), stream); + v = SI_Point(p.latitude, p.longitude); + break; + case T_ARRAY: + // read array from stream + v = SIArray_FromBinary(stream); + break; + case T_STRING: + // read string length from stream + fread_assert(&len, sizeof(len), stream); + s = rm_malloc(sizeof(char) * len); + // read string from stream + fread_assert(s, sizeof(char) * len, stream); + v = SI_TransferStringVal(s); + break; + case T_BOOL: + // read bool from stream + fread_assert(&b, sizeof(b), stream); + v = SI_BoolVal(b); + break; + case T_INT64: + // read int from stream + fread_assert(&i, sizeof(i), stream); + v = SI_LongVal(i); + break; + case T_DOUBLE: + // read double from stream + fread_assert(&d, sizeof(d), stream); + v = SI_DoubleVal(d); + break; + case T_NULL: + v = SI_NullVal(); + break; + default: + assert(false && "unknown SIValue type"); + } + + return v; +} + void SIValue_Free(SIValue v) { // The free routine only performs work if it owns a heap allocation. if(v.allocation != M_SELF) return; diff --git a/src/value.h b/src/value.h index ac97bd0c31..90659b51de 100644 --- a/src/value.h +++ b/src/value.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #pragma once #include @@ -82,6 +85,11 @@ typedef enum { struct Pair; +typedef struct Point { + float latitude; // 32 bit + float longitude; // 32 bit +} Point; + typedef struct SIValue { union { int64_t longval; @@ -90,10 +98,7 @@ typedef struct SIValue { void *ptrval; struct Pair *map; struct SIValue *array; - struct { - float latitude; // 32 bit - float longitude; // 32 bit - } point; + Point point; }; SIType type; SIAllocation allocation; @@ -205,6 +210,12 @@ void SIValue_HashUpdate(SIValue v, XXH64_state_t *state); /* Returns a hash code for a given SIValue. */ XXH64_hash_t SIValue_HashCode(SIValue v); +// reads SIValue off of binary stream +SIValue SIValue_FromBinary +( + FILE *stream // stream to read value from +); + /* Free an SIValue's internal property if that property is a heap allocation owned * by this object. */ void SIValue_Free(SIValue v); diff --git a/src/version.h b/src/version.h index 45a3fc11fb..97cdd44ad1 100644 --- a/src/version.h +++ b/src/version.h @@ -1,8 +1,11 @@ /* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ + * Copyright (c) 2006-Present, Redis Ltd. + * All rights reserved. + * + * Licensed under your choice of the Redis Source Available License 2.0 + * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the + * GNU Affero General Public License v3 (AGPLv3). +*/ #ifndef REDISGRAPH_MODULE_VERSION diff --git a/tests/benchmarks/explicit_edge_deletion.yml b/tests/benchmarks/explicit_edge_deletion.yml index 0cfd44bd50..1cb4727174 100644 --- a/tests/benchmarks/explicit_edge_deletion.yml +++ b/tests/benchmarks/explicit_edge_deletion.yml @@ -4,7 +4,8 @@ remote: - type: oss-standalone dbconfig: - init_commands: - - '"GRAPH.QUERY" "g" "UNWIND range(0, 1000000) AS x CREATE (:N)-[:R]->(:N)"' + - '"GRAPH.QUERY" "g" "CREATE INDEX FOR ()-[e:R]->() ON (e.v)"' + - '"GRAPH.QUERY" "g" "UNWIND range(0, 1000000) AS x CREATE (:N)-[:R {v: x}]->(:N)"' clientconfig: - tool: redisgraph-benchmark-go - parameters: @@ -15,6 +16,6 @@ clientconfig: - connections: 1 - requests: 1000 - queries: - - { q: "MATCH (n:N)-[e]->() DELETE e RETURN 1 LIMIT 1", ratio: 1 } + - { q: "MATCH ()-[e:R]->() WHERE e.v > 0 WITH e LIMIT 1 DELETE e RETURN 1", ratio: 1 } kpis: - le: { $.OverallGraphInternalLatencies.Total.q50: 40.0 } diff --git a/tests/benchmarks/graph500-scale18-ef16_1hop.yml b/tests/benchmarks/graph500-scale18-ef16_1hop.yml index eb9d67c65c..05ae75e025 100644 --- a/tests/benchmarks/graph500-scale18-ef16_1hop.yml +++ b/tests/benchmarks/graph500-scale18-ef16_1hop.yml @@ -24,7 +24,7 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 1.0 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 1.0 } kpis: - le: { $.OverallClientLatencies.Total.q50: 5.0 } - ge: { $.OverallQueryRates.Total: 8000 } diff --git a/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_65_WRITE_25p_DEL_10p.yml b/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_65_WRITE_25p_DEL_10p.yml index d522b3414e..1725f36df5 100644 --- a/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_65_WRITE_25p_DEL_10p.yml +++ b/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_65_WRITE_25p_DEL_10p.yml @@ -24,6 +24,6 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 0.65 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 0.65 } - { q: "CYPHER Id1=__rand_int__ Id2=__rand_int__ MATCH (n1:Node {external_id: $Id1}) MATCH (n2:Node {external_id: $Id2}) MERGE(n1)-[rel:IS_CONNECTED]->(n2)", ratio: 0.25 } - { q: "CYPHER Id1=__rand_int__ Id2=__rand_int__ MATCH (n1:Node {external_id: $Id1})-[rel:IS_CONNECTED]->(n2:Node {external_id: $Id2}) DELETE rel", ratio: 0.10 } diff --git a/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_75_WRITE_25p.yml b/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_75_WRITE_25p.yml index 73933af9a7..faaa685289 100644 --- a/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_75_WRITE_25p.yml +++ b/tests/benchmarks/graph500-scale18-ef16_1hop_MIXED_READ_75_WRITE_25p.yml @@ -23,5 +23,5 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 0.75 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 0.75 } - { q: "CYPHER Id1=__rand_int__ Id2=__rand_int__ MATCH (n1:Node {external_id: $Id1}) MATCH (n2:Node {external_id: $Id2}) MERGE (n1)-[rel:IS_CONNECTED]->(n2)", ratio: 0.25 } diff --git a/tests/benchmarks/graph500-scale18-ef16_2hop.yml b/tests/benchmarks/graph500-scale18-ef16_2hop.yml index 07211a35d4..2c1096c61a 100644 --- a/tests/benchmarks/graph500-scale18-ef16_2hop.yml +++ b/tests/benchmarks/graph500-scale18-ef16_2hop.yml @@ -23,5 +23,5 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED*2]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 1.0 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED*2]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 1.0 } diff --git a/tests/benchmarks/graph500-scale18-ef16_2hop_MIXED_READ_75_WRITE_25p.yml b/tests/benchmarks/graph500-scale18-ef16_2hop_MIXED_READ_75_WRITE_25p.yml index 0d97a152d6..b6714346da 100644 --- a/tests/benchmarks/graph500-scale18-ef16_2hop_MIXED_READ_75_WRITE_25p.yml +++ b/tests/benchmarks/graph500-scale18-ef16_2hop_MIXED_READ_75_WRITE_25p.yml @@ -23,5 +23,5 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED*2]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 0.75 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED*2]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 0.75 } - { q: "CYPHER Id1=__rand_int__ Id2=__rand_int__ MATCH (n1:Node {external_id: $Id1}) MATCH (n2:Node {external_id: $Id2}) MERGE (n1)-[rel:IS_CONNECTED]->(n2)", ratio: 0.25 } diff --git a/tests/benchmarks/graph500-scale18-ef16_3hop.yml b/tests/benchmarks/graph500-scale18-ef16_3hop.yml index c3bbaa4a76..9f5853917a 100644 --- a/tests/benchmarks/graph500-scale18-ef16_3hop.yml +++ b/tests/benchmarks/graph500-scale18-ef16_3hop.yml @@ -23,5 +23,5 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED*3]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 1.0 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED*3]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 1.0 } diff --git a/tests/benchmarks/graph500-scale18-ef16_3hop_MIXED_READ_75_WRITE_25p.yml b/tests/benchmarks/graph500-scale18-ef16_3hop_MIXED_READ_75_WRITE_25p.yml index ce032443e1..2e85116949 100644 --- a/tests/benchmarks/graph500-scale18-ef16_3hop_MIXED_READ_75_WRITE_25p.yml +++ b/tests/benchmarks/graph500-scale18-ef16_3hop_MIXED_READ_75_WRITE_25p.yml @@ -23,5 +23,5 @@ clientconfig: - random-int-max: 262016 - random-seed: 12345 - queries: - - { q: "MATCH (n)-[:IS_CONNECTED*3]->(z) WHERE ID(n) = __rand_int__ RETURN ID(n), count(z)", ratio: 0.75 } + - { q: "CYPHER Id1=__rand_int__ MATCH (n)-[:IS_CONNECTED*3]->(z) WHERE ID(n) = $Id1 RETURN ID(n), count(z)", ratio: 0.75 } - { q: "CYPHER Id1=__rand_int__ Id2=__rand_int__ MATCH (n1:Node {external_id: $Id1}) MATCH (n2:Node {external_id: $Id2}) MERGE (n1)-[rel:IS_CONNECTED]->(n2)", ratio: 0.25 } diff --git a/tests/benchmarks/implicit_edge_deletion.yml b/tests/benchmarks/implicit_edge_deletion.yml index aa09dc131e..fbf30d81f6 100644 --- a/tests/benchmarks/implicit_edge_deletion.yml +++ b/tests/benchmarks/implicit_edge_deletion.yml @@ -4,7 +4,8 @@ remote: - type: oss-standalone dbconfig: - init_commands: - - '"GRAPH.QUERY" "g" "UNWIND range(0, 100000) AS x CREATE (src:N {v: x}), (src)-[:R]->(:N), (src)-[:R]->(:N), (src)-[:R]->(:N)"' + - '"GRAPH.QUERY" "g" "CREATE INDEX FOR (n:N) ON (n.v)"' + - '"GRAPH.QUERY" "g" "UNWIND range(0, 100000) AS x CREATE (src:N {v: x}), (src)-[:R]->(), (src)-[:R]->(:A), (src)-[:R]->(:B)""' clientconfig: - tool: redisgraph-benchmark-go - parameters: diff --git a/tests/flow/base.py b/tests/flow/base.py index 2f9f73a561..8d538e746c 100644 --- a/tests/flow/base.py +++ b/tests/flow/base.py @@ -71,4 +71,11 @@ def _assert_run_time(self, actual_result, query_info): if actual_result.run_time_ms > query_info.max_run_time_ms: warnings.warn('Maximum runtime for query \"%s\" was: %s, but should be %s' % (query_info.description, str(actual_result.run_time_ms), str(query_info.max_run_time_ms))) - + + # function which run the query and expects an specific error message + def _assert_exception(self, graph, query, expected_err_msg): + try: + graph.query(query) + self.env.assertTrue(False) + except Exception as e: + self.env.assertIn(expected_err_msg, str(e)) diff --git a/tests/flow/common.py b/tests/flow/common.py index 8c6f80f602..c8a1912015 100644 --- a/tests/flow/common.py +++ b/tests/flow/common.py @@ -1,5 +1,6 @@ import sys import os +from functools import wraps from RLTest import Env, Defaults @@ -27,3 +28,19 @@ OSNICK = paella.Platform().osnick OS = paella.Platform().os ARCH = paella.Platform().arch + + +def skip(cluster=False, macos=False): + def decorate(f): + @wraps(f) + def wrapper(x, *args, **kwargs): + env = x if isinstance(x, Env) else x.env + if not(cluster or macos): + env.skip() + if cluster and env.isCluster(): + env.skip() + if macos and OS == 'macos': + env.skip() + return f(x, *args, **kwargs) + return wrapper + return decorate diff --git a/tests/flow/constraint_utils.py b/tests/flow/constraint_utils.py index b34427ff2e..3cd1b86b57 100644 --- a/tests/flow/constraint_utils.py +++ b/tests/flow/constraint_utils.py @@ -3,11 +3,11 @@ class Constraint(): def __init__(self, ct, et, lbl, attrs, status): - self.lbl = lbl - self.s = status - self.et = et + self.s = status + self.ct = ct + self.et = et + self.lbl = lbl self.attrs = attrs - self.ct = ct def __eq__(self, other): return (self.lbl == other.lbl and diff --git a/tests/flow/execution_plan_util.py b/tests/flow/execution_plan_util.py index 5f731dd339..d90167f894 100644 --- a/tests/flow/execution_plan_util.py +++ b/tests/flow/execution_plan_util.py @@ -3,6 +3,8 @@ def locate_operation(op: Operation, name: str): + """Searches for a specific operation in the execution plan and returns it if + found, or None otherwise""" if op.name == name: return op if op.children: @@ -11,3 +13,15 @@ def locate_operation(op: Operation, name: str): if res: return res return None + +# Iterate recursively the operation's children and return the number of operations with a specific name +def count_operation(op: Operation, name: str): + """Returns the number of operations with a specific name in an execution + plan starting at op""" + res = 0 + if op.name == name: + res = 1 + if op.children: + for child in op.children: + res += count_operation(child, name) + return res diff --git a/tests/flow/index_utils.py b/tests/flow/index_utils.py index 07bfd955ef..1d2c9bb094 100644 --- a/tests/flow/index_utils.py +++ b/tests/flow/index_utils.py @@ -6,7 +6,7 @@ def _wait_on_index(graph, label, t): RETURN count(1)""" while True: - result = graph.query(q) + result = graph.query(q, read_only=True) if result.result_set[0][0] == 0: break @@ -31,7 +31,7 @@ def list_indicies(graph, label=None, t=None): q += f" WHERE type = '{t}'" q += " RETURN type, label, properties, language, stopwords, entitytype, info, status" - return graph.query(q) + return graph.query(q, read_only=True) def create_node_exact_match_index(graph, label, *properties, sync=False): q = f"CREATE INDEX for (n:{label}) on (" + ','.join(map('n.{0}'.format, properties)) + ")" @@ -58,14 +58,15 @@ def drop_fulltext_index(graph, label): # validate index is being populated def index_under_construction(graph, label, t): params = {'lbl': label, 'typ': t} - res = graph.query("CALL db.indexes() YIELD type, label, status WHERE label = $lbl AND type = $typ RETURN status", params) + q = "CALL db.indexes() YIELD type, label, status WHERE label = $lbl AND type = $typ RETURN status" + res = graph.query(q, params, read_only=True) return "UNDER CONSTRUCTION" in res.result_set[0][0] # wait for all graph indices to by operational def wait_for_indices_to_sync(graph): q = "CALL db.indexes() YIELD status WHERE status <> 'OPERATIONAL' RETURN count(1)" while True: - result = graph.query(q) + result = graph.query(q, read_only=True) if result.result_set[0][0] == 0: break time.sleep(0.5) # sleep 500ms diff --git a/tests/flow/random_graph.py b/tests/flow/random_graph.py index 91b3a86ad9..558a9cef35 100644 --- a/tests/flow/random_graph.py +++ b/tests/flow/random_graph.py @@ -216,8 +216,6 @@ def run_random_graph_ops(g, nodes, edges, ops): params, query = ops[op](nodes, edges) # print(query) res = g.query(query, params) - res.nodes_created - res.nodes_created result.append(res) return total, result diff --git a/tests/flow/test_access_del_entity.py b/tests/flow/test_access_del_entity.py new file mode 100644 index 0000000000..4ba0d9921d --- /dev/null +++ b/tests/flow/test_access_del_entity.py @@ -0,0 +1,409 @@ +from common import * + +class testAccessDelNode(): + def __init__(self): + self.env = Env(decodeResponses=True) + self.g= Graph(self.env.getConnection(), "access_del_node") + + def test01_return_deleted_attribute(self): + # try to return an attribute of a deleted entity + + # create a node + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + # retrieve attribute from a deleted node + q = "MATCH (n) DELETE n RETURN n.v" + res = self.g.query(q) + self.env.assertEquals(res.result_set[0][0], 1) + + def test02_return_deleted_node(self): + # try to return a deleted node + # expecting node ID and attributes to be returned + + # create a node + n = Node(label="A", properties = {'v':1}) + self.g.add_node(n) + self.g.flush() + + # return a deleted node + q = "MATCH (n) DELETE n RETURN n" + res = self.g.query(q) + deleted_node = res.result_set[0][0] + + self.env.assertEquals(n.properties, deleted_node.properties) + self.env.assertEquals(deleted_node.labels, None) + + def test03_deleted_node_as_argument(self): + # try to invoke a function on a deleted node + + # create a node + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + # invoke function on a deleted node + q = "MATCH (n) DELETE n RETURN labels(n)" + res = self.g.query(q) + self.env.assertEquals(res.result_set[0][0], []) + + #----------------------------------------------------------------------- + + # create a node + q = "CREATE (:A {a:1, b:'str', c:[1,2,3]})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + # invoke function on a deleted node + q = "MATCH (n) DELETE n RETURN properties(n)" + res = self.g.query(q) + properties = {'a': 1, 'b': 'str', 'c': [1,2,3]} + self.env.assertEquals(res.result_set[0][0], properties) + + def test04_update_deleted_node(self): + # try to update a deleted node + + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + # update a deleted node + q = "MATCH (n) DELETE n SET n.v = 2 RETURN n.v" + res = self.g.query(q) + self.env.assertEquals(res.properties_set, 0) + self.env.assertEquals(res.result_set[0][0], 1) + + #----------------------------------------------------------------------- + + q = "CREATE (:A {v:'value'}), (:B {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + + # set existing node to a deleted node + q = "MATCH (a:A), (b:B) DELETE a SET b = a RETURN b.v" + res = self.g.query(q) + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.result_set[0][0], 'value') + + # clear graph + self.env.flush() + + #----------------------------------------------------------------------- + + q = "CREATE (:A {a:'value'}), (:B {b:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + + # set existing node to a deleted node + q = "MATCH (a:A), (b:B) DELETE a SET b += a RETURN b.a, b.b" + res = self.g.query(q) + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.result_set[0][0], 'value') + self.env.assertEquals(res.result_set[0][1], 1) + + # clear graph + self.env.flush() + + def test05_update_deleted_node_lables(self): + # Add label to a deleted node + + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + # add label to a deleted node + q = "MATCH (n) DELETE n SET n:A" + res = self.g.query(q) + self.env.assertEquals(res.labels_added, 0) + self.env.assertEquals(res.nodes_deleted, 1) + + #----------------------------------------------------------------------- + + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + q = "MATCH (n) DELETE n REMOVE n:A" + res = self.g.query(q) + self.env.assertEquals(res.labels_removed, 0) + self.env.assertEquals(res.nodes_deleted, 1) + + def test06_merge_using_deleted_node_attr(self): + # try to merge a node based on a deleted node attribute + + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + q = "MATCH (n) DELETE n MERGE (m {v:n.v+2}) RETURN m.v" + res = self.g.query(q) + self.env.assertEquals(res.nodes_deleted, 1) + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(res.result_set[0][0], 3) + + # clear graph + self.env.flush() + + def test07_dobule_node_delete(self): + # try to delete a deleted node + # expecting a single delete to be performed + q = "CREATE (:A {v:1})" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + # delete a deleted node + q = "MATCH (n) DELETE n WITH n DELETE n" + res = self.g.query(q) + self.env.assertEquals(res.nodes_deleted, 1) + + def test08_create_edge_to_deleted_node(self): + # try to create an edge to a deleted node + # expecting an exception + + q = "CREATE (:A)" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + try: + q = "MATCH (n) DELETE n CREATE ()-[:R]->(n)" + res = self.g.query(q) + self.env.assertTrue(False) + except Exception as e: + self.env.assertEquals(str(e), "Failed to create relationship; endpoint was not found.") + + #----------------------------------------------------------------------- + + q = "CREATE (:A)" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 1) + + try: + q = "MATCH (n) DELETE n CREATE (n)-[:R]->()" + res = self.g.query(q) + self.env.assertTrue(False) + except Exception as e: + self.env.assertEquals(str(e), "Failed to create relationship; endpoint was not found.") + + # clear graph + self.env.flush() + + def test09_path_with_deleted_node(self): + # test path with deleted node + # create a 3 nodes path (a)->(b)->(c) + a = Node(label="A", properties = {'v':'a'}) + b = Node(label="B", properties = {'v':'b'}) + c = Node(label="C", properties = {'v':'c'}) + self.g.add_node(a) + self.g.add_node(b) + self.g.add_node(c) + + r1 = Edge(a, 'R', b) + r2 = Edge(b, 'R', c) + + self.g.add_edge(r1) + self.g.add_edge(r2) + + self.g.flush() + + # delete the middle node on the path + q = "MATCH p = (a:A)-[:R]->(b:B)-[:R]->(c:C) DELETE b RETURN nodes(p)" + res = self.g.query(q) + self.env.assertEquals(res.nodes_deleted, 1) + nodes = res.result_set[0][0] + self.env.assertEquals(len(nodes), 3) + + # assert individual nodes + self.env.assertEquals(nodes[0].properties['v'], 'a') + self.env.assertEquals(nodes[0].label, 'A') + + self.env.assertEquals(nodes[1].properties['v'], 'b') + self.env.assertIsNone(nodes[1].label) + + self.env.assertEquals(nodes[2].properties['v'], 'c') + self.env.assertEquals(nodes[2].label, 'C') + +class testAccessDelEdge(): + def __init__(self): + self.env = Env(decodeResponses=True) + self.g= Graph(self.env.getConnection(), "access_del_edge") + + def test01_return_deleted_attribute(self): + # try to return an attribute of a deleted entity + + # create an edge + q = "CREATE ()-[:R {v:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(res.relationships_created, 1) + + # retrieve attribute from a deleted edge + q = "MATCH ()-[e]->() DELETE e RETURN e.v" + res = self.g.query(q) + self.env.assertEquals(res.result_set[0][0], 1) + + def test02_return_deleted_edge(self): + # try to return a deleted edge + + # create an edge + src = Node(label="A", properties = {'v':1}) + dest = Node(label="B", properties = {'v':2}) + self.g.add_node(src) + self.g.add_node(dest) + + e = Edge(src, 'R', dest, properties = {'v':3}) + self.g.add_edge(e) + self.g.flush() + + # return a deleted edge + q = "MATCH ()-[e]->() DELETE e RETURN e" + res = self.g.query(q) + deleted_edge = res.result_set[0][0] + + self.env.assertEquals(e.relation, deleted_edge.relation) + self.env.assertEquals(e.properties, deleted_edge.properties) + + # clear graph + self.env.flush() + + def test03_deleted_edge_as_argument(self): + # try to invoke a function on a deleted edge + + # create an edge + q = "CREATE ()-[:R{v:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(res.relationships_created, 1) + + # invoke function on a deleted edge + q = "MATCH ()-[e]->() DELETE e RETURN type(e)" + res = self.g.query(q) + self.env.assertEquals(res.result_set[0][0], "R") + + # clear graph + self.env.flush() + + def test04_update_deleted_edge(self): + # try to update a deleted edge + + q = "CREATE ()-[:R{v:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(res.relationships_created, 1) + + # update a deleted edge + q = "MATCH ()-[e]->() DELETE e SET e.v = 2 RETURN e.v" + res = self.g.query(q) + self.env.assertEquals(res.properties_set, 0) + self.env.assertEquals(res.result_set[0][0], 1) + + # clear graph + self.env.flush() + + #----------------------------------------------------------------------- + + q = "CREATE ()-[:A{v:'value'}]->(), ()-[:B{v:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 4) + self.env.assertEquals(res.relationships_created, 2) + + # set existing edge to a deleted edge + q = "MATCH ()-[a:A]->(), ()-[b:B]->() DELETE a SET b = a RETURN b.v" + res = self.g.query(q) + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.result_set[0][0], "value") + + # clear graph + self.env.flush() + + #----------------------------------------------------------------------- + + q = "CREATE ()-[:A{a:'value'}]->(), ()-[:B{b:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 4) + self.env.assertEquals(res.relationships_created, 2) + + # set existing edge to a deleted edge + q = "MATCH ()-[a:A]->(), ()-[b:B]->() DELETE a SET b += a RETURN b.a, b.b" + res = self.g.query(q) + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.result_set[0][0], 'value') + self.env.assertEquals(res.result_set[0][1], 1) + + # clear graph + self.env.flush() + + def test05_merge_using_deleted_edge_attr(self): + # try to merge an edge based on a deleted edge attribute + + q = "CREATE ()-[:R{v:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(res.relationships_created, 1) + + q = "MATCH ()-[e]->() DELETE e MERGE (m {v:e.v+2}) RETURN m.v" + res = self.g.query(q) + self.env.assertEquals(res.result_set[0][0], 3) + + def test06_merge_using_deleted_edge_attr(self): + # try to merge an edge based on a deleted edge attribute + + q = "CREATE ()-[:R{v:1}]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(res.relationships_created, 1) + + q = "MATCH (a)-[e]->(b) DELETE e MERGE (a)-[:R {v:e.v+2}]->(b) RETURN e.v" + res = self.g.query(q) + self.env.assertEquals(res.result_set[0][0], 3) + self.env.assertEquals(res.relationships_deleted, 1) + self.env.assertEquals(res.relationships_created, 1) + + # clear graph + self.env.flush() + + def test07_dobule_edge_delete(self): + # try to delete a deleted edge + # expecting a single delete to be performed + q = "CREATE ()-[:R]->()" + res = self.g.query(q) + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(res.relationships_created, 1) + + # delete a deleted edge + q = "MATCH ()-[e]->() DELETE e WITH e DELETE e" + res = self.g.query(q) + self.env.assertEquals(res.relationships_deleted, 1) + + def test08_path_with_deleted_edge(self): + # test path with deleted edge + # create a 3 nodes path (a)->(b)->(c) + a = Node(label="A", properties = {'v':'a'}) + b = Node(label="B", properties = {'v':'b'}) + c = Node(label="C", properties = {'v':'c'}) + self.g.add_node(a) + self.g.add_node(b) + self.g.add_node(c) + + r1 = Edge(a, 'R1', b, properties = {'v':1}) + r2 = Edge(b, 'R2', c, properties = {'v':2}) + + self.g.add_edge(r1) + self.g.add_edge(r2) + + self.g.flush() + + # delete the middle node on the path + q = "MATCH p = (:A)-[e1:R1]->(:B)-[e2:R2]->(:C) DELETE e1 RETURN relationships(p)" + res = self.g.query(q) + self.env.assertEquals(res.relationships_deleted, 1) + edges = res.result_set[0][0] + self.env.assertEquals(len(edges), 2) + + # assert individual edges + self.env.assertEquals(edges[0].properties['v'], 1) + self.env.assertEquals(edges[0].relation, 'R1') + + self.env.assertEquals(edges[1].properties['v'], 2) + self.env.assertEquals(edges[1].relation, 'R2') + diff --git a/tests/flow/test_bulk_insertion.py b/tests/flow/test_bulk_insertion.py index 2bb81aabc8..a5c0e9ddfa 100644 --- a/tests/flow/test_bulk_insertion.py +++ b/tests/flow/test_bulk_insertion.py @@ -13,7 +13,7 @@ def run_bulk_loader(graphname, filename): runner = CliRunner() - runner.invoke(bulk_insert, ['--port', port, + runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', filename, graphname]) @@ -22,7 +22,7 @@ def __init__(self): self.env = Env(decodeResponses=True) # skip test if we're running under Valgrind - if VALGRIND or SANITIZER != "": + if VALGRIND: self.env.skip() # valgrind is not working correctly with replication global redis_graph @@ -38,7 +38,7 @@ def test01_run_script(self): runner = CliRunner() csv_path = os.path.dirname(os.path.abspath(__file__)) + '/../../demo/social/resources/bulk_formatted/' - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', csv_path + 'Person.csv', '--nodes', csv_path + 'Country.csv', '--relations', csv_path + 'KNOWS.csv', @@ -172,7 +172,7 @@ def test04_private_identifiers(self): out.writerow([5, 3]) runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', '--relations', '/tmp/relations.tmp', graphname]) @@ -208,7 +208,7 @@ def test05_reused_identifier(self): out.writerow([0, 3]) runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', '--relations', '/tmp/relations.tmp', graphname]) @@ -219,7 +219,7 @@ def test05_reused_identifier(self): # Run the script again without creating relations runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', graphname]) @@ -237,7 +237,7 @@ def test06_batched_build(self): runner = CliRunner() csv_path = os.path.dirname(os.path.abspath(__file__)) + '/../../demo/social/resources/bulk_formatted/' - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', csv_path + 'Person.csv', '--nodes', csv_path + 'Country.csv', '--relations', csv_path + 'KNOWS.csv', @@ -269,7 +269,7 @@ def test07_script_failures(self): out.writerow([0]) # Wrong number of properites runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', graphname]) @@ -289,7 +289,7 @@ def test07_script_failures(self): out.writerow([0]) runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', '--relations', '/tmp/relations.tmp', graphname]) @@ -304,7 +304,7 @@ def test07_script_failures(self): out.writerow([0, "fakeidentifier"]) runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', '--relations', '/tmp/relations.tmp', graphname]) @@ -340,7 +340,7 @@ def test08_property_types(self): out.writerow([7, 0, '']) runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/nodes.tmp', '--relations', '/tmp/relations.tmp', graphname]) @@ -387,7 +387,7 @@ def test09_large_bulk_insert(self): thread.join() # Verify that at least one ping was issued - self.env.assertGreater(ping_count, 1) + self.env.assertGreaterEqual(ping_count, 1) # Verify that nodes with multiple labels are created correctly def test10_multiple_labels(self): @@ -421,7 +421,7 @@ def test10_multiple_labels(self): out.writerow(["Connecticut", "US"]) runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', '/tmp/City:Place.tmp', '--nodes', '/tmp/Place:State.tmp', '--nodes', '/tmp/Place:Country.tmp', @@ -528,7 +528,7 @@ def test11_social_multiple_labels(self): csv_path = os.path.dirname(os.path.abspath(__file__)) + '/../../demo/social/resources/bulk_formatted/' runner = CliRunner() - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes-with-label', "Person:Visitor", csv_path + 'Person.csv', '--nodes-with-label', "Country:Place", csv_path + 'Country.csv', '--relations', csv_path + 'KNOWS.csv', diff --git a/tests/flow/test_call_subquery.py b/tests/flow/test_call_subquery.py new file mode 100644 index 0000000000..f496b90690 --- /dev/null +++ b/tests/flow/test_call_subquery.py @@ -0,0 +1,2143 @@ +from common import * +from collections import OrderedDict +from index_utils import create_node_exact_match_index +from execution_plan_util import locate_operation, count_operation + +graph = None +GRAPH_ID = "call_subquery" + +def _assert_subquery_contains_single(plan: ExecutionPlan, operation_name: str, env): + """Asserts that the sub-plan embedded in a CallSubquery contains a single + operation with name `operation_name`. If `plan` contains more than one + CallSubquery operations, only the first will be checked.""" + + callsubquery = locate_operation(plan.structured_plan, "CallSubquery") + env.assertIsNotNone(callsubquery) + env.assertEquals(count_operation(callsubquery, operation_name), 1) + +class testCallSubqueryFlow(): + def __init__(self): + self.env = Env(decodeResponses=True) + global graph + global redis_con + redis_con = self.env.getConnection() + graph = Graph(redis_con, GRAPH_ID) + + def get_res_and_assertEquals(self, query, expected_result): + """Run the query and assert the result set is as expected""" + + actual_result = graph.query(query) + self.env.assertEquals(actual_result.result_set, expected_result) + return actual_result + + def expect_error(self, query, expected_err_msg): + """Run the query and expect an error that contains the given message""" + + try: + graph.query(query) + assert(False) + except redis.exceptions.ResponseError as e: + self.env.assertIn(expected_err_msg, str(e)) + + def test01_test_validations(self): + """Make sure we fail on invalid queries""" + + import_error = "WITH imports in CALL {} must consist of only simple references to outside variables" + match_after_updating = "A WITH clause is required to introduce MATCH after an updating clause" + union_column_name_error = "All sub queries in a UNION must have the same column names." + queries_errors = [ + ("WITH 1 AS a CALL {WITH a+1 AS b RETURN b} RETURN b", import_error), + ("WITH {a: 1} AS map CALL {WITH map.a AS b RETURN b} RETURN b", import_error), + ("WITH [1, 2, 3] AS list CALL {WITH list[0] AS b RETURN b} RETURN b", import_error), + ("WITH 'RAZ' AS str CALL {WITH toUpper(str) AS b RETURN b} RETURN b", import_error), + ("WITH 1 AS a CALL {WITH a AS b RETURN b} RETURN b", import_error), + ("WITH 1 AS a CALL {WITH a LIMIT 5 RETURN a} RETURN a", import_error), + ("WITH 1 AS a CALL {WITH a ORDER BY a.v RETURN a} RETURN a", import_error), + ("WITH 1 AS a CALL {WITH a WHERE a > 5 RETURN a} RETURN a", import_error), + ("WITH 1 AS a CALL {WITH a SKIP 5 RETURN a} RETURN a", import_error), + ("WITH true AS a CALL {WITH NOT(a) AS b RETURN b} RETURN b", import_error), + ("CALL {CREATE (n:N) MATCH (n:N) RETURN n} RETURN 1", match_after_updating), + ("WITH 1 AS a CALL {WITH a CREATE (n:N) MATCH (n:N) RETURN n} RETURN a", match_after_updating), + ("CALL {MATCH (n:N) CREATE (n:N2)} RETURN 1 ", "The bound variable 'n' can't be redeclared in a CREATE clause"), + ("MATCH (n) CALL {WITH n AS n1 RETURN n1 UNION WITH n RETURN n1} RETURN n, n1", import_error), + ("MATCH (n) CALL {WITH n RETURN n AS n1 UNION WITH n AS n1 RETURN n1} RETURN n, n1", import_error), + ("CALL {RETURN 1 AS one UNION RETURN 2 AS two} RETURN 1", union_column_name_error), + ("MATCH (n) CALL {RETURN 1 AS one UNION RETURN 2 AS two} RETURN 1", union_column_name_error) + ] + for query, err in queries_errors: + self.expect_error(query, err) + + # invalid queries: import an undefined identifier + queries = [ + # There is no variable 'a' to import from the outer scope + """ + CALL { + WITH a + RETURN 1 AS one + } + RETURN one + """, + # 'a' is not defined in the first `WITH` + """ + WITH a + CALL { + WITH a + RETURN a AS b + } + RETURN b + """, + # 'a' in the inner RETURN is not defined + """ + MATCH (a:N) + CALL { + RETURN a.v AS INNERRETURN + } + RETURN 1 + """, + # 'a' in the outer RETURN is not defined + """ + CALL { + MATCH (a:N) + RETURN 1 as innerReturn + } + RETURN a + """, + # 'a' in inner RETURN is not defined + """ + UNWIND [1, 2, 3, 4] AS a + MATCH (n) + CALL { + WITH n + RETURN a + 1 + } + RETURN a + n.v + """ + ] + for query in queries: + self.expect_error(query, "'a' not defined") + + # outer scope variables (bound) should not be returnable from the sq + query = "MATCH (n:N) CALL {RETURN 1 AS n} RETURN n" + self.expect_error(query, "Variable `n` already declared in outer scope") + + # a CALL {} after an updating clause requires a separating WITH + query = "CREATE (n:N) CALL {RETURN 1} RETURN 1" + self.expect_error(query, + "A WITH clause is required to introduce CALL SUBQUERY after an \ +updating clause.") + + # a query can not be terminated by a returning subquery + query = "MATCH (n:N) CALL {WITH n CREATE (m:M {n: n.v}) RETURN m}" + self.expect_error(query, "Query cannot conclude with a returning subquery \ +(must be a RETURN clause, an update clause, a procedure call or a non-returning\ + subquery)") + + def test02_simple_scan_return(self): + """Tests a simple scan and return subquery""" + + # the graph is empty + # create a node + res = graph.query("CREATE (n:N {name: 'Raz'})") + self.env.assertEquals(res.nodes_created, 1) + + # find and return a node via CALL {} + res = graph.query( + """CALL + { + MATCH (n:N {name: 'Raz'}) + RETURN n + } + RETURN n + """ + ) + + # one node should have been found + self.env.assertEquals(len(res.result_set), 1) + # node labels and props should match created node + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz'})) + + def test03_filter_results(self): + """Tests that no records return from the subquery for scans that found + nothing.""" + + # the graph has one node with label `N` and prop `name` with val `Raz` + # add the `v` property to the one node currently existing, with val 4 + res = graph.query("MATCH (n:N) SET n.v = 4") + self.env.assertEquals(res.properties_set, 1) + + # if a returning subquery doesn't return records, the input record is + # not passed as well. Here, only one record should be returned + res = graph.query( + """ + CALL { + UNWIND [1, 2, 3, 4] AS x + MATCH (n:N {v: x}) + RETURN n + } + RETURN n + """ + ) + + # assert correctness of the result + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 4})) + + def test04_reference_innerReturn_alias(self): + """Tests that the outer scope can reference the returned projections + from the subquery""" + + res = graph.query( + """ + UNWIND [1, 2, 3, 4] AS x + MATCH (n) + CALL { + WITH n + RETURN n.v as v + } + RETURN x + v AS ret ORDER BY ret ASC + """ + ) + + self.env.assertEquals(res.result_set, [[5], [6], [7], [8]]) + + res = graph.query ( + """ + UNWIND range(1,4) AS i + CALL { + WITH i + UNWIND range(1, 4) AS j + WITH j WHERE j >= i + RETURN count(1) AS v + } + RETURN i, v ORDER BY i ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 4) + for i in range(0, 4): + self.env.assertEquals(res.result_set[i][0], i + 1) + self.env.assertEquals(res.result_set[i][1], 4 - i) + + def test05_many_to_one_not_first(self): + """Tests the case Call {} gets several records, and returns only one, + that corresponds to a record that is not the first one it gets""" + + # first input record to sq yields no records, next inputs do + res = graph.query( + """ + UNWIND ['Omer', 'Raz', 'Moshe'] as name + CALL { + WITH name + MATCH (n:N {name: name}) + RETURN n + } + RETURN n + """ + ) + # assert correctness of the result + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 4})) + + def test06_one_to_many(self): + """Tests the case Call {} changes the amount of records such that there + are more output records than input""" + + # the graph contains the following node (:N {name: 'Raz', v: 4}}) + + res = graph.query( + """ + WITH 1 as one + CALL { + UNWIND [1, 2] AS x + RETURN x + } + RETURN x, one + """ + ) + + # validate the results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 1) + self.env.assertEquals(res.result_set[1][0], 2) + self.env.assertEquals(res.result_set[1][1], 1) + + # more than one component in the outer loop + res = graph.query( + """ + UNWIND [1, 2, 3, 4] AS x + CALL { + UNWIND [1, 2] AS y + RETURN y + } + RETURN x, y + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 8) + for i in range(0, 4): + for j in range(0, 2): + self.env.assertEquals(res.result_set[i * 2 + j][0], i + 1) + self.env.assertEquals(res.result_set[i * 2 + j][1], j + 1) + + def test07_optional_match(self): + """Tests that OPTIONAL MATCH within the subquery works appropriately, + i.e., passes records with empty columns in case no match was found""" + + graph.query("CREATE (:N {name: 'Raz', v: 1})") + + res = graph.query( + """ + CALL { + UNWIND [1, 2, 3, 4] AS x + OPTIONAL MATCH (n:N {v: x}) + RETURN n + } + RETURN n ORDER BY n.v ASC + """ + ) + + # validate the results + self.env.assertEquals(len(res.result_set), 4) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 1})) + self.env.assertEquals(res.result_set[1][0], + Node(label='N', properties={'name': 'Raz', 'v': 4})) + self.env.assertEquals(res.result_set[2][0], None) + self.env.assertEquals(res.result_set[3][0], None) + + def test08_filtering(self): + """Tests filtering within the subquery""" + + # the graph has two nodes, with `name` 'Raz' and `v` 1 and 4 + # test filter using WHERE + res = graph.query( + """ + CALL { + MATCH (n:N {v: 1}) + RETURN n + } + RETURN n + """ + ) + + # assert the correctness of the results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 1})) + + def test09_simple_ret_eager(self): + """Simple test for the eager and returning subquery case""" + + # the graph has two nodes, with `name` 'Raz' and `v` 1 and 4 + # execute a query with an eager operation and returning subquery inside + res = graph.query( + """ + CALL { + MATCH (n:N) + SET n.v = n.v + 1 + RETURN n + } + RETURN n ORDER BY n.v ASC + """ + ) + + # make sure the wanted actions occurred + self.env.assertEquals(res.properties_set, 2) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz', 'v': 2})) + self.env.assertEquals(res.result_set[1][0], Node(label='N', + properties={'name': 'Raz', 'v': 5})) + + # import outer-scope aliases, reference them inside and outside the sq + res = graph.query( + """ + WITH 2 AS x + CALL { + WITH x + MATCH (n:N {v: x}) + SET n.v = 2 * n.v + RETURN n + } + RETURN n, x + """ + ) + + # make sure the wanted actions occurred + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.result_set[0][0], Node(label='N', properties={'name': 'Raz', 'v': 4})) + self.env.assertEquals(res.result_set[0][1], 2) + + # test FOREACH within CALL {} (updating (eager), returning) + def test10_embedded_foreach(self): + """Tests that FOREACH works properly when used inside a subquery""" + + # the graph has two nodes with label `N`, with `name` 'Raz' and `v` 4 + # and 5 + + res = graph.query( + """ + CALL { + MATCH (n:N) + FOREACH (i in [1] | + SET n.v = n.v + 1 + ) + RETURN n + } + RETURN n ORDER BY n.v ASC + """ + ) + + # assert the correctness of the results + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 5})) + self.env.assertEquals(res.result_set[1][0], + Node(label='N', properties={'name': 'Raz', 'v': 6})) + + # Test with a non-returning subquery + # Update properties using FOREACH in subquery + graph.query( + """ + CALL { + MATCH (n:N) + FOREACH (m in [n] | + MERGE (:TEMP {v: m.v}) + ) + } + """ + ) + + # assert the correctness of the results + res = graph.query("MATCH(n:TEMP) RETURN n ORDER BY n.v ASC") + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], + Node(label='TEMP', properties={'v': 5})) + self.env.assertEquals(res.result_set[1][0], + Node(label='TEMP', properties={'v': 6})) + + # delete the nodes with label :TEMP + res = graph.query("MATCH (n:TEMP) DELETE n") + self.env.assertEquals(res.nodes_deleted, 2) + + # FOREACH is first clause inside {} + graph.query( + """ + CALL { + FOREACH (m in [1, 2] | + CREATE (:TEMP) + ) + } + """ + ) + + # assert the correctness of the results + res = graph.query("MATCH(n:TEMP) RETURN n ORDER BY n.v ASC") + self.env.assertEquals(len(res.result_set), 2) + + # delete the nodes with label :TEMP + res = graph.query("MATCH (n:TEMP) DELETE n") + self.env.assertEquals(res.nodes_deleted, 2) + + # tests that `FOREACH` is interpreted as an updating clause, properly + res = graph.query( + """ + MATCH (n) + CALL { + FOREACH (m in [1] | + CREATE (:TEMP) + ) + RETURN 1 AS one + } + RETURN n, one ORDER BY n.v ASC + """ + ) + + # assert results + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz', 'v': 5})) + self.env.assertEquals(res.result_set[0][1], 1) + self.env.assertEquals(res.result_set[1][0], Node(label='N', + properties={'name': 'Raz', 'v': 6})) + self.env.assertEquals(res.result_set[1][1], 1) + + # delete the nodes with label :TEMP + res = graph.query("MATCH (n:TEMP) DELETE n") + + def test11_skip_limit(self): + """Tests that SKIP and LIMIT work properly when placed inside a + subquery""" + + # the graph has two nodes, with `name` 'Raz' and `v` 5 and 6 + + # Test LIMIT + res = graph.query( + """ + CALL { + MATCH (n:N) + RETURN n + ORDER BY n.v ASC + LIMIT 1 + } + RETURN n + """ + ) + + # assert that only one record was returned + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 5})) + + # Test SKIP + res = graph.query( + """ + CALL { + MATCH (n:N) + RETURN n + ORDER BY n.v ASC + SKIP 1 + } + RETURN n + """ + ) + + # assert that only one record was returned + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 6})) + + # Tests SKIP and LIMIT together + + # Create 10 nodes with label :W + res = graph.query("UNWIND range(1,10) AS i CREATE(:W {name:tostring(i), value:i})") + self.env.assertEquals(res.nodes_created, 10) + + res = graph.query( + """ + CALL { + MATCH (n:W) + RETURN n + ORDER BY n.value ASC + SKIP 5 + LIMIT 2 + } + RETURN n + """ + ) + + # assert that only two records were returned + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], + Node(label='W', properties={'name': '6', 'value': 6})) + self.env.assertEquals(res.result_set[1][0], + Node(label='W', properties={'name': '7', 'value': 7})) + + # delete the nodes with label :W created only for LIMIT tests purpose + res = graph.query("MATCH (n:W) DELETE n") + self.env.assertEquals(res.nodes_deleted, 10) + + def test12_order_by(self): + """Tests the ordering of the output of the sq, and the outer query""" + + # the graph has two nodes: (:N {name: 'Raz', v: 2}) and + # (:N {name: 'Raz', v: 5}) + + res = graph.query( + """ + CALL { + UNWIND range(1, 7) AS x + MATCH (n:N {v: x}) + RETURN n ORDER BY n.v ASC + } + RETURN n + """ + ) + + # validate the results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 5})) + self.env.assertEquals(res.result_set[1][0], + Node(label='N', properties={'name': 'Raz', 'v': 6})) + + # same query, but with descending order + res = graph.query( + """ + CALL { + UNWIND range(1, 7) AS x + MATCH (n:N {v: x}) + RETURN n ORDER BY n.v DESC + } + RETURN n + """ + ) + + # validate the results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 6})) + self.env.assertEquals(res.result_set[1][0], + Node(label='N', properties={'name': 'Raz', 'v': 5})) + + # multiple Sort operations, in and outside the CallSubquery op + res = graph.query( + """ + CALL { + UNWIND range(1, 7) AS x + MATCH (n:N {v: x}) + RETURN n ORDER BY n.v ASC + } + RETURN n ORDER BY n.v ASC + """ + ) + + # validate the results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz', 'v': 5})) + self.env.assertEquals(res.result_set[1][0], + Node(label='N', properties={'name': 'Raz', 'v': 6})) + + def test13_midrun_fail(self): + """Tests that mid-run fails are recovered correctly (free'd)""" + + query = """ + UNWIND [1, 0, 3] as x + CALL { + WITH x + CREATE (:TEMP {v: 5 / x}) + RETURN x AS innerReturn + } + RETURN innerReturn + """ + self.expect_error(query, "Division by zero") + + # make sure the TEMP node was deleted + res = graph.query("MATCH (n:TEMP) RETURN n") + self.env.assertEquals(len(res.result_set), 0) + + # eager non-returning case + query = """ + UNWIND [1, 0, 3] as x + CALL { + WITH x + CREATE (:TEMP {v: 5 / x}) + } + """ + self.expect_error(query, "Division by zero") + + # make sure the TEMP node was deleted + res = graph.query("MATCH (n:TEMP) RETURN n") + self.env.assertEquals(len(res.result_set), 0) + + def test14_nested_call_subquery(self): + """Tests that embedded call subqueries are handled correctly.""" + + query_to_expected_result = [ + (""" + UNWIND [0, 1, 2] AS x + CALL { + CALL { + RETURN 1 AS one + } + RETURN 2 AS two, one + } + RETURN one, two, x + """ + , [[1, 2, 0],[1, 2, 1],[1, 2, 2]]), + (""" + UNWIND [0, 1, 2] AS x + CALL { + WITH x + CALL { + RETURN 1 AS one + } + RETURN one, 2 AS two + } + RETURN one, two, x + """ + , [[1, 2, 0],[1, 2, 1],[1, 2, 2]]), + (""" + UNWIND [0, 1, 2] AS x + CALL { + CALL { + RETURN 1 AS x + } + RETURN max(x) AS y + } + RETURN y, x ORDER BY x ASC + """ + , [[1, 0], [1, 1], [1, 2]]) + ] + for query, expected_result in query_to_expected_result: + self.get_res_and_assertEquals(query, expected_result) + + def test15_complex(self): + """A more complex test, using more data and inner Call {} calls""" + + # clean db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create data + graph.query("CREATE (english: Language {name: 'English'}), (spanish: Language {name: 'Spanish'}), (french: Language {name: 'French'}), (coastal: Property {name: 'Coastal'}), (usa: Country {name: 'USA', extra_data: 'foo'}), (cali: State {name: 'California'}), (sacramento: City {name: 'Sacramento', extra_data: 'bar'}), (ny: State {name: 'New York'}), (nyc: City {name: 'New York City'}), (sacramento) - [:CITY_IN_STATE] -> (cali) - [:STATE_IN_COUNTRY] -> (usa), (cali) - [:HAS_STATE_PROP] -> (coastal), (nyc) - [:CITY_IN_STATE] -> (ny) - [:STATE_IN_COUNTRY] -> (usa), (ny) - [:HAS_STATE_PROP] -> (coastal), (nyc) - [:HAS_CITY_PROP] -> (coastal), (canada: Country {name: 'Canada'}), (ontario: State {name: 'Ontario', extra_data: 'baz'}), (toronto: City {name: 'Toronto'}), (bc: State {name: 'British Columbia'}), (victoria: City {name: 'Victoria'}), (toronto) - [:CITY_IN_STATE] -> (ontario) - [:STATE_IN_COUNTRY] -> (canada), (victoria) - [:CITY_IN_STATE] -> (bc) - [:STATE_IN_COUNTRY] -> (canada), (bc) - [:HAS_STATE_PROP] -> (coastal), (victoria) - [:HAS_CITY_PROP] -> (coastal), (canada) - [:OFFICIAL_LANGUAGE] -> (english), (canada) - [:OFFICIAL_LANGUAGE] -> (french), (mexico: Country {name: 'Mexico'}), (coahuila: State {name: 'Coahuila'}), (saltillo: City {name: 'Saltillo'}), (jalisco: State {name: 'Jalisco'}), (guadalajara: City {name: 'Guadalajara'}), (saltillo) - [:CITY_IN_STATE] -> (coahuila) - [:STATE_IN_COUNTRY] -> (mexico), (guadalajara) - [:CITY_IN_STATE] -> (jalisco) - [:STATE_IN_COUNTRY] -> (mexico), (jalisco) - [:HAS_STATE_PROP] -> (coastal), (mexico) - [:OFFICIAL_LANGUAGE] -> (spanish)") + + query = """ + MATCH (c:City)-[:CITY_IN_STATE]->(state)-[:STATE_IN_COUNTRY]->(country)-[:OFFICIAL_LANGUAGE]->({name: 'English'}) + WITH collect(distinct country) as counties + UNWIND counties as country + MATCH (country)-[:OFFICIAL_LANGUAGE]->(lang) + WITH country, collect(distinct lang.name) as langs + MATCH (country)<-[:STATE_IN_COUNTRY]->(state) + CALL { + WITH state + MATCH (state)<-[:CITY_IN_STATE]-(city:City) + CALL { + WITH city + RETURN {type: labels(city)[0], name: city.name} as cityDetails + } + WITH state, collect(cityDetails) as citiesDetails + RETURN {type: labels(state)[0], name:state.name, cities:citiesDetails} as stateDetails + } + WITH country, langs, collect(stateDetails) as statesDetails + RETURN {name: country.name, langs: langs, states: statesDetails} + """ + + res = graph.query(query) + + # assert results + expected_res = {'name': 'Canada', + 'langs': ['English', 'French'], + 'states': + [OrderedDict([ + ('type', 'State'), + ('name', 'British Columbia'), + ('cities', [OrderedDict([ + ('type', 'City'), + ('name', 'Victoria')])])]), + OrderedDict([ + ('type', 'State'), + ('name', 'Ontario'), + ('cities', [OrderedDict([ + ('type', 'City'), + ('name', 'Toronto')])])])]} + self.env.assertEquals(res.result_set[0][0], expected_res) + + def test16_rewrite_same_clauses(self): + """Tests that the AST-rewriting of same consecutive clauses works + properly in a subquery""" + + # Test CREATE compression + query = """ + CALL { + CREATE (x:X) + CREATE (m:M) + } + """ + plan = graph.explain(query) + # make sure that CREATE is called only once + _assert_subquery_contains_single(plan, "Create", self.env) + + # Test SET compression + query = """ + CALL { + MATCH (x:X) + SET x.v = 3 + SET x.t ='a' + }""" + plan = graph.explain(query) + # make sure that Update is called only once + _assert_subquery_contains_single(plan, "Update", self.env) + + # Test REMOVE compression + query = """ + CALL { + MATCH (x:X) + REMOVE x.v + REMOVE x.t + }""" + plan = graph.explain(query) + # make sure that Update is called only once + _assert_subquery_contains_single(plan, "Update", self.env) + + # Test DELETE compression + query = """ + CALL { + MATCH (x:X) + MATCH (m:M) + DELETE x + DELETE m + } + """ + plan = graph.explain(query) + # make sure that DELETE is called only once + _assert_subquery_contains_single(plan, "Delete", self.env) + + def test17_leading_with(self): + """Tests that we can use leading WITH queries with non-simple + projections if they do not import any outer-scope data""" + + query_to_expected_result = [ + (""" + CALL { + WITH 1 AS b + RETURN b + } + RETURN b + """ + , [[1]]), + (""" + CALL { + WITH {} AS b + RETURN b + } + RETURN b + """ + , [[{}]]), + (""" + CALL { + WITH 'a' AS b + RETURN b + } + RETURN b""" + , [['a']]), + (""" + CALL { + WITH ['foo', 'bar'] AS l1 + RETURN l1 + } + RETURN l1 + """ + , [[['foo', 'bar']]]), + (""" + CALL { + WITH toUpper('a') AS A, 5 - 2 AS num + RETURN A, num + } + RETURN * + """, [['A', 3]]) + ] + for query, expected_result in query_to_expected_result: + self.get_res_and_assertEquals(query, expected_result) + + def test18_returning_aggregations(self): + """Tests that we deal properly with returning aggregations instead of + regular projections""" + + # clear the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create a node with label N + graph.query("CREATE (:N)") + + query = """ + MATCH (n) + CALL { + WITH n + OPTIONAL MATCH (m:M) + SET m.v = 1 + RETURN collect(n) AS cn + } + WITH n, cn + UNWIND cn as ns + RETURN ns + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], Node(label='N')) + + query = """ + UNWIND ['a', 'b', 'c', 'a', 'b', 'b'] AS x + CALL { + WITH x + RETURN toUpper(x) AS key, count(1) AS count + } + RETURN key, count ORDER BY key + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(res.result_set), 3) + self.env.assertEquals(res.result_set[0][0], 'A') + self.env.assertEquals(res.result_set[0][1], 2) + self.env.assertEquals(res.result_set[1][0], 'B') + self.env.assertEquals(res.result_set[1][1], 3) + self.env.assertEquals(res.result_set[2][0], 'C') + self.env.assertEquals(res.result_set[2][1], 1) + + def test19_optional_match(self): + """Tests that we deal properly with `OPTIONAL MATCH` clauses in a + subquery""" + + res = graph.query ( + """ + CALL { + UNWIND ['S','T'] AS l1 + OPTIONAL MATCH (n:XX) + WITH n + RETURN n + } + RETURN n + """ + ) + + # validate the results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], None) + self.env.assertEquals(res.result_set[1][0], None) + + def test20_aggregation_in_subquery(self): + """Tests that we deal properly with aggregations in a subquery""" + + # Create 3 nodes + graph.query("UNWIND range(1, 3) AS i CREATE (n:A {v:i})") + + query_to_expected_result = [ + (""" + CALL { + MATCH (n:A) + WHERE n.v % 2 = 0 + WITH max(n.v) AS cn + RETURN cn + } + RETURN cn + """ + , [[2]]), + (""" + CALL { + OPTIONAL MATCH (n:A) + WHERE n.v % 2 = 0 + WITH collect(n.v) AS cn + OPTIONAL MATCH (m:A) + WHERE m.v % 2 = 1 + WITH sum(m.v) AS cm, cn + RETURN cn, cm + } + RETURN cn, cm""" + , [[[2], 4]]) + ] + for query, expected_result in query_to_expected_result: + self.get_res_and_assertEquals(query, expected_result) + + def test21_union(self): + """Tests that UNION works properly within a subquery""" + + # clear the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # a simple subquery, returning 2 rows + res = graph.query( + """ + CALL { + RETURN 1 AS num + UNION + RETURN 2 AS num + } + RETURN num + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[1][0], 2) + + # a simple subquery, using input from the outer query + res = graph.query( + """ + UNWIND range(1, 2) AS i + WITH i AS i, i AS x + CALL { + WITH i + RETURN i AS num + UNION + WITH x + RETURN x + 1 AS num + } + RETURN i, num ORDER BY i, num ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 4) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 1) + self.env.assertEquals(res.result_set[1][0], 1) + self.env.assertEquals(res.result_set[1][1], 2) + self.env.assertEquals(res.result_set[2][0], 2) + self.env.assertEquals(res.result_set[2][1], 2) + self.env.assertEquals(res.result_set[3][0], 2) + self.env.assertEquals(res.result_set[3][1], 3) + + # create nodes in both branches of the UNION + res = graph.query( + """ + CALL { + CREATE (n:N {v: 1}) + RETURN n AS node + UNION + CREATE (m:M {v: 2}) + RETURN m AS node + } + RETURN node + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'v': 1})) + self.env.assertEquals(res.result_set[1][0], Node(label='M', + properties={'v': 2})) + + # match nodes in one branch, and create nodes in the other + res = graph.query( + """ + CALL { + MATCH (n:N) + RETURN n AS node + UNION + CREATE (m:M {v: 2}) + RETURN m AS node + } + RETURN node + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'v': 1})) + self.env.assertEquals(res.result_set[1][0], Node(label='M', + properties={'v': 2})) + + # use bound data + res = graph.query( + """ + UNWIND range(1, 2) AS i + CALL { + WITH i + CREATE (n:TEMP {v: i}) + RETURN n.v AS num + UNION ALL + RETURN 1 AS num + } + RETURN i, num ORDER BY i, num ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 4) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 1) + self.env.assertEquals(res.result_set[1][0], 1) + self.env.assertEquals(res.result_set[1][1], 1) + self.env.assertEquals(res.result_set[2][0], 2) + self.env.assertEquals(res.result_set[2][1], 1) + self.env.assertEquals(res.result_set[3][0], 2) + self.env.assertEquals(res.result_set[3][1], 2) + + # match nodes in both branches + # the graph contains: (:N {v: 1}), (:M {v: 2}), (:M {v: 2}) + res = graph.query( + """ + CALL { + MATCH (n:N) + RETURN n AS node + UNION + MATCH (m:M) + RETURN m AS node + } + RETURN node ORDER BY node.v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 3) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'v': 1})) + self.env.assertEquals(res.result_set[1][0], Node(label='M', + properties={'v': 2})) + self.env.assertEquals(res.result_set[2][0], Node(label='M', + properties={'v': 2})) + + # simple embedded call with UNION + res = graph.query( + """ + CALL { + CALL { + RETURN 1 AS num + UNION + RETURN 2 AS num + } + RETURN num + } + RETURN num + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[1][0], 2) + + # simple embedded call with UNION + res = graph.query( + """ + CALL { + CALL { + RETURN 1 AS num + UNION + RETURN 2 AS num + } + RETURN num + } + RETURN num, 5 + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 5) + self.env.assertEquals(res.result_set[1][0], 2) + self.env.assertEquals(res.result_set[1][1], 5) + + # TODO: + # this is a subquery that will require a change for the Join operation, + # as it requires the changes of one input record to be visible to the + # next input record + + # # clean the db + # self.env.flush() + # graph = Graph(self.env.getConnection(), GRAPH_ID) + + # # create two nodes with label N and property v=1, v=2 + # graph.query("CREATE (:N {v: 1}), (:N {v: 2})") + + # res = graph.query( + # """ + # MATCH (n:N) + # CALL { + # WITH n + # MERGE (:N {v: n.v + 1}) + # RETURN 1 AS ret + # UNION + # WITH n + # CREATE (:N {v: n.v + 2}) + # RETURN 1 AS ret + # } + # RETURN count(1) + # """ + # ) + + # # assert results + # self.env.assertEquals(len(res.result_set), 1) + # self.env.assertEquals(res.result_set[0][0], 2) + # self.env.assertEquals(res.nodes_created, 2) + + # union and aggregation function + res = graph.query ( + """ + CALL { + RETURN 1 AS v + UNION + MATCH(m:SUM) + RETURN tointeger(sum(m.v)) AS v + } + RETURN v ORDER BY v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 0) + self.env.assertEquals(res.result_set[1][0], 1) + + # one branch is eager and the other is not + res = graph.query ( + """ + CALL { + WITH 0 AS i + RETURN i AS v + UNION + CREATE (n:EAGER {v:1}) + RETURN n.v AS v + } + RETURN v ORDER BY v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 0) + self.env.assertEquals(res.result_set[1][0], 1) + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(res.properties_set, 1) + + # both branches are eager + res = graph.query ( + """ + CALL { + MERGE (m:EAGER {v:0}) + RETURN m.v AS v + UNION + MERGE (n:EAGER {v:1}) + SET n.v = 2 + RETURN n.v AS v + } + RETURN v ORDER BY v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 0) + self.env.assertEquals(res.result_set[1][0], 2) + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(res.properties_set, 2) + + # both branches are not eager + graph.query("CREATE (:X {v: 1})") + + res = graph.query ( + """ + CALL { + MATCH (n:X) + RETURN n.v AS v + UNION + MATCH (n:X {v: 1}) + RETURN n.v AS v + } + RETURN v + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.nodes_created, 0) + self.env.assertEquals(res.properties_set, 0) + + # UNION ALL with more than 2 branches + res = graph.query ( + """ + CALL { + MERGE (n:EAGER {v:7}) + WITH n + RETURN n.v AS v + UNION ALL + MATCH (n:X {v: 1}) + RETURN n.v AS v + UNION ALL + UNWIND range(1, 3) AS i + RETURN i AS v + UNION ALL + CALL { + MERGE (n:X {v: 1}) + RETURN n.v AS j + } + RETURN j AS v + } + RETURN v + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 6) + self.env.assertEquals(res.result_set[0][0], 7) + self.env.assertEquals(res.result_set[1][0], 1) + self.env.assertEquals(res.result_set[2][0], 1) + self.env.assertEquals(res.result_set[3][0], 2) + self.env.assertEquals(res.result_set[4][0], 3) + self.env.assertEquals(res.result_set[5][0], 1) + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(res.properties_set, 1) + + # single eager & returning branch out of 2, using input data inside and + # outside the subquery + res = graph.query( + """ + UNWIND [1, 2] AS data + CALL { + WITH data + RETURN data AS v + UNION + WITH data + UNWIND data AS i + RETURN collect(data) AS v + } + RETURN data, v ORDER BY data, v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 4) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], [1]) + self.env.assertEquals(res.result_set[1][0], 1) + self.env.assertEquals(res.result_set[1][1], 1) + self.env.assertEquals(res.result_set[2][0], 2) + self.env.assertEquals(res.result_set[2][1], [2]) + self.env.assertEquals(res.result_set[3][0], 2) + self.env.assertEquals(res.result_set[3][1], 2) + + # both branches are eager and returning + res = graph.query( + """ + UNWIND [1, 2] AS data + CALL { + WITH data + RETURN collect(data) AS v + UNION ALL + WITH data + RETURN collect(data) AS v + } + RETURN data, v ORDER BY data ASC, v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 4) + for i, subres in enumerate([[1, [1]], [1, [1]], [2, [2]], [2, [2]]]): + self.env.assertEquals(res.result_set[i], subres) + + # same query with Distinct (UNION instead of UNION ALL) + res = graph.query( + """ + UNWIND [1, 2] AS data + CALL { + WITH data + RETURN collect(data) AS v + UNION + WITH data + RETURN collect(data) AS v + } + RETURN data, v ORDER BY data ASC, v ASC + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + for i in [1, 2]: + self.env.assertEquals(res.result_set[i-1][0], i) + self.env.assertEquals(res.result_set[i-1][1], [i]) + + def test22_indexes(self): + """Tests that operations on indexes are properly executed (and reset) + in subqueries""" + + # clear the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # polulate the graph + query = """UNWIND range(10,20) AS i + CREATE (n:N {v:tostring(i)})-[:R]->(m:M {v:tostring(i+1)})""" + graph.query(query) + create_node_exact_match_index(graph, "N", "v", sync=True) + + # use the index in a scan as the lhs of a CallSubquery op, which + # contains an eager operation + query = """ + MATCH (n:N {v:'10'}) + CALL { + WITH n + SET n.v = '11' + } + RETURN n.v + """ + + # assert that we indeed utilize the index to find the node + plan = graph.explain(query) + index_scan = locate_operation(plan.structured_plan, + "Node By Index Scan") + self.env.assertNotEqual(index_scan, None) + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], '11') + + def test25_named_paths(self): + """Tests that named paths are handled correctly, when defined/referred + inside or outside of a subquery""" + + # clear the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create a node with label N + graph.query("CREATE (:N {v: 1})") + node = Node(label='N', properties={'v': 1}) + + # refer to a named path defined outside of a subquery, from within the + # subquery + query = """ + MATCH p = (n:N) + CALL { + WITH p + RETURN nodes(p)[0] AS s + } + RETURN s + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(graph.query(query).result_set), 1) + self.env.assertEquals(res.result_set[0][0], node) + + # refer a named path defined inside of a subquery, from within the + # subquery + query = """ + CALL { + MATCH p = (n:N) + RETURN nodes(p)[0] AS s + } + RETURN s + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(graph.query(query).result_set), 1) + self.env.assertEquals(res.result_set[0][0], node) + + # return a path from a subquery and refer to it outside of the subquery + query = """ + CALL { + MATCH p = (n:N) + RETURN p + } + RETURN nodes(p)[0] + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(graph.query(query).result_set), 1) + self.env.assertEquals(res.result_set[0][0], node) + + # refer to a named path defined in a subquery, from a nested subquery + query = """ + CALL { + MATCH p = (n:N) + CALL { + WITH p + RETURN nodes(p)[0] AS s + } + RETURN s + } + RETURN s + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(graph.query(query).result_set), 1) + self.env.assertEquals(res.result_set[0][0], node) + + # import named paths inside a subquery containing a UNION clause + query = """ + MATCH p = (n:N) + CALL { + RETURN {v: 2} AS node + UNION + WITH p + RETURN nodes(p)[0] AS node + } + RETURN node ORDER BY node.v ASC + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(len(graph.query(query).result_set), 2) + self.env.assertEquals(res.result_set[0][0], node) + self.env.assertEquals(res.result_set[1][0], OrderedDict([('v', 2)])) + + def test26_eager_returning(self): + """Tests the eager and returning case of Call {}""" + + # clean the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + query = """ + OPTIONAL MATCH (m) + CALL { + CREATE (n:N {name: 'Raz'}) + RETURN n + } + RETURN n + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='N', properties={'name': 'Raz'})) + + # use memory from outer scope after the subquery + query = """ + MATCH (n) + CALL { + CREATE (m:M {name: 'Moshe'}) + RETURN m + } + RETURN n, m + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 2) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz'})) + self.env.assertEquals(res.result_set[0][1], Node(label='M', + properties={'name': 'Moshe'})) + + # nested eager & returning subquery + query = """ + MATCH (n:N) + CALL { + CREATE (m:M {name: 'Moshe'}) + WITH m + CALL { + CREATE (o:O {name: 'Omer'}) + RETURN o + } + RETURN m, o + } + RETURN n, m, o + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz'})) + self.env.assertEquals(res.result_set[0][1], Node(label='M', + properties={'name': 'Moshe'})) + self.env.assertEquals(res.result_set[0][2], Node(label='O', + properties={'name': 'Omer'})) + + # highly nested eager & returning subquery + query = """ + MATCH (n:N) + CALL { + CREATE (m:M {name: 'Moshe'}) + WITH m + CALL { + CREATE (o:O {name: 'Omer'}) + WITH o + CALL { + CREATE (p:P {name: 'Pini'}) + RETURN p + } + RETURN o, p + } + RETURN m, o, p + } + RETURN n, m, o, p + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(res.nodes_created, 3) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 4) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz'})) + self.env.assertEquals(res.result_set[0][1], Node(label='M', + properties={'name': 'Moshe'})) + self.env.assertEquals(res.result_set[0][2], Node(label='O', + properties={'name': 'Omer'})) + self.env.assertEquals(res.result_set[0][3], Node(label='P', + properties={'name': 'Pini'})) + + # multiple eager & returning subqueries sequentially + query = """ + MATCH (n:N) + CALL { + CREATE (m:M {name: 'Moshe'}) + RETURN m + } + CALL { + CREATE (o:O {name: 'Omer'}) + RETURN o + } + RETURN n, m, o + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(res.nodes_created, 2) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz'})) + self.env.assertEquals(res.result_set[0][1], Node(label='M', + properties={'name': 'Moshe'})) + self.env.assertEquals(res.result_set[0][2], Node(label='O', + properties={'name': 'Omer'})) + + # nested eager & returning subquery in a non-(eager & returning) + # subquery + query = """ + MATCH (n:N) + CALL { + CALL { + CREATE (m:M {name: 'Moshe'}) + RETURN m + } + RETURN m + } + RETURN n, m + """ + + res = graph.query(query) + + # assert results + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 2) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz'})) + self.env.assertEquals(res.result_set[0][1], Node(label='M', + properties={'name': 'Moshe'})) + + # outer {} is not eager, inner is + res = graph.query( + """ + CALL { + WITH 1 AS x + CALL { + UNWIND range(1, 5) AS x + RETURN collect(x) as y + } + RETURN x, y + } + RETURN x, y + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 2) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], list(range(1, 6))) + + # outer {} is eager, but not returning, inner is + res = graph.query( + """ + MATCH (n:N) + CALL { + WITH n + WITH n, 1 AS x + CALL { + CREATE (m:M {name: 'Moshe'}) + RETURN m + } + SET n.v = 1 + } + RETURN n + """ + ) + + # assert results + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 1) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Raz', 'v': 1})) + + # same concept as the above test, using input data + # create 3 nodes (:TEMP {v: 1\2\3}) + res = graph.query("UNWIND range(1, 3) AS x CREATE (n:TEMP {v: x})") + self.env.assertEquals(res.nodes_created, 3) + + res = graph.query( + """ + UNWIND range(1, 3) AS x + CALL { + WITH x + MATCH (n:TEMP {v: x}) + CALL { + WITH n + UNWIND range(0, n.v) AS num + RETURN collect(num) AS y + } + RETURN y + } + RETURN x, y ORDER BY x + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 3) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], list(range(0, 2))) + self.env.assertEquals(res.result_set[1][0], 2) + self.env.assertEquals(res.result_set[1][1], list(range(0, 3))) + self.env.assertEquals(res.result_set[2][0], 3) + self.env.assertEquals(res.result_set[2][1], list(range(0, 4))) + + def test27_read_no_with_after_writing_subquery(self): + """Tests that a read clause following a writing subquery is handled + correctly with\without a separating `WITH` clause""" + + # clean the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # using a separating `WITH` + res = graph.query( + """ + CALL { + CREATE (n:N {name: 'Roi'}) + RETURN n + } + WITH n + MATCH (n2:N) + RETURN n2 + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Roi'})) + + # delete the node + res = graph.query("MATCH (n) DELETE n") + self.env.assertEquals(res.nodes_deleted, 1) + + # same query, without a separating `WITH` + res = graph.query( + """ + CALL { + CREATE (n:N {name: 'Roi'}) + RETURN n + } + MATCH (n2:N) + RETURN n2 + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Roi'})) + + # delete the node + res = graph.query("MATCH (n) DELETE n") + self.env.assertEquals(res.nodes_deleted, 1) + + # same query, without a separating `WITH`, and without a `RETURN` clause + res = graph.query( + """ + CALL { + CREATE (n:N {name: 'Roi'}) + } + MATCH (n2:N) + RETURN n2 + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], Node(label='N', + properties={'name': 'Roi'})) + + def test28_reset(self): + """Tests that the resetting of a call {} operation is handled + correctly""" + + # clean the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create 2 nodes (:N {v: 2\4}) + res = graph.query("UNWIND [2, 4] AS x CREATE (n:N {v: x})") + + # in the following query, the inner call {} is reset (lhs of outer {}) + res = graph.query( + """ + UNWIND [1, 2 ,3, 4] AS x + CALL { + WITH x + CALL { + WITH x + MATCH (n {v: x}) + RETURN n + } + RETURN n + } + RETURN x, n + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(res.result_set[0][0], 2) + self.env.assertEquals(res.result_set[0][1], Node(label='N', + properties={'v': 2})) + self.env.assertEquals(res.result_set[1][0], 4) + self.env.assertEquals(res.result_set[1][1], Node(label='N', + properties={'v': 4})) + + def test29_rewrite_star_projections(self): + """Tests that star projections within call {}are rewritten correctly""" + + # clean the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # import data with * + res = graph.query( + """ + WITH 1 AS a, 2 AS b + CALL { + WITH * + RETURN a + b AS c + } + RETURN a, b, c + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + for i in range(3): + self.env.assertEquals(res.result_set[0][i], i + 1) + + # return with * + res = graph.query( + """ + CALL { + WITH 1 AS a, 2 AS b + RETURN * + } + RETURN a, b + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 2) + for i in range(2): + self.env.assertEquals(res.result_set[0][i], i + 1) + + # both import with * and return with * + res = graph.query( + """ + WITH 1 AS a, 2 AS b + CALL { + WITH * + WITH a + b AS c + RETURN * + } + RETURN a, b, c + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + for i in range(3): + self.env.assertEquals(res.result_set[0][i], i + 1) + + # using union + res = graph.query( + """ + WITH 1 AS a + CALL { + WITH * + RETURN a AS num + UNION + WITH * + RETURN a + 1 AS num + } + RETURN a, num order by a, num + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(len(res.result_set[0]), 2) + self.env.assertEquals(len(res.result_set[1]), 2) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 1) + self.env.assertEquals(res.result_set[1][0], 1) + self.env.assertEquals(res.result_set[1][1], 2) + + # embedded call {} + query = """ + WITH 1 AS a + CALL { + WITH * + CALL { + WITH * + RETURN a AS num + UNION + WITH * + RETURN a + 1 AS num + } + RETURN * + } + RETURN a, num order by a, num + """ + + self.expect_error(query, "Variable `a` already declared in outer scope") + + # intermediate with * + + # create a node with label N + res = graph.query("CREATE (:N)") + + res = graph.query( + """ + WITH 1 AS a, 2 AS b + CALL { + WITH * + MATCH (n) + WITH * + RETURN n + } + RETURN a, b, n + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 2) + self.env.assertEquals(res.result_set[0][2], Node(label='N')) + + # create node and project it with star + res = graph.query( + """ + WITH 1 AS a, 2 AS b + CALL { + WITH * + CREATE (n:C) + WITH * + RETURN n + } + RETURN a, b, n + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 2) + self.env.assertEquals(res.result_set[0][2], Node(label='C')) + + # merge node and project it with star + res = graph.query( + """ + WITH 1 AS a, 2 AS b + CALL { + WITH * + MERGE (n:C) + WITH * + RETURN n + } + RETURN a, b, n + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 2) + self.env.assertEquals(res.result_set[0][2], Node(label='C')) + + # create node and return it with star + res = graph.query( + """ + WITH 1 AS a, 2 AS b + CALL { + WITH * + CREATE (n:C) + WITH n + RETURN * + } + RETURN a, b, n + """ + ) + + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], 1) + self.env.assertEquals(res.result_set[0][1], 2) + self.env.assertEquals(res.result_set[0][2], Node(label='C')) + + def test30_surrounding_matches(self): + """Tests that in case the call {} is surrounded by matches, the + following match does not affect the input records to the call {} op""" + + # clean the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create two nodes with label N, and one with label I with increasing v + # property values for the N nodes + res = graph.query("CREATE (:N {v: 1}), (:N {v: 2}), (:I)") + + # query with a surrounding match clauses, such that the right-most match + # is prioritized (less nodes with its label in the graph) + query = """ + MATCH (n:N) + CALL { + RETURN 1 AS x + } + MATCH (i:I) + RETURN n, i, x ORDER BY n.v ASC + """ + + # assert that (i:I) was not scanned and inserted to the call {} op + plan = graph.explain(query) + # make sure that CREATE is called only once + label_scan = locate_operation(plan.structured_plan, "Node By Label Scan") + self.env.assertIsNotNone(label_scan) + cartesian = locate_operation(plan.structured_plan, "CartesianProduct") + self.env.assertIsNone(cartesian) + + res = graph.query(query) + # assert results + n1 = Node(label='N', properties={'v': 1}) + n2 = Node(label='N', properties={'v': 2}) + n3 = Node(label='I') + self.env.assertEquals(len(res.result_set), 2) + self.env.assertEquals(len(res.result_set[0]), 3) + self.env.assertEquals(res.result_set[0][0], n1) + self.env.assertEquals(res.result_set[0][1], n3) + self.env.assertEquals(res.result_set[0][2], 1) + self.env.assertEquals(res.result_set[1][0], n2) + self.env.assertEquals(res.result_set[1][1], n3) + self.env.assertEquals(res.result_set[1][2], 1) + + def test31_following_scans(self): + """Tests that in case the call {} is followed by scans, the + following scans are planned and executed properly""" + + # clean the db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create the node (:N {v: 1}) + res = graph.query("CREATE (:N {v: 1})") + + # query with a match clause following a call {} clause with a scan + res = graph.query( + """ + CALL { + MATCH (m:M) + SET m.v = 2 + } + MATCH (n:N) + RETURN n + """ + ) + + # assert results + n = Node(label='N', properties={'v': 1}) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 1) + self.env.assertEquals(res.result_set[0][0], n) + + # query with a match clause following a call {} clause with a scan, + # using the same alias (reduce-scans optimization fixed) + query = """ + CALL { + MATCH (n:M) + SET n.v = 2 + } + MATCH (n:N) + RETURN n + """ + + # assert that the execution-plan holds a label scan for :M, and not a + # conditional-traverse. This is true if we have to label-scans in the + # plan + plan = graph.explain(query) + n_label_scans = count_operation(plan.structured_plan, + "Node By Label Scan") + self.env.assertEquals(n_label_scans, 2) + + res = graph.query(query) + # assert results + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(len(res.result_set[0]), 1) + self.env.assertEquals(res.result_set[0][0], n) + + # query with a match clause, followed by a call {} clause with a scan + # with the same alias, followed by a match clause with the same alias. + # we expect the aliases before and after the call {} to be tied + # (the `UNWIND` is placed to separate the scan and the call {}, since + # this was a bug in the past) + query = """ + MATCH (n:N) + CALL { + MATCH (n:M) + SET n.v = 5 + } + UNWIND [1] AS one + MATCH (n:O) + RETURN n + """ + + plan = graph.explain(query) + self.env.assertEquals(count_operation(plan.structured_plan, "Node By Label Scan"), 2) + self.env.assertEquals(count_operation(plan.structured_plan, "Conditional Traverse"), 1) + + # assert that the `O` label is scanned via cond-traverse + scan = locate_operation(plan.structured_plan, "Conditional Traverse") + self.env.assertEquals(str(scan), "Conditional Traverse | (n:O)->(n:O)") + + # return a bound variable from the call {} clause, with a scan on it + # after + query = """ + CALL { + MATCH (n:M) + SET n.v = 2 + RETURN n + } + MATCH (n:N) + RETURN n + """ + + # assert that the execution-plan holds a cond-traverse for :N + plan = graph.explain(query) + scan = locate_operation(plan.structured_plan, "Conditional Traverse") + self.env.assertEquals(str(scan), "Conditional Traverse | (n:N)->(n:N)") diff --git a/tests/flow/test_concurrent_query.py b/tests/flow/test_concurrent_query.py index 969fe5d5ca..4557630f12 100644 --- a/tests/flow/test_concurrent_query.py +++ b/tests/flow/test_concurrent_query.py @@ -45,7 +45,11 @@ def run_concurrent(queries, f): barriers = [barrier] * CLIENT_COUNT # invoke queries - return pool.map(f, queries, barriers) + results = pool.map(f, queries, barriers) + + pool.clear() + + return results class testConcurrentQueryFlow(FlowTestsBase): def __init__(self): @@ -113,6 +117,8 @@ def test_04_concurrent_delete(self): # Exactly one thread should have successfully deleted the graph. self.env.assertEquals(assertions.count(True), 1) + pool.clear() + # Try to delete a graph while multiple queries are executing. def test_05_concurrent_read_delete(self): ############################################################################################## @@ -194,6 +200,8 @@ def test_05_concurrent_read_delete(self): resultset = self.graph.query("MATCH (n) RETURN count(n)").result_set self.env.assertEquals(resultset[0][0], 0) + pool.clear() + def test_06_concurrent_write_delete(self): # Test setup - validate that graph exists and possible results are None self.graph.query("MATCH (n) RETURN n") @@ -210,6 +218,8 @@ def test_06_concurrent_write_delete(self): self.env.assertContains(result, possible_exceptions) else: self.env.assertEquals(1000000, result["result_set"][0][0]) + + pool.clear() def test_07_concurrent_write_rename(self): # Test setup - validate that graph exists and possible results are None @@ -236,6 +246,8 @@ def test_07_concurrent_write_rename(self): self.env.assertContains(result, possible_exceptions) else: self.env.assertEquals(1000000, result["result_set"][0][0]) + + pool.clear() def test_08_concurrent_write_replace(self): # Test setup - validate that graph exists and possible results are None @@ -262,6 +274,8 @@ def test_08_concurrent_write_replace(self): # Delete the key self.conn.delete(GRAPH_ID) + pool.clear() + def test_09_concurrent_multiple_readers_after_big_write(self): # Test issue #890 self.graph = Graph(self.conn, GRAPH_ID) @@ -332,6 +346,8 @@ def test_10_write_starvation(self): # delete the key self.conn.delete(GRAPH_ID) + pool.clear() + def test_11_concurrent_resize_zero_matrix(self): if "to_thread" not in dir(asyncio): # no need to check diff --git a/tests/flow/test_config.py b/tests/flow/test_config.py index 93e7a0e13a..0e87b25653 100644 --- a/tests/flow/test_config.py +++ b/tests/flow/test_config.py @@ -3,7 +3,7 @@ redis_con = None redis_graph = None # Number of options available. -NUMBER_OF_OPTIONS = 13 +NUMBER_OF_OPTIONS = 16 class testConfig(FlowTestsBase): def __init__(self): @@ -25,7 +25,7 @@ def test01_config_get(self): # Try reading all configurations config_name = "*" response = redis_con.execute_command("GRAPH.CONFIG GET " + config_name) - # 12 configurations should be reported + # 16 configurations should be reported self.env.assertEquals(len(response), NUMBER_OF_OPTIONS) def test02_config_get_invalid_name(self): diff --git a/tests/flow/test_constraint.py b/tests/flow/test_constraint.py index 5401a7898d..fb5728a620 100644 --- a/tests/flow/test_constraint.py +++ b/tests/flow/test_constraint.py @@ -1,3 +1,4 @@ +import threading from common import * from index_utils import * from constraint_utils import * @@ -553,6 +554,7 @@ class testConstraintEdges(): def __init__(self): self.env = Env(decodeResponses=True) self.con = self.env.getConnection() + self.con.flushall() # clear DB self.g = Graph(self.con, GRAPH_ID) self.populate_graph() @@ -575,13 +577,13 @@ def test01_create_constraint(self): create_unique_edge_constraint(self.g, 'Person', 'height') # create unique edge constraint over Person name and age - create_unique_edge_constraint(self.g, 'Person', 'name', 'age') + create_unique_edge_constraint(self.g, 'Person', 'name', 'age', sync=True) # validate constrains constraints = list_constraints(self.g) self.env.assertEqual(len(constraints), 3) for c in constraints: - self.env.assertTrue(c.status != 'FAILED') + self.env.assertTrue(c.status == 'OPERATIONAL') def test02_edge_constraint_violations(self): # active constrains: @@ -961,3 +963,76 @@ def test07_constraint_creation_with_new_relation_attr(self): self.env.assertTrue(False) except ResponseError as e: self.env.assertContains("unique constraint violation, on edge of relationship-type Artist", str(e)) + +MONITOR_ATTACHED = False + +class testConstraintReplication(): + def __init__(self): + self.env = Env(decodeResponses=True, env='oss', useSlaves=True) + self.source = self.env.getConnection() + self.replica = self.env.getSlaveConnection() + self.monitor = [] + self.g = Graph(self.source, GRAPH_ID) + + self.monitor_thread = threading.Thread(target=self.monitor_thread) + self.monitor_thread.start() + + # wait for monitor thread to attach + while MONITOR_ATTACHED is False: + time.sleep(0.2) + + # clear DB + self.source.flushall() + + # the WAIT command forces master slave sync to complete + self.source.execute_command("WAIT", 1, 0) + + def monitor_thread(self): + global MONITOR_ATTACHED + try: + with self.replica.monitor() as m: + MONITOR_ATTACHED = True + for cmd in m.listen(): + if 'GRAPH.CONSTRAINT' in cmd['command']: + self.monitor.append(cmd) + except: + pass + + def test_01_constraint_replication(self): + # create mandatory node constraint over Person height + create_mandatory_node_constraint(self.g, 'Person', 'height') + + # create unique node constraint over Person height + create_unique_node_constraint(self.g, 'Person', 'height') + + # create unique node constraint over Person name and age + create_unique_node_constraint(self.g, 'Person', 'name', 'age') + + # create unique node constraint over Person loc + create_unique_node_constraint(self.g, 'Person', 'loc') + + # create mandatory edge constraint over Knows since + create_mandatory_edge_constraint(self.g, 'Knows', 'since') + + # create unique edge constraint over Knows since + create_unique_edge_constraint(self.g, 'Knows', 'since', sync=True) + + # validate constrains + constraints = list_constraints(self.g) + self.env.assertEqual(len(constraints), 6) + for c in constraints: + self.env.assertEqual(c.status, 'OPERATIONAL') + + # each constraint should be replicated twice from source to replica: + # 1. upon creation + # 2. upon constraint becoming activate + self.source.execute_command("WAIT", 1, 0) + + # wait for all 12 GRAPH.CONSTRAINT commands to be replicated + elapsed = 10 + while len(self.monitor) < 12 and elapsed > 0: + time.sleep(0.2) + elapsed -= 0.2 + + self.env.assertEqual(len(self.monitor), 12) + diff --git a/tests/flow/test_edge_index_scans.py b/tests/flow/test_edge_index_scans.py index b4e307a609..c9ef492848 100644 --- a/tests/flow/test_edge_index_scans.py +++ b/tests/flow/test_edge_index_scans.py @@ -193,7 +193,7 @@ def test07_index_scan_with_params(self): expected_result = ["Ailon"] self.env.assertEquals(query_result.result_set[0], expected_result) - def test8_index_scan_with_param_array(self): + def test08_index_scan_with_param_array(self): query = "MATCH (n)-[f:friend]->() WHERE f.created_at in $times RETURN n.name" params = {'times': [31]} plan = redis_graph.execution_plan(query, params=params) @@ -202,7 +202,7 @@ def test8_index_scan_with_param_array(self): expected_result = ["Ailon"] self.env.assertEquals(query_result.result_set[0], expected_result) - def test9_single_index_multiple_scans(self): + def test09_single_index_multiple_scans(self): query = "MATCH (p1:person {name: 'Roi'}), (p2:person {name: 'Alon'}) MERGE (p1)-[:friend {created_at: 100}]->(p2) MERGE (p1)-[:friend {created_at: 101}]->(p2)" plan = redis_graph.execution_plan(query) # Two index scans should be performed. diff --git a/tests/flow/test_effects.py b/tests/flow/test_effects.py new file mode 100644 index 0000000000..c758ff173b --- /dev/null +++ b/tests/flow/test_effects.py @@ -0,0 +1,838 @@ +import time +import threading +from common import * + +GRAPH_ID = "effects" +MONITOR_ATTACHED = False + +class testEffects(): + # enable effects replication + def effects_enable(self): + self.master.execute_command("GRAPH.CONFIG", "SET", "EFFECTS_THRESHOLD", '0') + + # disable effects replication + def effects_disable(self): + res = self.master.execute_command("GRAPH.CONFIG", "SET", "EFFECTS_THRESHOLD", '999999') + + # checks if effects replication is enabled + def effects_enabled(self): + conf = self.master.execute_command("GRAPH.CONFIG", "GET", "EFFECTS_THRESHOLD") + return (conf[1] == 0) + + # checks if effects replication is enabled + def effects_disabled(self): + return not self.effects_enabled() + + def monitor_thread(self): + global MONITOR_ATTACHED + try: + with self.replica.monitor() as m: + MONITOR_ATTACHED = True + for cmd in m.listen(): + if 'GRAPH.EFFECT' in cmd['command'] or 'GRAPH.QUERY' in cmd['command']: + self.monitor.append(cmd) + except: + pass + + def wait_for_command(self, cmd, timeout=500): + # wait for monitor to receive cmd + found = False + interval = 0.2 + + while not found and timeout > 0: + while len(self.monitor) == 0: + # wait for an item + time.sleep(interval) + timeout -= interval + item = self.monitor.pop() + found = cmd in item['command'] + + if found is False: + raise Exception(f"missing expected replicated command: {cmd}") + + def wait_for_effect(self): + self.wait_for_command('GRAPH.EFFECT') + + def wait_for_query(self): + self.wait_for_command('GRAPH.QUERY') + + def monitor_containt_effect(self): + for item in self.monitor: + if 'GRAPH.EFFECT' in item['command']: + return True + return False + + def clear_monitor(self): + self.monitor = [] + + # query master and wait for replica + def query_master_and_wait(self, q): + res = self.master_graph.query(q) + + # wait for replica to ack write + self.master.wait(1, 400) + + return res + + # asserts that master and replica have the same view over the graph + def assert_graph_eq(self): + #validate schema: + # labels + q = "CALL db.labels()" + master_labels = self.master_graph.query(q).result_set + replica_labels = self.replica_graph.query(q, read_only=True).result_set + self.env.assertEquals(master_labels, replica_labels) + + # relationship-types + q = "CALL db.relationshiptypes()" + master_relations = self.master_graph.query(q).result_set + replica_relations = self.replica_graph.query(q, read_only=True).result_set + self.env.assertEquals(master_relations, replica_relations) + + # properties + q = "CALL db.propertyKeys()" + master_props = self.master_graph.query(q).result_set + replica_props = self.replica_graph.query(q, read_only=True).result_set + self.env.assertEquals(master_props, replica_props) + + # validate nodes + q = "MATCH (n) RETURN n ORDER BY(n)" + master_resultset = self.master_graph.query(q).result_set + replica_resultset = self.replica_graph.query(q, read_only=True).result_set + self.env.assertEquals(master_resultset, replica_resultset) + + # validate relationships + q = "MATCH ()-[e]->() RETURN e ORDER BY(e)" + master_resultset = self.master_graph.query(q).result_set + replica_resultset = self.replica_graph.query(q, read_only=True).result_set + self.env.assertEquals(master_resultset, replica_resultset) + + def __init__(self): + self.env = Env(decodeResponses=True, env='oss', useSlaves=True) + self.monitor = [] + self.master = self.env.getConnection() + self.replica = self.env.getSlaveConnection() + self.master_graph = Graph(self.master, GRAPH_ID) + self.replica_graph = Graph(self.replica, GRAPH_ID) + + # create indices + self.master_graph.query("CREATE INDEX FOR (n:L) ON (n.a, n.b, n.c)") + self.master_graph.query("CREATE INDEX FOR ()-[e:R]->() ON (e.a, e.b, e.c)") + + # wait for replica and master to sync + self.master.wait(1, 0) + + self.effects_enable() + + self.monitor_thread = threading.Thread(target=self.monitor_thread) + self.monitor_thread.start() + # wait for monitor thread to attach + while MONITOR_ATTACHED is False: + time.sleep(0.2) + + def __del__(self): + # all done, shutdown replica + # stops monitor thread + self.replica.shutdown() + + def test01_effect_default_config(self): + # make sure effects are enabled by default + self.env.assertTrue(self.effects_enabled()) + + def test02_add_schema_effect(self, expect_effect=True): + # test the introduction of a schema by an effect + + # introduce a new label which in turn creates a new schema + q = "CREATE (:L)" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.nodes_created, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # introduce multiple labels + q = "CREATE (:X:Y)" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.labels_added, 2) + self.env.assertEquals(res.nodes_created, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # introduce a new relationship-type which in turn creates a new schema + q = "CREATE ()-[:R]->()" + res = self.query_master_and_wait(q) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test03_add_attribute_effect(self, expect_effect=True): + # test the introduction of an attribute by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + # set a new attribute for each supported attribute type + q = """MATCH (n:L) WITH n + LIMIT 1 + SET + n.a = 1, + n.b = 'str', + n.c = True, + n.d = [1, [2], '3'] + """ + + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 4) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + SET + e.e = point({latitude: 51, longitude: 0}), + e.f=3.14, + e.empty_string = '' + """ + + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 3) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test04_create_node_effect(self, expect_effect=True): + # test the introduction of a new node by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + # empty node + q0 = """CREATE ()""" + + # label-less node with attributes + q1 = """CREATE ({ + i:1, + s:'str', + b:True, + a:[1, [2], '3'], + p:point({latitude: 51, longitude: 0}), + f:3.14, + empty_string: '' + })""" + + # labeled node without attributes + q2 = """CREATE (:L)""" + + # node with multiple labels and attributes + q3 = """CREATE (:A:B { + i:1, + s:'str', + b:True, + a:[1, [2], '3'], + p:point({latitude: 51, longitude: 0}), + f:3.14, + empty_string: '' + })""" + + queries = [q0, q1, q2, q3] + for q in queries: + res = self.query_master_and_wait(q) + self.env.assertEquals(res.nodes_created, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test05_create_edge_effect(self, expect_effect=True): + # tests the introduction of a new edge by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + # edge without attributes + q1 = """CREATE ()-[:R]->()""" + + # edge with attributes + q2 = """CREATE ()-[:CONNECT { + ei:1, + s:'str', + eb:True, + a:[1, [2], '3'], + ep:point({latitude: 51, longitude: 0}), + f:3.14, + empty_string: ''} + ]->()""" + + # edge between an existing node and a new node + q3 = """MATCH (a) WITH a LIMIT 1 CREATE (a)-[:R]->()""" + + # edge between two existing nodes + q4 = """MATCH (a), (b) WITH a, b LIMIT 1 CREATE (a)-[:R]->(b)""" + + queries = [q1, q2, q3, q4] + for q in queries: + res = self.query_master_and_wait(q) + self.env.assertEquals(res.relationships_created, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test06_update_node_effect(self, expect_effect=True): + # test an entity attribute set update by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + q = """MATCH (n:L) + WITH n + LIMIT 1 + SET + n.xa = 2, + n.b = 'string', + n.xc = False, + n.d = [[2], 1, '3'], + n.xe = point({latitude: 41, longitude: 2}), + n.f=6.28, + n.xempty_string = ''""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # update the same attribute multiple times + q = """MATCH (n:L) + WITH n + LIMIT 1 + UNWIND range(0, 10) AS i + SET + n.xa = n.xa + 1""" + + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 11) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # update using map overwrite + q = """MATCH (n:L) + WITH n + LIMIT 1 + SET n = { + a:3, + b:'_string_', + c:True, + d:[['3'], 2, 1], + e:point({latitude: 2, longitude: 41}), + f:2.68, + empty_string:''}""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # update using map addition + q = """MATCH (n:L) + WITH n + LIMIT 1 + SET n += { + a:4, + b:'string_', + c:False, + d:[['1'], 3, 2.0], + e:point({latitude: 3, longitude: 40}), + f:8.26, + empty_string:''}""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # remove attribute + + q = "MATCH (n:L) WITH n LIMIT 1 SET n.b = NULL" + + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_removed, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # remove all attributes + + q = "MATCH (n:L) WITH n LIMIT 1 SET n = {}" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # add attribute, remove all attributes and add again + q = """MATCH (n:L) + WITH n + LIMIT 1 + SET n.v = 'value' + WITH n + SET n = {} + WITH n + SET n.v = 'value2'""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # remove attribute via map addition + q = """MATCH (n:L) + WITH n + LIMIT 1 + SET n += {x:1, v:NULL, y:2}""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test07_update_edge_effect(self, expect_effect=True): + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + # test an edge attribute set update by an effect + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + SET + e.a = 2, + e.b = 'string', + e.c = False, + e.d = [[2], 1, '3'], + e.e = point({latitude: 41, longitude: 2}), + e.f=6.28, + e.empty_string = ''""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # update the same attribute multiple times + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + UNWIND range(0, 10) AS i + SET + e.a = e.a + 1""" + + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 11) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # update using map overwrite + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + SET e = { + a:3, + b:'_string_', + c:True, + d:[['3'], 2, 1], + e:point({latitude: 2, longitude: 41}), + f:2.68, + empty_string:''}""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # update using map addition + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + SET e += { + a:4, + b:'string_', + c:False, + d:[['1'], 3, 2.0], + e:point({latitude: 3, longitude: 40}), + f:8.26, + empty_string:''}""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # remove attribute + + q = "MATCH ()-[e]->() WITH e LIMIT 1 SET e.b = NULL" + + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_removed, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # remove all attributes + + q = "MATCH ()-[e]->() WITH e LIMIT 1 SET e = {}" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # add attribute, remove all attributes and add again + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + SET e.v = 'value' + WITH e + SET e = {} + WITH e + SET e.v = 'value2'""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # remove attribute via map addition + q = """MATCH ()-[e]->() + WITH e + LIMIT 1 + SET e += {x:1, v:NULL, y:2}""" + + res = self.query_master_and_wait(q) + self.env.assertGreater(res.properties_set, 0) + self.env.assertGreater(res.properties_removed, 0) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test08_set_labels_effect(self, expect_effect=True): + # test the addition of a new node label by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + q = """MATCH (n:A:B) SET n:C""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.labels_added, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # test the addition of an existing and anew node label by an effect + q = """MATCH (n:A:B:C) SET n:C:D""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.labels_added, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test09_remove_labels_effect(self, expect_effect=True): + # test the removal of a node label by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + q = """MATCH (n:C) REMOVE n:C RETURN n""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.labels_removed, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test10_delete_edge_effect(self, expect_effect=True): + # test the deletion of an edge by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + q = """MATCH ()-[e]->() WITH e LIMIT 1 DELETE e""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.relationships_deleted, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test11_delete_node_effect(self, expect_effect=True): + # test the deletion of a node by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + # using 'n' and 'x' to try and introduce "duplicated" deletions + q = "MATCH (n) WITH n as n, n as x DELETE n, x" + res = self.query_master_and_wait(q) + self.env.assertGreater(res.nodes_deleted, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test12_merge_node(self, expect_effect=True): + # test create and update of a node by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + q = """MERGE (n:A {v:'red'}) + ON MATCH SET n.v = 'green' + ON CREATE SET n.v = 'blue'""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(res.properties_set, 2) + self.env.assertEquals(res.properties_removed, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # this time MERGE will match + q = """MERGE (n:A {v:'blue'}) + ON MATCH SET n.v = 'green' + ON CREATE SET n.v = 'red'""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.properties_removed, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test13_merge_edge(self, expect_effect=True): + # test create and update of an edge by an effect + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + q = """MERGE (n:A {v:'red'}) + MERGE (n)-[e:R{v:'red'}]->(n) + ON MATCH SET e.v = 'green' + ON CREATE SET e.v = 'blue'""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 3) + self.env.assertEquals(res.relationships_created, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + # this time MERGE will match + q = """MERGE (n:A {v:'red'}) + MERGE (n)-[e:R{v:'blue'}]->(n) + ON MATCH SET e.v = 'green' + ON CREATE SET e.v = 'red'""" + res = self.query_master_and_wait(q) + self.env.assertEquals(res.properties_set, 1) + self.env.assertEquals(res.properties_removed, 1) + + if(expect_effect): + self.wait_for_effect() + else: + self.wait_for_query() + + self.assert_graph_eq() + + def test14_rerun_disable_effects(self): + # test replication works when effects are disabled + + # no leftovers from previous test + self.env.assertFalse(self.monitor_containt_effect()) + + # update graph key + global GRAPH_ID + GRAPH_ID = "effects_disabled" + + # update graph objects to use new graph key + self.master_graph = Graph(self.master, GRAPH_ID) + self.replica_graph = Graph(self.replica, GRAPH_ID) + + # disable effects replication + self.effects_disable() + + # re-run tests, this time effects is turned off + # replication should be done via query replication + self.test02_add_schema_effect(False) + self.test03_add_attribute_effect(False) + self.test04_create_node_effect(False) + self.test05_create_edge_effect(False) + self.test06_update_node_effect(False) + self.test07_update_edge_effect(False) + self.test08_set_labels_effect(False) + self.test09_remove_labels_effect(False) + self.test10_delete_edge_effect(False) + self.test11_delete_node_effect(False) + self.test12_merge_node(False) + self.test13_merge_edge(False) + + # make sure no effects had been recieved + self.env.assertFalse(self.monitor_containt_effect()) + + def test_15_random_ops(self): + # update graph key + global GRAPH_ID + GRAPH_ID = "random_graph" + + # update graph objects to use new graph key + self.master_graph = Graph(self.master, GRAPH_ID) + self.replica_graph = Graph(self.replica, GRAPH_ID) + + # enable effects replication + self.effects_enable() + + from random_graph import create_random_schema, create_random_graph, run_random_graph_ops, ALL_OPS + nodes, edges = create_random_schema() + create_random_graph(self.master_graph, nodes, edges) + + # wait for replica and master to sync + self.master.wait(1, 0) + self.assert_graph_eq() + + run_random_graph_ops(self.master_graph, nodes, edges, ALL_OPS) + + # wait for replica and master to sync + self.master.wait(1, 0) + self.assert_graph_eq() + diff --git a/tests/flow/test_entity_update.py b/tests/flow/test_entity_update.py index 7e8c0e8915..f85158a0cc 100644 --- a/tests/flow/test_entity_update.py +++ b/tests/flow/test_entity_update.py @@ -393,7 +393,7 @@ def test_24_fail_update_non_matched_nodes(self): graph.query(query) self.env.assertTrue(False) except ResponseError as e: - self.env.assertContains("x not defined", str(e)) + self.env.assertContains("'x' not defined", str(e)) def test_25_fail_update_labels_for_edge(self): @@ -540,3 +540,14 @@ def test_37_set_property_null(self): result = graph.query("MATCH (v) RETURN v") self.env.assertEqual(result.header, [[1, 'v']]) + def test38_accumulating_updates(self): + """Tests that updates are performed relative to the latest update""" + graph.delete() + + # create a node with property `v` with value 1 + graph.query("CREATE ({v: 1})") + + res = graph.query("MATCH (n) UNWIND [0, 1, 2, 3] AS x SET n.v = n.v + x RETURN n") + + # assert results + self.env.assertEquals(res.result_set[0][0], Node(properties={'v': 7})) diff --git a/tests/flow/test_foreach.py b/tests/flow/test_foreach.py index 922d5646e7..150bf21da4 100644 --- a/tests/flow/test_foreach.py +++ b/tests/flow/test_foreach.py @@ -648,11 +648,48 @@ def test14_unbound_list_var(self): graph.query("FOREACH(n in li | CREATE (:N))") self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertIn("li not defined", str(e)) + self.env.assertIn("'li' not defined", str(e)) # same check, when the list-var is the same as the list expression try: graph.query("FOREACH(n in n | CREATE (:N))") self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertIn("n not defined", str(e)) + self.env.assertIn("'n' not defined", str(e)) + + def test15_foreach_and_index_scan(self): + query = """UNWIND range(1,9) AS i + CREATE (n:N {v:i})-[:R]->(m:M {v:(i+1)})""" + graph.query(query) + query = """CREATE INDEX FOR (n:N) ON (n.v)""" + graph.query(query) + query = """MATCH p=(n:N)-[:R]->(:M) WHERE n.v <= 5 + FOREACH( n in nodes(p) | SET n.x = 3) RETURN count(n.v)""" + result = graph.query(query) + expected_result = [[5]] + self.env.assertEquals(result.result_set, expected_result) + + def test16_accumulate_updates(self): + """Tests that updates in between cycles of body execution are treated + correctly""" + + # clear db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create a node with property `v` initialized with value 1 + res = graph.query("CREATE (:N {v: 1})") + self.env.assertEquals(res.nodes_created, 1) + + query = """ + CYPHER li=[0, 1, 2, 3] + MATCH (n) + FOREACH(x in $li | + SET n.v = n.v + x + ) + RETURN n.v + """ + + res = graph.query(query) + # check that the `v` property of the node is now 1 + 0 + 1 + 2 + 3 = 7 + self.env.assertEquals(res.result_set[0][0], 7) diff --git a/tests/flow/test_function_calls.py b/tests/flow/test_function_calls.py index 0aba4c2276..f1fc51ed21 100644 --- a/tests/flow/test_function_calls.py +++ b/tests/flow/test_function_calls.py @@ -1049,7 +1049,7 @@ def test32_toStringOrNull(self): # list query = """RETURN toStringOrNull([1])""" actual_result = graph.query(query) - self.env.assertEquals(actual_result.result_set[0][0], None) + self.env.assertEquals(actual_result.result_set[0][0], "[1]") # node query = """CREATE (n) RETURN toStringOrNull(n)""" @@ -1105,8 +1105,12 @@ def test33_toString(self): actual_result = graph.query(query) self.env.assertEquals(actual_result.result_set[0][0], None) + # null + query = """RETURN toString([1])""" + actual_result = graph.query(query) + self.env.assertEquals(actual_result.result_set[0][0], "[1]") + queries = [ - """RETURN toString([1])""", # list """CREATE (n) RETURN toString(n)""", # node """CREATE ()-[r:R]->() RETURN toString(r)""" # edge ] @@ -1250,6 +1254,17 @@ def test38_properties(self): expected_result = [[{'name': 'R1', 'len': 5}]] self.env.assertEquals(query_result.result_set, expected_result) + # properies of entity properties subset + query = """MATCH (p:Person {name: 'Alexa'}) RETURN properties(p{.name, .age})""" + query_result = graph.query(query) + expected_result = [[{'name': 'Alexa', 'age': 44}]] + self.env.assertEquals(query_result.result_set, expected_result) + + query = """MATCH ()-[r:R {name:'R1', len:5}]->() RETURN properties(r{.name})""" + query_result = graph.query(query) + expected_result = [[{'name': 'R1'}]] + self.env.assertEquals(query_result.result_set, expected_result) + # string input query = """RETURN properties('a')""" self.expect_type_error(query) @@ -2218,7 +2233,7 @@ def test86_type_mismatch_message(self): "CREATE ()-[r:R]->() RETURN hasLabels(r, ['abc', 'def'])": "Type mismatch: expected Node or Null but was Edge", "RETURN toBoolean(1.2)": "Type mismatch: expected String, Boolean, Integer, or Null but was Float", "RETURN isEmpty(1)": "Type mismatch: expected Map, List, String, or Null but was Integer", - "CREATE ()-[r:R]->() RETURN toString(r)": "Type mismatch: expected Datetime, Duration, String, Boolean, Integer, Float, Null, or Point but was Edge", + "CREATE ()-[r:R]->() RETURN toString(r)": "Type mismatch: expected List, Datetime, Duration, String, Boolean, Integer, Float, Null, or Point but was Edge", } for query, error in queries_with_errors.items(): self.expect_error(query, error) @@ -2484,7 +2499,18 @@ def test89_JOIN(self): query = """RETURN string.join(['HELL','OW', 'NOW'], ' ')""" actual_result = graph.query(query) self.env.assertEquals(actual_result.result_set[0], expected_result) - + + # join overflow + q = """UNWIND RANGE(0, 10000000) as x + WITH collect('looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string') as list + RETURN string.join(list, 'loooooooooooooooooooooooooooooooooooooooooonggggggggggggggggggggggggggggggggggggggggggggggggggggg delimiterrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr') + """ + try: + result = graph.query(q) + self.env.assertFalse(True) + except ResponseError as e: + self.env.assertContains("String overflow", str(e)) + def test90_size(self): query_to_expected_result = { "RETURN size(NULL)" : [[None]], @@ -2714,3 +2740,28 @@ def test92_REPLACEREGEX(self): query = """RETURN string.replaceRegEx('bl😉a', '😉', '😀')""" actual_result = graph.query(query) self.env.assertEquals(actual_result.result_set[0], expected_result) + + def test93_overflow(self): + # Test integer overflow caused by string to long conversion + queries_with_errors = { + "RETURN 10000000000000000000000" : "Integer overflow '10000000000000000000000'", + "RETURN -10000000000000000000000" : "Integer overflow '-10000000000000000000000'", + "RETURN 9223372036854775808" : "Integer overflow '9223372036854775808'", + "RETURN -9223372036854775809" : "Integer overflow '-9223372036854775809'", + } + for query, error in queries_with_errors.items(): + self.expect_error(query, error) + + # Test valid queries + query_to_expected_result = { + "RETURN 10^-324" : [[0]], + "RETURN pow(10,-324)" : [[0]], + "RETURN 10^+324" : [[float('inf')]], + "RETURN pow(10,324)" : [[float('inf')]], + "RETURN 0.5 + pow(10,-324)" : [[0.5]], + "RETURN pow(100,200), 5" : [[float('inf'), 5]], + "RETURN 9223372036854775807" : [[9223372036854775807]], + "RETURN -9223372036854775808" : [[-9223372036854775808]], + } + for query, expected_result in query_to_expected_result.items(): + self.get_res_and_assertEquals(query, expected_result) diff --git a/tests/flow/test_graph_deletion.py b/tests/flow/test_graph_deletion.py index 3c161ef3f9..b4b45dddc6 100644 --- a/tests/flow/test_graph_deletion.py +++ b/tests/flow/test_graph_deletion.py @@ -293,7 +293,7 @@ def test15_update_deleted_entities(self): self.env.assertEquals(actual_result.relationships_deleted, 1) # No properties should be set. # (Note that this behavior is left unspecified by Cypher.) - self.env.assertEquals(actual_result.properties_set, 0) + # self.env.assertEquals(actual_result.properties_set, 0) # Validate that the graph is empty. query = """MATCH (a) RETURN a""" @@ -393,7 +393,7 @@ def test18_delete_self_edge(self): self.env.assertEquals(res.nodes_deleted, 1) self.env.assertEquals(res.relationships_deleted, 1) - def test10_random_delete(self): + def test19_random_delete(self): # test random graph deletion added as a result of a crash found in Graph_GetNodeEdges # when iterating RG_Matrix of type BOOL with RG_MatrixTupleIter_next_UINT64 for i in range(1, 10): @@ -405,3 +405,82 @@ def test10_random_delete(self): query = """MATCH (n:N {v: floor(rand()*100001)}) DELETE n RETURN 1 LIMIT 1""" for _ in range(1, 10): redis_graph.query(query) + + def test20_consecutive_delete_clauses(self): + """Tests that consecutive `DELETE` clauses are handled correctly.""" + + # clean the db + self.env.flush() + redis_graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create a graph with 2 nodes, with labels N and M + redis_graph.query("CREATE (n:N) CREATE (m:M)") + + # delete the nodes in 2 consecutive delete clauses + res = redis_graph.query("MATCH p1=(n:N), p2=(m:M) DELETE nodes(p1)[0] \ + DELETE nodes(p2)[0]") + + # validate that the nodes were deleted + self.env.assertEquals(res.nodes_deleted, 2) + + # create 2 nodes, with the same label N + redis_graph.query("CREATE (:N), (:N)") + res = redis_graph.query("MATCH p=(n:N) DELETE nodes(p)[0] DELETE \ + nodes(p)[0]") + + # validate that the nodes were deleted + self.env.assertEquals(res.nodes_deleted, 2) + + def test21_not_existed_label(self): + # clean the db + self.env.flush() + redis_graph = Graph(self.env.getConnection(), GRAPH_ID) + + res = redis_graph.query("CREATE (n:Foo:Bar)") + self.env.assertEquals(res.nodes_created, 1) + self.env.assertEquals(res.labels_added, 2) + + res = redis_graph.query("MATCH (n) REMOVE n:Bar") + self.env.assertEquals(res.labels_removed, 1) + + res = redis_graph.query("MATCH (n) REMOVE n:Bar") + self.env.assertEquals(res.labels_removed, 0) + + res = redis_graph.query("MATCH (n:Bar) RETURN count(n)") + self.env.assertEquals(res.result_set[0][0], 0) + + def test22_delete_reserve_id(self): + # clean the db + self.env.flush() + redis_graph = Graph(self.env.getConnection(), GRAPH_ID) + + res = redis_graph.query("UNWIND range(0, 10) AS i CREATE (:A {id: i})") + self.env.assertEquals(res.nodes_created, 11) + + # expecting IDs to be reused + res = redis_graph.query("MATCH (a:A) DELETE a CREATE (b:A) RETURN id(b)") + self.env.assertEquals(res.nodes_deleted, 11) + self.env.assertEquals(res.nodes_created, 11) + self.env.assertEquals(res.result_set, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]) + + res = redis_graph.query("MATCH (a:A) DELETE a CREATE (b:A) RETURN id(b)") + self.env.assertEquals(res.nodes_deleted, 11) + self.env.assertEquals(res.nodes_created, 11) + self.env.assertEquals(res.result_set, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]) + + # clean the db + self.env.flush() + redis_graph = Graph(self.env.getConnection(), GRAPH_ID) + + res = redis_graph.query("UNWIND range(0, 10) AS i CREATE (:A {id: i})") + self.env.assertEquals(res.nodes_created, 11) + + res = redis_graph.query("MATCH (a:A) WITH a, a.id as id DELETE a MERGE (b:A {id: id}) RETURN id(b), b.id") + self.env.assertEquals(res.nodes_deleted, 11) + self.env.assertEquals(res.nodes_created, 11) + self.env.assertEquals(res.result_set, [[10, 0], [9, 1], [8, 2], [7, 3], [6, 4], [5, 5], [4, 6], [3, 7], [2, 8], [1, 9], [0, 10]]) + + res = redis_graph.query("MATCH (a:A) WITH a, a.id as id DELETE a MERGE (b:A {id: id}) RETURN id(b), b.id") + self.env.assertEquals(res.nodes_deleted, 11) + self.env.assertEquals(res.nodes_created, 11) + self.env.assertEquals(res.result_set, [[10, 10], [9, 9], [8, 8], [7, 7], [6, 6], [5, 5], [4, 4], [3, 3], [2, 2], [1, 1], [0, 0]]) diff --git a/tests/flow/test_graph_info.py b/tests/flow/test_graph_info.py new file mode 100644 index 0000000000..db8870e9bc --- /dev/null +++ b/tests/flow/test_graph_info.py @@ -0,0 +1,435 @@ +import time +import queue +import string +import random +import datetime +import threading +import multiprocessing +from common import * + +GRAPH_ID ="info" + +class LoggedQuery: + def __init__(self, event): + # make sure event contains all expected fields + fields = ["Received at", "Query", "Total duration", "Wait duration", + "Execution duration", "Report duration", "Utilized cache", + "Write", "Timeout"] + assert(all(field in event for field in fields)) + + # cast and initialize + self.received_at = datetime.datetime.fromtimestamp(int(event['Received at'])) + self.query = event['Query'] + self.total_duration = float(event['Total duration']) + self.wait_duration = float(event['Wait duration']) + self.execution_duration = float(event['Execution duration']) + self.report_duration = float(event['Report duration']) + self.utilized_cache = False if event['Utilized cache'] == '0' else True + + assert (self.TotalDuration >= (self.ExecutionDuration + self.ReportDuration)) + + def __str__(self): + return f"""ReceivedAt: {self.ReceivedAt} + Query: {self.Query} + TotalDuration: {self.TotalDuration} + WaitDuration: {self.WaitDuration} + ExecutionDuration: {self.ExecutionDuration} + ReportDuration: {self.ReportDuration} + UtilizedCache: {self.UtilizedCache}""" + + @property + def ReceivedAt(self): + return self.received_at + + @property + def Query(self): + return self.query + + @property + def TotalDuration(self): + return self.total_duration + + @property + def WaitDuration(self): + return self.wait_duration + + @property + def ExecutionDuration(self): + return self.execution_duration + + @property + def ReportDuration(self): + return self.report_duration + + @property + def UtilizedCache(self): + return self.utilized_cache + +def StreamName(graph): + return f"telemetry{{{graph.name}}}" + +class testGraphInfo(FlowTestsBase): + def __init__(self): + self.env = Env(decodeResponses=True) + self.conn = self.env.getConnection() + self.graph = Graph(self.conn, GRAPH_ID) + + def consumeStream(self, stream, drop=True, n_items=1): + # wait for telemetry stream to be created + t = 'none' # type of stream_key + + while t == 'none': + t = self.conn.type(stream) + + self.env.assertEquals(t, "stream") + + # convert stream events to LoggedQueries + logged_queries = [] + streams = {stream: '0-0'} + + elapsed = 10 + while len(logged_queries) < n_items and elapsed > 0: + # read messages from the stream + messages = self.conn.xread(streams, block=0) + + if len(messages) > 0: + # process each message received + stream_messages = messages[0][1] + for message_id, message_payload in stream_messages: + logged_queries.append(LoggedQuery(message_payload)) + + # update stream last ID + streams[stream] = stream_messages[-1][0] + + time.sleep(0.2) + elapsed -= 0.2 + + # drop stream + if drop: + self.conn.delete(stream) + + # reverse order to match expected order of events + logged_queries.reverse() + + return logged_queries + + def assertLoggedQuery(self, logged_query, query, utilized_cache): + # validate event values + self.env.assertEquals(logged_query.Query, query) + self.env.assertEquals(logged_query.UtilizedCache, utilized_cache) + + def test01_read_logged_queries(self): + """issue a number of queries + make sure they show up within the telemetry stream""" + + q0 = "RETURN 1" + q1 = "CREATE ()" + q2 = "MATCH (n) RETURN n" + queries = [q0, q1, q2] + + # issue queries + for q in queries: + self.graph.query(q) + + # read stream + logged_queries = self.consumeStream(StreamName(self.graph), n_items=3) + + # validate events + self.env.assertEquals(len(logged_queries), 3) + utilized_cache = False # first time executing queies, no cache + self.assertLoggedQuery(logged_queries[0], q2, utilized_cache) + self.assertLoggedQuery(logged_queries[1], q1, utilized_cache) + self.assertLoggedQuery(logged_queries[2], q0, utilized_cache) + + #----------------------------------------------------------------------- + # re-issue queries + #----------------------------------------------------------------------- + + for i in range(0, 2): + for q in queries: + self.graph.query(q) + + # read stream + logged_queries = self.consumeStream(StreamName(self.graph), n_items=6) + + # validate events + self.env.assertEquals(len(logged_queries), 6) + utilized_cache = True # second time executing queies + self.assertLoggedQuery(logged_queries[0], q2, utilized_cache) + self.assertLoggedQuery(logged_queries[1], q1, utilized_cache) + self.assertLoggedQuery(logged_queries[2], q0, utilized_cache) + self.assertLoggedQuery(logged_queries[3], q2, utilized_cache) + self.assertLoggedQuery(logged_queries[4], q1, utilized_cache) + self.assertLoggedQuery(logged_queries[5], q0, utilized_cache) + + def test02_capped_logged_queries(self): + """make sure number of queries is capped""" + + q = "RETURN 1" + + # worker function, invoked by multiple threads + def issue_query(g, q): + for i in range(125): + g.query(q) + + # create multiple connections + connections = [] + for i in range(16): + connections.append(self.env.getConnection()) + + # create multiple threads + threads = [] + for i in range(16): + t = threading.Thread(target=issue_query, args=(Graph(connections[i], GRAPH_ID), q)) + threads.append(t) + + # issue threads + for t in threads: + t.start() + + # wait for all threads to complete + for t in threads: + t.join() + + # read stream + logged_queries = self.consumeStream(StreamName(self.graph)) + + # make sure number of logged queries is capped + self.env.assertLess(len(logged_queries), 1200) + + def test03_long_query(self): + """long queries are truncated with: ...""" + + # create a long string + length = 4000 + long_str = ''.join(random.choice(string.ascii_lowercase) for _ in range(length)) + + q = f"RETURN '{long_str}'" + self.graph.query(q) + + # read stream + logged_queries = self.consumeStream(StreamName(self.graph), drop=False) + + logged_query = logged_queries[0] + + self.env.assertEquals(logged_query.Query, q) + + def test04_delete_graph(self): + """make sure reporting stream is deleted when graph is deleted""" + + # validate that stream exists + stream_name = StreamName(self.graph) + self.env.assertEquals(self.conn.type(stream_name), "stream") + + # make sure graph is deleted synchronously + self.graph.config("ASYNC_DELETE", "no", set=True) + + # delete graph + self.graph.delete() + + # validate that stream was deleted + self.env.assertEquals(self.conn.type(stream_name), "none") + + # restore ASYNC_DELETE + self.graph.config("ASYNC_DELETE", "yes", set=True) + + def test05_rename_graph(self): + """make sure reporting stream is renamed when graph is renamed""" + + old_name = "old_graph" + new_name = "new_graph" + old_graph = Graph(self.conn, old_name) + new_graph = Graph(self.conn, new_name) + + # issue query to create and populate stream + old_graph.query("RETURN 1") + + # wait for stream to be created + logged_queries = self.consumeStream(StreamName(old_graph), drop=False) + self.env.assertEquals(len(logged_queries), 1) + + # validate that stream exists + self.env.assertEquals(self.conn.type(StreamName(old_graph)), "stream") + + # rename graph + self.conn.rename(old_name, new_name) + + # issue query to create and populate stream + new_graph.query("RETURN 1") + + # wait for stream to be created + logged_queries = self.consumeStream(StreamName(new_graph), drop=False) + self.env.assertEquals(len(logged_queries), 1) + + # validate that stream was renamed + self.env.assertEquals(self.conn.type(StreamName(old_graph)), "none") + self.env.assertEquals(self.conn.type(StreamName(new_graph)), "stream") + + def test06_multiple_streams(self): + """test a more realistic example for how logged-queries streams + will be processed""" + + # shared variable, single consumer thread to exit + alive = True + + # streams consumer thread + def consume_streams(conn, queue): + # continuously poll for new messages + streams = {'telemetry{g}': '0-0', 'telemetry{x}': '0-0'} + + # as long as we're alive + while alive: + # read messages from the stream + messages = conn.xread(streams, block=0) + + # process each message received + for stream, stream_messages in messages: + for message_id, message_payload in stream_messages: + queue.put((stream, LoggedQuery(message_payload))) + + if messages: + # update stream last ID + streams[stream] = stream_messages[-1][0] + + # create two graphs: 'g' and 'x' + g = Graph(self.conn, "g") + x = Graph(self.conn, "x") + + # create threads communication queue + q = queue.Queue() + + # start streams consumer thread + t = threading.Thread(target=consume_streams, args=(self.conn, q)) + t.start() + + # issue queries multiple times against graphs 'g' and 'x' + for i in range (2): + # issue queries + g.query("RETURN 1") + x.query("RETURN 1") + + # read logged queries + logged_query = q.get() + logged_query = q.get() + + # signal consumer thread to stop + alive = False + + # issue another query to unblock consumer thread + g.query("RETURN 1") + + # wait for stream consumer thread to exit + t.join() + + def test07_current_queries(self): + """test currently running queries""" + + # flush DB + self.conn.flushall() + + # shared variable, single consumer thread to exit + alive = True + + # issue a number of threads all running the same query + def issue_query(g, q): + while alive: + g.query(q) + + def issue_2_query(g, q1, q2): + while alive: + g.query(q1) + time.sleep(1) + g.query(q2) + + num_threads = multiprocessing.cpu_count() * 2 + + # create multiple connections + connections = [] + for i in range(num_threads+1): + connections.append(self.env.getConnection()) + + read_query = "MATCH (n) WHERE n.v > 100 RETURN count(1)" + write_query1 = "UNWIND range(1, 10000) AS x CREATE (v: x)" + write_query2 = "MATCH (n) DELETE n" + # create multiple threads + threads = [] + for i in range(num_threads): + # read queries + t = threading.Thread(target=issue_query, args=(Graph(connections[i], GRAPH_ID), read_query)) + threads.append(t) + + # write query + t = threading.Thread(target=issue_2_query, args=(Graph(connections[-1], GRAPH_ID), write_query1, write_query2)) + threads.append(t) + + # issue threads + for t in threads: + t.start() + + # wait for graph to be created + res = self.conn.type(GRAPH_ID) + while res != "graphdata": + res = self.conn.type(GRAPH_ID) + + # get waiting and running queries + + #----------------------------------------------------------------------- + # validate running queries + #----------------------------------------------------------------------- + + res = self.conn.execute_command("GRAPH.INFO") + while True: + # validate response structure + self.env.assertEquals(len(res), 4) + self.env.assertEquals(res[0], "# Running queries") + self.env.assertEquals(res[2], "# Waiting queries") + if len(res[1]) > 0: + break + res = self.conn.execute_command("GRAPH.INFO") + + running_queries = res[1] + running_query = running_queries[0] + self.env.assertEquals(running_query[0], "Received at") + self.env.assertEquals(running_query[2], "Graph name") + self.env.assertEquals(running_query[4], "Query") + self.env.assertEquals(running_query[6], "Execution duration") + self.env.assertEquals(running_query[8], "Replicated command") + + self.env.assertEquals(running_query[3], GRAPH_ID) + self.env.assertTrue(running_query[5] == read_query or + running_query[5] == write_query1 or + running_query[5] == write_query2) + self.env.assertEquals(running_query[9], False) + + #----------------------------------------------------------------------- + # validate waiting queries + #----------------------------------------------------------------------- + + res = self.conn.execute_command("GRAPH.INFO") + while True: + # validate response structure + self.env.assertEquals(len(res), 4) + self.env.assertEquals(res[0], "# Running queries") + self.env.assertEquals(res[2], "# Waiting queries") + if len(res[3]) > 0: + break + res = self.conn.execute_command("GRAPH.INFO") + + waiting_queries = res[3] + waiting_query = waiting_queries[0] + self.env.assertEquals(waiting_query[0], "Received at") + self.env.assertEquals(waiting_query[2], "Graph name") + self.env.assertEquals(waiting_query[4], "Query") + self.env.assertEquals(waiting_query[6], "Wait duration") + + self.env.assertEquals(waiting_query[3], GRAPH_ID) + self.env.assertTrue(waiting_query[5] == read_query or + waiting_query[5] == write_query1 or + waiting_query[5] == write_query2) + + # signal worker threads to stop + alive = False + + # wait for all threads to complete + for t in threads: + t.join() diff --git a/tests/flow/test_graph_merge.py b/tests/flow/test_graph_merge.py index 31dafe0611..ff8c69311c 100644 --- a/tests/flow/test_graph_merge.py +++ b/tests/flow/test_graph_merge.py @@ -550,7 +550,7 @@ def test27_merge_create_invalid_entity(self): assert(False) except redis.exceptions.ResponseError as e: # Expecting an error. - assert("Cannot merge node using null property value" in str(e)) + self.env.assertIn("Cannot merge node using null property value", str(e)) pass # Verify that no entities were created. @@ -565,7 +565,7 @@ def test27_merge_create_invalid_entity(self): assert(False) except redis.exceptions.ResponseError as e: # Expecting an error. - self.env.assertIn("undefined attribute", str(e)) + self.env.assertIn("Cannot merge node using null property value", str(e)) def test28_merge_reset_label_scan(self): redis_con = self.env.getConnection() @@ -675,3 +675,27 @@ def test31_alias_multiple_definition(self): except redis.exceptions.ResponseError as e: # Expecting an error. assert("can't be redeclared in a MERGE clause" in str(e)) + + def test32_reset_op(self): + # MERGE operation register a reset function validate that it works as expected + redis_con = self.env.getConnection() + graph = Graph(redis_con, "reset_op") + + res = graph.query("CREATE (a:A), (b:B)") + self.env.assertEquals(res.nodes_created, 2) + + res = graph.query("MATCH (a:A), (b:B) SET a:X MERGE (c:C) MERGE (d:D)") + self.env.assertEquals(res.nodes_created, 2) + + def test33_merge_create_reserve_id(self): + # MERGE and CREATE node id reservation should be done only if new node is created + redis_con = self.env.getConnection() + graph = Graph(redis_con, "merge_create_reserve_id") + + # ensure that only 21 nodes are created + res = graph.query("UNWIND range(0, 10) AS i CREATE (:A {id: i}) MERGE (:B {id: i % 10})") + self.env.assertEquals(res.nodes_created, 21) + + # ensure that only 11 nodes are created and no crash + res = graph.query("UNWIND range(0, 10) AS i CREATE (:A {id: i}) MERGE (:B {id: i % 10})") + self.env.assertEquals(res.nodes_created, 11) diff --git a/tests/flow/test_index_delete.py b/tests/flow/test_index_delete.py index de06b2a9b7..3c16c0255f 100644 --- a/tests/flow/test_index_delete.py +++ b/tests/flow/test_index_delete.py @@ -116,3 +116,41 @@ def test05_drop_index_during_population(self): indicies = list_indicies(g).result_set self.env.assertEquals(len(indicies), 0) + def test06_reset_order(self): + """Tests that the reset order is correct, i.e., that the reading ops are + reset before the writing ops (otherwise we write while a read-lock is + held).""" + + # clear the db + self.env.flush() + g = Graph(self.env.getConnection(), GRAPH_ID) + + # create data + g.query( + """ + WITH 1 AS x + CREATE (:X {uid: toString(x)})-[:R]->(y:Y {v: x}) + """ + ) + + # create an index + create_node_exact_match_index(g, 'X', 'uid', sync=True) + create_node_exact_match_index(g, 'Y', 'v', sync=True) + + # utilize the index for a scan, followed by a deletion of the indexed + # entity and setting of a property on the other entity + res = g.query( + """ + MATCH (x:X {uid: '1'})-[:R]->(y:Y) + DELETE y + SET x.uid = '10' + RETURN x + """ + ) + + # validate results + self.env.assertEquals(res.nodes_deleted, 1) + self.env.assertEquals(res.relationships_deleted, 1) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], + Node(label='X', properties={'uid': '10'})) diff --git a/tests/flow/test_list.py b/tests/flow/test_list.py index 5935cdb841..d3a8ba70a0 100644 --- a/tests/flow/test_list.py +++ b/tests/flow/test_list.py @@ -700,8 +700,8 @@ def test09_toStringList(self): self.env.assertEquals(actual_result.result_set[0], expected_result) # Test list with mixed type values - query = """RETURN toStringList(['abc', 7, '5.32', null, ['a','b']]) """ - expected_result = [['abc', '7', '5.32', None, None]] + query = """RETURN toStringList(['abc', 7, '5.32', null, ['a','b', [{key:'value'}]]]) """ + expected_result = [['abc', '7', '5.32', None, '[a, b, [{key: value}]]']] actual_result = redis_graph.query(query) self.env.assertEquals(actual_result.result_set[0], expected_result) diff --git a/tests/flow/test_optimizations_plan.py b/tests/flow/test_optimizations_plan.py index 240fcaa5a0..bd28270686 100644 --- a/tests/flow/test_optimizations_plan.py +++ b/tests/flow/test_optimizations_plan.py @@ -3,7 +3,7 @@ graph = None redis_con = None people = ["Roi", "Alon", "Ailon", "Boaz"] - +GRAPH_ID = "g" class testOptimizationsPlan(FlowTestsBase): def __init__(self): @@ -11,7 +11,7 @@ def __init__(self): global graph global redis_con redis_con = self.env.getConnection() - graph = Graph(redis_con, "g") + graph = Graph(redis_con, GRAPH_ID) self.populate_graph() def populate_graph(self): @@ -475,4 +475,70 @@ def test29_optimize_label_scan_cached_label_id(self): self.env.assertEquals(res.result_set, [[1]]) plan = graph.execution_plan(query) - self.env.assertIn("Node By Label Scan | (n:N)", plan) \ No newline at end of file + self.env.assertIn("Node By Label Scan | (n:N)", plan) + + # mandatory match labels should not be replaced with optional ones in + # optimize-label-scan + def test30_optimize_mandatory_labels_order_only(self): + # clean db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create a node with label N + query = """CREATE (n:N {v: 1})""" + graph.query(query) + + query = """MATCH (n:N) OPTIONAL MATCH (n:Q) RETURN n.v""" + plan = graph.execution_plan(query) + + # make sure N is traversed first, even though there are no nodes with + # label Q + self.env.assertIn("Node By Label Scan | (n:N)", plan) + res = graph.query(query) + self.env.assertEquals(res.result_set, [[1]]) + + # create nodes so there are two nodes with label N, and one with label Q. + graph.query("CREATE (:N:Q {v: 2})") + + # The most tempting label to start traversing from is Z, as there are + # no nodes of label Z, but it is optional, so the second most tempting + # label (Q) must be traversed first (order swapped with N) + queries = ["MATCH (n:N) MATCH (n:Q) OPTIONAL MATCH (n:Z) RETURN n", + "MATCH (n:Q) MATCH (n:N) OPTIONAL MATCH (n:Z) RETURN n"] + + for q in queries: + plan = graph.execution_plan(q) + self.env.assertIn("Node By Label Scan | (n:Q)", plan) + self.env.assertIn("Conditional Traverse | (n:N)->(n:N)", plan) + + # assert correctness of the results + res = graph.query(q) + self.env.assertEquals(len(res.result_set), 1) + self.env.assertEquals(res.result_set[0][0], Node(label=['N', 'Q'], properties={'v': 2})) + + def test31_optimize_optional_labels(self): + """Tests that the optimization of the Label-Scan op works on optional + labels properly""" + + # clean db + self.env.flush() + graph = Graph(self.env.getConnection(), GRAPH_ID) + + # create a node with label `N` + graph.query("CREATE (:N)") + + plan = graph.execution_plan("OPTIONAL MATCH (n:N:M) RETURN n") + + # make sure `M` is traversed first, as it has less labels + self.env.assertIn("Node By Label Scan | (n:M)", plan) + self.env.assertIn("Conditional Traverse | (n:N)->(n:N)", plan) + + # make sure that labels from different `OPTIONAL MATCH` clauses are not + # "mixed" in Label-Scan optimization + query = "OPTIONAL MATCH (n:N) OPTIONAL MATCH (n:M) RETURN n" + plan = graph.execution_plan(query) + + # make sure `N` is the first label traversed, even though there are less + # labels with label `M` + self.env.assertIn("Node By Label Scan | (n:N)", plan) + self.env.assertIn("Conditional Traverse | (n:M)->(n:M)", plan) diff --git a/tests/flow/test_optional_match.py b/tests/flow/test_optional_match.py index e1bbb85f08..ab096e878d 100644 --- a/tests/flow/test_optional_match.py +++ b/tests/flow/test_optional_match.py @@ -290,3 +290,10 @@ def test22_optional_repeats_reference(self): ['v3'], ['v4']] self.env.assertEquals(actual_result.result_set, expected_result) + + def test23_optional_after_apply(self): + global redis_graph + self.env.flush() + query = """WITH [0, 0] AS n0 OPTIONAL MATCH () MERGE ()""" + actual_result = redis_graph.query(query) + self.env.assertEquals(actual_result.nodes_created, 1) diff --git a/tests/flow/test_path_algorithms.py b/tests/flow/test_path_algorithms.py index a68f58ca49..9751816d1e 100644 --- a/tests/flow/test_path_algorithms.py +++ b/tests/flow/test_path_algorithms.py @@ -180,14 +180,14 @@ def test01_SPpaths_validations(self): self.graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertContains("weightProp must be a string", str(e)) + self.env.assertContains("weightProp must be string", str(e)) query = """MATCH (n:L {v: 1}), (m:L {v: 5}) CALL algo.SPpaths({sourceNode: n, targetNode: m, costProp: 1})""" try: self.graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertContains("costProp must be a string", str(e)) + self.env.assertContains("costProp must be string", str(e)) query = """MATCH (n:L {v: 1}), (m:L {v: 5}) CALL algo.SPpaths({sourceNode: n, targetNode: m, maxCost: '1'})""" try: @@ -208,7 +208,7 @@ def test01_SPpaths_validations(self): self.graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertContains("pathCount must be greater than or equal to 0", str(e)) + self.env.assertContains("pathCount must be a non-negative integer", str(e)) def test01_SSpaths_validations(self): query = """CALL algo.SSpaths({})""" @@ -269,14 +269,14 @@ def test01_SSpaths_validations(self): self.graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertContains("weightProp must be a string", str(e)) + self.env.assertContains("weightProp must be string", str(e)) query = """MATCH (n:L {v: 1}), (m:L {v: 5}) CALL algo.SSpaths({sourceNode: n, costProp: 1})""" try: self.graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertContains("costProp must be a string", str(e)) + self.env.assertContains("costProp must be string", str(e)) query = """MATCH (n:L {v: 1}), (m:L {v: 5}) CALL algo.SSpaths({sourceNode: n, maxCost: '1'})""" try: @@ -297,7 +297,7 @@ def test01_SSpaths_validations(self): self.graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertContains("pathCount must be greater than or equal to 0", str(e)) + self.env.assertContains("pathCount must be a non-negative integer", str(e)) def sp_query(self, source, target, relTypes, maxLen, maxCost, pathCount, relDirection): args = ["sourceNode: n", diff --git a/tests/flow/test_persistency.py b/tests/flow/test_persistency.py index e590e62722..8f2e22d657 100644 --- a/tests/flow/test_persistency.py +++ b/tests/flow/test_persistency.py @@ -248,7 +248,7 @@ def test06_bulk_insert(self): runner = CliRunner() csv_path = os.path.dirname(os.path.abspath(__file__)) + '/../../demo/social/resources/bulk_formatted/' - res = runner.invoke(bulk_insert, ['--port', port, + res = runner.invoke(bulk_insert, ['--redis-url', f"redis://localhost:{port}", '--nodes', csv_path + 'Person.csv', '--nodes', csv_path + 'Country.csv', '--relations', csv_path + 'KNOWS.csv', diff --git a/tests/flow/test_query_mem_limit.py b/tests/flow/test_query_mem_limit.py index c437212676..03ea51339e 100644 --- a/tests/flow/test_query_mem_limit.py +++ b/tests/flow/test_query_mem_limit.py @@ -16,18 +16,10 @@ # 5. test a mixture of queries, ~90% successful ones and the rest are expected # to fail due to out of memory error -g = None -GRAPH_NAME = "max_query_mem" -MEM_HOG_QUERY = """UNWIND range(0, 100000) AS x - WITH x - WHERE (x / 2) = 50 - RETURN x, count(x)""" - -MEM_THRIFTY_QUERY = """UNWIND range(0, 10) AS x - WITH x - WHERE (x / 2) = 50 - RETURN x, count(x)""" - +g = None +GRAPH_NAME = "max_query_mem" +MEM_HOG_QUERY = """UNWIND range(0, 100000) AS x RETURN x, count(x)""" +MEM_THRIFTY_QUERY = """RETURN 1""" def issue_query(conn, q, should_fail): try: @@ -48,19 +40,21 @@ def __init__(self): self.conn = self.env.getConnection() def stress_server(self, queries): - connections = [] qs = [] + connections = [] should_fails = [] + shared_connections = [] thread_count = self.conn.execute_command("GRAPH.CONFIG", "GET", "THREAD_COUNT")[1] pool = Pool(nodes=thread_count) - # init connections + # init shared connections for t in range(thread_count): - connections.append(self.env.getConnection()) + shared_connections.append(self.env.getConnection()) - for q in queries: + for idx, q in enumerate(queries): qs.append(q[0]) should_fails.append(q[1]) + connections.append(shared_connections[idx%len(shared_connections)]) # invoke queries result = pool.map(issue_query, connections, qs, should_fails) @@ -68,6 +62,9 @@ def stress_server(self, queries): # validate all process return true self.env.assertTrue(all(result)) + # clear pool + pool.clear() + def test_01_read_memory_limit_config(self): # read configuration, test default value, expecting unlimited memory cap result = self.conn.execute_command("GRAPH.CONFIG", "GET", "QUERY_MEM_CAPACITY") @@ -136,3 +133,4 @@ def test_05_test_mixed_queries(self): queries.append((q, should_fail)) self.stress_server(queries) + diff --git a/tests/flow/test_query_validation.py b/tests/flow/test_query_validation.py index 53c06f7044..7f5c18ac73 100644 --- a/tests/flow/test_query_validation.py +++ b/tests/flow/test_query_validation.py @@ -489,7 +489,7 @@ def test33_alias_reference_in_param(self): assert(False) except redis.exceptions.ResponseError as e: # Expecting an error. - assert("a not defined" in str(e)) + assert("'a' not defined" in str(e)) pass def test34_self_referential_properties(self): @@ -649,3 +649,43 @@ def test43_invalid_variable_length_edge_use(self): self.env.assertTrue(False) except redis.exceptions.ResponseError as e: self.env.assertContains("Variable length relationships cannot be used in", str(e)) + + def test44_undefined_variables(self): + # invalid usage of undefined variables in a `WITH` clause + invalid_queries = [ + "WITH a RETURN a", + "WITH a AS a RETURN a", + "WITH [a] AS a RETURN a", + "WITH [a[a[a]]] AS a RETURN a", + "WITH a AS b, b AS c, c AS a RETURN a", + "WITH {a:a} AS a RETURN a", + "WITH a RETURN 0", + "WITH 3 AS a, 4 AS b, a + b AS c RETURN c", + "WITH [x in a | x.prop1] AS a RETURN 1", + "WITH [(n)-[x:R]->(m) | a.prop1] AS a RETURN 1" + ] + for query in invalid_queries: + try: + redis_graph.query(query) + self.env.assertTrue(False) + except redis.exceptions.ResponseError as e: + # Expecting an error. + self.env.assertIn("'a' not defined", str(e)) + + # invalid usage of undefined variables in a `RETURN` clause + invalid_queries = [ + "RETURN a AS a", + "RETURN [a] AS a", + "RETURN [a[a[a]]] AS a", + "RETURN a AS b, b AS c, c AS a", + "RETURN {a:a} AS a", + "RETURN [x in a | x.prop1] AS a", + "RETURN [(n)-[x:R]->(m) | a.prop1] AS a" + ] + for query in invalid_queries: + try: + redis_graph.query(query) + self.env.assertTrue(False) + except redis.exceptions.ResponseError as e: + # Expecting an error. + self.env.assertIn("'a' not defined", str(e)) diff --git a/tests/flow/test_reduce.py b/tests/flow/test_reduce.py index 564cce0bb3..2a021b9839 100644 --- a/tests/flow/test_reduce.py +++ b/tests/flow/test_reduce.py @@ -108,21 +108,21 @@ def test_missing_variables_reduction(self): try: actual = self.graph.query(q).result_set except ResponseError as e: - self.env.assertIn("x not defined", str(e)) + self.env.assertIn("'x' not defined", str(e)) #----------------------------------------------------------------------- q = "RETURN reduce(sum=0, n in x | sum+n)" try: actual = self.graph.query(q).result_set except ResponseError as e: - self.env.assertIn("x not defined", str(e)) + self.env.assertIn("'x' not defined", str(e)) #----------------------------------------------------------------------- q = "RETURN reduce(sum=0, n in [1,2,3] | sum+x)" try: actual = self.graph.query(q).result_set except ResponseError as e: - self.env.assertIn("x not defined", str(e)) + self.env.assertIn("'x' not defined", str(e)) def test_nested_reduction(self): # sum = 1 + 1 diff --git a/tests/flow/test_relation_patterns.py b/tests/flow/test_relation_patterns.py index da149d238d..8b979eeb51 100644 --- a/tests/flow/test_relation_patterns.py +++ b/tests/flow/test_relation_patterns.py @@ -51,9 +51,16 @@ def test01_one_hop_traversals(self): query = """MATCH (a)-[*1]->(b) RETURN a.val, b.val ORDER BY a.val, b.val""" result_d = redis_graph.query(query) + # default minimum length is 1 + # the following query is equivalent to: + # MATCH (a)-[]->(b) RETURN a.val, b.val ORDER BY a.val, b.val + query = """MATCH (a)-[*..1]->(b) RETURN a.val, b.val ORDER BY a.val, b.val""" + result_e = redis_graph.query(query) + self.env.assertEquals(result_b.result_set, result_a.result_set) self.env.assertEquals(result_c.result_set, result_a.result_set) self.env.assertEquals(result_d.result_set, result_a.result_set) + self.env.assertEquals(result_e.result_set, result_a.result_set) # Test patterns that traverse 2 edges. def test02_two_hop_traversals(self): @@ -300,3 +307,70 @@ def test10_triple_edge_type(self): res = g.query(q.format(L0=perm[0], L1=perm[1], L2=perm[2])) self.env.assertEquals(res.result_set, expected_result) + def test11_shared_node_detection(self): + # Construct a simple graph + # (s)<-[:A]-(x) + # (x)<-[:B]-(x) + # (x)-[:B]->(t) + # (t)<-[:B]-(x) + g = Graph(redis_con, "shared_node") + q = "MERGE (s)<-[:A]-(x)<-[:B]-(x)-[:B]->(t)<-[:B]-(x)" + result = g.query(q) + + self.env.assertEquals(result.nodes_created, 3) + self.env.assertEquals(result.relationships_created, 4) + + result = g.query(q) + self.env.assertEquals(result.nodes_created, 0) + self.env.assertEquals(result.relationships_created, 0) + + # test error reporting for invalid min, max variable length edge length + def test12_lt_zero_hop_traversals(self): + # Construct an empty graph + g = Graph(redis_con, "lt_zero_hop_traversals") + + queries = [ + "MATCH p=()-[*..0]->() RETURN nodes(p) AS nodes", + "MATCH p=()-[*1..0]->() RETURN nodes(p) AS nodes", + "MATCH p=()-[*2..1]->() RETURN nodes(p) AS nodes", + "MATCH p=()-[e*2..1]->() RETURN nodes(p) AS nodes", + "MATCH p=()-[e:R*20..10]->() RETURN nodes(p) AS nodes", + "MATCH p=()-[]->()-[*1..0]->() RETURN nodes(p) AS nodes", + ] + for query in queries: + self._assert_exception(g, query, + "Variable length path, maximum number of hops must be greater or equal to minimum number of hops.") + + def test13_return_var_len_edge_array(self): + # Construct a simple graph: + # (A)-[R]->(b) + # (b)-[R]->(c) + g = Graph(redis_con, "return_var_len_edge_array") + q = "CREATE (a)-[:R]->(b)-[:R]->(c)" + g.query(q) + + query_to_expected_result = [ + ("MATCH (a)-[r*2..2]->(b) RETURN size(nodes(r))" , [[3]]), + ("MATCH (a)-[r:R*2..2]->(b) RETURN size(nodes(r))" , [[3]]), + ("MATCH (a)-[r*1..2]->(b) RETURN size(nodes(r)) AS x ORDER BY x" , [[2], [2], [3]]), + ("MATCH (a)-[r*0..2]->(b) RETURN size(nodes(r)) AS x ORDER BY x" , [[1], [1], [1], [2], [2], [3]]), + ("MATCH (a)-[r*0..1]->(b) RETURN size(nodes(r)) AS x ORDER BY x" , [[1], [1], [1], [2], [2]]), + ("MATCH (a)-[r*0..0]->(b) RETURN size(nodes(r)) AS x ORDER BY x" , [[1], [1], [1]]), + ] + for query, expected_result in query_to_expected_result: + actual_result = g.query(query) + self.env.assertEquals(actual_result.result_set, expected_result) + + # for patterns of length equals to one, the expected result is of type edge + q = "MATCH (a)-[r*1..1]->(b) RETURN r" + actual_result = g.query(q) + + e01 = actual_result.result_set[0][0] + self.env.assertEquals(e01.src_node, 0) + self.env.assertEquals(e01.dest_node, 1) + self.env.assertEquals(e01.relation, 'R') + + e12 = actual_result.result_set[1][0] + self.env.assertEquals(e12.src_node, 1) + self.env.assertEquals(e12.dest_node, 2) + self.env.assertEquals(e12.relation, 'R') diff --git a/tests/flow/test_replication.py b/tests/flow/test_replication.py index 5f259b66ed..6188faa547 100644 --- a/tests/flow/test_replication.py +++ b/tests/flow/test_replication.py @@ -14,6 +14,7 @@ # read queries shouldn't be replicated. class testReplication(FlowTestsBase): + def __init__(self): # skip test if we're running under Valgrind if VALGRIND or SANITIZER != "": @@ -40,58 +41,62 @@ def test_CRUD_replication(self): # create a simple graph #----------------------------------------------------------------------- - origin = Graph(source_con, GRAPH_ID) + src = Graph(source_con, GRAPH_ID) replica = Graph(replica_con, GRAPH_ID) s = Node(label='L', properties={'id': 0, 'name': 'abcd', 'height' : 178}) t = Node(label='L', properties={'id': 1, 'name': 'efgh', 'height' : 178}) e = Edge(s, 'R', t) - origin.add_node(s) - origin.add_node(t) - origin.add_edge(e) - origin.flush() + src.add_node(s) + src.add_node(t) + src.add_edge(e) + src.flush() #----------------------------------------------------------------------- # create indices #----------------------------------------------------------------------- # create index - create_node_exact_match_index(origin, 'L', 'id', sync=True) + create_node_exact_match_index(src, 'L', 'id') # create full-text index - create_fulltext_index(origin, 'L', 'name', sync=True) + create_fulltext_index(src, 'L', 'name') # add fields to existing index - create_fulltext_index(origin, 'L', 'title', 'desc', sync=True) + create_fulltext_index(src, 'L', 'title', 'desc', sync=True) # create full-text index with index config q = "CALL db.idx.fulltext.createNodeIndex({label: 'L1', language: 'german', stopwords: ['a', 'b'] }, 'title', 'desc')" - origin.query(q) + src.query(q) #----------------------------------------------------------------------- # create constraints #----------------------------------------------------------------------- # create node unique constraint - create_unique_node_constraint(origin, "L", "id", sync=True) + create_unique_node_constraint(src, "L", "id") # add another unique constraint - create_unique_node_constraint(origin, "L", "id", "name", sync=True) + create_unique_node_constraint(src, "L", "id", "name", sync=True) # add a unique constraint which is destined to fail - origin.query("CREATE (:Actor {age: 10, name: 'jerry'}), (:Actor {age: 10, name: 'jerry'})") - create_unique_node_constraint(origin, "Actor", "age", sync=True) - c = get_constraint(origin, "UNIQUE", "LABEL", "Actor", "age") + result = src.query("CREATE (:Actor {age: 10, name: 'jerry'}), (:Actor {age: 10, name: 'jerry'})") + self.env.assertEquals(result.nodes_created, 2) + + create_unique_node_constraint(src, "Actor", "age", sync=True) + c = get_constraint(src, "UNIQUE", "LABEL", "Actor", "age") self.env.assertEquals(c.status, "FAILED") # update entity q = "MATCH (n:L {id:1}) SET n.id = 2" - origin.query(q) + result = src.query(q) + self.env.assertEquals(result.properties_set, 1) # delete entity q = "MATCH (n:L {id:0}) DELETE n" - origin.query(q) + result = src.query(q) + self.env.assertEquals(result.nodes_deleted, 1) # the WAIT command forces master slave sync to complete source_con.execute_command("WAIT", "1", "0") @@ -101,100 +106,101 @@ def test_CRUD_replication(self): # make sure index is available on replica q = "MATCH (s:L {id:2}) RETURN s.name" - plan = origin.execution_plan(q) + plan = src.execution_plan(q) replica_plan = replica.execution_plan(q) env.assertIn("Index Scan", plan) env.assertEquals(replica_plan, plan) # issue query on both source and replica # make sure results are the same - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set env.assertEquals(replica_result, result) # make sure node count on both primary and replica is the same q = "MATCH (n) RETURN count(n)" - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set env.assertEquals(replica_result, result) # make sure nodes are in sync q = "MATCH (n) RETURN n ORDER BY n" - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set env.assertEquals(replica_result, result) # remove label - q = "MATCH (s:L {id:2}) REMOVE s:L RETURN s" - result = origin.query(q) + q = "MATCH (s:L {id:2}) REMOVE s:L" + result = src.query(q) env.assertEqual(result.labels_removed, 1) # the WAIT command forces master slave sync to complete source_con.execute_command("WAIT", "1", "0") q = "MATCH (s:L {id:2}) RETURN s" - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set - env.assertEquals(replica_result, result) env.assertEqual(len(result), 0) + env.assertEquals(replica_result, result) # remove property q = "MATCH (s {id:2}) SET s.id = NULL RETURN s" - result = origin.query(q) + result = src.query(q) env.assertEqual(result.properties_removed, 1) # the WAIT command forces master slave sync to complete source_con.execute_command("WAIT", "1", "0") q = "MATCH (s {id:2}) RETURN s" - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set - env.assertEquals(replica_result, result) env.assertEqual(len(result), 0) + env.assertEquals(replica_result, result) # make sure both primary and replica have the same set of indexes q = "CALL db.indexes() YIELD type, label, properties, language, stopwords, entitytype" - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set env.assertEquals(replica_result, result) # drop fulltext index q = "CALL db.idx.fulltext.drop('L')" - origin.query(q) + result = src.query(q) + env.assertEquals(result.indices_deleted, 1) # the WAIT command forces master slave sync to complete source_con.execute_command("WAIT", "1", "0") # make sure both primary and replica have the same set of indexes q = "CALL db.indexes() YIELD type, label, properties, language, stopwords, entitytype" - result = origin.query(q).result_set + result = src.query(q, read_only=True).result_set replica_result = replica.query(q, read_only=True).result_set env.assertEquals(replica_result, result) # make sure both primary and replica have the same set of constraints - origin_result = list_constraints(origin) + origin_result = list_constraints(src) replica_result = list_constraints(replica) env.assertEquals(replica_result, origin_result) # drop constraint - drop_unique_node_constraint(origin, "L", "id") + drop_unique_node_constraint(src, "L", "id") # the WAIT command forces master slave sync to complete source_con.execute_command("WAIT", "1", "0") # make sure both primary and replica have the same set of constraints - origin_result = list_constraints(origin) + origin_result = list_constraints(src) replica_result = list_constraints(replica) env.assertEquals(replica_result, origin_result) # drop failed constraint - drop_unique_node_constraint(origin, "Actor", "age") + drop_unique_node_constraint(src, "Actor", "age") # the WAIT command forces master slave sync to complete source_con.execute_command("WAIT", "1", "0") # make sure both primary and replica have the same set of constraints - origin_result = list_constraints(origin) + origin_result = list_constraints(src) replica_result = list_constraints(replica) env.assertEquals(replica_result, origin_result) diff --git a/tests/flow/test_shortest_path.py b/tests/flow/test_shortest_path.py index fe2ab74ec4..8d729f9abc 100644 --- a/tests/flow/test_shortest_path.py +++ b/tests/flow/test_shortest_path.py @@ -46,7 +46,7 @@ def test01_invalid_shortest_paths(self): redis_graph.query(query) self.env.assertTrue(False) except redis.exceptions.ResponseError as e: - self.env.assertIn("RedisGraph currently only supports shortestPath in WITH or RETURN clauses", str(e)) + self.env.assertIn("RedisGraph currently only supports shortestPaths in WITH or RETURN clauses", str(e)) query = """MATCH (a {v: 1}), (b {v: 4}) RETURN shortestPath((a)-[*2..]->(b))""" try: diff --git a/tests/flow/test_stress.py b/tests/flow/test_stress.py index 5278a52487..c4ad841afb 100644 --- a/tests/flow/test_stress.py +++ b/tests/flow/test_stress.py @@ -112,6 +112,8 @@ def test00_stress(self): conn.ping() conn.close() + pool.clear() + def test01_bgsave_stress(self): n_reads = 50000 n_creations = 50000 @@ -144,6 +146,8 @@ def test01_bgsave_stress(self): conn.ping() conn.close() + pool.clear() + def test02_write_only_workload(self): pool = Pool(nodes=3) n_creations = 20000 @@ -169,6 +173,8 @@ def test02_write_only_workload(self): conn.ping() conn.close() + pool.clear() + def test03_clean_shutdown(self): # issue SHUTDOWN while traffic is generated indexes = range(self.client_count) @@ -187,3 +193,5 @@ def test03_clean_shutdown(self): self.env.assertTrue(self.env.checkExitCode()) + pool.clear() + diff --git a/tests/flow/test_timeout.py b/tests/flow/test_timeout.py index b0e21b4376..7d4282024e 100644 --- a/tests/flow/test_timeout.py +++ b/tests/flow/test_timeout.py @@ -7,6 +7,7 @@ GRAPH_ID = "timeout" + class testQueryTimeout(): def __init__(self): self.env = Env(decodeResponses=True, moduleArgs="TIMEOUT 1000") @@ -35,7 +36,7 @@ def test01_read_write_query_timeout(self): except: self.env.assertTrue(False) - query = """UNWIND range(0, 100000) AS x CREATE (p:Person {age: x%90, height: x%200, weight: x%80})""" + query = """UNWIND range(0, 1000000) AS x CREATE (p:Person {age: x%90, height: x%200, weight: x%80})""" try: # The query is expected to succeed redis_graph.query(query, timeout=1) @@ -98,12 +99,10 @@ def test03_timeout_index_scan(self): for q in queries: q += " LIMIT 10" try: - res = redis_graph.query(q, timeout=20) + res = redis_graph.query(q, timeout=5) timeouts.append(res.run_time_ms) except: - print(q) - print(res.run_time_ms) - self.env.assertTrue(False) + timeouts.append(res.run_time_ms) for i, q in enumerate(queries): try: @@ -182,8 +181,8 @@ def test06_error_timeout_default_higher_than_timeout_max(self): try: redis_con.execute_command("GRAPH.CONFIG", "SET", "TIMEOUT_DEFAULT", 0) self.env.assertTrue(True) - # revert timeout_default to 10 - redis_con.execute_command("GRAPH.CONFIG", "SET", "TIMEOUT_DEFAULT", 10) + # revert timeout_default to 5 + redis_con.execute_command("GRAPH.CONFIG", "SET", "TIMEOUT_DEFAULT", 5) except ResponseError as error: self.env.assertTrue(False) @@ -197,9 +196,7 @@ def test07_read_write_query_timeout_default(self): for query in queries: try: # The query is expected to timeout - res = redis_graph.query(query) - print(query) - print(res.run_time_ms) + redis_graph.query(query) self.env.assertTrue(False) except ResponseError as error: self.env.assertContains("Query timed out", str(error)) @@ -309,3 +306,4 @@ def query(): tasks.append(loop.create_task(asyncio.to_thread(query))) loop.run_until_complete(asyncio.wait(tasks)) + diff --git a/tests/flow/test_traversal_construction.py b/tests/flow/test_traversal_construction.py index d3c5470a01..2172fdc459 100644 --- a/tests/flow/test_traversal_construction.py +++ b/tests/flow/test_traversal_construction.py @@ -413,3 +413,30 @@ def test_traverse_zero_length_edge(self): result = graph.query(q).result_set self.env.assertTrue(result == expected) + def test_consume_depleted_ops(self): + # as op conditional traverse can call consume on its children + # validate that the children not crash + + graph.query("CREATE (:A)-[:R]->(:B)") + + # test op_create + graph.query("""CREATE (x:X) + WITH * + MATCH (:A)-[r:R]->(b:B) + RETURN x""") + + # test op_delete + graph.query("""MATCH (x:X) + DELETE x + WITH * + MATCH (a)-[r:R]->(b:B) + RETURN x""") + + graph.query("CREATE (x:X)") + + # test op_foreach + graph.query("""MATCH (x:X) + FOREACH(i in range(0, 4) | CREATE (x1:X)) + WITH * + MATCH (a)-[r:R]->(b:B) + RETURN x""") \ No newline at end of file diff --git a/tests/flow/test_union.py b/tests/flow/test_union.py index e28ae06a03..2f7fe52984 100644 --- a/tests/flow/test_union.py +++ b/tests/flow/test_union.py @@ -142,3 +142,40 @@ def test07_union_with_partial_ordering(self): UNWIND range(1, 3) AS b RETURN b""" result = redis_graph.query(query) self.env.assertEquals(result.result_set, expected_result) + + def test08_union_with_index_scan(self): + query = """UNWIND range(10,20) AS i + CREATE (n:N {v:tostring(i)})-[:R]->(m:M {v:tostring(i+1)})""" + redis_graph.query(query) + query = """CREATE INDEX ON :N(v)""" + redis_graph.query(query) + + # test MATCH and CREATE + query = """MATCH (n:N {v:'10'})-[:R]->(m:M) RETURN m.v AS p + UNION + MATCH (s:M {v:'12'}) CREATE (:N {v:'10'})-[:R]->(s) RETURN s.v AS p""" + result = redis_graph.query(query) + expected_result = [['11'],['12']] + self.env.assertEquals(result.result_set, expected_result) + + # test MATCH, CREATE and MERGE + query = """MATCH (n:N {v:'10'})-[:R]->(:M) RETURN n.v AS p + UNION + MATCH (s:M {v:'12'}) CREATE (:N {v:'10'})-[:R]->(s) RETURN s.v AS p + UNION + MERGE(x:N {v:'15'})-[:R]->(:M {v:'18'}) RETURN x.v AS p""" + result = redis_graph.query(query) + expected_result = [['10'],['12'],['15']] + self.env.assertEquals(result.result_set, expected_result) + + def test09_union_validation(self): + try: + query = """OPTIONAL MATCH (a:N) + RETURN a + UNION + MATCH (a:N) + RETURN a""" + redis_graph.query(query) + self.env.assertTrue(True) + except redis.exceptions.ResponseError: + self.env.assertTrue(False) \ No newline at end of file diff --git a/tests/flow/test_variable_length_traversals.py b/tests/flow/test_variable_length_traversals.py index a63152cf2a..694d6c3478 100644 --- a/tests/flow/test_variable_length_traversals.py +++ b/tests/flow/test_variable_length_traversals.py @@ -37,7 +37,9 @@ def populate_graph(self): # Sanity check against single-hop traversal def test01_conditional_traverse(self): - query = """MATCH (a)-[e]->(b) RETURN a.name, e.connects, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[e]->(b) + RETURN a.name, e.connects, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) expected_result = [['A', 'AB', 'B'], ['B', 'BC', 'C'], @@ -46,31 +48,43 @@ def test01_conditional_traverse(self): # Traversal with no labels def test02_unlabeled_traverse(self): - query = """MATCH (a)-[*]->(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[*]->(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), max_results) - query = """MATCH (a)<-[*]-(b) RETURN a, b ORDER BY a.name, b.name""" + query = """MATCH (a)<-[*]-(b) + RETURN a, b + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), max_results) # Traversal with labeled source def test03_source_labeled(self): - query = """MATCH (a:node)-[*]->(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a:node)-[*]->(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), max_results) - query = """MATCH (a:node)<-[*]-(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a:node)<-[*]-(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), max_results) # Traversal with labeled dest def test04_dest_labeled(self): - query = """MATCH (a)-[*]->(b:node) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[*]->(b:node) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), max_results) - query = """MATCH (a)<-[*]-(b:node) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)<-[*]-(b:node) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), max_results) @@ -82,25 +96,34 @@ def test05_invalid_traversal(self): # Test bidirectional traversal def test06_bidirectional_traversal(self): - query = """MATCH (a)-[*]-(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[*]-(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) # The undirected traversal should represent every combination twice. self.env.assertEquals(len(actual_result.result_set), max_results * 2) def test07_non_existing_edge_traversal_with_zero_length(self): # Verify that zero length traversals always return source, even for non existing edges. - query = """MATCH (a)-[:not_knows*0..1]->(b) RETURN a""" + query = """MATCH (a)-[:not_knows*0..1]->(b) + RETURN a""" actual_result = redis_graph.query(query) self.env.assertEquals(len(actual_result.result_set), 4) # Test traversal with a possibly-null source. def test08_optional_source(self): - query = """OPTIONAL MATCH (a:fake) OPTIONAL MATCH (a)-[*]->(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """OPTIONAL MATCH (a:fake) + OPTIONAL MATCH (a)-[*]->(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) expected_result = [[None, None]] self.env.assertEquals(actual_result.result_set, expected_result) - query = """OPTIONAL MATCH (a:node {name: 'A'}) OPTIONAL MATCH (a)-[*]->(b {name: 'B'}) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """OPTIONAL MATCH (a:node {name: 'A'}) + OPTIONAL MATCH (a)-[*]->(b {name: 'B'}) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) expected_result = [['A', 'B']] self.env.assertEquals(actual_result.result_set, expected_result) @@ -108,7 +131,9 @@ def test08_optional_source(self): # Test traversals with filters on variable-length edges def test09_filtered_edges(self): # Test an inline equality predicate - query = """MATCH (a)-[* {connects: 'BC'}]->(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[* {connects: 'BC'}]->(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" # The filter op should have been optimized out plan = redis_graph.execution_plan(query) self.env.assertNotIn("Filter", plan) @@ -117,7 +142,10 @@ def test09_filtered_edges(self): self.env.assertEquals(actual_result.result_set, expected_result) # Test a WHERE clause predicate - query = """MATCH (a)-[e*]->(b) WHERE e.connects IN ['BC', 'CD'] RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[e*]->(b) + WHERE e.connects IN ['BC', 'CD'] + RETURN a.name, b.name + ORDER BY a.name, b.name""" # The filter op should have been optimized out plan = redis_graph.execution_plan(query) self.env.assertNotIn("Filter", plan) @@ -128,7 +156,10 @@ def test09_filtered_edges(self): self.env.assertEquals(actual_result.result_set, expected_result) # Test a WHERE clause predicate with an OR condition - query = """MATCH (a)-[e*]->(b) WHERE e.connects = 'BC' OR e.connects = 'CD' RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[e*]->(b) + WHERE e.connects = 'BC' OR e.connects = 'CD' + RETURN a.name, b.name + ORDER BY a.name, b.name""" # The filter op should have been optimized out plan = redis_graph.execution_plan(query) self.env.assertNotIn("Filter", plan) @@ -137,7 +168,10 @@ def test09_filtered_edges(self): self.env.assertEquals(actual_result.result_set, expected_result) # Test the concatenation of multiple predicates - query = """MATCH (a)-[e*]->(b) WHERE e.connects IN ['AB', 'BC', 'CD'] AND e.connects <> 'CD' RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[e*]->(b) + WHERE e.connects IN ['AB', 'BC', 'CD'] AND e.connects <> 'CD' + RETURN a.name, b.name + ORDER BY a.name, b.name""" # The filter op should have been optimized out plan = redis_graph.execution_plan(query) self.env.assertNotIn("Filter", plan) @@ -148,7 +182,10 @@ def test09_filtered_edges(self): self.env.assertEquals(actual_result.result_set, expected_result) # Test the concatenation of AND and OR conditions - query = """MATCH (a)-[e*]->(b) WHERE e.connects IN ['AB', 'BC', 'CD'] AND (e.connects = 'AB' OR e.connects = 'BC') AND e.connects <> 'CD' RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[e*]->(b) + WHERE e.connects IN ['AB', 'BC', 'CD'] AND (e.connects = 'AB' OR e.connects = 'BC') AND e.connects <> 'CD' + RETURN a.name, b.name + ORDER BY a.name, b.name""" # The filter op should have been optimized out plan = redis_graph.execution_plan(query) self.env.assertNotIn("Filter", plan) @@ -159,7 +196,10 @@ def test09_filtered_edges(self): self.env.assertEquals(actual_result.result_set, expected_result) # Validate that WHERE clause predicates are applied to edges lower than the minHops value - query = """MATCH (a)-[e*2..]->(b) WHERE e.connects <> 'AB' RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a)-[e*2..]->(b) + WHERE e.connects <> 'AB' + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) expected_result = [['B', 'D']] self.env.assertEquals(actual_result.result_set, expected_result) @@ -178,7 +218,11 @@ def test10_filtered_edges_after_segment_change(self): # built in different ExecutionPlan segments. The segments must be # updated before cloning the Optional subtree, # or else the variable-length edge reference will be lost. - query = """MATCH (a {name: 'A'}) WITH a OPTIONAL MATCH (a)-[* {connects: 'AB'}]->(b) RETURN a.name, b.name ORDER BY a.name, b.name""" + query = """MATCH (a {name: 'A'}) + WITH a + OPTIONAL MATCH (a)-[* {connects: 'AB'}]->(b) + RETURN a.name, b.name + ORDER BY a.name, b.name""" actual_result = redis_graph.query(query) expected_result = [['A', 'B']] self.env.assertEquals(actual_result.result_set, expected_result) @@ -214,3 +258,89 @@ def test11_range_length_edges(self): for query, expected_result in query_to_expected_result.items(): actual_result = redis_graph.query(query) self.env.assertEquals(actual_result.result_set, expected_result) + + def test12_close_cycle(self): + # create a graph with a cycle in it + # a->d + # a->b->c->a + # + # variable length traversal should not get stuck in a cycle + # in addition, the traversal mustn't continue traversing once a cycle + # is detected, for the test graph that means that the path: a->b->c->a->d/b + # can't be matched + + # clear previous data + conn = self.env.getConnection() + conn.flushall() + + # create graph + query = """CREATE (a:A {v:'a'}), (b:B {v:'b'}), (c:C {v:'c'}), (d:D {v:'d'}), + (a)-[:R]->(b)-[:R]->(c)-[:R]->(a), + (a)-[:R]->(d)""" + + result = redis_graph.query(query) + self.env.assertEquals(result.nodes_created, 4) + self.env.assertEquals(result.relationships_created, 4) + + # perform variable length traverse from 'a' + query = """MATCH (a:A)-[*2..]->(z) + RETURN z.v + ORDER BY z.v""" + + result = redis_graph.query(query).result_set + self.env.assertEquals(len(result), 2) + self.env.assertEquals(result[0][0], 'a') + self.env.assertEquals(result[1][0], 'c') + + def test13_fanout(self): + # create a tree structure graph with a fanout of 3 + # root->a1 + # root->a2 + # root->a3 + # a1->b1 + # a1->b2 + # a1->b3 + # ... + # a3->d3 + + conn = self.env.getConnection() + conn.flushall() + + # create a tree structure with a fanout of 3 + q = """CREATE (root {l:0, id:0}) + WITH root + UNWIND range(0, 2) AS i + CREATE (root)-[:R]->(a{l:1, id:i}) + WITH collect(a) as nodes + UNWIND nodes AS n + UNWIND range(0, 2) AS i + CREATE (n)-[:R]->(a{l:2, id:n.id*3+i})""" + + res = redis_graph.query(q) + self.env.assertEquals(res.nodes_created, 13) + + # get all reachable nodes from root + q = """MATCH (root {l:0})-[*0..]->(n) + RETURN n.l, n.id + ORDER BY n.l, n.id""" + res = redis_graph.query(q).result_set + self.env.assertEquals(len(res), 13) + + # root + self.env.assertEquals(res[0][0], 0) + self.env.assertEquals(res[0][1], 0) + + # children of root + for i in range(3): + l = res[i+1][0] + identity = res[i+1][1] + self.env.assertEquals(l, 1) + self.env.assertEquals(identity, i) + + # grandchildren of root + for i in range(9): + l = res[i+4][0] + identity = res[i+4][1] + self.env.assertEquals(l, 2) + self.env.assertEquals(identity, i) + diff --git a/tests/flow/tests.sh b/tests/flow/tests.sh index a7b6c60600..442954ef2a 100755 --- a/tests/flow/tests.sh +++ b/tests/flow/tests.sh @@ -10,8 +10,10 @@ READIES=$ROOT/deps/readies export PYTHONUNBUFFERED=1 -VALGRIND_REDIS_VER=6.2 -SAN_REDIS_VER=6.2 +VG_REDIS_VER=7.2-rc3 +VG_REDIS_SUFFIX=7.2 +SAN_REDIS_VER=7.2-rc3 +SAN_REDIS_SUFFIX=7.2 cd $HERE @@ -68,6 +70,7 @@ help() { STATFILE=file Write test status (0|1) into `file` LIST=1 List all tests and exit + ENV_ONLY=1 Just start environment, run no tests V|VERBOSE=1 Print commands and Redis output LOG=1 Send results to log (even on single-test mode) KEEP=1 Do not remove intermediate files @@ -134,6 +137,8 @@ setup_rltest() { fi fi + RLTEST_ARGS+=" --enable-debug-command" + if [[ $RLTEST_VERBOSE == 1 ]]; then RLTEST_ARGS+=" -v" fi @@ -167,11 +172,11 @@ setup_clang_sanitizer() { RLTEST_SAN_ARGS="--sanitizer $SAN" if [[ $SAN == addr || $SAN == address ]]; then - REDIS_SERVER=${REDIS_SERVER:-redis-server-asan-$SAN_REDIS_VER} + REDIS_SERVER=${REDIS_SERVER:-redis-server-asan-$SAN_REDIS_SUFFIX} if ! command -v $REDIS_SERVER > /dev/null; then echo Building Redis for clang-asan ... - $READIES/bin/getredis --force -v $SAN_REDIS_VER --own-openssl --no-run \ - --suffix asan --clang-asan --clang-san-blacklist $ignorelist + V="$VERBOSE" runn $READIES/bin/getredis --force -v $SAN_REDIS_VER --own-openssl --no-run \ + --suffix asan-${SAN_REDIS_SUFFIX} --clang-asan --clang-san-blacklist $ignorelist fi export ASAN_OPTIONS="detect_odr_violation=0:halt_on_error=0:detect_leaks=1" @@ -202,14 +207,23 @@ setup_redis_server() { #---------------------------------------------------------------------------------------------- setup_valgrind() { - REDIS_SERVER=${REDIS_SERVER:-redis-server-vg} + REDIS_SERVER=${REDIS_SERVER:-redis-server-vg-$VG_REDIS_SUFFIX} if ! is_command $REDIS_SERVER; then echo Building Redis for Valgrind ... - $READIES/bin/getredis -v $VALGRIND_REDIS_VER --valgrind --suffix vg + V="$VERBOSE" runn $READIES/bin/getredis -v ${VG_REDIS_VER} --valgrind --suffix vg-${VG_REDIS_VER} fi + if [[ $VG_LEAKS == 0 ]]; then + VG_LEAK_CHECK=no + RLTEST_VG_NOLEAKS="--vg-no-leakcheck" + else + VG_LEAK_CHECK=full + RLTEST_VG_NOLEAKS="" + fi # RLTest reads this VG_OPTIONS="\ + -q \ + --leak-check=$VG_LEAK_CHECK \ --show-reachable=no \ --track-origins=yes \ --show-possibly-lost=no" @@ -217,18 +231,12 @@ setup_valgrind() { # To generate supressions and/or log to file # --gen-suppressions=all --log-file=valgrind.log - if [[ $VG_LEAKS == 0 ]]; then - RLTEST_VG_ARGS+=" --vg-no-leakcheck" - VG_OPTIONS+=" --leak-check=no" - else - VG_OPTIONS+=" --leak-check=full" - fi - VALGRIND_SUPRESSIONS=$ROOT/tests/memcheck/valgrind.supp RLTEST_VG_ARGS+="\ --use-valgrind \ --vg-verbose \ + $RLTEST_VG_NOLEAKS \ --vg-no-fail-on-errors \ --vg-suppressions $VALGRIND_SUPRESSIONS" @@ -250,6 +258,48 @@ setup_coverage() { #---------------------------------------------------------------------------------------------- +run_env() { + rltest_config=$(mktemp "${TMPDIR:-/tmp}/rltest.XXXXXXX") + rm -f $rltest_config + cat <<-EOF > $rltest_config + --env-only + --oss-redis-path=$REDIS_SERVER + --module $MODULE + --module-args '$MODARGS' + $RLTEST_ARGS + $RLTEST_TEST_ARGS + $RLTEST_PARALLEL_ARG + $RLTEST_VG_ARGS + $RLTEST_SAN_ARGS + $RLTEST_COV_ARGS + + EOF + + # Use configuration file in the current directory if it exists + if [[ -n $CONFIG_FILE && -e $CONFIG_FILE ]]; then + cat $CONFIG_FILE >> $rltest_config + fi + + if [[ $VERBOSE == 1 || $NOP == 1 ]]; then + echo "RLTest configuration:" + cat $rltest_config + [[ -n $VG_OPTIONS ]] && { echo "VG_OPTIONS: $VG_OPTIONS"; echo; } + fi + + local E=0 + if [[ $NOP != 1 ]]; then + { $OP python3 -m RLTest @$rltest_config; (( E |= $? )); } || true + else + $OP python3 -m RLTest @$rltest_config + fi + + [[ $KEEP != 1 ]] && rm -f $rltest_config + + return $E +} + +#---------------------------------------------------------------------------------------------- + run_tests() { local title="$1" shift @@ -257,7 +307,7 @@ run_tests() { if [[ -n $GITHUB_ACTIONS ]]; then echo "::group::$title" else - $READIES/bin/sep -0 + $READIES/bin/sep1 -0 printf "Running $title:\n\n" fi fi @@ -275,6 +325,7 @@ run_tests() { $RLTEST_PARALLEL_ARG $RLTEST_VG_ARGS $RLTEST_SAN_ARGS + $RLTEST_COV_ARGS EOF else @@ -324,6 +375,11 @@ run_tests() { fi fi + # Use configuration file in the current directory if it exists + if [[ -n $CONFIG_FILE && -e $CONFIG_FILE ]]; then + cat $CONFIG_FILE >> $rltest_config + fi + if [[ $VERBOSE == 1 || $NOP == 1 ]]; then echo "RLTest configuration:" cat $rltest_config @@ -374,6 +430,8 @@ EXT_PORT=${EXT_PORT:-6379} PID=$$ OS=$($READIES/bin/platform --os) +ARCH=$($READIES/bin/platform --arch) +OSNICK=$($READIES/bin/platform --osnick) #---------------------------------------------------------------------------------- Tests scope @@ -421,8 +479,8 @@ if [[ $PLATFORM_MODE == 1 ]]; then CLEAR_LOGS=0 COLLECT_LOGS=1 NOFAIL=1 - STATFILE=$ROOT/bin/artifacts/tests/status fi +STATFILE=${STATFILE:-$ROOT/bin/artifacts/tests/status} #---------------------------------------------------------------------------------- Parallelism @@ -474,10 +532,14 @@ if [[ $VERBOSE == 1 ]]; then fi RLTEST_LOG=${RLTEST_LOG:-$LOG} -#if [[ $LOG == 1 ]]; then -# echo "Log=1!" -# RLTEST_LOG=1 -#fi + +if [[ $COV == 1 ]]; then + setup_coverage +fi + +if [[ -n $REDIS_PORT ]]; then + RLTEST_ARGS+="--redis-port $REDIS_PORT" +fi [[ $UNIX == 1 ]] && RLTEST_ARGS+=" --unix" [[ $RANDPORTS == 1 ]] && RLTEST_ARGS+=" --randomize-ports" @@ -498,8 +560,11 @@ if [[ $RLEC != 1 ]]; then setup_redis_server fi -if [[ $COV == 1 ]]; then - setup_coverage +#------------------------------------------------------------------------------------- Env only + +if [[ $ENV_ONLY == 1 ]]; then + run_env + exit 0 fi #-------------------------------------------------------------------------------- Running tests @@ -555,8 +620,6 @@ if [[ $NOP != 1 ]]; then fi if [[ $COLLECT_LOGS == 1 ]]; then - ARCH=$($READIES/bin/platform --arch) - OSNICK=$($READIES/bin/platform --osnick) cd $ROOT mkdir -p bin/artifacts/tests if [[ $GEN == 1 || $AOF == 1 ]]; then @@ -568,7 +631,7 @@ if [[ $COLLECT_LOGS == 1 ]]; then fi if [[ -n $STATFILE ]]; then - mkdir -p $(dirname $STATFILE) + mkdir -p "$(dirname "$STATFILE")" if [[ -f $STATFILE ]]; then (( E |= $(cat $STATFILE || echo 1) )) || true fi diff --git a/tests/requirements.txt b/tests/requirements.txt index 0bc0d78587..a56ab3446f 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,9 +1,9 @@ -git+https://github.com/redis/redis-py.git@a246f40#egg=redis -redisgraph-bulk-loader~=0.10.2 +# redis~=4.5.5 +# RLTest~=0.6.0 +# ramp-packer~=2.5.4 + +redisgraph-bulk-loader~=0.12.3 click behave~=1.2 pathos~=0.2.8 - -RLTest~=0.5.12 -ramp-packer~=2.5.2 diff --git a/tests/tck/features/clauses/merge/Merge5.feature b/tests/tck/features/clauses/merge/Merge5.feature index cc0be9da7b..f77bae441c 100644 --- a/tests/tck/features/clauses/merge/Merge5.feature +++ b/tests/tck/features/clauses/merge/Merge5.feature @@ -389,7 +389,6 @@ Feature: Merge5 - Merge relationships And the side effects should be: | +relationships | 1 | - @skip Scenario: [20] Do not match on deleted entities Given an empty graph And having executed: @@ -418,7 +417,6 @@ Feature: Merge5 - Merge relationships | +relationships | 2 | | -relationships | 4 | | +properties | 1 | - | -properties | 2 | @skip Scenario: [21] Do not match on deleted relationships diff --git a/tests/tck/features/expressions/typeConversion/TypeConversion4.feature b/tests/tck/features/expressions/typeConversion/TypeConversion4.feature index 4af8ab79ce..160f45fd5e 100644 --- a/tests/tck/features/expressions/typeConversion/TypeConversion4.feature +++ b/tests/tck/features/expressions/typeConversion/TypeConversion4.feature @@ -152,6 +152,7 @@ Feature: TypeConversion4 - To String | 'x' | And no side effects + @skip Scenario Outline: [10] Fail `toString()` on invalid types #Example: Given an empty graph And having executed: diff --git a/tests/unit/test_algebraic_expression.c b/tests/unit/test_algebraic_expression.c index 72864f35a9..789a4f5771 100644 --- a/tests/unit/test_algebraic_expression.c +++ b/tests/unit/test_algebraic_expression.c @@ -10,6 +10,7 @@ #include "src/redismodule.h" #include "src/graph/graph.h" #include "src/util/rmalloc.h" +#include "src/util/thpool/pools.h" #include "src/graph/query_graph.h" #include "src/graph/graphcontext.h" #include "src/util/simple_timer.h" @@ -61,21 +62,20 @@ const char *query_return_last_edge = "MATCH (p:Person)-[ef:friend]->(f:Person)-[ev:visit]->(c:City)-[ew:war]->(e:City) RETURN ew"; static void _fake_graph_context() { - GraphContext *gc = (GraphContext *)malloc(sizeof(GraphContext)); + GraphContext *gc = (GraphContext *)calloc(1, sizeof(GraphContext)); gc->g = Graph_New(16, 16); - gc->ref_count = 1; - gc->index_count = 0; - gc->graph_name = strdup("G"); - gc->attributes = raxNew(); - pthread_rwlock_init(&gc->_attribute_rwlock, NULL); - gc->string_mapping = (char **)array_new(char *, 64); - gc->node_schemas = (Schema **)array_new(Schema *, GRAPH_DEFAULT_LABEL_CAP); - gc->relation_schemas = (Schema **)array_new(Schema *, GRAPH_DEFAULT_RELATION_TYPE_CAP); - gc->cache = NULL; - gc->slowlog = NULL; - gc->encoding_context = NULL; - gc->decoding_context = NULL; + + gc->ref_count = 1; + gc->index_count = 0; + gc->graph_name = strdup("G"); + gc->attributes = raxNew(); + gc->string_mapping = (char**)array_new(char*, 64); + gc->node_schemas = (Schema**)array_new(Schema*, GRAPH_DEFAULT_LABEL_CAP); + gc->relation_schemas = (Schema**)array_new(Schema*, GRAPH_DEFAULT_RELATION_TYPE_CAP); + gc->queries_log = QueriesLog_New(); + + pthread_rwlock_init(&gc->_attribute_rwlock, NULL); GraphContext_AddSchema(gc, "Person", SCHEMA_NODE); GraphContext_AddSchema(gc, "City", SCHEMA_NODE); @@ -107,10 +107,12 @@ static void _build_graph() { Graph_AllocateNodes(g, node_count); for(int i = 0; i < person_count; i++) { + n = GE_NEW_NODE(); Graph_CreateNode(g, &n, person_label, 1); } for(int i = 0; i < city_count; i++) { + n = GE_NEW_NODE(); Graph_CreateNode(g, &n, city_label, 1); } @@ -309,6 +311,9 @@ void setup() { // Use the malloc family for allocations Alloc_Reset(); + // Initialize the thread pool. + TEST_ASSERT(ThreadPools_CreatePools(1, 1, 2)); + // Initialize GraphBLAS. GrB_Info info; info = GrB_init(GrB_NONBLOCKING); @@ -1814,3 +1819,4 @@ TEST_LIST = { {"LocateOperand", test_LocateOperand}, {NULL, NULL} }; + diff --git a/tests/unit/test_all_paths.c b/tests/unit/test_all_paths.c index 493e251108..200b8d207c 100644 --- a/tests/unit/test_all_paths.c +++ b/tests/unit/test_all_paths.c @@ -23,6 +23,7 @@ static Graph *BuildGraph() { Graph *g = Graph_New(nodeCount, nodeCount); int relation = Graph_AddRelationType(g); for(int i = 0; i < 4; i++) { + n = GE_NEW_NODE(); Graph_CreateNode(g, &n, NULL, 0); } @@ -91,16 +92,16 @@ void tearDown() { void test_noPaths() { Graph *g = BuildGraph(); - NodeID srcNodeID = 0; + NodeID src_id = 0; unsigned int minLen = 999; unsigned int maxLen = minLen + 1; Node src; - Graph_GetNode(g, srcNodeID, &src); + Graph_GetNode(g, src_id, &src); int relationships[] = {GRAPH_NO_RELATION}; - AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, GRAPH_EDGE_DIR_OUTGOING, minLen, - maxLen, NULL, NULL, 0, false); + AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, + GRAPH_EDGE_DIR_OUTGOING, minLen, maxLen, NULL, NULL, 0, false); Path *p = AllPathsCtx_NextPath(ctx); TEST_ASSERT(p == NULL); @@ -112,15 +113,15 @@ void test_noPaths() { void test_longest_Paths() { Graph *g = BuildGraph(); - NodeID srcNodeID = 0; + NodeID src_id = 0; Node src; - Graph_GetNode(g, srcNodeID, &src); + Graph_GetNode(g, src_id, &src); unsigned int minLen = 0; unsigned int maxLen = UINT_MAX - 2; int relationships[] = {GRAPH_NO_RELATION}; - AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, GRAPH_EDGE_DIR_OUTGOING, minLen, - maxLen, NULL, NULL, 0, false); + AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, + GRAPH_EDGE_DIR_OUTGOING, minLen, maxLen, NULL, NULL, 0, false); Path *path; unsigned int longestPath = 0; @@ -139,17 +140,17 @@ void test_longest_Paths() { void test_upToThreeLegsPaths() { Graph *g = BuildGraph(); - NodeID srcNodeID = 0; + NodeID src_id = 0; Node src; - Graph_GetNode(g, srcNodeID, &src); + Graph_GetNode(g, src_id, &src); Path *path = NULL; unsigned int minLen = 0; unsigned int maxLen = 3; uint pathsCount = 0; int relationships[] = {GRAPH_NO_RELATION}; - AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, GRAPH_EDGE_DIR_OUTGOING, minLen, - maxLen, NULL, NULL, 0, false); + AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, + GRAPH_EDGE_DIR_OUTGOING, minLen, maxLen, NULL, NULL, 0, false); /* Connections: * 0 -> 1 @@ -216,16 +217,16 @@ void test_upToThreeLegsPaths() { void test_twoLegPaths() { Graph *g = BuildGraph(); - NodeID srcNodeID = 0; + NodeID src_id = 0; Node src; Path *path = NULL; - Graph_GetNode(g, srcNodeID, &src); + Graph_GetNode(g, src_id, &src); unsigned int minLen = 2; unsigned int maxLen = 2; unsigned int pathsCount = 0; int relationships[] = {GRAPH_NO_RELATION}; - AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, GRAPH_EDGE_DIR_OUTGOING, minLen, - maxLen, NULL, NULL, 0, false); + AllPathsCtx *ctx = AllPathsCtx_New(&src, NULL, g, relationships, 1, + GRAPH_EDGE_DIR_OUTGOING, minLen, maxLen, NULL, NULL, 0, false); /* Connections: * 0 -> 1 * 0 -> 2 @@ -279,16 +280,16 @@ void test_destinationSpecificPaths() { Graph *g = BuildGraph(); - NodeID srcNodeID = 0; + NodeID src_id = 0; Node src; Path *path = NULL; - Graph_GetNode(g, srcNodeID, &src); + Graph_GetNode(g, src_id, &src); unsigned int minLen = 0; unsigned int maxLen = UINT_MAX - 2; unsigned int pathsCount = 0; int relationships[] = {GRAPH_NO_RELATION}; - AllPathsCtx *ctx = AllPathsCtx_New(&src, &src, g, relationships, 1, GRAPH_EDGE_DIR_OUTGOING, - minLen, maxLen, NULL, NULL, 0, false); + AllPathsCtx *ctx = AllPathsCtx_New(&src, &src, g, relationships, 1, + GRAPH_EDGE_DIR_OUTGOING, minLen, maxLen, NULL, NULL, 0, false); while((path = AllPathsCtx_NextPath(ctx))) { TEST_ASSERT(pathsCount < 5); diff --git a/tests/unit/test_circular_buffer.c b/tests/unit/test_circular_buffer.c index a3600ab0f1..796e1dba0c 100644 --- a/tests/unit/test_circular_buffer.c +++ b/tests/unit/test_circular_buffer.c @@ -5,6 +5,7 @@ */ #include "src/util/rmalloc.h" +#include "src/util/arr.h" #include "src/util/circular_buffer.h" void setup() { @@ -27,8 +28,7 @@ void test_CircularBufferInit(void) { TEST_ASSERT(CircularBuffer_Full(buff) == false); // clean up - CircularBuffer_Free(&buff); - TEST_ASSERT(buff == NULL); + CircularBuffer_Free(buff); } void test_CircularBufferPopulation(void) { @@ -37,7 +37,7 @@ void test_CircularBufferPopulation(void) { CircularBuffer buff = CircularBuffer_New(sizeof(int), cap); // remove item from an empty buffer should report failure - TEST_ASSERT(CircularBuffer_Remove(buff, &n) == 0); + TEST_ASSERT(CircularBuffer_Read(buff, &n) == NULL); //-------------------------------------------------------------------------- // fill buffer @@ -60,20 +60,20 @@ void test_CircularBufferPopulation(void) { //-------------------------------------------------------------------------- for(int i = 0; i < cap; i++) { // get item from buffer - TEST_ASSERT(CircularBuffer_Remove(buff, &n) == 1); + TEST_ASSERT(CircularBuffer_Read(buff, &n) != NULL); // validate item's value TEST_ASSERT(n == i); } TEST_ASSERT(CircularBuffer_Empty(buff) == true); - // forcefully try to remove an item from an empty buffer + // forcefully try to read an item from an empty buffer for(int i = 0; i < 10; i++) { - TEST_ASSERT(CircularBuffer_Remove(buff, &n) == 0); + TEST_ASSERT(CircularBuffer_Read(buff, &n) == NULL); } // clean up - CircularBuffer_Free(&buff); + CircularBuffer_Free(buff); } void test_CircularBuffer_Circularity(void) { @@ -94,32 +94,104 @@ void test_CircularBuffer_Circularity(void) { TEST_ASSERT(CircularBuffer_Add(buff, &n) == 0); // removing an item should make space in the buffer - TEST_ASSERT(CircularBuffer_Remove(buff, &n) == 1); + TEST_ASSERT(CircularBuffer_Read(buff, &n) != NULL); TEST_ASSERT(CircularBuffer_Add(buff, &n) == 1); //-------------------------------------------------------------------------- // clear buffer //-------------------------------------------------------------------------- + while(CircularBuffer_Empty(buff) == false) { - CircularBuffer_Remove(buff, &n); + CircularBuffer_Read(buff, &n); } // add/remove elements cycling through the buffer multiple times for(int i = 0; i < cap * 4; i++) { TEST_ASSERT(CircularBuffer_Add(buff, &i) == 1); - TEST_ASSERT(CircularBuffer_Remove(buff, &n) == 1); + TEST_ASSERT(CircularBuffer_Read(buff, &n) != NULL); TEST_ASSERT(n == i); } TEST_ASSERT(CircularBuffer_Empty(buff) == true); // clean up - CircularBuffer_Free(&buff); + CircularBuffer_Free(buff); +} + +void test_CircularBuffer_free(void) { + //-------------------------------------------------------------------------- + // fill a buffer of size 16 with int * + //-------------------------------------------------------------------------- + + uint cap = 16; + CircularBuffer buff = CircularBuffer_New(sizeof(int64_t *), cap); + for(int i = 0; i < cap; i++) { + int64_t *j = malloc(sizeof(int64_t)); + CircularBuffer_Add(buff, (void*)&j); + } + + //-------------------------------------------------------------------------- + // free the buffer + //-------------------------------------------------------------------------- + + for(int i = 0; i < cap; i++) { + int64_t *item; + CircularBuffer_Read(buff, &item); + free(item); + } + + CircularBuffer_Free(buff); +} + +void test_CircularBuffer_Reserve(void) { + + // ------------------------------------------------------------------------- + // fill a buffer of size 16 with 32 integers + // ------------------------------------------------------------------------- + + uint cap = 16; + CircularBuffer buff = CircularBuffer_New(sizeof(int), cap); + for(int i = 0; i < 2 * cap; i++) { + int *item = CircularBuffer_Reserve(buff); + *item = i; + } + + // make sure item count did not exceeded buffer cap + TEST_ASSERT(CircularBuffer_ItemCount(buff) == CircularBuffer_Cap(buff)); + + // ------------------------------------------------------------------------- + // assert override correctness + // ------------------------------------------------------------------------- + + for(uint i = 0; i < 16; i++) { + int item; + void *res = CircularBuffer_Read(buff, &item); + TEST_ASSERT(res != NULL); + TEST_ASSERT(item == (i + 16)); + TEST_ASSERT(CircularBuffer_ItemCount(buff) == 16-i-1); + } + + // ------------------------------------------------------------------------- + // free the buffer + // ------------------------------------------------------------------------- + + CircularBuffer_Free(buff); +} + +void _assert_val_cb +( + const void *item, + void *user_data +) { + int n = array_pop((int *)user_data); + TEST_ASSERT(n == *(int *)item); } TEST_LIST = { {"CircularBuffer_Init", test_CircularBufferInit}, {"CircularBuffer_Population", test_CircularBufferPopulation}, {"CircularBuffer_Circularity", test_CircularBuffer_Circularity}, + {"CircularBuffer_Free", test_CircularBuffer_free}, + {"CircularBuffer_Reserve", test_CircularBuffer_Reserve}, {NULL, NULL} }; diff --git a/tests/unit/test_cron.c b/tests/unit/test_cron.c index 258b2d5165..08e8c13c80 100644 --- a/tests/unit/test_cron.c +++ b/tests/unit/test_cron.c @@ -4,7 +4,7 @@ * the Server Side Public License v1 (SSPLv1). */ -#include "src/util/cron.h" +#include "src/cron/cron.h" #include "src/util/rmalloc.h" #include @@ -243,8 +243,8 @@ static void test_cronExec() { AddTaskData add_task_data = _AddTaskData_New(add_task, (void *)&Z); AddTaskData mul_task_data = _AddTaskData_New(mul_task, (void *)&Y); - Cron_AddTask(15, _AddTaskData_Execute, &add_task_data); - Cron_AddTask(5, _AddTaskData_Execute, &mul_task_data); + Cron_AddTask(15, _AddTaskData_Execute, NULL, &add_task_data); + Cron_AddTask(5, _AddTaskData_Execute, NULL, &mul_task_data); _AddTaskData_Wait(add_task_data); _AddTaskData_Wait(mul_task_data); @@ -267,7 +267,8 @@ static void test_cronAbort() { AddTaskData data = _AddTaskData_New(add_task, (void *)&Y); // issue task X += 2 - CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, &data); + CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, NULL, + &data); // abort task Cron_AbortTask(task_handle); @@ -294,7 +295,8 @@ static void test_cronLateAbort() { AddTaskData data = _AddTaskData_New(add_task, (void *)&Y); // issue task X += 2 - CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, &data); + CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, NULL, + &data); _AddTaskData_Wait(data); _AddTaskData_Free(data); @@ -317,7 +319,8 @@ static void test_MultiAbort() { AddTaskData data = _AddTaskData_New(add_task, (void *)&Y); // issue task X += 2 - CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, &data); + CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, NULL, + &data); // abort task multiple times, should not crash or hang for(int i = 0; i < 20; i++) { @@ -346,7 +349,8 @@ static void test_abortNoneExistingTask() { AddTaskData data = _AddTaskData_New(add_task, (void*)&Y); // issue task X += 2 - CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, &data); + CronTaskHandle task_handle = Cron_AddTask(15, _AddTaskData_Execute, NULL, + &data); CronTaskHandle none_existing_task_handle = task_handle + 1; // abort task, should not crash hang @@ -363,32 +367,28 @@ static void test_abortNoneExistingTask() { static void test_AbortRunningTask() { // issue a long running task ~100ms // issue abort 20ms into execution - // validate call to Cron_AbortTask returns in less than ~10 ms + // validate call to Cron_AbortTask returns after task compelted int ms = 100; AddTaskData data = _AddTaskData_New(long_running_task, (void*)&ms); // issue a long running task, task will sleep for 100 'ms' - CronTaskHandle task_handle = Cron_AddTask(0, _AddTaskData_Execute, &data); + CronTaskHandle task_handle = Cron_AddTask(0, _AddTaskData_Execute, NULL, + &data); _AddTaskData_WaitForRunning(data); clock_t t = clock(); // start timer // the task should be already running - // abort the task, call should return immediately without waiting - // until the task completed. + // abort the task, call should return until the task completed. Cron_AbortTask(task_handle); - // As the function call should've been as fast as possible, the - // task is expected to not have yet been completed. - TEST_ASSERT(!_AddTaskData_HasCompleted(data)); t = clock() - t; // stop timer double time_taken_sec = ((double)t)/CLOCKS_PER_SEC; - // expecting Cron_AbortTask to return before at-most 10 ms - TEST_ASSERT(time_taken_sec < 0.01); + // expecting Cron_AbortTask to return after task completed + TEST_ASSERT(time_taken_sec >= 0.1); - _AddTaskData_WaitForCompletion(data); _AddTaskData_Free(data); } diff --git a/tests/unit/test_execution_plan_clone.c b/tests/unit/test_execution_plan_clone.c index 7ad5dfc05a..80c2d48ae7 100644 --- a/tests/unit/test_execution_plan_clone.c +++ b/tests/unit/test_execution_plan_clone.c @@ -8,6 +8,7 @@ #include "src/query_ctx.h" #include "src/util/rmalloc.h" #include "src/arithmetic/funcs.h" +#include "src/util/thpool/pools.h" #include "src/procedures/procedure.h" #include "src/execution_plan/execution_plan_clone.h" @@ -32,25 +33,24 @@ static void build_ast_and_plan ctx->query_data.query_no_params = query; cypher_parse_result_t *parse_result = cypher_parse(query, NULL, NULL, CYPHER_PARSE_ONLY_STATEMENTS); *ast = AST_Build(parse_result); - *plan = NewExecutionPlan(); + *plan = ExecutionPlan_FromTLS_AST(); } static void _fake_graph_context() { - GraphContext *gc = (GraphContext *)malloc(sizeof(GraphContext)); + GraphContext *gc = (GraphContext *)calloc(1, sizeof(GraphContext)); gc->g = Graph_New(16, 16); - gc->ref_count = 1; - gc->index_count = 0; - gc->graph_name = strdup("G"); - gc->attributes = raxNew(); - pthread_rwlock_init(&gc->_attribute_rwlock, NULL); - gc->string_mapping = (char **)array_new(char *, 64); - gc->node_schemas = (Schema **)array_new(Schema *, GRAPH_DEFAULT_LABEL_CAP); - gc->relation_schemas = (Schema **)array_new(Schema *, GRAPH_DEFAULT_RELATION_TYPE_CAP); - gc->cache = NULL; - gc->slowlog = NULL; - gc->encoding_context = NULL; - gc->decoding_context = NULL; + + gc->ref_count = 1; + gc->index_count = 0; + gc->graph_name = strdup("G"); + gc->attributes = raxNew(); + gc->string_mapping = (char**)array_new(char*, 64); + gc->node_schemas = (Schema**)array_new(Schema*, GRAPH_DEFAULT_LABEL_CAP); + gc->relation_schemas = (Schema**)array_new(Schema*, GRAPH_DEFAULT_RELATION_TYPE_CAP); + gc->queries_log = QueriesLog_New(); + + pthread_rwlock_init(&gc->_attribute_rwlock, NULL); QueryCtx_SetGraphCtx(gc); } @@ -99,9 +99,17 @@ static void validate_query_plans_clone } void setup() { + // skip if memory sanitizer is enabled + if(getenv("SANITIZER") != NULL || getenv("VALGRIND") != NULL) { + exit(0); + } + // use the malloc family for allocations Alloc_Reset(); + // Initialize the thread pool. + TEST_ASSERT(ThreadPools_CreatePools(1, 1, 2)); + // init query context TEST_ASSERT(QueryCtx_Init()); diff --git a/tests/unit/test_filter_tree.c b/tests/unit/test_filter_tree.c index 139f5d0a8d..868b5015e4 100644 --- a/tests/unit/test_filter_tree.c +++ b/tests/unit/test_filter_tree.c @@ -4,10 +4,10 @@ * the Server Side Public License v1 (SSPLv1). */ -#include "src/errors.h" #include "src/query_ctx.h" #include "src/util/arr.h" #include "src/util/rmalloc.h" +#include "src/errors/errors.h" #include "src/filter_tree/filter_tree.h" #include "src/ast/ast_build_filter_tree.h" #include "src/arithmetic/funcs.h" diff --git a/tests/unit/test_graph.c b/tests/unit/test_graph.c index 27cbc90b56..e79c7d81f1 100644 --- a/tests/unit/test_graph.c +++ b/tests/unit/test_graph.c @@ -39,7 +39,10 @@ void _test_node_creation(Graph *g, size_t node_count) { // Create nodes. Node n; - for(uint i = 0; i < node_count; i++) Graph_CreateNode(g, &n, NULL, 0); + for(uint i = 0; i < node_count; i++) { + n = GE_NEW_NODE(); + Graph_CreateNode(g, &n, NULL, 0); + } // Validate nodes creation. RG_Matrix adj = Graph_GetAdjacencyMatrix(g, false); @@ -78,7 +81,10 @@ void benchmark_node_creation_with_labels() { // Create N nodes with labels. for(int i = 0; i < samples; i++) { simple_tic(tic); - for(unsigned int j = 0; j < n; j++) Graph_CreateNode(g, &node, NULL, 0); + for(unsigned int j = 0; j < n; j++) { + node = GE_NEW_NODE(); + Graph_CreateNode(g, &node, NULL, 0); + } timings[i] = simple_toc(tic); printf("%zu Nodes created, time: %.6f sec\n", n, timings[i]); @@ -115,7 +121,10 @@ void benchmark_node_creation_no_labels() { for(int i = 0; i < samples; i++) { // Create N nodes, don't use labels. simple_tic(tic); - for(int j = 0; j < n; j++) Graph_CreateNode(g, &node, NULL, 0); + for(int j = 0; j < n; j++) { + node = GE_NEW_NODE(); + Graph_CreateNode(g, &node, NULL, 0); + } timings[i] = simple_toc(tic); printf("%zu Nodes created, time: %.6f sec\n", n, timings[i]); if(timings[i] > threshold) outliers++; @@ -151,7 +160,10 @@ void benchmark_edge_creation_with_relationships() { // Introduce relations types. for(int i = 0; i < relation_count; i++) Graph_AddRelationType(g); - for(int i = 0; i < node_count; i++) Graph_CreateNode(g, &node, NULL, 0); + for(int i = 0; i < node_count; i++) { + node = GE_NEW_NODE(); + Graph_CreateNode(g, &node, NULL, 0); + } for(int i = 0; i < samples; i++) { // Describe connections; // Node I is connected to Node I+1, @@ -255,7 +267,10 @@ void test_removeNodes() { Node node; Edge edge; - for(int i = 0; i < 3; i++) Graph_CreateNode(g, &node, NULL, 0); + for(int i = 0; i < 3; i++) { + node = GE_NEW_NODE(); + Graph_CreateNode(g, &node, NULL, 0); + } int r = Graph_AddRelationType(g); /* Connections: @@ -294,7 +309,7 @@ void test_removeNodes() { uint edge_count = array_len(edges); TEST_ASSERT(edge_count == 2); - Graph_DeleteEdges(g, edges, array_len(edges)); + Graph_DeleteEdges(g, edges, edge_count); Graph_GetNode(g, 0, &node); Graph_DeleteNodes(g, &node, 1); @@ -319,7 +334,10 @@ void test_getNode() { Graph_AcquireWriteLock(g); { - for(int i = 0 ; i < nodeCount; i++) Graph_CreateNode(g, &n, NULL, 0); + for(int i = 0 ; i < nodeCount; i++) { + n = GE_NEW_NODE(); + Graph_CreateNode(g, &n, NULL, 0); + } } Graph_ReleaseLock(g); @@ -349,7 +367,10 @@ void test_getEdge() { Graph *g = Graph_New(nodeCount, nodeCount); Graph_AcquireWriteLock(g); - for(int i = 0; i < nodeCount; i++) Graph_CreateNode(g, &n, NULL, 0); + for(int i = 0; i < nodeCount; i++) { + n = GE_NEW_NODE(); + Graph_CreateNode(g, &n, NULL, 0); + } for(int i = 0; i < relationCount; i++) relations[i] = Graph_AddRelationType(g); /* Connect nodes: diff --git a/tests/unit/test_leak.c b/tests/unit/test_leak.c index c9ee3bd1b8..34a03dd75f 100644 --- a/tests/unit/test_leak.c +++ b/tests/unit/test_leak.c @@ -6,7 +6,6 @@ #include #include - #include "acutest.h" //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unit/test_num.c b/tests/unit/test_num.c deleted file mode 100644 index 3229c3a8b9..0000000000 --- a/tests/unit/test_num.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Redis Ltd. 2018 - present - * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or - * the Server Side Public License v1 (SSPLv1). - */ - -#include "src/util/num.h" -#include - -#include "acutest.h" - -#define TYPE(width) uint##width##_t -#define ADD(width) checked_add_u##width - -#define DEFINE_TEST(name, width) \ -void test_NumOverflow_CheckedAddU##width(void) { \ - TYPE(width) out = 0; \ - static const TYPE(width) MAX = UINT##width##_MAX; \ - bool is_ok = ADD(width)(MAX - 1, 1, &out); \ - /* The value hasn't overflown. */ \ - TEST_ASSERT(out == MAX); \ - TEST_ASSERT(is_ok == true); \ - is_ok = ADD(width)(MAX - 1, 2, &out); \ - /* The value has overflown. */ \ - TEST_ASSERT(out == 0); \ - TEST_ASSERT(is_ok == false); \ - is_ok = ADD(width)(MAX - 1, 100, &out); \ - /* The value has overflown. */ \ - TEST_ASSERT(out == 98); \ - TEST_ASSERT(is_ok == false); \ -} - -DEFINE_TEST(test_NumOverflow_CheckedAddU8, 8); -DEFINE_TEST(test_NumOverflow_CheckedAddU16, 16); -DEFINE_TEST(test_NumOverflow_CheckedAddU32, 32); -DEFINE_TEST(test_NumOverflow_CheckedAddU64, 64); - - -TEST_LIST = { - {"NumOverflow_CheckedAddU8", test_NumOverflow_CheckedAddU8}, - {"NumOverflow_CheckedAddU16", test_NumOverflow_CheckedAddU16}, - {"NumOverflow_CheckedAddU32", test_NumOverflow_CheckedAddU32}, - {"NumOverflow_CheckedAddU64", test_NumOverflow_CheckedAddU64}, - {NULL, NULL} -}; diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 54ba549be6..15c496eef8 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -359,8 +359,8 @@ void test_path() { ns[i].id = i; es[i].id = i; - es[i].srcNodeID = i; - es[i].destNodeID = i + 1; + es[i].src_id = i; + es[i].dest_id = i + 1; } ns[2].id = 2;