First commit

This commit is contained in:
Leonardo Bonati
2021-12-08 20:17:46 +00:00
commit 60dffad583
2923 changed files with 463894 additions and 0 deletions

25
setup/dbaas/.gitattributes vendored Normal file
View File

@@ -0,0 +1,25 @@
# https://help.github.com/articles/dealing-with-line-endings/
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized
# and converted to native line endings on checkout.
*.c text diff=cpp
*.cpp text diff=cpp
*.css text
*.go text diff=golang
*.htm text diff=html
*.html text diff=html
*.java text diff=java
*.js text
*.jsp text
*.less text
*.properties text
*.py text diff=python
*.sql text
*.xml text
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

3
setup/dbaas/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# documentation
.tox
docs/_build/

4
setup/dbaas/.gitreview Normal file
View File

@@ -0,0 +1,4 @@
[gerrit]
host=gerrit.o-ran-sc.org
port=29418
project=ric-plt/dbaas.git

View File

@@ -0,0 +1,16 @@
---
version: 2
formats:
- htmlzip
build:
image: latest
python:
version: 3.7
install:
- requirements: docs/requirements-docs.txt
sphinx:
configuration: docs/conf.py

68
setup/dbaas/INFO.yaml Normal file
View File

@@ -0,0 +1,68 @@
---
project: 'ric_plt_dbaas'
project_creation_date: '2019-11-08'
project_category: ''
lifecycle_state: 'Incubation'
project_lead: &oran_ric_plt_dbaas_ptl
name: 'Thoralf Czichy'
email: 'thoralf.czichy@nokia.com'
id: 'czichy'
company: 'Nokia'
timezone: 'America/New_York'
primary_contact: *oran_ric_plt_dbaas_ptl
issue_tracking:
type: 'jira'
url: 'https://jira.o-ran-sc.org/projects/'
key: 'ric_plt_dbaas'
mailing_list:
type: 'groups.io'
url: 'technical-discuss@lists.o-ran-sc.org'
tag: '[]'
realtime_discussion:
type: 'irc'
server: 'freenode.net'
channel: '#oran'
meetings:
- type: 'gotomeeting+irc'
agenda: 'https://wiki.o-ran-sc.org/display/'
url: ''
server: 'freenode.net'
channel: '#oran'
repeats: ''
time: ''
repositories:
- ric-plt/dbaas
committers:
- <<: *oran_ric_plt_dbaas_ptl
- name: 'makiaija'
email: 'jussi.maki-aijala@nokia.com'
company: 'nokia'
id: 'makiaija'
timezone: 'Unknown/Unknown'
- name: 'Marco Tallskog'
email: 'marco.tallskog@nokia.com'
company: 'nokia'
id: 'tallskog'
timezone: 'Unknown/Unknown'
- name: 'Timo Tietavainen'
email: 'timo.tietavainen@nokia.com'
company: 'nokia'
id: 'tietavai'
timezone: 'Unknown/Unknown'
- name: 'Rolf Badorek'
email: 'rolf.badorek@nokia.com'
company: 'nokia'
id: 'badorek'
timezone: 'Unknown/Unknown'
- name: 'Arvo Heinonen'
email: 'arvo.heinonen@nokia.com'
company: 'nokia'
id: 'arvo.heinonen'
timezone: 'Unknown/Unknown'
tsc:
# yamllint disable rule:line-length
approval: 'missing'
changes:
- type: ''
name: ''
link: ''

34
setup/dbaas/LICENSES.txt Normal file
View File

@@ -0,0 +1,34 @@
LICENSES.txt
Unless otherwise specified, all software contained herein is licensed
under the Apache License, Version 2.0 (the "Software License");
you may not use this software except in compliance with the Software
License. You may obtain a copy of the Software License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the Software License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the Software License for the specific language governing permissions
and limitations under the Software License.
Unless otherwise specified, all documentation contained herein is licensed
under the Creative Commons License, Attribution 4.0 Intl. (the
"Documentation License"); you may not use this documentation except in
compliance with the Documentation License. You may obtain a copy of the
Documentation License at
https://creativecommons.org/licenses/by/4.0/
Unless required by applicable law or agreed to in writing, documentation
distributed under the Documentation License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the Documentation License for the specific language governing
permissions and limitations under the Documentation License.

122
setup/dbaas/README.md Normal file
View File

@@ -0,0 +1,122 @@
# Database as a service repository
This repository containes all the needed elements to deploy database as a service to kubernetes
## Architecture
Redis is the chosen database technology and the final product will deploy autonomous
redis cluster. In R0 schedule, single, non-redundant, non-persistent redis server is
deployed
## Subsystem structure
**docker** Contains dockerfiles to produce dbaas / testapplication container images
**charts** Contais helm charts to deploy dbaas service / testapplication
**testapplication** Contains dbaas test applications with various languages such as go, ..
## Container image creation
The images must be built at subsystem root level
To produce dbaas service image:
```
docker build --file docker/Dockerfile.redis --tag redis-standalone .
```
To produce testapplication image:
```
docker build --file docker/Dockerfile.testapp --tag dbaas-test .
```
## Deployment
### DBaaS service
In R0, dbaas service is realized with single container running redis database.
The database is configured to be non-persistent and non-redundant. The container
exposes single port which is hardcoded to be 6379.
After dbaas service is installed, environment variables **DBAAS_SERVICE_HOST**
and **DBAAS_SERVICE_PORT** are exposed to application containers. SDL library
will automatically use these environment variables.
The service is installed via helm by using dbaas-service chart. Modify the
values accordingly before installation (repository location, image name, ..)
```
helm install ./dbaas-service
```
### DBaaS test application
Test application is installed via helm by using dbaas-test chart. Modify the
values accordingly before installation (repository location, image name, ..)
```
helm install ./dbaas-test
```
## Testing
Make sure that dbaas-service and dbaas-test application are deployed:
```
>>helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
angry-greyhound 1 Thu Mar 21 11:36:23 2019 DEPLOYED dbaas-test-0.1.0 1.0 default
loitering-toad 1 Thu Mar 21 11:35:21 2019 DEPLOYED dbaas-0.1.0 1.0 default
```
Check the deployed pods
```
>>kubectl get pods
NAME READY STATUS RESTARTS AGE
dbaas-test-app-7695dbb9ff-qn8c2 1/1 Running 0 5s
redis-standalone-78978f4c6f-54b2s 1/1 Running 0 66s
```
Connect to the test application container:
```
kubectl exec -it dbaas-test-app-7695dbb9ff-qn8c2 -- /bin/bash
```
In test application container:
```
The environment variables for database backend should be set:
>>printenv
DBAAS_SERVICE_HOST=10.108.103.51
DBAAS_SERVICE_PORT=6379
Go test application using preliminary go SDL-API should be able to perform reads and writes:
>>./testapp
key1:data1
key3:%!s(<nil>)
key2:data2
num1:1
num2:2
-------------
mix2:2
num1:1
num2:2
pair1:data1
array1:adata1
mix1:data1
mix3:data3
mix4:4
arr1:
key1:data1
key2:data2
pair2:data2
array2:adata2
Redis server can be pinged with redis-cli:
>>redis-cli -h $DBAAS_SERVICE_HOST -p $DBAAS_SERVICE_PORT ping
PONG
```
## License
This project is licensed under the Apache License 2.0 - see the [LICENSE.md](LICENSE.md) file for details

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
apiVersion: v1
appVersion: "1.0"
description: DBaaS realized with standalone, non-persistent, non-redundant Redis
name: dbaas
version: 0.1.0

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ .Values.backend.name }}
spec:
replicas: {{ .Values.backend.replicas }}
template:
metadata:
labels:
app: {{ .Values.backend.name }}
spec:
terminationGracePeriodSeconds: {{ .Values.backend.terminationGracePeriodSeconds }}
containers:
- image: {{ .Values.backend.image.name }}:{{ .Values.backend.image.tag }}
imagePullPolicy: {{ .Values.backend.image.imagePullPolicy }}
ports:
- containerPort: {{ .Values.backend.targetPort }}
name: {{ .Values.backend.name }}
restartPolicy: Always

View File

@@ -0,0 +1,30 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}
spec:
selector:
app: {{ .Values.backend.name }}
ports:
- port: {{ .Values.backend.port }}
targetPort: {{ .Values.backend.targetPort }}

View File

@@ -0,0 +1,30 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
backend:
terminationGracePeriodSeconds: 0
replicas: 1
name: "redis-standalone"
port: 6379
targetPort: 6379
image:
name: snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com/redis-standalone
tag: latest
imagePullPolicy: IfNotPresent

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
apiVersion: v1
appVersion: "1.0"
description: Application for testing DBAAS connectivity
name: dbaas-test
version: 0.1.0

View File

@@ -0,0 +1,37 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ .Values.testapp.name }}
spec:
replicas: {{ .Values.testapp.replicas }}
template:
metadata:
labels:
app: {{ .Values.testapp.name }}
spec:
terminationGracePeriodSeconds: {{ .Values.testapp.terminationGracePeriodSeconds }}
containers:
- image: {{ .Values.testapp.image.name }}:{{ .Values.testapp.image.tag }}
imagePullPolicy: {{ .Values.testapp.image.imagePullPolicy }}
name: {{ .Values.testapp.name }}
restartPolicy: Always

View File

@@ -0,0 +1,28 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
testapp:
terminationGracePeriodSeconds: 0
replicas: 1
name: "dbaas-test-app"
image:
name: snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com/dbaas-test
tag: latest
imagePullPolicy: IfNotPresent

View File

@@ -0,0 +1,5 @@
# The Jenkins job requires a tag to build the Docker image.
# This file is expected to be in the docker build directory;
# can be moved with suitable JJB configuration.
---
tag: '0.4.1'

View File

@@ -0,0 +1,77 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
# Alpine-linux based containers use musl implementation of libc which causes
# valgrind to emit false positives. Therefore we run UT with valgrind in
# a separate build stage that uses ubuntu container with GNU libc installed.
#
# NOTE: The valgrind false positive problem could also potentially be solved
# with valgrind suppression files but that kind of approach may be fragile.
FROM ubuntu:18.04 as cpputest-build
RUN apt-get update \
&& apt install -y \
automake \
autoconf \
cmake \
curl \
g++ \
gcc \
libtool \
make \
pkg-config \
valgrind \
&& rm -rf /var/lib/apt/lists/*
# Cpputest built-in memory checks generate false positives in valgrind.
# This is solved by compiling cpputest with memory checking disabled.
WORKDIR /cpputest
RUN curl -L https://github.com/cpputest/cpputest/releases/download/v3.8/cpputest-3.8.tar.gz | \
tar --strip-components=1 -xzf -
WORKDIR /cpputest/builddir
RUN cmake -DMEMORY_LEAK_DETECTION=OFF .. && \
make install
COPY ./redismodule /redismodule
WORKDIR /redismodule
RUN ./autogen.sh && \
./configure
#&& make test
FROM nexus3.o-ran-sc.org:10004/o-ran-sc/bldr-alpine3-go:6-a3.11-rmr3 as build-env
RUN apk add cpputest
COPY ./redismodule /redismodule
WORKDIR /redismodule
RUN ./autogen.sh && \
./configure --disable-unit-test-memcheck && \
# make test && \
make install
FROM redis:5.0.5-alpine3.9
RUN apk add curl
COPY --from=build-env /usr/local/libexec/redismodule/libredismodule.so /usr/local/libexec/redismodule/libredismodule.so
WORKDIR /data
#ENTRYPOINT ["sh", "/usr/local/bin/docker-entrypoint.sh"]
ENTRYPOINT ["redis-server"]

View File

@@ -0,0 +1,44 @@
# Copyright (c) 2019 AT&T Intellectual Property.
# Copyright (c) 2019 Nokia.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This source code is part of the near-RT RIC (RAN Intelligent Controller)
# platform project (RICP).
#
FROM ubuntu:latest
# Install redis tools & golang & git
RUN apt-get update && \
apt install -y redis-tools && \
apt install -y git && \
apt install -y wget && \
wget https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz && \
tar -xvf go1.11.4.linux-amd64.tar.gz && \
mv go /usr/local && \
apt-get clean
# Copy sourcefiles
COPY ./testapplication ./testapplication
# Install go testapplication
RUN export GOROOT=/usr/local/go && \
export GOPATH=$HOME/Projects/Proj1 && \
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH && \
go get github.com/go-redis/redis && \
go build /testapplication/go/testapp.go
# Keep the container alive
ENTRYPOINT ["tail", "-f", "/dev/null"]

BIN
setup/dbaas/docs/_static/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

6
setup/dbaas/docs/conf.py Normal file
View File

@@ -0,0 +1,6 @@
from docs_conf.conf import *
linkcheck_ignore = [
'http://localhost.*',
'http://127.0.0.1.*',
'https://gerrit.o-ran-sc.org.*'
]

View File

@@ -0,0 +1,3 @@
---
project_cfg: oran
project: ric-plt/dbaas

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,31 @@
..
.. Copyright (c) 2019 AT&T Intellectual Property.
.. Copyright (c) 2019 Nokia.
..
.. Licensed under the Creative Commons Attribution 4.0 International
.. Public License (the "License"); you may not use this file except
.. in compliance with the License. You may obtain a copy of the License at
..
.. https://creativecommons.org/licenses/by/4.0/
..
.. Unless required by applicable law or agreed to in writing, documentation
.. distributed under the License is distributed on an "AS IS" BASIS,
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
..
.. See the License for the specific language governing permissions and
.. limitations under the License.
..
Welcome to O-RAN DBAAS Documentation
====================================
.. toctree::
:maxdepth: 2
:caption: Contents:
overview.rst
release-notes.rst
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@@ -0,0 +1,28 @@
..
.. Copyright (c) 2019 AT&T Intellectual Property.
.. Copyright (c) 2019 Nokia.
..
.. Licensed under the Creative Commons Attribution 4.0 International
.. Public License (the "License"); you may not use this file except
.. in compliance with the License. You may obtain a copy of the License at
..
.. https://creativecommons.org/licenses/by/4.0/
..
.. Unless required by applicable law or agreed to in writing, documentation
.. distributed under the License is distributed on an "AS IS" BASIS,
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
..
.. See the License for the specific language governing permissions and
.. limitations under the License.
..
Overview
========
The ric-plt/dbaas repo provides all the needed elements to deploy database as
a service (Dbaas) to kubernetes. Dbaas service is realized with a single
container running Redis database. The database is configured to be
non-persistent and non-redundant.
For the time being Dbaas only allowed usage is to provide database backend
service for Shared Data Layer (SDL).

View File

@@ -0,0 +1,75 @@
..
.. Copyright (c) 2019 AT&T Intellectual Property.
.. Copyright (c) 2019 Nokia.
..
.. Licensed under the Creative Commons Attribution 4.0 International
.. Public License (the "License"); you may not use this file except
.. in compliance with the License. You may obtain a copy of the License at
..
.. https://creativecommons.org/licenses/by/4.0/
..
.. Unless required by applicable law or agreed to in writing, documentation
.. distributed under the License is distributed on an "AS IS" BASIS,
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
..
.. See the License for the specific language governing permissions and
.. limitations under the License.
..
Release-Notes
=============
This document provides the release notes of the dbaas.
.. contents::
:depth: 3
:local:
Version history
---------------
[0.4.1] - 2020-06-17
* Upgrade base image to bldr-alpine3:12-a3.11 in Redis docker build
[0.4.0] - 2020-04-23
* Bump version to 0.4.0 to follow RIC versioning rules (4 is meaning RIC release R4). No functional changes.
[0.3.2] - 2020-04-22
* Upgrade base image to bldr-alpine3:10-a3.22-rmr3 in Redis docker build
* Fix redismodule resource leak
[0.3.1] - 2020-02-13
* Upgrade base image to alpine3-go:1-rmr1.13.1 in Redis docker build
[0.3.0] - 2020-01-23
* Enable unit tests and valgrind in CI.
* Update redismodule with new commands.
* Update documentation.
[0.2.2] - 2019-11-12
* Take Alpine (version 6-a3.9) linux base image into use in Redis docker image.
* Add mandatory documentation files.
[0.2.1] - 2019-09-17
* Add the curl tool to docker image to facilitate trouble-shooting.
[0.2.0] - 2019-09-03
* Take Redis 5.0 in use.
[0.1.0] - 2019-06-17
* Initial Implementation to provide all the needed elements to deploy database
as a service docker image to kubernetes.
* Introduce new Redis modules: SETIE, SETNE, DELIE, DELNE, MSETPUB, MSETMPUB,
SETXXPUB, SETNXPUB, SETIEPUB, SETNEPUB, DELPUB, DELMPUB, DELIEPUB, DELNEPUB,
NGET, NDEL.

View File

@@ -0,0 +1,5 @@
sphinx
sphinx-rtd-theme
sphinxcontrib-httpdomain
recommonmark
lfdocs-conf

View File

@@ -0,0 +1,134 @@
ACLOCAL_AMFLAGS = -I m4
redismoduledir = @libexecdir@/$(PACKAGE)
redismodule_LTLIBRARIES = libredismodule.la
#lib_LTLIBRARIES = libredismodule.la
BASE_LDFLAGS =
libredismodule_la_SOURCES = \
include/redismodule.h\
src/exstrings.c
libredismodule_la_CFLAGS = \
-std=c11 -fPIC -g -Wall -Werror -Wextra \
-DREDISMODULE_EXPERIMENTAL_API \
-I${includedir} -I${top_srcdir}/include
libredismodule_la_LDFLAGS = $(BASE_LDFLAGS) -avoid-version -module -shared
#pkgincludedir = ${includedir}
#pkginclude_HEADERS = include/redismodule.h
clean-local:
rm -rf ${builddir}/libredismodule.pc
if UNIT_TEST_ENABLED
# UT
CPP_U_TEST=$(CPP_U_TEST_LATEST)
check_PROGRAMS = redismodule_ut redismodule_ut2
#TESTS = ${check_PROGRAMS}
redismodule_ut_SOURCES = \
src/exstrings.c \
tst/mock/include/commonStub.h \
tst/mock/include/exstringsStub.h \
tst/mock/include/redismodule.h \
tst/mock/src/commonStub.cpp \
tst/mock/src/redismoduleStub.cpp \
tst/src/exstrings_test.cpp \
tst/src/main.cpp
redismodule_ut_CFLAGS = \
-std=c11 -g -Wall \
-fprofile-arcs -ftest-coverage \
-D__UT__ \
$(LIBCPPUTEST_CFLAGS) \
-I${top_srcdir}/tst/mock/include \
-I${includedir} \
-I${top_srcdir}/include \
-I${CPP_U_TEST_LATEST}/include \
-Wall -Werror -Wextra
redismodule_ut_CXXFLAGS = \
-std=c++11 -g -Wall \
-fprofile-arcs -ftest-coverage \
-D__UT__ \
$(LIBCPPUTEST_CFLAGS) \
-I${top_srcdir}/tst/mock/include \
-I${includedir} \
-I${top_srcdir}/include \
-I${CPP_U_TEST_LATEST}/include \
-Wall -Werror -Wextra
redismodule_ut_LDFLAGS = -Wl,-rpath=${libdir} ${UT_COVERAGE_LDFLAGS}
redismodule_ut_LDADD = -L${libdir} $(LIBCPPUTEST_LIBS) -lgcov
redismodule_ut2_SOURCES = \
src/exstrings.c \
tst/include/ut_helpers.hpp \
tst/mock/include/commonStub.h \
tst/mock/include/exstringsStub.h \
tst/mock/include/redismodule.h \
tst/mock/src/commonStub.cpp \
tst/mock/src/redismoduleNewStub.cpp \
tst/src/exstrings_ndel_test.cpp \
tst/src/exstrings_nget_test.cpp \
tst/src/main.cpp \
tst/src/ut_helpers.cpp
redismodule_ut2_CFLAGS = \
-std=c11 -g -Wall \
-fprofile-arcs -ftest-coverage \
-D__UT__ \
$(LIBCPPUTEST_CFLAGS) \
-I${top_srcdir}/tst/mock/include \
-I${includedir} \
-I${top_srcdir}/include \
-I${CPP_U_TEST_LATEST}/include \
-Wall -Werror -Wextra
redismodule_ut2_CXXFLAGS = \
-std=c++11 -g -Wall \
-fprofile-arcs -ftest-coverage \
-D__UT__ \
$(LIBCPPUTEST_CFLAGS) \
-I${top_srcdir}/tst/mock/include \
-I${top_srcdir}/tst/include \
-I${includedir} \
-I${top_srcdir}/include \
-I${CPP_U_TEST_LATEST}/include \
-Wall -Werror -Wextra
redismodule_ut2_LDFLAGS = -Wl,-rpath=${libdir} ${UT_COVERAGE_LDFLAGS}
redismodule_ut2_LDADD = -L${libdir} $(LIBCPPUTEST_LIBS) -lgcov
if UNIT_TEST_MEMCHECK_ENABLED
test: ut_memcheck_test
else
test: ut_test
endif
ut_test: redismodule_ut redismodule_ut2
./redismodule_ut
./redismodule_ut2
ut_memcheck_test: redismodule_ut redismodule_ut2
valgrind --error-exitcode=1 --leak-check=full ./redismodule_ut
valgrind --error-exitcode=1 --leak-check=full ./redismodule_ut2
TESTS = run-tests.sh
else
test:
echo 'enable ut with configure flag: --enable-unit-test and valgrind memcheck with: --enable-unit-test-memcheck'
exit 1
endif #UNIT_TEST_ENABLED

260
setup/dbaas/redismodule/README.md Executable file
View File

@@ -0,0 +1,260 @@
# Introduction
This subdirectory provides implementation for the commands which are implemented
as a [Redis modules](https://redis.io/topics/modules-intro).
# Compiling and Unit Tests
To compile, run unit tests and install use the commands:
```
./autogen.sh
./configure
make
make test
make install
```
By default unit tests and valgrind memory checking are enabled.
This requires `cpputest` and `valgrind` as additional dependencies.
Unit test memory checking can be disabled with the `configure` option
`--disable-unit-test-memcheck` and the unit tests can be completely disabled
with the `configure` option `--disable-unit-test`.
For example to compile and install with unit tests completely disabled
one would run the commands:
```
./autogen.sh
./configure --disable-unit-test
make
make install
```
# Commands
## SETIE key value oldvalue [expiration EX seconds|PX milliseconds]
Time complexity: O(1) + O(1)
Checks a String 'key' for 'oldvalue' equality and set key for 'value' with
optional expired.
```
Example:
redis> get mykey
(nil)
redis> setie mykey "Hello again" "Hello"
(nil)
redis> set mykey "Hello"
OK
redis> get mykey
"Hello"
redis> setie mykey "Hello again" "Hello"
"OK"
redis> get mykey
"Hello again"
redis> setie mykey "Hello 2" "Hello"
(nil)
redis> get mykey
"Hello again"
redis> setie mykey "Hello 2" "Hello again" ex 100
"OK"
redis> ttl mykey
(integer) 96
redis> get mykey
"Hello 2"
```
## SETNE key value oldvalue [expiration EX seconds|PX milliseconds]
Time complexity: O(1) + O(1)
Checks a String 'key' for 'oldvalue' not equality and set key for 'value' with optional expired.
Example:
```
redis> get mykey
(nil)
redis> setne mykey "Hello again" "Hello"
"OK"
redis> get mykey
"Hello again"
redis> setne mykey "Hello 2" "Hello again"
(nil)
redis> setne mykey "Hello 2" "Hello"
"OK"
redis> get mykey
"Hello 2"
redis> setne mykey "Hello 3" "Hello" ex 100
"OK"
redis> get mykey
"Hello 3"
redis> ttl mykey
(integer) 93
```
## DELIE key oldvalue
Time complexity: O(1) + O(1)
Checks a String 'key' for 'oldvalue' equality and delete the key.
```
Example:
redis> get mykey
(nil)
redis> set mykey "Hello"
"OK"
redis> get mykey
"Hello"
redis> delie mykey "Hello again"
(integer) 0
redis> get mykey
"Hello"
redis> delie mykey "Hello"
(integer) 1
redis> get mykey
(nil)
```
## DELNE key oldvalue
Time complexity: O(1) + O(1)
Checks a String 'key' for 'oldvalue' not equality and delete the key.
```
Example:
redis> get mykey
(nil)
redis> set mykey "Hello"
"OK"
redis> get mykey
"Hello"
redis> delne mykey "Hello"
(integer) 0
redis> get mykey
"Hello"
redis> delne mykey "Hello again"
(integer) 1
redis> get mykey
(nil)
```
## MSETPUB key value [key value...] channel message
Time complexity: O(N) where N is the number of keys to set + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
Set the given keys to their respective values and post a message to the given channel
## MSETMPUB number_of_key_value_pairs number_of_channel_message_pairs key value [ key value ... ] channel message [ channel message ... ]
Time complexity: O(N) where N is the number of keys to set + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the corresponding receiving channel and M is the total number of subscribed patterns (by any client)
Set the given keys to their respective values and post messages to their respective channels
## SETXXPUB key value channel message [channel message...]
Time complexity: O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
Set key to hold string value if key already exists and post given messages to the corresponding channels if key value was set successfully
## SETNXPUB key value channel message [channel message...]
Time complexity: O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
Set key to hold string value if key does not exist and post given messages to the corresponding channels if key value was set successfully
## SETIEPUB key value oldvalue channel message [channel message...]
Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
If the string corresponding to 'key' is equal to 'oldvalue' then set key for 'value' and post given messages to the corresponding channels if key value was set successfully
## SETNEPUB key value oldvalue channel message [channel message...]
Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
If the string corresponding to 'key' is not equal to 'oldvalue' then set key for 'value' and post given messages to the corresponding channels if key value was set successfully
## DELPUB key [key...] channel message
Time complexity: O(N) where N is the number of keys that will be removed + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
Removes the specified keys and post a message to the given channel if delete key successfully(return >0)
## DELMPUB number_of_keys number_of_channel_message_pairs key [ key ... ] channel message [ channel message ... ]
Time complexity: O(N) where N is the number of keys that will be removed + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
Remove the specified keys. If any of the keys was deleted succesfully (delete return value > 0) then post given messages to the corresponding channels.
## DELIEPUB key oldvalue channel message [channel message...]
Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ...] where N_i are the number of clients subscribed to the corrensponding receiving channel and M is the total number of subscribed patterns (by any client)
If the string corresponding to 'key' is equal to 'oldvalue' then delete the key. If deletion was succesful (delete return value was 1) then post given messages to the corresponding channels.
## DELNEPUB key oldvalue channel message [channel message...]
Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ...] where N_i are the number of clients subscribed to the corrensponding receiving channel and M is the total number of subscribed patterns (by any client)
If the string corresponding to 'key' is not equal to 'oldvalue' then delete the key. If deletion was succesful (delete return value was 1) then post given messages to the corresponding channels.
## NGET pattern
Time complexity: O(N) with N being the number of keys in the instance + O(N) where N is the number of keys to retrieve
Returns all key-value pairs matching pattern.
```
example:
redis> nget mykey*
(empty list or set)
redis> set mykey1 "myvalue1"
OK
redis> set mykey2 "myvalue2"
OK
redis> set mykey3 "myvalue3"
OK
redis> set mykey4 "myvalue4"
OK
redis> nget mykey*
1) "mykey2"
2) "myvalue2"
3) "mykey1"
4) "myvalue1"
5) "mykey4"
6) "myvalue4"
7) "mykey3"
8) "myvalue3"
```
## NDEL pattern
Time complexity: O(N) with N being the number of keys in the instance + O(N) where N is the number of keys that will be removed
Remove all key-value pairs matching pattern.
```
example:
redis> nget mykey*
1) "mykey2"
2) "myvalue2"
3) "mykey1"
4) "myvalue1"
5) "mykey4"
6) "myvalue4"
7) "mykey3"
8) "myvalue3"
redis> ndel mykey*
(integer) 4
redis> ndel mykey*
(integer) 0
```

View File

@@ -0,0 +1,3 @@
#!/bin/bash
autoreconf --install

View File

@@ -0,0 +1,54 @@
AC_INIT([redismodule], [0.0.0], [], [], [https://gerrit.oran-osc.org/r/#/admin/projects/ric-plt/dbaas])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIRS([m4])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects tar-pax])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT([disable-static])
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_ARG_ENABLE([unit-test],
[--disable-unit-test], [Disable unit tests]
)
AS_IF([test x"$enable_unit_test" != x"no"],
[
PKG_CHECK_MODULES([LIBCPPUTEST],[cpputest])
AM_CONDITIONAL([UNIT_TEST_ENABLED], [true])
],
[
AM_CONDITIONAL([UNIT_TEST_ENABLED], [false])
]
)
AC_ARG_ENABLE([unit-test-memcheck],
[AS_HELP_STRING([--disable-unit-test-memcheck], [Do not run unit tests with valgrind])]
)
AS_IF([test x"$enable_unit_test_memcheck" != x"no"],
[
AC_CHECK_PROG(VALGRIND_CHECK, valgrind, yes)
AM_CONDITIONAL([UNIT_TEST_MEMCHECK_ENABLED], [true])
],
[
AM_CONDITIONAL([UNIT_TEST_MEMCHECK_ENABLED], [false])
]
)
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@@ -0,0 +1,574 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#ifndef REDISMODULE_H
#define REDISMODULE_H
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
/* ---------------- Defines common between core and modules --------------- */
/* Error status return values. */
#define REDISMODULE_OK 0
#define REDISMODULE_ERR 1
/* API versions. */
#define REDISMODULE_APIVER_1 1
/* API flags and constants */
#define REDISMODULE_READ (1<<0)
#define REDISMODULE_WRITE (1<<1)
#define REDISMODULE_LIST_HEAD 0
#define REDISMODULE_LIST_TAIL 1
/* Key types. */
#define REDISMODULE_KEYTYPE_EMPTY 0
#define REDISMODULE_KEYTYPE_STRING 1
#define REDISMODULE_KEYTYPE_LIST 2
#define REDISMODULE_KEYTYPE_HASH 3
#define REDISMODULE_KEYTYPE_SET 4
#define REDISMODULE_KEYTYPE_ZSET 5
#define REDISMODULE_KEYTYPE_MODULE 6
/* Reply types. */
#define REDISMODULE_REPLY_UNKNOWN -1
#define REDISMODULE_REPLY_STRING 0
#define REDISMODULE_REPLY_ERROR 1
#define REDISMODULE_REPLY_INTEGER 2
#define REDISMODULE_REPLY_ARRAY 3
#define REDISMODULE_REPLY_NULL 4
/* Postponed array length. */
#define REDISMODULE_POSTPONED_ARRAY_LEN -1
/* Expire */
#define REDISMODULE_NO_EXPIRE -1
/* Sorted set API flags. */
#define REDISMODULE_ZADD_XX (1<<0)
#define REDISMODULE_ZADD_NX (1<<1)
#define REDISMODULE_ZADD_ADDED (1<<2)
#define REDISMODULE_ZADD_UPDATED (1<<3)
#define REDISMODULE_ZADD_NOP (1<<4)
/* Hash API flags. */
#define REDISMODULE_HASH_NONE 0
#define REDISMODULE_HASH_NX (1<<0)
#define REDISMODULE_HASH_XX (1<<1)
#define REDISMODULE_HASH_CFIELDS (1<<2)
#define REDISMODULE_HASH_EXISTS (1<<3)
/* Context Flags: Info about the current context returned by
* RM_GetContextFlags(). */
/* The command is running in the context of a Lua script */
#define REDISMODULE_CTX_FLAGS_LUA (1<<0)
/* The command is running inside a Redis transaction */
#define REDISMODULE_CTX_FLAGS_MULTI (1<<1)
/* The instance is a master */
#define REDISMODULE_CTX_FLAGS_MASTER (1<<2)
/* The instance is a slave */
#define REDISMODULE_CTX_FLAGS_SLAVE (1<<3)
/* The instance is read-only (usually meaning it's a slave as well) */
#define REDISMODULE_CTX_FLAGS_READONLY (1<<4)
/* The instance is running in cluster mode */
#define REDISMODULE_CTX_FLAGS_CLUSTER (1<<5)
/* The instance has AOF enabled */
#define REDISMODULE_CTX_FLAGS_AOF (1<<6)
/* The instance has RDB enabled */
#define REDISMODULE_CTX_FLAGS_RDB (1<<7)
/* The instance has Maxmemory set */
#define REDISMODULE_CTX_FLAGS_MAXMEMORY (1<<8)
/* Maxmemory is set and has an eviction policy that may delete keys */
#define REDISMODULE_CTX_FLAGS_EVICT (1<<9)
/* Redis is out of memory according to the maxmemory flag. */
#define REDISMODULE_CTX_FLAGS_OOM (1<<10)
/* Less than 25% of memory available according to maxmemory. */
#define REDISMODULE_CTX_FLAGS_OOM_WARNING (1<<11)
/* The command was sent over the replication link. */
#define REDISMODULE_CTX_FLAGS_REPLICATED (1<<12)
/* Redis is currently loading either from AOF or RDB. */
#define REDISMODULE_CTX_FLAGS_LOADING (1<<13)
#define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */
#define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */
#define REDISMODULE_NOTIFY_LIST (1<<4) /* l */
#define REDISMODULE_NOTIFY_SET (1<<5) /* s */
#define REDISMODULE_NOTIFY_HASH (1<<6) /* h */
#define REDISMODULE_NOTIFY_ZSET (1<<7) /* z */
#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
#define REDISMODULE_NOTIFY_STREAM (1<<10) /* t */
#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) /* A */
/* 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)
/* Error messages. */
#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
/* Cluster API defines. */
#define REDISMODULE_NODE_ID_LEN 40
#define REDISMODULE_NODE_MYSELF (1<<0)
#define REDISMODULE_NODE_MASTER (1<<1)
#define REDISMODULE_NODE_SLAVE (1<<2)
#define REDISMODULE_NODE_PFAIL (1<<3)
#define REDISMODULE_NODE_FAIL (1<<4)
#define REDISMODULE_NODE_NOFAILOVER (1<<5)
#define REDISMODULE_CLUSTER_FLAG_NONE 0
#define REDISMODULE_CLUSTER_FLAG_NO_FAILOVER (1<<1)
#define REDISMODULE_CLUSTER_FLAG_NO_REDIRECTION (1<<2)
#define REDISMODULE_NOT_USED(V) ((void) V)
/* Bit flags for aux_save_triggers and the aux_load and aux_save callbacks */
#define REDISMODULE_AUX_BEFORE_RDB (1<<0)
#define REDISMODULE_AUX_AFTER_RDB (1<<1)
/* 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
* of timers that are going to expire, sorted by expire time. */
typedef uint64_t RedisModuleTimerID;
/* CommandFilter Flags */
/* Do filter RedisModule_Call() commands initiated by module itself. */
#define REDISMODULE_CMDFILTER_NOSELF (1<<0)
/* ------------------------- End of common defines ------------------------ */
#ifndef REDISMODULE_CORE
typedef long long mstime_t;
/* Incomplete structures for compiler checks but opaque access. */
typedef struct RedisModuleCtx RedisModuleCtx;
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 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 *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
typedef int (*RedisModuleTypeAuxLoadFunc)(RedisModuleIO *rdb, int encver, int when);
typedef void (*RedisModuleTypeAuxSaveFunc)(RedisModuleIO *rdb, int when);
typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
typedef void (*RedisModuleTypeFreeFunc)(void *value);
typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len);
typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter);
#define REDISMODULE_TYPE_METHOD_VERSION 2
typedef struct RedisModuleTypeMethods {
uint64_t version;
RedisModuleTypeLoadFunc rdb_load;
RedisModuleTypeSaveFunc rdb_save;
RedisModuleTypeRewriteFunc aof_rewrite;
RedisModuleTypeMemUsageFunc mem_usage;
RedisModuleTypeDigestFunc digest;
RedisModuleTypeFreeFunc free;
RedisModuleTypeAuxLoadFunc aux_load;
RedisModuleTypeAuxSaveFunc aux_save;
int aux_save_triggers;
} RedisModuleTypeMethods;
#define REDISMODULE_GET_API(name) \
RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
#define REDISMODULE_API_FUNC(x) (*x)
void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes);
void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes);
void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr);
void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size);
char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str);
int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *);
int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
void REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
int REDISMODULE_API_FUNC(RedisModule_IsModuleNameBusy)(const char *name);
int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll);
int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid);
void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp);
int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp);
size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp);
int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where);
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len);
void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply);
int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply);
long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply);
size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply);
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...);
void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str);
const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithCString)(RedisModuleCtx *ctx, const char *buf);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll);
int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d);
void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx);
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply);
int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_UnlinkKey)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str);
char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode);
int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen);
mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire);
int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr);
int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore);
int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key);
int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...);
int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...);
int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos);
unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_GetContextFlags)(RedisModuleCtx *ctx);
void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes);
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods);
int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value);
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key);
void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key);
void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value);
uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io);
void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value);
int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io);
void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...);
void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s);
void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io);
char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr);
void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value);
double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value);
float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io);
void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...);
void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...);
int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetKeyNameFromIO)(RedisModuleIO *io);
long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
RedisModuleDict *REDISMODULE_API_FUNC(RedisModule_CreateDict)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_FreeDict)(RedisModuleCtx *ctx, RedisModuleDict *d);
uint64_t REDISMODULE_API_FUNC(RedisModule_DictSize)(RedisModuleDict *d);
int REDISMODULE_API_FUNC(RedisModule_DictSetC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr);
int REDISMODULE_API_FUNC(RedisModule_DictReplaceC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr);
int REDISMODULE_API_FUNC(RedisModule_DictSet)(RedisModuleDict *d, RedisModuleString *key, void *ptr);
int REDISMODULE_API_FUNC(RedisModule_DictReplace)(RedisModuleDict *d, RedisModuleString *key, void *ptr);
void *REDISMODULE_API_FUNC(RedisModule_DictGetC)(RedisModuleDict *d, void *key, size_t keylen, int *nokey);
void *REDISMODULE_API_FUNC(RedisModule_DictGet)(RedisModuleDict *d, RedisModuleString *key, int *nokey);
int REDISMODULE_API_FUNC(RedisModule_DictDelC)(RedisModuleDict *d, void *key, size_t keylen, void *oldval);
int REDISMODULE_API_FUNC(RedisModule_DictDel)(RedisModuleDict *d, RedisModuleString *key, void *oldval);
RedisModuleDictIter *REDISMODULE_API_FUNC(RedisModule_DictIteratorStartC)(RedisModuleDict *d, const char *op, void *key, size_t keylen);
RedisModuleDictIter *REDISMODULE_API_FUNC(RedisModule_DictIteratorStart)(RedisModuleDict *d, const char *op, RedisModuleString *key);
void REDISMODULE_API_FUNC(RedisModule_DictIteratorStop)(RedisModuleDictIter *di);
int REDISMODULE_API_FUNC(RedisModule_DictIteratorReseekC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
int REDISMODULE_API_FUNC(RedisModule_DictIteratorReseek)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
void *REDISMODULE_API_FUNC(RedisModule_DictNextC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr);
void *REDISMODULE_API_FUNC(RedisModule_DictPrevC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictNext)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictPrev)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr);
int REDISMODULE_API_FUNC(RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
int REDISMODULE_API_FUNC(RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
/* Experimental APIs */
#ifdef REDISMODULE_EXPERIMENTAL_API
#define REDISMODULE_EXPERIMENTAL_API_VERSION 3
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms);
int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientHandle)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
int REDISMODULE_API_FUNC(RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback);
int REDISMODULE_API_FUNC(RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len);
int REDISMODULE_API_FUNC(RedisModule_GetClusterNodeInfo)(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags);
char **REDISMODULE_API_FUNC(RedisModule_GetClusterNodesList)(RedisModuleCtx *ctx, size_t *numnodes);
void REDISMODULE_API_FUNC(RedisModule_FreeClusterNodesList)(char **ids);
RedisModuleTimerID REDISMODULE_API_FUNC(RedisModule_CreateTimer)(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data);
int REDISMODULE_API_FUNC(RedisModule_StopTimer)(RedisModuleCtx *ctx, RedisModuleTimerID id, void **data);
int REDISMODULE_API_FUNC(RedisModule_GetTimerInfo)(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data);
const char *REDISMODULE_API_FUNC(RedisModule_GetMyClusterID)(void);
size_t REDISMODULE_API_FUNC(RedisModule_GetClusterSize)(void);
void REDISMODULE_API_FUNC(RedisModule_GetRandomBytes)(unsigned char *dst, size_t len);
void REDISMODULE_API_FUNC(RedisModule_GetRandomHexChars)(char *dst, size_t len);
void REDISMODULE_API_FUNC(RedisModule_SetDisconnectCallback)(RedisModuleBlockedClient *bc, RedisModuleDisconnectFunc callback);
void REDISMODULE_API_FUNC(RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags);
int REDISMODULE_API_FUNC(RedisModule_ExportSharedAPI)(RedisModuleCtx *ctx, const char *apiname, void *func);
void *REDISMODULE_API_FUNC(RedisModule_GetSharedAPI)(RedisModuleCtx *ctx, const char *apiname);
RedisModuleCommandFilter *REDISMODULE_API_FUNC(RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags);
int REDISMODULE_API_FUNC(RedisModule_UnregisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter);
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgsCount)(RedisModuleCommandFilterCtx *fctx);
const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos);
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg);
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg);
int REDISMODULE_API_FUNC(RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos);
#endif
/* This is included inline inside each Redis module. */
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) {
void *getapifuncptr = ((void**)ctx)[0];
RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr;
REDISMODULE_GET_API(Alloc);
REDISMODULE_GET_API(Calloc);
REDISMODULE_GET_API(Free);
REDISMODULE_GET_API(Realloc);
REDISMODULE_GET_API(Strdup);
REDISMODULE_GET_API(CreateCommand);
REDISMODULE_GET_API(SetModuleAttribs);
REDISMODULE_GET_API(IsModuleNameBusy);
REDISMODULE_GET_API(WrongArity);
REDISMODULE_GET_API(ReplyWithLongLong);
REDISMODULE_GET_API(ReplyWithError);
REDISMODULE_GET_API(ReplyWithSimpleString);
REDISMODULE_GET_API(ReplyWithArray);
REDISMODULE_GET_API(ReplySetArrayLength);
REDISMODULE_GET_API(ReplyWithStringBuffer);
REDISMODULE_GET_API(ReplyWithCString);
REDISMODULE_GET_API(ReplyWithString);
REDISMODULE_GET_API(ReplyWithNull);
REDISMODULE_GET_API(ReplyWithCallReply);
REDISMODULE_GET_API(ReplyWithDouble);
REDISMODULE_GET_API(ReplySetArrayLength);
REDISMODULE_GET_API(GetSelectedDb);
REDISMODULE_GET_API(SelectDb);
REDISMODULE_GET_API(OpenKey);
REDISMODULE_GET_API(CloseKey);
REDISMODULE_GET_API(KeyType);
REDISMODULE_GET_API(ValueLength);
REDISMODULE_GET_API(ListPush);
REDISMODULE_GET_API(ListPop);
REDISMODULE_GET_API(StringToLongLong);
REDISMODULE_GET_API(StringToDouble);
REDISMODULE_GET_API(Call);
REDISMODULE_GET_API(CallReplyProto);
REDISMODULE_GET_API(FreeCallReply);
REDISMODULE_GET_API(CallReplyInteger);
REDISMODULE_GET_API(CallReplyType);
REDISMODULE_GET_API(CallReplyLength);
REDISMODULE_GET_API(CallReplyArrayElement);
REDISMODULE_GET_API(CallReplyStringPtr);
REDISMODULE_GET_API(CreateStringFromCallReply);
REDISMODULE_GET_API(CreateString);
REDISMODULE_GET_API(CreateStringFromLongLong);
REDISMODULE_GET_API(CreateStringFromString);
REDISMODULE_GET_API(CreateStringPrintf);
REDISMODULE_GET_API(FreeString);
REDISMODULE_GET_API(StringPtrLen);
REDISMODULE_GET_API(AutoMemory);
REDISMODULE_GET_API(Replicate);
REDISMODULE_GET_API(ReplicateVerbatim);
REDISMODULE_GET_API(DeleteKey);
REDISMODULE_GET_API(UnlinkKey);
REDISMODULE_GET_API(StringSet);
REDISMODULE_GET_API(StringDMA);
REDISMODULE_GET_API(StringTruncate);
REDISMODULE_GET_API(GetExpire);
REDISMODULE_GET_API(SetExpire);
REDISMODULE_GET_API(ZsetAdd);
REDISMODULE_GET_API(ZsetIncrby);
REDISMODULE_GET_API(ZsetScore);
REDISMODULE_GET_API(ZsetRem);
REDISMODULE_GET_API(ZsetRangeStop);
REDISMODULE_GET_API(ZsetFirstInScoreRange);
REDISMODULE_GET_API(ZsetLastInScoreRange);
REDISMODULE_GET_API(ZsetFirstInLexRange);
REDISMODULE_GET_API(ZsetLastInLexRange);
REDISMODULE_GET_API(ZsetRangeCurrentElement);
REDISMODULE_GET_API(ZsetRangeNext);
REDISMODULE_GET_API(ZsetRangePrev);
REDISMODULE_GET_API(ZsetRangeEndReached);
REDISMODULE_GET_API(HashSet);
REDISMODULE_GET_API(HashGet);
REDISMODULE_GET_API(IsKeysPositionRequest);
REDISMODULE_GET_API(KeyAtPos);
REDISMODULE_GET_API(GetClientId);
REDISMODULE_GET_API(GetContextFlags);
REDISMODULE_GET_API(PoolAlloc);
REDISMODULE_GET_API(CreateDataType);
REDISMODULE_GET_API(ModuleTypeSetValue);
REDISMODULE_GET_API(ModuleTypeGetType);
REDISMODULE_GET_API(ModuleTypeGetValue);
REDISMODULE_GET_API(SaveUnsigned);
REDISMODULE_GET_API(LoadUnsigned);
REDISMODULE_GET_API(SaveSigned);
REDISMODULE_GET_API(LoadSigned);
REDISMODULE_GET_API(SaveString);
REDISMODULE_GET_API(SaveStringBuffer);
REDISMODULE_GET_API(LoadString);
REDISMODULE_GET_API(LoadStringBuffer);
REDISMODULE_GET_API(SaveDouble);
REDISMODULE_GET_API(LoadDouble);
REDISMODULE_GET_API(SaveFloat);
REDISMODULE_GET_API(LoadFloat);
REDISMODULE_GET_API(EmitAOF);
REDISMODULE_GET_API(Log);
REDISMODULE_GET_API(LogIOError);
REDISMODULE_GET_API(StringAppendBuffer);
REDISMODULE_GET_API(RetainString);
REDISMODULE_GET_API(StringCompare);
REDISMODULE_GET_API(GetContextFromIO);
REDISMODULE_GET_API(GetKeyNameFromIO);
REDISMODULE_GET_API(Milliseconds);
REDISMODULE_GET_API(DigestAddStringBuffer);
REDISMODULE_GET_API(DigestAddLongLong);
REDISMODULE_GET_API(DigestEndSequence);
REDISMODULE_GET_API(CreateDict);
REDISMODULE_GET_API(FreeDict);
REDISMODULE_GET_API(DictSize);
REDISMODULE_GET_API(DictSetC);
REDISMODULE_GET_API(DictReplaceC);
REDISMODULE_GET_API(DictSet);
REDISMODULE_GET_API(DictReplace);
REDISMODULE_GET_API(DictGetC);
REDISMODULE_GET_API(DictGet);
REDISMODULE_GET_API(DictDelC);
REDISMODULE_GET_API(DictDel);
REDISMODULE_GET_API(DictIteratorStartC);
REDISMODULE_GET_API(DictIteratorStart);
REDISMODULE_GET_API(DictIteratorStop);
REDISMODULE_GET_API(DictIteratorReseekC);
REDISMODULE_GET_API(DictIteratorReseek);
REDISMODULE_GET_API(DictNextC);
REDISMODULE_GET_API(DictPrevC);
REDISMODULE_GET_API(DictNext);
REDISMODULE_GET_API(DictPrev);
REDISMODULE_GET_API(DictCompare);
REDISMODULE_GET_API(DictCompareC);
#ifdef REDISMODULE_EXPERIMENTAL_API
REDISMODULE_GET_API(GetThreadSafeContext);
REDISMODULE_GET_API(FreeThreadSafeContext);
REDISMODULE_GET_API(ThreadSafeContextLock);
REDISMODULE_GET_API(ThreadSafeContextUnlock);
REDISMODULE_GET_API(BlockClient);
REDISMODULE_GET_API(UnblockClient);
REDISMODULE_GET_API(IsBlockedReplyRequest);
REDISMODULE_GET_API(IsBlockedTimeoutRequest);
REDISMODULE_GET_API(GetBlockedClientPrivateData);
REDISMODULE_GET_API(GetBlockedClientHandle);
REDISMODULE_GET_API(AbortBlock);
REDISMODULE_GET_API(SetDisconnectCallback);
REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
REDISMODULE_GET_API(BlockedClientDisconnected);
REDISMODULE_GET_API(RegisterClusterMessageReceiver);
REDISMODULE_GET_API(SendClusterMessage);
REDISMODULE_GET_API(GetClusterNodeInfo);
REDISMODULE_GET_API(GetClusterNodesList);
REDISMODULE_GET_API(FreeClusterNodesList);
REDISMODULE_GET_API(CreateTimer);
REDISMODULE_GET_API(StopTimer);
REDISMODULE_GET_API(GetTimerInfo);
REDISMODULE_GET_API(GetMyClusterID);
REDISMODULE_GET_API(GetClusterSize);
REDISMODULE_GET_API(GetRandomBytes);
REDISMODULE_GET_API(GetRandomHexChars);
REDISMODULE_GET_API(SetClusterFlags);
REDISMODULE_GET_API(ExportSharedAPI);
REDISMODULE_GET_API(GetSharedAPI);
REDISMODULE_GET_API(RegisterCommandFilter);
REDISMODULE_GET_API(UnregisterCommandFilter);
REDISMODULE_GET_API(CommandFilterArgsCount);
REDISMODULE_GET_API(CommandFilterArgGet);
REDISMODULE_GET_API(CommandFilterArgInsert);
REDISMODULE_GET_API(CommandFilterArgReplace);
REDISMODULE_GET_API(CommandFilterArgDelete);
#endif
if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
return REDISMODULE_OK;
}
#else
/* Things only defined for the modules core, not exported to modules
* including this file. */
#define RedisModuleString robj
#endif /* REDISMODULE_CORE */
#endif /* REDISMOUDLE_H */

View File

@@ -0,0 +1,586 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html
# ===========================================================================
#
# SYNOPSIS
#
# DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...)
# DX_DOXYGEN_FEATURE(ON|OFF)
# DX_DOT_FEATURE(ON|OFF)
# DX_HTML_FEATURE(ON|OFF)
# DX_CHM_FEATURE(ON|OFF)
# DX_CHI_FEATURE(ON|OFF)
# DX_MAN_FEATURE(ON|OFF)
# DX_RTF_FEATURE(ON|OFF)
# DX_XML_FEATURE(ON|OFF)
# DX_PDF_FEATURE(ON|OFF)
# DX_PS_FEATURE(ON|OFF)
#
# DESCRIPTION
#
# The DX_*_FEATURE macros control the default setting for the given
# Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
# generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
# help (for MS users), 'CHI' for generating a separate .chi file by the
# .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
# output formats. The environment variable DOXYGEN_PAPER_SIZE may be
# specified to override the default 'a4wide' paper size.
#
# By default, HTML, PDF and PS documentation is generated as this seems to
# be the most popular and portable combination. MAN pages created by
# Doxygen are usually problematic, though by picking an appropriate subset
# and doing some massaging they might be better than nothing. CHM and RTF
# are specific for MS (note that you can't generate both HTML and CHM at
# the same time). The XML is rather useless unless you apply specialized
# post-processing to it.
#
# The macros mainly control the default state of the feature. The use can
# override the default by specifying --enable or --disable. The macros
# ensure that contradictory flags are not given (e.g.,
# --enable-doxygen-html and --enable-doxygen-chm,
# --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each
# feature will be automatically disabled (with a warning) if the required
# programs are missing.
#
# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
# with the following parameters: a one-word name for the project for use
# as a filename base etc., an optional configuration file name (the
# default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an
# optional output directory name (the default is 'doxygen-doc'). To run
# doxygen multiple times for different configuration files and output
# directories provide more parameters: the second, forth, sixth, etc
# parameter are configuration file names and the third, fifth, seventh,
# etc parameter are output directories. No checking is done to catch
# duplicates.
#
# Automake Support
#
# The DX_RULES substitution can be used to add all needed rules to the
# Makefile. Note that this is a substitution without being a variable:
# only the @DX_RULES@ syntax will work.
#
# The provided targets are:
#
# doxygen-doc: Generate all doxygen documentation.
#
# doxygen-run: Run doxygen, which will generate some of the
# documentation (HTML, CHM, CHI, MAN, RTF, XML)
# but will not do the post processing required
# for the rest of it (PS, PDF).
#
# doxygen-ps: Generate doxygen PostScript documentation.
#
# doxygen-pdf: Generate doxygen PDF documentation.
#
# Note that by default these are not integrated into the automake targets.
# If doxygen is used to generate man pages, you can achieve this
# integration by setting man3_MANS to the list of man pages generated and
# then adding the dependency:
#
# $(man3_MANS): doxygen-doc
#
# This will cause make to run doxygen and generate all the documentation.
#
# The following variable is intended for use in Makefile.am:
#
# DX_CLEANFILES = everything to clean.
#
# Then add this variable to MOSTLYCLEANFILES.
#
# LICENSE
#
# Copyright (c) 2009 Oren Ben-Kiki <oren@ben-kiki.org>
# Copyright (c) 2015 Olaf Mandel <olaf@mandel.name>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 23
## ----------##
## Defaults. ##
## ----------##
DX_ENV=""
AC_DEFUN([DX_FEATURE_doc], ON)
AC_DEFUN([DX_FEATURE_dot], OFF)
AC_DEFUN([DX_FEATURE_man], OFF)
AC_DEFUN([DX_FEATURE_html], ON)
AC_DEFUN([DX_FEATURE_chm], OFF)
AC_DEFUN([DX_FEATURE_chi], OFF)
AC_DEFUN([DX_FEATURE_rtf], OFF)
AC_DEFUN([DX_FEATURE_xml], OFF)
AC_DEFUN([DX_FEATURE_pdf], ON)
AC_DEFUN([DX_FEATURE_ps], ON)
## --------------- ##
## Private macros. ##
## --------------- ##
# DX_ENV_APPEND(VARIABLE, VALUE)
# ------------------------------
# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it
# as a substitution (but not a Makefile variable). The substitution
# is skipped if the variable name is VERSION.
AC_DEFUN([DX_ENV_APPEND],
[AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl
m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl
AM_SUBST_NOTMAKE([$1])])dnl
])
# DX_DIRNAME_EXPR
# ---------------
# Expand into a shell expression prints the directory part of a path.
AC_DEFUN([DX_DIRNAME_EXPR],
[[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
# -------------------------------------
# Expands according to the M4 (static) status of the feature.
AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
# ----------------------------------
# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
AC_DEFUN([DX_REQUIRE_PROG], [
AC_PATH_TOOL([$1], [$2])
if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
fi
])
# DX_TEST_FEATURE(FEATURE)
# ------------------------
# Expand to a shell expression testing whether the feature is active.
AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
# -------------------------------------------------
# Verify that a required features has the right state before trying to turn on
# the DX_CURRENT_FEATURE.
AC_DEFUN([DX_CHECK_DEPEND], [
test "$DX_FLAG_$1" = "$2" \
|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
requires, contradicts) doxygen-DX_CURRENT_FEATURE])
])
# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
# ----------------------------------------------------------
# Turn off the DX_CURRENT_FEATURE if the required feature is off.
AC_DEFUN([DX_CLEAR_DEPEND], [
test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
])
# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
# CHECK_DEPEND, CLEAR_DEPEND,
# REQUIRE, DO-IF-ON, DO-IF-OFF)
# --------------------------------------------
# Parse the command-line option controlling a feature. CHECK_DEPEND is called
# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
# otherwise CLEAR_DEPEND is called to turn off the default state if a required
# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
AC_DEFUN([DX_ARG_ABLE], [
AC_DEFUN([DX_CURRENT_FEATURE], [$1])
AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
AC_ARG_ENABLE(doxygen-$1,
[AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
[--enable-doxygen-$1]),
DX_IF_FEATURE([$1], [don't $2], [$2]))],
[
case "$enableval" in
#(
y|Y|yes|Yes|YES)
AC_SUBST([DX_FLAG_$1], 1)
$3
;; #(
n|N|no|No|NO)
AC_SUBST([DX_FLAG_$1], 0)
;; #(
*)
AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
;;
esac
], [
AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
$4
])
if DX_TEST_FEATURE([$1]); then
$5
:
fi
if DX_TEST_FEATURE([$1]); then
$6
:
else
$7
:
fi
])
## -------------- ##
## Public macros. ##
## -------------- ##
# DX_XXX_FEATURE(DEFAULT_STATE)
# -----------------------------
AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])])
AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...)
# --------------------------------------------------------------
# PROJECT also serves as the base name for the documentation files.
# The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is
# "doxygen-doc".
# More arguments are interpreted as interleaved CONFIG-FILE and
# OUTPUT-DOC-DIR values.
AC_DEFUN([DX_INIT_DOXYGEN], [
# Files:
AC_SUBST([DX_PROJECT], [$1])
AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])'])
AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])'])
m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2,
[AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]),
'm4_default_nblank_quoted(m4_argn(DX_i, $@),
[$(srcdir)/Doxyfile])')])])dnl
m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2,
[AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]),
'm4_default_nblank_quoted(m4_argn(DX_i, $@),
[doxygen-doc])')])])dnl
m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1,
[m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])],
[])))dnl
# Environment variables used inside doxygen.cfg:
DX_ENV_APPEND(SRCDIR, $srcdir)
DX_ENV_APPEND(PROJECT, $DX_PROJECT)
DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
# Doxygen itself:
DX_ARG_ABLE(doc, [generate any doxygen documentation],
[],
[],
[DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
DX_REQUIRE_PROG([DX_PERL], perl)],
[DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
# Dot for graphics:
DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_DOT], dot)],
[DX_ENV_APPEND(HAVE_DOT, YES)
DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
[DX_ENV_APPEND(HAVE_DOT, NO)])
# Man pages generation:
DX_ARG_ABLE(man, [generate doxygen manual pages],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_MAN, YES)],
[DX_ENV_APPEND(GENERATE_MAN, NO)])
# RTF file generation:
DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_RTF, YES)],
[DX_ENV_APPEND(GENERATE_RTF, NO)])
# XML file generation:
DX_ARG_ABLE(xml, [generate doxygen XML documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_XML, YES)],
[DX_ENV_APPEND(GENERATE_XML, NO)])
# (Compressed) HTML help generation:
DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_HHC], hhc)],
[DX_ENV_APPEND(HHC_PATH, $DX_HHC)
DX_ENV_APPEND(GENERATE_HTML, YES)
DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
[DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
# Separate CHI file generation.
DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file],
[DX_CHECK_DEPEND(chm, 1)],
[DX_CLEAR_DEPEND(chm, 1)],
[],
[DX_ENV_APPEND(GENERATE_CHI, YES)],
[DX_ENV_APPEND(GENERATE_CHI, NO)])
# Plain HTML pages generation:
DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
[DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
[DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
[],
[DX_ENV_APPEND(GENERATE_HTML, YES)],
[DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
# PostScript file generation:
DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_LATEX], latex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_DVIPS], dvips)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# PDF file generation:
DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# LaTeX generation for PS and/or PDF:
if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
DX_ENV_APPEND(GENERATE_LATEX, YES)
else
DX_ENV_APPEND(GENERATE_LATEX, NO)
fi
# Paper size for PS and/or PDF:
AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
[a4wide (default), a4, letter, legal or executive])
case "$DOXYGEN_PAPER_SIZE" in
#(
"")
AC_SUBST(DOXYGEN_PAPER_SIZE, "")
;; #(
a4wide|a4|letter|legal|executive)
DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
;; #(
*)
AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
;;
esac
# Rules:
AS_IF([[test $DX_FLAG_html -eq 1]],
[[DX_SNIPPET_html="## ------------------------------- ##
## Rules specific for HTML output. ##
## ------------------------------- ##
DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/html]])[
"]],
[[DX_SNIPPET_html=""]])
AS_IF([[test $DX_FLAG_chi -eq 1]],
[[DX_SNIPPET_chi="
DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]],
[[DX_SNIPPET_chi=""]])
AS_IF([[test $DX_FLAG_chm -eq 1]],
[[DX_SNIPPET_chm="## ------------------------------ ##
## Rules specific for CHM output. ##
## ------------------------------ ##
DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/chm]])[\
${DX_SNIPPET_chi}
"]],
[[DX_SNIPPET_chm=""]])
AS_IF([[test $DX_FLAG_man -eq 1]],
[[DX_SNIPPET_man="## ------------------------------ ##
## Rules specific for MAN output. ##
## ------------------------------ ##
DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/man]])[
"]],
[[DX_SNIPPET_man=""]])
AS_IF([[test $DX_FLAG_rtf -eq 1]],
[[DX_SNIPPET_rtf="## ------------------------------ ##
## Rules specific for RTF output. ##
## ------------------------------ ##
DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/rtf]])[
"]],
[[DX_SNIPPET_rtf=""]])
AS_IF([[test $DX_FLAG_xml -eq 1]],
[[DX_SNIPPET_xml="## ------------------------------ ##
## Rules specific for XML output. ##
## ------------------------------ ##
DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/xml]])[
"]],
[[DX_SNIPPET_xml=""]])
AS_IF([[test $DX_FLAG_ps -eq 1]],
[[DX_SNIPPET_ps="## ----------------------------- ##
## Rules specific for PS output. ##
## ----------------------------- ##
DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[
DX_PS_GOAL = doxygen-ps
doxygen-ps: \$(DX_CLEAN_PS)
]m4_foreach([DX_i], [DX_loop],
[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
\$(DX_LATEX) refman.tex; \\
\$(DX_MAKEINDEX) refman.idx; \\
\$(DX_LATEX) refman.tex; \\
countdown=5; \\
while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
refman.log > /dev/null 2>&1 \\
&& test \$\$countdown -gt 0; do \\
\$(DX_LATEX) refman.tex; \\
countdown=\`expr \$\$countdown - 1\`; \\
done; \\
\$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
]])["]],
[[DX_SNIPPET_ps=""]])
AS_IF([[test $DX_FLAG_pdf -eq 1]],
[[DX_SNIPPET_pdf="## ------------------------------ ##
## Rules specific for PDF output. ##
## ------------------------------ ##
DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[
DX_PDF_GOAL = doxygen-pdf
doxygen-pdf: \$(DX_CLEAN_PDF)
]m4_foreach([DX_i], [DX_loop],
[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
\$(DX_PDFLATEX) refman.tex; \\
\$(DX_MAKEINDEX) refman.idx; \\
\$(DX_PDFLATEX) refman.tex; \\
countdown=5; \\
while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
refman.log > /dev/null 2>&1 \\
&& test \$\$countdown -gt 0; do \\
\$(DX_PDFLATEX) refman.tex; \\
countdown=\`expr \$\$countdown - 1\`; \\
done; \\
mv refman.pdf ../\$(PACKAGE).pdf
]])["]],
[[DX_SNIPPET_pdf=""]])
AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]],
[[DX_SNIPPET_latex="## ------------------------------------------------- ##
## Rules specific for LaTeX (shared for PS and PDF). ##
## ------------------------------------------------- ##
DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
_DX_v_LATEX_0 = @echo \" LATEX \" \$][@;
DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl
m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
\$(DX_DOCDIR]DX_i[)/latex]])[
"]],
[[DX_SNIPPET_latex=""]])
AS_IF([[test $DX_FLAG_doc -eq 1]],
[[DX_SNIPPET_doc="## --------------------------------- ##
## Format-independent Doxygen rules. ##
## --------------------------------- ##
${DX_SNIPPET_html}\
${DX_SNIPPET_chm}\
${DX_SNIPPET_man}\
${DX_SNIPPET_rtf}\
${DX_SNIPPET_xml}\
${DX_SNIPPET_ps}\
${DX_SNIPPET_pdf}\
${DX_SNIPPET_latex}\
DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
_DX_v_DXGEN_0 = @echo \" DXGEN \" \$<;
.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
doxygen-run:]m4_foreach([DX_i], [DX_loop],
[[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[
doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
]m4_foreach([DX_i], [DX_loop],
[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS)
\$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[)
\$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[)
\$(A""M_V_at)echo Timestamp >\$][@
]])dnl
[DX_CLEANFILES = \\]
m4_foreach([DX_i], [DX_loop],
[[ \$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\
\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\
]])dnl
[ -r \\
\$(DX_CLEAN_HTML) \\
\$(DX_CLEAN_CHM) \\
\$(DX_CLEAN_CHI) \\
\$(DX_CLEAN_MAN) \\
\$(DX_CLEAN_RTF) \\
\$(DX_CLEAN_XML) \\
\$(DX_CLEAN_PS) \\
\$(DX_CLEAN_PDF) \\
\$(DX_CLEAN_LATEX)"]],
[[DX_SNIPPET_doc=""]])
AC_SUBST([DX_RULES],
["${DX_SNIPPET_doc}"])dnl
AM_SUBST_NOTMAKE([DX_RULES])
#For debugging:
#echo DX_FLAG_doc=$DX_FLAG_doc
#echo DX_FLAG_dot=$DX_FLAG_dot
#echo DX_FLAG_man=$DX_FLAG_man
#echo DX_FLAG_html=$DX_FLAG_html
#echo DX_FLAG_chm=$DX_FLAG_chm
#echo DX_FLAG_chi=$DX_FLAG_chi
#echo DX_FLAG_rtf=$DX_FLAG_rtf
#echo DX_FLAG_xml=$DX_FLAG_xml
#echo DX_FLAG_pdf=$DX_FLAG_pdf
#echo DX_FLAG_ps=$DX_FLAG_ps
#echo DX_ENV=$DX_ENV
])

View File

@@ -0,0 +1,986 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#include "redismodule.h"
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#ifdef __UT__
#include "exstringsStub.h"
#include "commonStub.h"
#endif
/* make sure the response is not NULL or an error.
sends the error to the client and exit the current function if its */
#define ASSERT_NOERROR(r) \
if (r == NULL) { \
return RedisModule_ReplyWithError(ctx,"ERR reply is NULL"); \
} else if (RedisModule_CallReplyType(r) == REDISMODULE_REPLY_ERROR) { \
return RedisModule_ReplyWithCallReply(ctx,r); \
}
#define OBJ_OP_NO 0
#define OBJ_OP_XX (1<<1) /* OP if key exist */
#define OBJ_OP_NX (1<<2) /* OP if key not exist */
#define OBJ_OP_IE (1<<4) /* OP if equal old value */
#define OBJ_OP_NE (1<<5) /* OP if not equal old value */
#define DEF_COUNT 50
#define ZERO 0
#define MATCH_STR "MATCH"
#define COUNT_STR "COUNT"
#define SCANARGC 5
RedisModuleString *def_count_str = NULL, *match_str = NULL, *count_str = NULL, *zero_str = NULL;
typedef struct _NgetArgs {
RedisModuleString *key;
RedisModuleString *count;
} NgetArgs;
typedef struct RedisModuleBlockedClientArgs {
RedisModuleBlockedClient *bc;
NgetArgs nget_args;
} RedisModuleBlockedClientArgs;
void InitStaticVariable()
{
if (def_count_str == NULL)
def_count_str = RedisModule_CreateStringFromLongLong(NULL, DEF_COUNT);
if (match_str == NULL)
match_str = RedisModule_CreateString(NULL, MATCH_STR, sizeof(MATCH_STR));
if (count_str == NULL)
count_str = RedisModule_CreateString(NULL, COUNT_STR, sizeof(COUNT_STR));
if (zero_str == NULL)
zero_str = RedisModule_CreateStringFromLongLong(NULL, ZERO);
return;
}
int getKeyType(RedisModuleCtx *ctx, RedisModuleString *key_str)
{
RedisModuleKey *key = RedisModule_OpenKey(ctx, key_str, REDISMODULE_READ);
int type = RedisModule_KeyType(key);
RedisModule_CloseKey(key);
return type;
}
bool replyContentsEqualString(RedisModuleCallReply *reply, RedisModuleString *expected_value)
{
size_t replylen = 0, expectedlen = 0;
const char *expectedval = RedisModule_StringPtrLen(expected_value, &expectedlen);
const char *replyval = RedisModule_CallReplyStringPtr(reply, &replylen);
return replyval &&
expectedlen == replylen &&
!strncmp(expectedval, replyval, replylen);
}
typedef struct _SetParams {
RedisModuleString **key_val_pairs;
size_t length;
} SetParams;
typedef struct _PubParams {
RedisModuleString **channel_msg_pairs;
size_t length;
} PubParams;
typedef struct _DelParams {
RedisModuleString **keys;
size_t length;
} DelParams;
typedef enum _ExstringsStatus {
EXSTRINGS_STATUS_NO_ERRORS = 0,
EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT,
EXSTRINGS_STATUS_NOT_SET
} ExstringsStatus;
void readNgetArgs(RedisModuleCtx *ctx, RedisModuleString **argv, int argc,
NgetArgs* nget_args, ExstringsStatus* status)
{
size_t str_len;
long long number;
if(argc == 2) {
nget_args->key = argv[1];
nget_args->count = def_count_str;
} else if (argc == 4) {
if (strcasecmp(RedisModule_StringPtrLen(argv[2], &str_len), "count")) {
RedisModule_ReplyWithError(ctx,"-ERR syntax error");
*status = EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT;
return;
}
int ret = RedisModule_StringToLongLong(argv[3], &number) != REDISMODULE_OK;
if (ret != REDISMODULE_OK || number < 1) {
RedisModule_ReplyWithError(ctx,"-ERR value is not an integer or out of range");
*status = EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT;
return;
}
nget_args->key = argv[1];
nget_args->count = argv[3];
} else {
/* In redis there is a bug (or undocumented feature see link)
* where calling 'RedisModule_WrongArity'
* within a blocked client will crash redis.
*
* Therefore we need to call this function to validate args
* before putting the client into blocking mode.
*
* Link to issue:
* https://github.com/antirez/redis/issues/6382
* 'If any thread tries to access the command arguments from
* within the ThreadSafeContext they will crash redis' */
RedisModule_WrongArity(ctx);
*status = EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT;
return;
}
*status = EXSTRINGS_STATUS_NO_ERRORS;
return;
}
long long callReplyLongLong(RedisModuleCallReply* reply)
{
const char* cursor_str_ptr = RedisModule_CallReplyStringPtr(reply, NULL);
return strtoll(cursor_str_ptr, NULL, 10);
}
void forwardIfError(RedisModuleCtx *ctx, RedisModuleCallReply *reply, ExstringsStatus* status)
{
if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_ERROR) {
RedisModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply);
*status = EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT;
}
*status = EXSTRINGS_STATUS_NO_ERRORS;
}
typedef struct _ScannedKeys {
RedisModuleString **keys;
size_t len;
} ScannedKeys;
ScannedKeys* allocScannedKeys(size_t len)
{
ScannedKeys *sk = RedisModule_Alloc(sizeof(ScannedKeys));
if (sk) {
sk->len = len;
sk->keys = RedisModule_Alloc(sizeof(RedisModuleString *)*len);
}
return sk;
}
void freeScannedKeys(RedisModuleCtx *ctx, ScannedKeys* sk)
{
if (sk) {
size_t j;
for (j = 0; j < sk->len; j++)
RedisModule_FreeString(ctx, sk->keys[j]);
RedisModule_Free(sk->keys);
}
RedisModule_Free(sk);
}
typedef struct _ScanSomeState {
RedisModuleString *key;
RedisModuleString *count;
long long cursor;
} ScanSomeState;
ScannedKeys *scanSome(RedisModuleCtx* ctx, ScanSomeState* state, ExstringsStatus* status)
{
RedisModuleString *scanargv[SCANARGC] = {NULL};
scanargv[0] = RedisModule_CreateStringFromLongLong(ctx, state->cursor);
scanargv[1] = match_str;
scanargv[2] = state->key;
scanargv[3] = count_str;
scanargv[4] = state->count;
RedisModuleCallReply *reply;
reply = RedisModule_Call(ctx, "SCAN", "v", scanargv, SCANARGC);
RedisModule_FreeString(ctx, scanargv[0]);
forwardIfError(ctx, reply, status);
if (*status == EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT)
return NULL;
state->cursor = callReplyLongLong(RedisModule_CallReplyArrayElement(reply, 0));
RedisModuleCallReply *cr_keys =
RedisModule_CallReplyArrayElement(reply, 1);
size_t scanned_keys_len = RedisModule_CallReplyLength(cr_keys);
if (scanned_keys_len == 0) {
RedisModule_FreeCallReply(reply);
*status = EXSTRINGS_STATUS_NO_ERRORS;
return NULL;
}
ScannedKeys *scanned_keys = allocScannedKeys(scanned_keys_len);
if (scanned_keys == NULL) {
RedisModule_FreeCallReply(reply);
RedisModule_ReplyWithError(ctx,"-ERR Out of memory");
*status = EXSTRINGS_STATUS_ERROR_AND_REPLY_SENT;
return NULL;
}
scanned_keys->len = scanned_keys_len;
size_t j;
for (j = 0; j < scanned_keys_len; j++) {
RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(cr_keys,j));
scanned_keys->keys[j] = rms;
}
RedisModule_FreeCallReply(reply);
*status = EXSTRINGS_STATUS_NO_ERRORS;
return scanned_keys;
}
inline void unlockThreadsafeContext(RedisModuleCtx *ctx, bool using_threadsafe_context)
{
if (using_threadsafe_context)
RedisModule_ThreadSafeContextUnlock(ctx);
}
inline void lockThreadsafeContext(RedisModuleCtx *ctx, bool using_threadsafe_context)
{
if (using_threadsafe_context)
RedisModule_ThreadSafeContextLock(ctx);
}
void multiPubCommand(RedisModuleCtx *ctx, PubParams* pubParams)
{
RedisModuleCallReply *reply = NULL;
for (unsigned int i = 0 ; i < pubParams->length ; i += 2) {
reply = RedisModule_Call(ctx, "PUBLISH", "v", pubParams->channel_msg_pairs + i, 2);
RedisModule_FreeCallReply(reply);
}
}
int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc, const int flag)
{
RedisModuleString *oldvalstr = NULL;
RedisModuleCallReply *reply = NULL;
if (argc < 4)
return RedisModule_WrongArity(ctx);
else
oldvalstr = argv[3];
/*Check if key type is string*/
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ);
int type = RedisModule_KeyType(key);
RedisModule_CloseKey(key);
if (type == REDISMODULE_KEYTYPE_EMPTY) {
if (flag == OBJ_OP_IE){
RedisModule_ReplyWithNull(ctx);
return REDISMODULE_OK;
}
} else if (type != REDISMODULE_KEYTYPE_STRING) {
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
}
/*Get the value*/
reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
ASSERT_NOERROR(reply)
size_t curlen=0, oldvallen=0;
const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
if (((flag == OBJ_OP_IE) &&
(!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
||
((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
!strncmp(oldval, curval, curlen))) {
RedisModule_FreeCallReply(reply);
return RedisModule_ReplyWithNull(ctx);
}
RedisModule_FreeCallReply(reply);
/* Prepare the arguments for the command. */
int i, j=0, cmdargc=argc-2;
RedisModuleString *cmdargv[cmdargc];
for (i = 1; i < argc; i++) {
if (i == 3)
continue;
cmdargv[j++] = argv[i];
}
/* Call the command and pass back the reply. */
reply = RedisModule_Call(ctx, "SET", "v!", cmdargv, cmdargc);
ASSERT_NOERROR(reply)
RedisModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply);
return REDISMODULE_OK;
}
int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
return setStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
}
int SetNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
return setStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
}
int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc, const int flag)
{
RedisModuleString *oldvalstr = NULL;
RedisModuleCallReply *reply = NULL;
if (argc == 3)
oldvalstr = argv[2];
else
return RedisModule_WrongArity(ctx);
/*Check if key type is string*/
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ);
int type = RedisModule_KeyType(key);
RedisModule_CloseKey(key);
if (type == REDISMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithLongLong(ctx, 0);
} else if (type != REDISMODULE_KEYTYPE_STRING) {
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
}
/*Get the value*/
reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
ASSERT_NOERROR(reply)
size_t curlen = 0, oldvallen = 0;
const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
if (((flag == OBJ_OP_IE) &&
(!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
||
((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
!strncmp(oldval, curval, curlen))) {
RedisModule_FreeCallReply(reply);
return RedisModule_ReplyWithLongLong(ctx, 0);
}
RedisModule_FreeCallReply(reply);
/* Prepare the arguments for the command. */
int cmdargc=1;
RedisModuleString *cmdargv[1];
cmdargv[0] = argv[1];
/* Call the command and pass back the reply. */
reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, cmdargc);
ASSERT_NOERROR(reply)
RedisModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply);
return REDISMODULE_OK;
}
int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
return delStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
}
int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
return delStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
}
int setPubStringCommon(RedisModuleCtx *ctx, SetParams* setParamsPtr, PubParams* pubParamsPtr)
{
RedisModuleCallReply *setReply;
setReply = RedisModule_Call(ctx, "MSET", "v!", setParamsPtr->key_val_pairs, setParamsPtr->length);
ASSERT_NOERROR(setReply)
multiPubCommand(ctx, pubParamsPtr);
RedisModule_ReplyWithCallReply(ctx, setReply);
RedisModule_FreeCallReply(setReply);
return REDISMODULE_OK;
}
int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 5 || (argc % 2) == 0)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
SetParams setParams = {
.key_val_pairs = argv + 1,
.length = argc - 3
};
PubParams pubParams = {
.channel_msg_pairs = argv + 1 + setParams.length,
.length = 2
};
return setPubStringCommon(ctx, &setParams, &pubParams);
}
int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 7 || (argc % 2) == 0)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
long long setPairsCount, pubPairsCount;
RedisModule_StringToLongLong(argv[1], &setPairsCount);
RedisModule_StringToLongLong(argv[2], &pubPairsCount);
if (setPairsCount < 1 || pubPairsCount < 1)
return RedisModule_ReplyWithError(ctx, "ERR SET_PAIR_COUNT and PUB_PAIR_COUNT must be greater than zero");
long long setLen, pubLen;
setLen = 2*setPairsCount;
pubLen = 2*pubPairsCount;
if (setLen + pubLen + 3 != argc)
return RedisModule_ReplyWithError(ctx, "ERR SET_PAIR_COUNT or PUB_PAIR_COUNT do not match the total pair count");
SetParams setParams = {
.key_val_pairs = argv + 3,
.length = setLen
};
PubParams pubParams = {
.channel_msg_pairs = argv + 3 + setParams.length,
.length = pubLen
};
return setPubStringCommon(ctx, &setParams, &pubParams);
}
int setIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
{
SetParams setParams = {
.key_val_pairs = argv + 1,
.length = 2
};
PubParams pubParams = {
.channel_msg_pairs = argv + 4,
.length = argc - 4
};
RedisModuleString *key = setParams.key_val_pairs[0];
RedisModuleString *oldvalstr = argv[3];
int type = getKeyType(ctx, key);
if (flag == OBJ_OP_IE && type == REDISMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithNull(ctx);
} else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
}
RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key);
ASSERT_NOERROR(reply)
bool is_equal = replyContentsEqualString(reply, oldvalstr);
RedisModule_FreeCallReply(reply);
if ((flag == OBJ_OP_IE && !is_equal) ||
(flag == OBJ_OP_NE && is_equal)) {
return RedisModule_ReplyWithNull(ctx);
}
return setPubStringCommon(ctx, &setParams, &pubParams);
}
int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc != 6)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
}
int SetIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 6 || (argc % 2) != 0)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
}
int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc != 6)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
}
int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
{
SetParams setParams = {
.key_val_pairs = argv + 1,
.length = 2
};
PubParams pubParams = {
.channel_msg_pairs = argv + 3,
.length = argc - 3
};
RedisModuleString *key = setParams.key_val_pairs[0];
int type = getKeyType(ctx, key);
if ((flag == OBJ_OP_XX && type == REDISMODULE_KEYTYPE_EMPTY) ||
(flag == OBJ_OP_NX && type == REDISMODULE_KEYTYPE_STRING)) {
return RedisModule_ReplyWithNull(ctx);
} else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
return REDISMODULE_OK;
}
return setPubStringCommon(ctx, &setParams, &pubParams);
}
int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc != 5)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
}
int SetNXMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 5 || (argc % 2) == 0)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
}
int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc != 5)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_XX);
}
int delPubStringCommon(RedisModuleCtx *ctx, DelParams *delParamsPtr, PubParams *pubParamsPtr)
{
RedisModuleCallReply *reply = RedisModule_Call(ctx, "UNLINK", "v!", delParamsPtr->keys, delParamsPtr->length);
ASSERT_NOERROR(reply)
int replytype = RedisModule_CallReplyType(reply);
if (replytype == REDISMODULE_REPLY_NULL) {
RedisModule_ReplyWithNull(ctx);
} else if (RedisModule_CallReplyInteger(reply) == 0) {
RedisModule_ReplyWithCallReply(ctx, reply);
} else {
RedisModule_ReplyWithCallReply(ctx, reply);
multiPubCommand(ctx, pubParamsPtr);
}
RedisModule_FreeCallReply(reply);
return REDISMODULE_OK;
}
int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 4)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
DelParams delParams = {
.keys = argv + 1,
.length = argc - 3
};
PubParams pubParams = {
.channel_msg_pairs = argv + 1 + delParams.length,
.length = 2
};
return delPubStringCommon(ctx, &delParams, &pubParams);
}
int DelMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 6)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
long long delCount, pubPairsCount;
RedisModule_StringToLongLong(argv[1], &delCount);
RedisModule_StringToLongLong(argv[2], &pubPairsCount);
if (delCount < 1 || pubPairsCount < 1)
return RedisModule_ReplyWithError(ctx, "ERR DEL_COUNT and PUB_PAIR_COUNT must be greater than zero");
long long delLen, pubLen;
delLen = delCount;
pubLen = 2*pubPairsCount;
if (delLen + pubLen + 3 != argc)
return RedisModule_ReplyWithError(ctx, "ERR DEL_COUNT or PUB_PAIR_COUNT do not match the total pair count");
DelParams delParams = {
.keys = argv + 3,
.length = delLen
};
PubParams pubParams = {
.channel_msg_pairs = argv + 3 + delParams.length,
.length = pubLen
};
return delPubStringCommon(ctx, &delParams, &pubParams);
}
int delIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
{
DelParams delParams = {
.keys = argv + 1,
.length = 1
};
PubParams pubParams = {
.channel_msg_pairs = argv + 3,
.length = argc - 3
};
RedisModuleString *key = argv[1];
RedisModuleString *oldvalstr = argv[2];
int type = getKeyType(ctx, key);
if (type == REDISMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithLongLong(ctx, 0);
} else if (type != REDISMODULE_KEYTYPE_STRING) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
}
RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key);
ASSERT_NOERROR(reply)
bool is_equal = replyContentsEqualString(reply, oldvalstr);
RedisModule_FreeCallReply(reply);
if ((flag == OBJ_OP_IE && !is_equal) ||
(flag == OBJ_OP_NE && is_equal)) {
return RedisModule_ReplyWithLongLong(ctx, 0);
}
return delPubStringCommon(ctx, &delParams, &pubParams);
}
int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc != 5)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
}
int DelIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc < 5 || (argc % 2) == 0)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
}
int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc != 5)
return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx);
return delIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
}
int Nget_RedisCommand(RedisModuleCtx *ctx, NgetArgs* nget_args, bool using_threadsafe_context)
{
int ret = REDISMODULE_OK;
size_t replylen = 0;
RedisModuleCallReply *reply = NULL;
ExstringsStatus status = EXSTRINGS_STATUS_NOT_SET;
ScanSomeState scan_state;
ScannedKeys *scanned_keys;
scan_state.key = nget_args->key;
scan_state.count = nget_args->count;
scan_state.cursor = 0;
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN);
do {
lockThreadsafeContext(ctx, using_threadsafe_context);
status = EXSTRINGS_STATUS_NOT_SET;
scanned_keys = scanSome(ctx, &scan_state, &status);
if (status != EXSTRINGS_STATUS_NO_ERRORS) {
unlockThreadsafeContext(ctx, using_threadsafe_context);
ret = REDISMODULE_ERR;
break;
} else if (scanned_keys == NULL) {
unlockThreadsafeContext(ctx, using_threadsafe_context);
continue;
}
reply = RedisModule_Call(ctx, "MGET", "v", scanned_keys->keys, scanned_keys->len);
unlockThreadsafeContext(ctx, using_threadsafe_context);
status = EXSTRINGS_STATUS_NOT_SET;
forwardIfError(ctx, reply, &status);
if (status != EXSTRINGS_STATUS_NO_ERRORS) {
freeScannedKeys(ctx, scanned_keys);
ret = REDISMODULE_ERR;
break;
}
size_t i;
for (i = 0; i < scanned_keys->len; i++) {
RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, i));
if (rms) {
RedisModule_ReplyWithString(ctx, scanned_keys->keys[i]);
RedisModule_ReplyWithString(ctx, rms);
RedisModule_FreeString(ctx, rms);
replylen += 2;
}
}
RedisModule_FreeCallReply(reply);
freeScannedKeys(ctx, scanned_keys);
} while (scan_state.cursor != 0);
RedisModule_ReplySetArrayLength(ctx,replylen);
return ret;
}
/* The thread entry point that actually executes the blocking part
* of the command nget.noatomic
*/
void *NGet_NoAtomic_ThreadMain(void *arg)
{
pthread_detach(pthread_self());
RedisModuleBlockedClientArgs *bca = arg;
RedisModuleBlockedClient *bc = bca->bc;
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(bc);
Nget_RedisCommand(ctx, &bca->nget_args, true);
RedisModule_FreeThreadSafeContext(ctx);
RedisModule_UnblockClient(bc, NULL);
RedisModule_Free(bca);
return NULL;
}
int NGet_NoAtomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
pthread_t tid;
InitStaticVariable();
RedisModuleBlockedClientArgs *bca = RedisModule_Alloc(sizeof(RedisModuleBlockedClientArgs));
if (bca == NULL) {
RedisModule_ReplyWithError(ctx,"-ERR Out of memory");
return REDISMODULE_ERR;
}
ExstringsStatus status = EXSTRINGS_STATUS_NOT_SET;
readNgetArgs(ctx, argv, argc, &bca->nget_args, &status);
if (status != EXSTRINGS_STATUS_NO_ERRORS) {
RedisModule_Free(bca);
return REDISMODULE_ERR;
}
/* Note that when blocking the client we do not set any callback: no
* timeout is possible since we passed '0', nor we need a reply callback
* because we'll use the thread safe context to accumulate a reply. */
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx,NULL,NULL,NULL,0);
bca->bc = bc;
/* Now that we setup a blocking client, we need to pass the control
* to the thread. However we need to pass arguments to the thread:
* the reference to the blocked client handle. */
if (pthread_create(&tid,NULL,NGet_NoAtomic_ThreadMain,bca) != 0) {
RedisModule_AbortBlock(bc);
RedisModule_Free(bca);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread");
}
return REDISMODULE_OK;
}
int NGet_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
NgetArgs nget_args;
ExstringsStatus status = EXSTRINGS_STATUS_NOT_SET;
InitStaticVariable();
readNgetArgs(ctx, argv, argc, &nget_args, &status);
if (status != EXSTRINGS_STATUS_NO_ERRORS) {
return REDISMODULE_ERR;
}
return Nget_RedisCommand(ctx, &nget_args, false);
}
int NDel_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModule_AutoMemory(ctx);
int ret = REDISMODULE_OK;
long long replylen = 0;
RedisModuleCallReply *reply = NULL;
ExstringsStatus status = EXSTRINGS_STATUS_NOT_SET;
ScanSomeState scan_state;
ScannedKeys *scanned_keys = NULL;
InitStaticVariable();
if (argc != 2)
return RedisModule_WrongArity(ctx);
scan_state.key = argv[1];
scan_state.count = def_count_str;
scan_state.cursor = 0;
do {
status = EXSTRINGS_STATUS_NOT_SET;
scanned_keys = scanSome(ctx, &scan_state, &status);
if (status != EXSTRINGS_STATUS_NO_ERRORS) {
ret = REDISMODULE_ERR;
break;
} else if (scanned_keys == NULL) {
continue;
}
reply = RedisModule_Call(ctx, "UNLINK", "v!", scanned_keys->keys, scanned_keys->len);
status = EXSTRINGS_STATUS_NOT_SET;
forwardIfError(ctx, reply, &status);
if (status != EXSTRINGS_STATUS_NO_ERRORS) {
freeScannedKeys(ctx, scanned_keys);
ret = REDISMODULE_ERR;
break;
}
replylen += RedisModule_CallReplyInteger(reply);
RedisModule_FreeCallReply(reply);
freeScannedKeys(ctx, scanned_keys);
} while (scan_state.cursor != 0);
if (ret == REDISMODULE_OK) {
RedisModule_ReplyWithLongLong(ctx, replylen);
}
return ret;
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"exstrings",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setie",
SetIE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setne",
SetNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"delie",
DelIE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"delne",
DelNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"nget.atomic",
NGet_Atomic_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"nget.noatomic",
NGet_NoAtomic_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"ndel.atomic",
NDel_Atomic_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"msetpub",
SetPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"msetmpub",
SetMPub_RedisCommand,"write deny-oom pubsub",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setiepub",
SetIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setiempub",
SetIEMPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setnepub",
SetNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setxxpub",
SetXXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setnxpub",
SetNXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"setnxmpub",
SetNXMPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"delpub",
DelPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"delmpub",
DelMPub_RedisCommand,"write deny-oom pubsub",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"deliepub",
DelIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"deliempub",
DelIEMPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"delnepub",
DelNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#ifndef EXSTRING_UT_HELPERS_H_
#define EXSTRING_UT_HELPERS_H_
extern "C" {
#include "exstringsStub.h"
#include "redismodule.h"
}
#define UT_DUMMY_BUFFER_SIZE 1
#define UT_DUMMY_PTR_ADDRESS 1234
RedisModuleString **createRedisStrVec(size_t size);
void returnNKeysFromScanSome(long keys);
#endif

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#ifndef COMMONSTUB_H_
#define COMMONSTUB_H_
#include <pthread.h>
#define UT_DUMMY_THREAD_ID 1234
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
int pthread_detach(pthread_t thread);
pthread_t pthread_self(void);
#endif

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#ifndef EXSTRINGSTUB_H_
#define EXSTRINGSTUB_H_
#include "redismodule.h"
int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) ;
int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetNXMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int DelMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int DelIEMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int NDel_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int NGet_Atomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int NGet_NoAtomic_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
void *NGet_NoAtomic_ThreadMain(void *arg);
#endif

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#ifndef REDISMODULE_H
#define REDISMODULE_H
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
/* Error status return values. */
#define REDISMODULE_OK 0
#define REDISMODULE_ERR 1
/* API versions. */
#define REDISMODULE_APIVER_1 1
/* API flags and constants */
#define REDISMODULE_READ (1<<0)
#define REDISMODULE_WRITE (1<<1)
/* Key types. */
#define REDISMODULE_KEYTYPE_EMPTY 0
#define REDISMODULE_KEYTYPE_STRING 1
#define REDISMODULE_KEYTYPE_LIST 2
#define REDISMODULE_KEYTYPE_HASH 3
#define REDISMODULE_KEYTYPE_SET 4
#define REDISMODULE_KEYTYPE_ZSET 5
#define REDISMODULE_KEYTYPE_MODULE 6
/* Reply types. */
#define REDISMODULE_REPLY_UNKNOWN -1
#define REDISMODULE_REPLY_STRING 0
#define REDISMODULE_REPLY_ERROR 1
#define REDISMODULE_REPLY_INTEGER 2
#define REDISMODULE_REPLY_ARRAY 3
#define REDISMODULE_REPLY_NULL 4
/* Postponed array length. */
#define REDISMODULE_POSTPONED_ARRAY_LEN -1
/* Error messages. */
#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
#define REDISMODULE_NOT_USED(V) ((void) V)
typedef long long mstime_t;
/* UT dummy definitions for opaque redis types */
typedef struct { int dummy; } RedisModuleCtx;
typedef struct { int dummy; } RedisModuleKey;
typedef struct { int dummy; } RedisModuleString;
typedef struct { int dummy; } RedisModuleCallReply;
typedef struct { int dummy; } RedisModuleIO;
typedef struct { int dummy; } RedisModuleType;
typedef struct { int dummy; } RedisModuleDigest;
typedef struct { int dummy; } RedisModuleBlockedClient;
typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
typedef void (*RedisModuleTypeFreeFunc)(void *value);
typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
int RedisModule_WrongArity(RedisModuleCtx *ctx);
int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll);
void *RedisModule_OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
void RedisModule_FreeCallReply(RedisModuleCallReply *reply);
int RedisModule_CallReplyType(RedisModuleCallReply *reply);
long long RedisModule_CallReplyInteger(RedisModuleCallReply *reply);
const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len);
int RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err);
int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str);
int RedisModule_ReplyWithNull(RedisModuleCtx *ctx);
int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len);
RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply);
int RedisModule_KeyType(RedisModuleKey *kp);
void RedisModule_CloseKey(RedisModuleKey *kp);
int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply);
RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx);
int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len);
void RedisModule_FreeString(RedisModuleCtx *ctx, RedisModuleString *str);
RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms);
int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata);
int RedisModule_AbortBlock(RedisModuleBlockedClient *bc);
RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len);
void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx);
int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll);
void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx);
void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx);
void RedisModule_ReplySetArrayLength(RedisModuleCtx *ctx, long len);
RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc);
RedisModuleString *RedisModule_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll);
void RedisModule_AutoMemory(RedisModuleCtx *ctx);
void *RedisModule_Alloc(size_t bytes);
void RedisModule_Free(void *ptr);
#endif /* REDISMODULE_H */

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#include <unistd.h>
#include <string.h>
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "redismodule.h"
#include "commonStub.h"
}
#include <CppUTest/TestHarness.h>
#include <CppUTestExt/MockSupport.h>
#include <CppUTest/MemoryLeakDetectorMallocMacros.h>
typedef struct RedisModuleBlockedClientArgs {
RedisModuleBlockedClient *bc;
RedisModuleString **argv;
int argc;
} RedisModuleBlockedClientArgs;
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
{
(void)thread;
(void)attr;
(void)start_routine;
if (mock().getData("pthread_create_free_block_client_args").getIntValue()) {
RedisModuleBlockedClientArgs* bca = (RedisModuleBlockedClientArgs*)arg;
free(bca->bc);
free(bca);
}
return mock()
.actualCall("pthread_create")
.returnIntValueOrDefault(0);
}
int pthread_detach(pthread_t thread)
{
(void)thread;
return mock()
.actualCall("pthread_detach")
.returnIntValueOrDefault(0);
}
pthread_t pthread_self(void)
{
return mock()
.actualCall("pthread_self")
.returnIntValueOrDefault(UT_DUMMY_THREAD_ID);
}

View File

@@ -0,0 +1,360 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#include <unistd.h>
#include <string.h>
extern "C" {
#include "redismodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
}
#include <CppUTest/TestHarness.h>
#include <CppUTestExt/MockSupport.h>
#include "ut_helpers.hpp"
RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...)
{
(void)ctx;
(void)fmt;
return (RedisModuleCallReply *)mock().actualCall("RedisModule_Call")
.withParameter("cmdname", cmdname)
.returnPointerValueOrDefault(malloc(UT_DUMMY_BUFFER_SIZE));
}
int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str)
{
(void)ctx;
(void)str;
return mock()
.actualCall("RedisModule_ReplyWithString")
.returnIntValueOrDefault(REDISMODULE_OK);
}
RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply)
{
(void)reply;
return (RedisModuleString *)mock().actualCall("RedisModule_CreateStringFromCallReply")
.returnPointerValue();
}
void RedisModule_CloseKey(RedisModuleKey *kp)
{
(void)kp;
mock().actualCall("RedisModule_CloseKey");
}
size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply)
{
(void)reply;
return (size_t)mock().actualCall("RedisModule_CallReplyLength")
.returnIntValue();
}
int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len)
{
(void)ctx;
return (int)mock().actualCall("RedisModule_ReplyWithArray")
.withParameter("len", len)
.returnIntValueOrDefault(REDISMODULE_OK);
}
void RedisModule_ReplySetArrayLength(RedisModuleCtx *ctx, long len)
{
(void)ctx;
mock().actualCall("RedisModule_ReplySetArrayLength")
.withParameter("len", len);
}
RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len)
{
(void)ctx;
(void)ptr;
(void)len;
void* buf = malloc(UT_DUMMY_BUFFER_SIZE);
return (RedisModuleString *) mock()
.actualCall("RedisModule_CreateString")
.returnPointerValueOrDefault(buf);
}
RedisModuleString *RedisModule_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll)
{
(void)ctx;
(void)ll;
void* buf = malloc(UT_DUMMY_BUFFER_SIZE);
return (RedisModuleString *)mock()
.actualCall("RedisModule_CreateStringFromLongLong")
.returnPointerValueOrDefault(buf);
}
void RedisModule_AutoMemory(RedisModuleCtx *ctx)
{
(void)ctx;
mock().actualCall("RedisModule_AutoMemory");
}
void RedisModule_FreeString(RedisModuleCtx *ctx, RedisModuleString *str)
{
(void)ctx;
free(str);
mock().actualCall("RedisModule_FreeString");
}
int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll)
{
(void)str;
return (int)mock().actualCall("RedisModule_StringToLongLong")
.withOutputParameter("ll", ll)
.returnIntValueOrDefault(REDISMODULE_OK);
}
void RedisModule_FreeCallReply(RedisModuleCallReply *reply)
{
free(reply);
mock().actualCall("RedisModule_FreeCallReply");
}
RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx)
{
(void)reply;
(void)idx;
return (RedisModuleCallReply *)mock()
.actualCall("RedisModule_CallReplyArrayElement")
.returnPointerValueOrDefault(NULL);
}
int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll)
{
(void)ctx;
return (int)mock()
.actualCall("RedisModule_ReplyWithLongLong")
.withParameter("ll", (int)ll)
.returnIntValueOrDefault(REDISMODULE_OK);
}
long long RedisModule_CallReplyInteger(RedisModuleCallReply *reply)
{
(void)reply;
return (long long)mock()
.actualCall("RedisModule_CallReplyInteger")
.returnIntValue();
}
int RedisModule_CallReplyType(RedisModuleCallReply *reply)
{
(void)reply;
return (int)mock()
.actualCall("RedisModule_CallReplyType")
.returnIntValue();
}
int RedisModule_WrongArity(RedisModuleCtx *ctx)
{
(void)ctx;
return (int)mock()
.actualCall("RedisModule_WrongArity")
.returnIntValueOrDefault(REDISMODULE_ERR);
}
int RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err)
{
(void)ctx;
(void)err;
return (int)mock()
.actualCall("RedisModule_ReplyWithError")
.returnIntValueOrDefault(REDISMODULE_OK);
}
int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply)
{
(void)ctx;
(void)reply;
return (int)mock()
.actualCall("RedisModule_ReplyWithCallReply")
.returnIntValueOrDefault(REDISMODULE_OK);
}
void *RedisModule_OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode)
{
(void)ctx;
(void)keyname;
(void)mode;
return (void *)mock()
.actualCall("RedisModule_OpenKey")
.returnPointerValue();
}
int RedisModule_KeyType(RedisModuleKey *kp)
{
(void)kp;
return (int)mock()
.actualCall("RedisModule_KeyType")
.returnIntValue();
}
const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len)
{
(void)str;
if (len != NULL) {
return (const char *)mock()
.actualCall("RedisModule_StringPtrLen")
.withOutputParameter("len", len)
.returnPointerValue();
} else {
return (const char *)mock()
.actualCall("RedisModule_StringPtrLen")
.returnPointerValue();
}
}
RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback,
RedisModuleCmdFunc timeout_callback,
void (*free_privdata)(RedisModuleCtx*,void*),
long long timeout_ms)
{
(void)ctx;
(void)reply_callback;
(void)timeout_callback;
(void)free_privdata;
(void)timeout_ms;
void *buf = malloc(UT_DUMMY_BUFFER_SIZE);
return (RedisModuleBlockedClient *)mock()
.actualCall("RedisModule_BlockClient")
.returnPointerValueOrDefault(buf);
}
int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata)
{
(void)privdata;
free(bc);
return (int)mock()
.actualCall("RedisModule_UnblockClient")
.returnIntValueOrDefault(REDISMODULE_OK);
}
const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len)
{
(void)reply;
(void)len;
static char cursor_zero_literal[] = "0";
return (const char *)mock()
.actualCall("RedisModule_CallReplyStringPtr")
.returnPointerValueOrDefault(cursor_zero_literal);
}
int RedisModule_AbortBlock(RedisModuleBlockedClient *bc)
{
free(bc);
return mock()
.actualCall("RedisModule_AbortBlock")
.returnIntValueOrDefault(REDISMODULE_OK);
}
int RedisModule_ReplyWithNull(RedisModuleCtx *ctx)
{
(void)ctx;
return mock()
.actualCall("RedisModule_ReplyWithNull")
.returnIntValueOrDefault(REDISMODULE_OK);
}
void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx)
{
(void)ctx;
int tmp = mock().getData("TimesThreadSafeContextWasUnlocked").getIntValue();
mock().setData("TimesThreadSafeContextWasUnlocked", tmp + 1);
mock()
.actualCall("RedisModule_ThreadSafeContextUnlock");
}
void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx)
{
(void)ctx;
int tmp = mock().getData("TimesThreadSafeContextWasLocked").getIntValue();
mock().setData("TimesThreadSafeContextWasLocked", tmp + 1);
mock()
.actualCall("RedisModule_ThreadSafeContextLock");
}
RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc)
{
(void)bc;
return (RedisModuleCtx *)mock()
.actualCall("RedisModule_GetThreadSafeContext")
.returnPointerValueOrDefault(0);
}
void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx)
{
(void)ctx;
mock()
.actualCall("RedisModule_FreeThreadSafeContext");
}
/* This is included inline inside each Redis module. */
int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver)
{
(void)ctx;
(void)name;
(void)ver;
(void)apiver;
return mock()
.actualCall("RedisModule_Init")
.returnIntValueOrDefault(REDISMODULE_OK);
}
int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep)
{
(void)ctx;
(void)name;
(void)cmdfunc;
(void)strflags;
(void)firstkey;
(void)lastkey;
(void)keystep;
return mock()
.actualCall("RedisModule_CreateCommand")
.returnIntValueOrDefault(REDISMODULE_OK);
}
void *RedisModule_Alloc(size_t bytes)
{
void *buf = malloc(bytes);
return mock()
.actualCall("RedisModule_Alloc")
.returnPointerValueOrDefault(buf);
}
void RedisModule_Free(void *ptr)
{
free(ptr);
mock()
.actualCall("RedisModule_Free");
}

View File

@@ -0,0 +1,437 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#include <unistd.h>
#include <string.h>
extern "C" {
#include "redismodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
}
#include <CppUTest/TestHarness.h>
#include <CppUTestExt/MockSupport.h>
int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep)
{
(void)ctx;
(void)name;
(void)cmdfunc;
(void)strflags;
(void)firstkey;
(void)lastkey;
(void)keystep;
return REDISMODULE_OK;
}
int RedisModule_WrongArity(RedisModuleCtx *ctx)
{
(void)ctx;
mock().setData("RedisModule_WrongArity", 1);
return REDISMODULE_ERR;
}
int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll)
{
(void)ctx;
mock().setData("RedisModule_ReplyWithLongLong", (int)ll);
return REDISMODULE_OK;
}
void *RedisModule_OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode)
{
(void)ctx;
(void)keyname;
(void)mode;
if (mock().hasData("RedisModule_OpenKey_no"))
{
return (void*)(0);
}
if (mock().hasData("RedisModule_OpenKey_have"))
{
return (void*)(111111);
}
return (void*)(0);
}
RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...)
{
(void)ctx;
(void)cmdname;
(void)fmt;
if (!strcmp(cmdname, "GET"))
mock().setData("GET", 1);
else if (!strcmp(cmdname, "SET"))
mock().setData("SET", 1);
else if (!strcmp(cmdname, "MSET"))
mock().setData("MSET", 1);
else if (!strcmp(cmdname, "DEL"))
mock().setData("DEL", 1);
else if (!strcmp(cmdname, "UNLINK"))
mock().setData("UNLINK", 1);
else if (!strcmp(cmdname, "PUBLISH"))
mock().setData("PUBLISH", mock().getData("PUBLISH").getIntValue() + 1);
else if (!strcmp(cmdname, "KEYS"))
mock().setData("KEYS", 1);
else if (!strcmp(cmdname, "MGET"))
mock().setData("MGET", 1);
else if (!strcmp(cmdname, "SCAN"))
mock().setData("SCAN", 1);
if (mock().hasData("RedisModule_Call_Return_Null"))
return NULL;
else
return (RedisModuleCallReply *)1;
}
void RedisModule_FreeCallReply(RedisModuleCallReply *reply)
{
(void)reply;
mock().setData("RedisModule_FreeCallReply", mock().getData("RedisModule_FreeCallReply").getIntValue()+1);
}
int RedisModule_CallReplyType(RedisModuleCallReply *reply)
{
(void)reply;
if (mock().hasData("RedisModule_CallReplyType_null"))
{
return REDISMODULE_REPLY_NULL;
}
if (mock().hasData("RedisModule_CallReplyType_inter"))
{
return REDISMODULE_REPLY_INTEGER;
}
if (mock().hasData("RedisModule_CallReplyType_str"))
{
return REDISMODULE_REPLY_STRING;
}
if (mock().hasData("RedisModule_CallReplyType_err"))
{
return REDISMODULE_REPLY_ERROR;
}
return REDISMODULE_REPLY_NULL;;
}
long long RedisModule_CallReplyInteger(RedisModuleCallReply *reply)
{
(void)reply;
return mock().getData("RedisModule_CallReplyInteger").getIntValue();
}
const char *RedisModule_StringPtrLen(const RedisModuleString *str, size_t *len)
{
(void)str;
if (len) *len = 5;
if (mock().hasData("RedisModule_String_same"))
{
return "11111";
}
if (mock().hasData("RedisModule_String_nosame"))
{
return "22222";
}
if (mock().hasData("RedisModule_String_count"))
{
return "COUNT";
}
if (mock().hasData("RedisModule_String_count1"))
{
if (len) *len = 6;
return "COUNT1";
}
return "11111";
}
int RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err)
{
(void)ctx;
(void)err;
mock().setData("RedisModule_ReplyWithError", 1);
return REDISMODULE_OK;
}
int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str)
{
(void)ctx;
(void)str;
mock().setData("RedisModule_ReplyWithString", mock().getData("RedisModule_ReplyWithString").getIntValue()+1);
return REDISMODULE_OK;
}
int RedisModule_ReplyWithNull(RedisModuleCtx *ctx)
{
(void)ctx;
mock().setData("RedisModule_ReplyWithNull", 1);
return REDISMODULE_OK;
}
int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply)
{
(void)ctx;
(void)reply;
mock().setData("RedisModule_ReplyWithCallReply", 1);
return REDISMODULE_OK;
}
const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len)
{
(void)reply;
if (mock().hasData("RedisModule_String_same"))
{
if (len)
*len = 5;
return "11111";
}
if (mock().hasData("RedisModule_String_nosame"))
{
if (len)
*len = 6;
return "333333";
}
return "11111";
}
RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply)
{
(void)reply;
return (RedisModuleString *)1;
}
int RedisModule_KeyType(RedisModuleKey *kp)
{
(void)kp;
if (mock().hasData("RedisModule_KeyType_empty"))
{
return REDISMODULE_KEYTYPE_EMPTY;
}
if (mock().hasData("RedisModule_KeyType_str"))
{
return REDISMODULE_KEYTYPE_STRING;
}
if (mock().hasData("RedisModule_KeyType_set"))
{
return REDISMODULE_KEYTYPE_SET;
}
return REDISMODULE_KEYTYPE_EMPTY;
}
void RedisModule_CloseKey(RedisModuleKey *kp)
{
(void)kp;
mock().actualCall("RedisModule_CloseKey");
}
/* This is included inline inside each Redis module. */
int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver)
{
(void)ctx;
(void)name;
(void)ver;
(void)apiver;
return REDISMODULE_OK;
}
size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply)
{
(void)reply;
return mock().getData("RedisModule_CallReplyLength").getIntValue();
}
RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx)
{
(void)reply;
(void)idx;
return (RedisModuleCallReply *)1;
}
int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len)
{
(void)ctx;
mock().setData("RedisModule_ReplyWithArray", (int)len);
return REDISMODULE_OK;
}
void RedisModule_FreeString(RedisModuleCtx *ctx, RedisModuleString *str)
{
(void)ctx;
(void)str;
mock().setData("RedisModule_FreeString", mock().getData("RedisModule_FreeString").getIntValue()+1);
return;
}
RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms)
{
(void)ctx;
(void)reply_callback;
(void)timeout_callback;
(void)free_privdata;
(void)timeout_ms;
RedisModuleBlockedClient *bc = (RedisModuleBlockedClient*)malloc(sizeof(RedisModuleBlockedClient));
mock().setData("RedisModule_BlockClient", 1);
return bc;
}
int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata)
{
(void)privdata;
free(bc);
mock().setData("RedisModule_UnblockClient", mock().getData("RedisModule_UnblockClient").getIntValue()+1);
return REDISMODULE_OK;
}
int RedisModule_AbortBlock(RedisModuleBlockedClient *bc)
{
free(bc);
mock().setData("RedisModule_AbortBlock", 1);
return REDISMODULE_OK;
}
RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len)
{
(void)ctx;
(void)ptr;
(void)len;
RedisModuleString *rms = (RedisModuleString*)malloc(sizeof(RedisModuleString));
mock().setData("RedisModule_CreateString", mock().getData("RedisModule_CreateString").getIntValue()+1);
return rms;
}
void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx)
{
(void)ctx;
mock().setData("RedisModule_FreeThreadSafeContext", 1);
return;
}
int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll)
{
(void)str;
int call_no = mock().getData("RedisModule_StringToLongLongCallCount").getIntValue();
switch(call_no) {
case 0:
*ll = mock().getData("RedisModule_StringToLongLongCall_1").getIntValue();
break;
case 1:
*ll = mock().getData("RedisModule_StringToLongLongCall_2").getIntValue();
break;
default:
*ll = mock().getData("RedisModule_StringToLongLongCallDefault").getIntValue();
}
mock().setData("RedisModule_StringToLongLongCallCount", call_no + 1);
return REDISMODULE_OK;
}
void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx)
{
(void)ctx;
mock().setData("RedisModule_ThreadSafeContextLock", 1);
return;
}
void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx)
{
(void)ctx;
mock().setData("RedisModule_ThreadSafeContextUnlock", 1);
return;
}
void RedisModule_ReplySetArrayLength(RedisModuleCtx *ctx, long len)
{
(void)ctx;
mock().setData("RedisModule_ReplySetArrayLength", (int)len);
return;
}
RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc)
{
(void) bc;
mock().setData("RedisModule_GetThreadSafeContext", 1);
return NULL;
}
RedisModuleString *RedisModule_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll)
{
(void)ctx;
(void)ll;
RedisModuleString *rms = (RedisModuleString*)malloc(sizeof(RedisModuleString));
mock().setData("RedisModule_CreateStringFromLongLong", mock().getData("RedisModule_CreateStringFromLongLong").getIntValue()+1);
return rms;
}
void RedisModule_AutoMemory(RedisModuleCtx *ctx)
{
(void)ctx;
int old = mock().getData("RedisModule_AutoMemory").getIntValue();
mock().setData("RedisModule_AutoMemory", old + 1);
return;
}
void *RedisModule_Alloc(size_t bytes)
{
mock()
.actualCall("RedisModule_Alloc");
return malloc(bytes);
}
void RedisModule_Free(void *ptr)
{
mock()
.actualCall("RedisModule_Free");
free(ptr);
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
extern "C" {
#include "exstringsStub.h"
#include "redismodule.h"
}
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"
#include "ut_helpers.hpp"
void nDelReturnNKeysFromUnlink(int count)
{
mock()
.expectOneCall("RedisModule_CallReplyInteger")
.andReturnValue(count);
}
TEST_GROUP(exstrings_ndel)
{
void setup()
{
mock().enable();
mock().ignoreOtherCalls();
}
void teardown()
{
mock().clear();
mock().disable();
}
};
TEST(exstrings_ndel, ndel_atomic_automemory_enabled)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_AutoMemory");
int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 3);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_ERR);
delete []redisStrVec;
}
TEST(exstrings_ndel, ndel_atomic_command_parameter_parameter_number_incorrect)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_WrongArity");
int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 3);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_ERR);
delete []redisStrVec;
}
TEST(exstrings_ndel, ndel_atomic_command_scan_0_keys_found)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
returnNKeysFromScanSome(0);
mock().expectOneCall("RedisModule_ReplyWithLongLong")
.withParameter("ll", 0);
int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_OK);
delete []redisStrVec;
}
TEST(exstrings_ndel, ndel_atomic_command_scan_3_keys_found_3_keys_deleted)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock()
.expectOneCall("RedisModule_Call")
.withParameter("cmdname", "UNLINK");
nDelReturnNKeysFromUnlink(3);
mock().expectOneCall("RedisModule_ReplyWithLongLong")
.withParameter("ll", 3);
int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_OK);
delete []redisStrVec;
}
TEST(exstrings_ndel, ndel_atomic_command_scan_3_keys_found_0_keys_deleted)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock()
.expectOneCall("RedisModule_Call")
.withParameter("cmdname", "UNLINK");
nDelReturnNKeysFromUnlink(0);
mock().expectOneCall("RedisModule_ReplyWithLongLong")
.withParameter("ll", 0);
int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_OK);
delete []redisStrVec;
}
TEST(exstrings_ndel, ndel_atomic_command_scan_3_keys_found_1_keys_deleted)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock()
.expectOneCall("RedisModule_Call")
.withParameter("cmdname", "UNLINK");
nDelReturnNKeysFromUnlink(1);
mock().expectOneCall("RedisModule_ReplyWithLongLong")
.withParameter("ll", 1);
int ret = NDel_Atomic_RedisCommand(&ctx, redisStrVec, 2);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_OK);
delete []redisStrVec;
}

View File

@@ -0,0 +1,552 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
extern "C" {
#include "exstringsStub.h"
#include "redismodule.h"
}
#include <string.h>
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"
#include "ut_helpers.hpp"
TEST_GROUP(exstrings_nget)
{
void setup()
{
mock().enable();
mock().ignoreOtherCalls();
}
void teardown()
{
mock().clear();
mock().disable();
}
};
void threadDetachedSuccess()
{
mock().expectOneCall("pthread_detach")
.andReturnValue(0);
}
void nKeysFoundMget(long keys)
{
for (long i = 0 ; i < keys ; i++) {
mock().expectOneCall("RedisModule_CreateStringFromCallReply")
.andReturnValue(malloc(UT_DUMMY_BUFFER_SIZE));
mock().expectNCalls(2, "RedisModule_ReplyWithString");
}
}
void nKeysNotFoundMget(long keys)
{
void* ptr = NULL;
mock().expectNCalls(keys, "RedisModule_CreateStringFromCallReply")
.andReturnValue(ptr);
mock().expectNoCall("RedisModule_ReplyWithString");
}
void expectNReplies(long count)
{
mock().expectOneCall("RedisModule_ReplySetArrayLength")
.withParameter("len", 2*count);
}
void threadSafeContextLockedAndUnlockedEqualTimes()
{
int locked = mock().getData("TimesThreadSafeContextWasLocked").getIntValue();
int unlocked = mock().getData("TimesThreadSafeContextWasUnlocked").getIntValue();
CHECK_EQUAL(locked, unlocked);
}
TEST(exstrings_nget, nget_atomic_automemory_enabled)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
long keys_found_with_scan = 0;
mock().expectOneCall("RedisModule_AutoMemory");
mock().expectOneCall("RedisModule_CallReplyLength")
.andReturnValue((int)keys_found_with_scan);
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 2);
mock().checkExpectations();
CHECK_EQUAL(ret, REDISMODULE_OK);
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_parameter_number_incorrect)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().expectOneCall("RedisModule_WrongArity");
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 3);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_3rd_parameter_was_not_equal_to_COUNT)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(4);
const char * not_count_literal = "NOT_COUNT";
size_t not_count_len = strlen(not_count_literal);
mock().expectOneCall("RedisModule_StringPtrLen")
.withOutputParameterReturning("len", &not_count_len, sizeof(size_t))
.andReturnValue((void*)not_count_literal);
mock().expectOneCall("RedisModule_ReplyWithError");
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 4);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_4th_parameter_was_not_integer)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(4);
const char * count_literal = "COUNT";
size_t count_len = strlen(count_literal);
size_t count_number = 123;
mock().expectOneCall("RedisModule_StringPtrLen")
.withOutputParameterReturning("len", &count_len, sizeof(size_t))
.andReturnValue((void*)count_literal);
mock().expectOneCall("RedisModule_StringToLongLong")
.withOutputParameterReturning("ll", &count_number, sizeof(size_t))
.andReturnValue(REDISMODULE_ERR);
mock().expectOneCall("RedisModule_ReplyWithError");
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 4);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_4th_parameter_was_negative)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(4);
const char * count_literal = "COUNT";
size_t count_len = strlen(count_literal);
size_t count_number = -123;
mock().expectOneCall("RedisModule_StringPtrLen")
.withOutputParameterReturning("len", &count_len, sizeof(size_t))
.andReturnValue((void*)count_literal);
mock().expectOneCall("RedisModule_StringToLongLong")
.withOutputParameterReturning("ll", &count_number, sizeof(size_t))
.andReturnValue(REDISMODULE_OK);
mock().expectOneCall("RedisModule_ReplyWithError");
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 4);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_scan_returned_zero_keys)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(0);
expectNReplies(0);
mock().expectNoCall("RedisModule_Call");
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_3_keys_scanned_0_keys_mget)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "MGET");
nKeysNotFoundMget(3);
mock().expectOneCall("RedisModule_FreeCallReply");
expectNReplies(0);
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_3_keys_scanned_3_keys_mget)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "MGET");
nKeysFoundMget(3);
mock().expectOneCall("RedisModule_FreeCallReply");
expectNReplies(3);
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_atomic_command_3_keys_scanned_2_keys_mget)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "MGET");
nKeysFoundMget(2);
nKeysNotFoundMget(1);
mock().expectOneCall("RedisModule_FreeCallReply");
expectNReplies(2);
int ret = NGet_Atomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_automemory_enabled)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().setData("pthread_create_free_block_client_args", 1);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_AutoMemory");
int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_thread_create_success)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().setData("pthread_create_free_block_client_args", 1);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_BlockClient");
mock().expectOneCall("pthread_create");
mock().expectNoCall("RedisModule_AbortBlock");
int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_thread_create_fail)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(2);
mock().ignoreOtherCalls();
mock().expectOneCall("RedisModule_BlockClient");
mock().expectOneCall("pthread_create")
.andReturnValue(1);
mock().expectOneCall("RedisModule_AbortBlock");
int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec, 2);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_parameter_number_incorrect)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(4);
mock().expectOneCall("RedisModule_WrongArity");
mock().expectNoCall("RedisModule_BlockClient");
int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec, 3);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_threadmain_3rd_parameter_was_not_equal_to_COUNT)
{
RedisModuleCtx ctx;
RedisModuleString ** redisStrVec = createRedisStrVec(4);
const char * not_count_literal = "NOT_COUNT";
size_t not_count_len = strlen(not_count_literal);
mock().expectOneCall("RedisModule_StringPtrLen")
.withOutputParameterReturning("len", &not_count_len, sizeof(size_t))
.andReturnValue((void*)not_count_literal);
mock().expectOneCall("RedisModule_ReplyWithError");
mock().expectNoCall("RedisModule_BlockClient");
int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec, 4);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
threadSafeContextLockedAndUnlockedEqualTimes();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_4th_parameter_was_not_integer)
{
RedisModuleCtx ctx;
const char * count_literal = "COUNT";
size_t count_len = strlen(count_literal);
size_t count_number = -123;
RedisModuleString ** redisStrVec = createRedisStrVec(4);
mock().expectOneCall("RedisModule_StringPtrLen")
.withOutputParameterReturning("len", &count_len, sizeof(size_t))
.andReturnValue((void*)count_literal);
mock().expectOneCall("RedisModule_StringToLongLong")
.withOutputParameterReturning("ll", &count_number, sizeof(size_t))
.andReturnValue(REDISMODULE_OK);
mock().expectOneCall("RedisModule_ReplyWithError");
int ret = NGet_NoAtomic_RedisCommand(&ctx, redisStrVec, 4);
CHECK_EQUAL(ret, REDISMODULE_ERR);
mock().checkExpectations();
threadSafeContextLockedAndUnlockedEqualTimes();
delete []redisStrVec;
}
typedef struct RedisModuleBlockedClientArgs {
RedisModuleBlockedClient *bc;
RedisModuleString **argv;
int argc;
} RedisModuleBlockedClientArgs;
TEST(exstrings_nget, nget_noatomic_threadmain_3_keys_scanned_3_keys_mget)
{
RedisModuleCtx ctx;
RedisModuleBlockedClientArgs *bca =
(RedisModuleBlockedClientArgs*)RedisModule_Alloc(sizeof(RedisModuleBlockedClientArgs));
RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
RedisModuleString ** redisStrVec = createRedisStrVec(2);
bca->bc = bc;
bca->argv = redisStrVec;
bca->argc = 2;
mock().ignoreOtherCalls();
threadDetachedSuccess();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "MGET");
nKeysFoundMget(3);
mock().expectOneCall("RedisModule_FreeCallReply");
expectNReplies(3);
mock().expectOneCall("RedisModule_FreeThreadSafeContext");
mock().expectOneCall("RedisModule_UnblockClient");
NGet_NoAtomic_ThreadMain((void*)bca);
mock().checkExpectations();
threadSafeContextLockedAndUnlockedEqualTimes();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_threadmain_3_keys_scanned_0_keys_mget)
{
RedisModuleCtx ctx;
RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
RedisModuleString ** redisStrVec = createRedisStrVec(2);
bca->bc = bc;
bca->argv = redisStrVec;
bca->argc = 2;
mock().ignoreOtherCalls();
threadDetachedSuccess();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "MGET");
nKeysNotFoundMget(3);
mock().expectOneCall("RedisModule_FreeCallReply");
expectNReplies(0);
mock().expectOneCall("RedisModule_FreeThreadSafeContext");
mock().expectOneCall("RedisModule_UnblockClient");
NGet_NoAtomic_ThreadMain((void*)bca);
mock().checkExpectations();
threadSafeContextLockedAndUnlockedEqualTimes();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_threadmain_3_keys_scanned_2_keys_mget)
{
RedisModuleCtx ctx;
RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
RedisModuleString ** redisStrVec = createRedisStrVec(2);
bca->bc = bc;
bca->argv = redisStrVec;
bca->argc = 2;
mock().ignoreOtherCalls();
threadDetachedSuccess();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(3);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "MGET");
nKeysNotFoundMget(1);
nKeysFoundMget(2);
mock().expectOneCall("RedisModule_FreeCallReply");
expectNReplies(2);
mock().expectOneCall("RedisModule_FreeThreadSafeContext");
mock().expectOneCall("RedisModule_UnblockClient");
NGet_NoAtomic_ThreadMain((void*)bca);
mock().checkExpectations();
threadSafeContextLockedAndUnlockedEqualTimes();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_threadmain_scan_returned_zero_keys)
{
RedisModuleCtx ctx;
RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
RedisModuleString ** redisStrVec = createRedisStrVec(2);
bca->bc = bc;
bca->argv = redisStrVec;
bca->argc = 2;
mock().ignoreOtherCalls();
threadDetachedSuccess();
mock().expectOneCall("RedisModule_ReplyWithArray")
.withParameter("len", (long)REDISMODULE_POSTPONED_ARRAY_LEN);
mock().expectOneCall("RedisModule_Call")
.withParameter("cmdname", "SCAN");
returnNKeysFromScanSome(0);
mock().expectOneCall("RedisModule_FreeCallReply");
mock().expectNoCall("RedisModule_Call");
mock().expectOneCall("RedisModule_FreeThreadSafeContext");
mock().expectOneCall("RedisModule_UnblockClient");
NGet_NoAtomic_ThreadMain((void*)bca);
mock().checkExpectations();
threadSafeContextLockedAndUnlockedEqualTimes();
delete []redisStrVec;
}
TEST(exstrings_nget, nget_noatomic_threadmain_thread_detached)
{
RedisModuleCtx ctx;
RedisModuleBlockedClientArgs *bca = (RedisModuleBlockedClientArgs*)malloc(sizeof(RedisModuleBlockedClientArgs));
RedisModuleBlockedClient *bc = RedisModule_BlockClient(&ctx,NULL,NULL,NULL,0);
RedisModuleString ** redisStrVec = createRedisStrVec(2);
bca->bc = bc;
bca->argv = redisStrVec;
bca->argc = 2;
mock().ignoreOtherCalls();
threadDetachedSuccess();
NGet_NoAtomic_ThreadMain((void*)bca);
mock().checkExpectations();
delete []redisStrVec;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2019 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#include "CppUTest/CommandLineTestRunner.h"
extern "C" {
#include <stdio.h>
}
int main(int ac, char** av)
{
MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
return CommandLineTestRunner::RunAllTests(ac, av);
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2020 Nokia.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This source code is part of the near-RT RIC (RAN Intelligent Controller)
* platform project (RICP).
*/
#include <stdlib.h>
#include "redismodule.h"
#include "ut_helpers.hpp"
#include <CppUTest/TestHarness.h>
#include <CppUTestExt/MockSupport.h>
RedisModuleString **createRedisStrVec(size_t size)
{
RedisModuleString ** redisStrVec = new RedisModuleString*[size];
for (size_t i = 0 ; i < size ; i++) {
redisStrVec[i] = (RedisModuleString *)UT_DUMMY_PTR_ADDRESS;
}
return redisStrVec;
}
void returnNKeysFromScanSome(long keys)
{
mock().expectOneCall("RedisModule_CallReplyLength")
.andReturnValue((int)keys);
for (long i = 0 ; i < keys ; i++) {
mock().expectOneCall("RedisModule_CreateStringFromCallReply")
.andReturnValue(malloc(UT_DUMMY_BUFFER_SIZE));
}
}

View File

@@ -0,0 +1,10 @@
---
distribution_type: container
container_release_tag: 0.1.0
container_pull_registry: nexus3.o-ran-sc.org:10004
container_push_registry: nexus3.o-ran-sc.org:10002
project: ric-plt/dbaas
ref: a3454f896b5dc62ee0672febcb228a1b7c20e63e
containers:
- name: ric-plt-dbaas
version: 0.1.0

View File

@@ -0,0 +1,10 @@
---
distribution_type: container
container_release_tag: 0.4.0
container_pull_registry: nexus3.o-ran-sc.org:10004
container_push_registry: nexus3.o-ran-sc.org:10002
project: ric-plt/dbaas
ref: c8a0448d6b8f67f0c0bae546eeb8c0aae9914837
containers:
- name: ric-plt-dbaas
version: 0.4.0

View File

@@ -0,0 +1,139 @@
// Copyright (c) 2019 AT&T Intellectual Property.
// Copyright (c) 2019 Nokia.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
//
package sdl
import (
"github.com/go-redis/redis"
"os"
"reflect"
)
type SdlInstance struct {
nameSpace string
nsPrefix string
client *redis.Client
}
func Create(nameSpace string) *SdlInstance {
hostname := os.Getenv("DBAAS_SERVICE_HOST")
if hostname == "" {
hostname = "localhost"
}
port := os.Getenv("DBAAS_SERVICE_PORT")
if port == "" {
port = "6379"
}
redisAddress := hostname + ":" + port
client := redis.NewClient(&redis.Options{
Addr: redisAddress,
Password: "", // no password set
DB: 0, // use default DB
})
s := SdlInstance{
nameSpace: nameSpace,
nsPrefix: "{" + nameSpace + "},",
client: client,
}
return &s
}
func (s *SdlInstance) setNamespaceToKeys(pairs ...interface{}) []interface{} {
var retVal []interface{}
for i, v := range pairs {
if i%2 == 0 {
reflectType := reflect.TypeOf(v)
switch reflectType.Kind() {
case reflect.Slice:
x := reflect.ValueOf(v)
for i2 := 0; i2 < x.Len(); i2++ {
if i2%2 == 0 {
retVal = append(retVal, s.nsPrefix+x.Index(i2).Interface().(string))
} else {
retVal = append(retVal, x.Index(i2).Interface())
}
}
case reflect.Array:
x := reflect.ValueOf(v)
for i2 := 0; i2 < x.Len(); i2++ {
if i2%2 == 0 {
retVal = append(retVal, s.nsPrefix+x.Index(i2).Interface().(string))
} else {
retVal = append(retVal, x.Index(i2).Interface())
}
}
default:
retVal = append(retVal, s.nsPrefix+v.(string))
}
} else {
retVal = append(retVal, v)
}
}
return retVal
}
func (s *SdlInstance) Set(pairs ...interface{}) error {
keyAndData := s.setNamespaceToKeys(pairs...)
err := s.client.MSet(keyAndData...).Err()
return err
}
func (s *SdlInstance) Get(keys []string) (map[string]interface{}, error) {
var keysWithNs []string
for _, v := range keys {
keysWithNs = append(keysWithNs, s.nsPrefix+v)
}
val, err := s.client.MGet(keysWithNs...).Result()
m := make(map[string]interface{})
if err != nil {
return m, err
}
for i, v := range val {
m[keys[i]] = v
}
return m, err
}
func (s *SdlInstance) SetIf(key string, oldData, newData interface{}) {
panic("SetIf not implemented\n")
}
func (s *SdlInstance) SetIfiNotExists(key string, data interface{}) {
panic("SetIfiNotExists not implemented\n")
}
func (s *SdlInstance) Remove(keys ...string) {
panic("Remove not implemented\n")
}
func (s *SdlInstance) RemoveIf(key string, data interface{}) {
panic("RemoveIf not implemented\n")
}
func (s *SdlInstance) GetAll() []string {
panic("GetAll not implemented\n")
}
func (s *SdlInstance) RemoveAll() {
panic("RemoveAll not implemented\n")
}

View File

@@ -0,0 +1,104 @@
// Copyright (c) 2019 AT&T Intellectual Property.
// Copyright (c) 2019 Nokia.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
//
package main
import (
"fmt"
"./sdl"
)
func main() {
sdl1 := sdl.Create("test1")
var err error
err = sdl1.Set("key1", "data1", "key2", "data2")
if err != nil {
fmt.Printf("unable to write to DB\n")
}
err = sdl1.Set("num1", 1, "num2", 2)
if err != nil {
fmt.Printf("unable to write to DB\n")
}
d := make([]byte, 3)
d[0] = 1
d[1] = 2
d[2] = 3
err = sdl1.Set("arr1", d)
if err != nil {
fmt.Printf("unable to write to DB\n")
}
p := []string{"pair1", "data1", "pair2", "data2"}
err = sdl1.Set(p)
if err != nil {
fmt.Printf("unable to write to DB\n")
}
a := [4]string{"array1", "adata1", "array2", "adata2"}
err = sdl1.Set(a)
if err != nil {
fmt.Printf("unable to write to DB\n")
}
mix1 := []interface{}{"mix1", "data1", "mix2", 2}
err = sdl1.Set(mix1)
if err != nil {
fmt.Printf("unable to write to DB\n")
}
mix2 := [4]interface{}{"mix3", "data3", "mix4", 4}
err = sdl1.Set(mix2)
if err != nil {
fmt.Printf("unable to write to DB\n")
}
retDataMap, err := sdl1.Get([]string{"key1", "key3", "key2"})
if err != nil {
fmt.Printf("Unable to read from DB\n")
} else {
for i, v := range retDataMap {
fmt.Printf("%s:%s\n", i, v)
}
}
retDataMap2, err := sdl1.Get([]string{"num1", "num2"})
if err != nil {
fmt.Printf("Unable to read from DB\n")
} else {
for i, v := range retDataMap2 {
fmt.Printf("%s:%s\n", i, v)
}
}
fmt.Println("-------------")
allKeys := []string{"key1", "key2", "num1", "num2", "pair1", "pair2", "array1", "array2", "mix1", "mix2", "mix3", "mix4", "arr1"}
retDataMap3, err := sdl1.Get(allKeys)
if err != nil {
fmt.Printf("Unable to read from DB\n")
} else {
for i3, v3 := range retDataMap3 {
fmt.Printf("%s:%s\n", i3, v3)
}
}
}

30
setup/dbaas/tox.ini Normal file
View File

@@ -0,0 +1,30 @@
# documentation only
[tox]
minversion = 2.0
envlist =
docs,
docs-linkcheck,
skipsdist = true
[testenv:docs]
basepython = python3
deps =
sphinx
sphinx-rtd-theme
sphinxcontrib-httpdomain
recommonmark
lfdocs-conf
commands =
sphinx-build -W -b html -n -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/html
echo "Generated docs available in {toxinidir}/docs/_build/html"
whitelist_externals = echo
[testenv:docs-linkcheck]
basepython = python3
deps = sphinx
sphinx-rtd-theme
sphinxcontrib-httpdomain
recommonmark
lfdocs-conf
commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/linkcheck