├── example-gsgroups.conf
├── .gitmodules
├── example-gspasswd.conf
├── messages
├── en_US
│ └── LC_MESSAGES
│ │ ├── graphserv.mo
│ │ └── graphserv.po
└── graphserv.pot
├── .gitignore
├── proj
├── graphserv.workspace
├── graphserv-codelite
│ ├── graphserv-codelite.workspace
│ └── graphcore.project
├── graphserv.cbp
└── graphserv_codelite.project
├── test
├── closetest
│ ├── makefile
│ └── closetest.cpp
├── rtest.sh
└── concurrent.sh
├── README.rst
├── update-lang.sh
├── Makefile
├── src
├── servcli.h
├── const.h
├── utils.h
├── session.h
├── auth.h
├── coreinstance.h
├── main.cpp
└── servapp.h
├── doc
├── install.rst
└── usage.rst
└── LICENSE
/example-gsgroups.conf:
--------------------------------------------------------------------------------
1 | write:::melanie,jules,barney
2 | admin:::fred
3 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "graphcore"]
2 | path = graphcore
3 | url = git://github.com/wmde/graphcore.git
4 |
--------------------------------------------------------------------------------
/example-gspasswd.conf:
--------------------------------------------------------------------------------
1 | melanie:R.NyWzK/TEEvo
2 | jules:G7eHdvAu5yibQ
3 | barney:e/CBifV4.zT.6
4 | fred:b.Bma5vYLxCwA
5 |
--------------------------------------------------------------------------------
/messages/en_US/LC_MESSAGES/graphserv.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wmde/graphserv/master/messages/en_US/LC_MESSAGES/graphserv.mo
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.dat
2 | scite-session
3 | SciTE.properties
4 | *.list
5 | *.tags
6 | *.mk
7 | graphserv-codelite.workspace.*
8 | *.layout
9 | graphserv_codelite.sh
10 | graphserv
11 | graphserv.dbg
12 | *.log
13 |
14 |
15 |
--------------------------------------------------------------------------------
/proj/graphserv.workspace:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/closetest/makefile:
--------------------------------------------------------------------------------
1 | closetest: closetest.cpp
2 | g++ closetest.cpp -o closetest
3 |
4 |
5 | # to be used on linux.
6 | # watch fds for connection being opened and closed.
7 | test: closetest
8 | -../../graphserv -g ../../example-gsgroups.conf -p ../../example-gspasswd.conf -c ../../graphcore/graphcore & echo $$! > PID
9 | sleep 0.5
10 | (echo "authorize password fred:test"; echo "create-graph test") | nc localhost 6666
11 | xterm -e watch -n 1 lsof -p $$(pidof graphserv) & sleep 1
12 | # spawn lots of instances
13 | for i in $$(seq 1 5000); do ./closetest 127.0.0.1 & done
14 | sleep 10
15 | kill $$(cat PID)
16 | rm PID
17 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Graph Processor server component - GraphServ
2 | ============================================
3 | \(c) Wikimedia Deutschland, written by Johannes Kroll in 2011-2013
4 |
5 | For some information on using Graphserv/Graphcore for Wikipedia Tools -- what's currently running on Tool Labs, what can you do with it, how to use it -- see `this page `_.
6 |
7 | GraphServ Documentation: `install.rst `_, `usage.rst `_.
8 |
9 | Issue tracker: please file bugs and feature requests on `Phabricator `_.
10 |
--------------------------------------------------------------------------------
/proj/graphserv-codelite/graphserv-codelite.workspace:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/update-lang.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # this script:
3 | # - updates the translation template file $MSGDIR/$DOMAIN.pot
4 | # - updates .po files with new translatable strings in source code
5 | # - compiles .po files to .mo files
6 |
7 | # directory where localization files are placed
8 | MSGDIR=messages
9 |
10 | # textdomain
11 | DOMAIN=graphserv
12 |
13 | # find languages
14 | LANGUAGES=$(cd $MSGDIR; find -mindepth 1 -maxdepth 1 -type d -execdir basename '{}' ';')
15 |
16 | SRC=$(find src -name '*.cpp'; find src -name '*.h')
17 |
18 | TMPPOT=$(mktemp)
19 | xgettext -d graphserv $SRC --keyword=_ -o - | sed "s/CHARSET/UTF-8/" > $TMPPOT &&
20 | echo -n "merging new strings into template file $MSGDIR/$DOMAIN.pot " &&
21 | msgmerge -U $MSGDIR/$DOMAIN.pot $TMPPOT &&
22 | rm $TMPPOT &&
23 |
24 | for LANG in $LANGUAGES; do
25 | echo -n "merging new strings into $LANG " &&
26 | msgmerge -U $MSGDIR/$LANG/LC_MESSAGES/$DOMAIN.po $MSGDIR/$DOMAIN.pot &&
27 | echo generating binary message catalog for $LANG &&
28 | msgfmt -c -v -o $MSGDIR/$LANG/LC_MESSAGES/$DOMAIN.mo $MSGDIR/$LANG/LC_MESSAGES/$DOMAIN.po
29 | done
30 |
31 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # on solaris, we need -lsocket for socket functions. check for libsocket.
2 | ifneq ($(shell nm -DP /lib/libsocket.so* 2>/dev/null | grep -v UNDEF | grep '^accept[[:space:]]*'),)
3 | SOCKETLIB=-lsocket
4 | else
5 | SOCKETLIB=
6 | endif
7 |
8 | CCFLAGS=$(CFLAGS) -Wall -Wstrict-overflow=3 -std=c++0x -Igraphcore/src -DSYSTEMPAGESIZE=$(shell getconf PAGESIZE)
9 | LDFLAGS=-lcrypt $(SOCKETLIB) -levent
10 |
11 | all: Release Debug
12 |
13 | Release: graphserv
14 | Debug: graphserv.dbg
15 |
16 | graphcore/graphcore: graphcore/src/*
17 | +make -C graphcore STDERR_DEBUGGING=$(STDERR_DEBUGGING) USE_MMAP_POOL=$(USE_MMAP_POOL) DEBUG_COMMANDS=$(DEBUG_COMMANDS) Release
18 |
19 | graphcore/graphcore.dbg: graphcore/src/*
20 | +make -C graphcore STDERR_DEBUGGING=$(STDERR_DEBUGGING) USE_MMAP_POOL=$(USE_MMAP_POOL) DEBUG_COMMANDS=$(DEBUG_COMMANDS) Debug
21 |
22 | graphserv: src/main.cpp src/*.h graphcore/src/*.h graphcore/graphcore
23 | g++ $(CCFLAGS) -O3 -march=native src/main.cpp $(LDFLAGS) -ographserv
24 |
25 | graphserv.dbg: src/main.cpp src/*.h graphcore/src/*.h graphcore/graphcore.dbg
26 | g++ $(CCFLAGS) -DDEBUG_COMMANDS -ggdb src/main.cpp $(LDFLAGS) -ographserv.dbg
27 |
28 | # updatelang: update the language files
29 | # running this will generate changes in the repository
30 | updatelang: #
31 | ./update-lang.sh
32 |
33 | clean: #
34 | -rm graphserv graphserv.dbg graphcore/graphcore graphcore/graphcore.dbg
35 |
36 | # test: Release Debug
37 | # python test/talkback.py test/graphserv.tb ./graphserv
38 |
39 | .PHONY: updatelang clean
40 |
--------------------------------------------------------------------------------
/test/closetest/closetest.cpp:
--------------------------------------------------------------------------------
1 | // quick test hack to check for leaked file descriptors.
2 | // running 'make test' on linux will spawn lots of graphserv connections using this program.
3 | // lsof should show all fds being closed.
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include /* for sockaddr_in and inet_addr() */
11 | #include /* for memset() */
12 | #include /* for close() */
13 |
14 | void die(const char *str)
15 | {
16 | perror(str);
17 | exit(1);
18 | }
19 |
20 | int main(int argc, char **argv)
21 | {
22 | char *addrStr= (argc>1? argv[1]: (char*)"91.198.174.201");
23 | int sock= socket(AF_INET, SOCK_STREAM, 0);
24 | if(sock==-1) die("socket");
25 | sockaddr_in addr;
26 | memset(&addr, 0, sizeof(addr));
27 | addr.sin_family= AF_INET;
28 | addr.sin_addr.s_addr= inet_addr(addrStr);
29 | addr.sin_port= htons(6666);
30 | if( connect(sock, (const struct sockaddr*)&addr, sizeof(sockaddr_in)) != 0 ) die("connect");
31 |
32 | puts("connected.");
33 | const char *cmd= "use-graph test\n";
34 | if( write(sock, cmd, strlen(cmd)) != strlen(cmd) ) die("write");
35 | char buf[1024];
36 | int r= read(sock, buf, sizeof(buf));
37 | if(r==0) die("EOF");
38 | if(r<0) die("read");
39 | buf[r]= 0;
40 | printf("received: %s", buf);
41 | // sleep(3);
42 | puts("disconnecting.");
43 | close(sock);
44 |
45 | sleep(20); // keep the process alive for a while.
46 |
47 | return 0;
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/proj/graphserv.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/servcli.h:
--------------------------------------------------------------------------------
1 | // Graph Processor server component.
2 | // (c) Wikimedia Deutschland, written by Johannes Kroll in 2011, 2012
3 | // server cli command base classes and cli handler class.
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | #ifndef SERVCLI_H
19 | #define SERVCLI_H
20 |
21 | // base class for server commands.
22 | class ServCmd: public CliCommand
23 | {
24 | public:
25 | virtual AccessLevel getAccessLevel() { return ACCESS_READ; }
26 | };
27 |
28 | // cli commands which do not return any data.
29 | class ServCmd_RTVoid: public ServCmd
30 | {
31 | public:
32 | ReturnType getReturnType() { return RT_NONE; }
33 | virtual CommandStatus execute(vector words, class Graphserv &app, class SessionContext &sc)= 0;
34 | };
35 |
36 | // cli commands which return some other data set. execute() must write the result to the client.
37 | class ServCmd_RTOther: public ServCmd
38 | {
39 | public:
40 | ReturnType getReturnType() { return RT_OTHER; }
41 | virtual CommandStatus execute(vector words, class Graphserv &app, class SessionContext &sc)= 0;
42 | };
43 |
44 | // server cli class.
45 | class ServCli: public Cli
46 | {
47 | public:
48 | ServCli(class Graphserv &_app);
49 |
50 | void addCommand(ServCmd *cmd)
51 | { commands.push_back(cmd); }
52 |
53 | CommandStatus execute(string command, class SessionContext &sc);
54 | CommandStatus execute(class ServCmd *cmd, vector &words, class SessionContext &sc);
55 |
56 | private:
57 | class Graphserv &app;
58 | };
59 |
60 |
61 |
62 | #endif // SERVCLI_H
63 |
--------------------------------------------------------------------------------
/src/const.h:
--------------------------------------------------------------------------------
1 | // Graph Processor server component.
2 | // (c) Wikimedia Deutschland, written by Johannes Kroll in 2011, 2012
3 | // defines and constants used in the server.
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | #ifndef CONST_H
19 | #define CONST_H
20 |
21 |
22 | // default values for tcp & http listen ports
23 | #define DEFAULT_TCP_PORT 6666
24 | #define DEFAULT_HTTP_PORT 8090
25 |
26 | // listen backlog: how large may the queue of incoming connections grow
27 | #define LISTEN_BACKLOG 100
28 |
29 | // default filenames for htpasswd file, group file, and core binary
30 | #define DEFAULT_HTPASSWD_FILENAME "gspasswd.conf"
31 | #define DEFAULT_GROUP_FILENAME "gsgroups.conf"
32 | #define DEFAULT_CORE_PATH "./graphcore/graphcore"
33 |
34 |
35 | // the command status codes, including those used in the core.
36 | enum CommandStatus
37 | {
38 | CORECMDSTATUSCODES,
39 | // server-only status codes:
40 | CMD_ACCESSDENIED, // insufficient access level for command
41 | CMD_NOT_FOUND, // "command not found" results in a different HTTP status code, therefore it needs its own code.
42 | };
43 | // NOTE: these entries must match the status codes above.
44 | static const string statusMsgs[]=
45 | { CORECMDSTATUSSTRINGS, DENIED_STR, FAIL_STR };
46 |
47 |
48 | // the connection type of session contexts.
49 | enum ConnectionType
50 | {
51 | CONN_TCP= 0,
52 | CONN_HTTP
53 | };
54 |
55 |
56 | // log levels for flog(). LOG_CRIT is always printed, other levels can be individually enabled on the command line.
57 | enum Loglevel
58 | {
59 | LOG_INFO,
60 | LOG_ERROR,
61 | LOG_AUTH,
62 | LOG_CRIT
63 | };
64 |
65 |
66 | #endif // CONST_H
67 |
--------------------------------------------------------------------------------
/test/rtest.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # server binary
4 | SERVBIN="../graphserv.dbg"
5 | # core binary. must use the debug version for list-by-* commands.
6 | COREBIN="../graphcore/graphcore.dbg"
7 | # use the example password and group files
8 | PWFILE="../example-gspasswd.conf"
9 | GRPFILE="../example-gsgroups.conf"
10 | # tcp port the server will listen on
11 | TCPPORT=6666
12 |
13 | HOST=nightshade.toolserver.org
14 |
15 |
16 | function random() {
17 | echo 'r = ' $RANDOM ' % 10000; scale=8; r * 0.0001 * ' $1 + $2 | bc
18 | }
19 |
20 | function add_arcs() {
21 | while true; do (
22 | echo 'authorize password fred:test'
23 | echo 'use-graph test'
24 | local N=$(( $RANDOM % 5000 + 1 ))
25 | ( echo 'add-arcs:';
26 | for k in $(seq 1 $N ) ; do
27 | echo "$(( $RANDOM % 1000 + 1)), $(( $RANDOM % 1000 + 1))";
28 | done; echo "" ) ) | nc $HOST $TCPPORT >/dev/null || exit 0
29 | sleep $(random 1 .01)
30 | done
31 | }
32 |
33 | function remove_arcs() {
34 | while true; do
35 | N=$( (echo 'use-graph test'; echo 'stats'; sleep 2) | nc $HOST $TCPPORT | grep ArcCount | cut -d ',' -f 2 )
36 | if [[ x$N == x ]]; then N=100; fi
37 | if (( $N > 50000 )); then
38 | N=$(( $N / 2 ))
39 | echo ' ***' removing $N
40 | (echo 'authorize password fred:test'; echo 'use-graph test';
41 | echo "list-by-head 0 $N > tmpout") | nc $HOST $TCPPORT
42 | (echo 'authorize password fred:test';
43 | echo 'use-graph test'
44 | echo 'remove-arcs < tmpout'
45 | echo stats
46 | sleep 10
47 | ) | nc $HOST $TCPPORT || exit 0
48 | #date +'%F %H:%M:%S'
49 | #echo '====== server: ======'
50 | #pmap $SERVPID | grep total
51 | #echo '====== core: ======'
52 | #pmap $COREPID | grep total
53 | fi
54 | sleep .5 #$(random .1 .1)
55 | done
56 | }
57 |
58 |
59 | function intcleanup() {
60 | echo ' SIGINT received, terminating server.'
61 | kill $SERVPID
62 | exit 0
63 | }
64 |
65 |
66 | if [[ $HOST == localhost ]]; then
67 | # start the server
68 | $SERVBIN -lia -p $TCPPORT -c $COREBIN -p $PWFILE -g $GRPFILE > graphserv.log 2>&1 & SERVPID=$!
69 |
70 | sleep .5
71 |
72 | # check if the server failed to start up.
73 | ps -p $SERVPID >/dev/null || exit 1
74 |
75 | COREPID=$( (echo 'authorize password fred:test'; echo 'create-graph test'; sleep 1) | nc localhost $TCPPORT | grep "spawned pid" | sed 's/^.*pid \([0-9]*\).*/\1/')
76 |
77 | echo core pid: $COREPID
78 |
79 | else
80 |
81 | (echo 'authorize password fred:test'; echo 'create-graph test'; sleep 1) | nc $HOST $TCPPORT
82 |
83 | fi
84 |
85 | trap intcleanup SIGINT
86 |
87 | add_arcs &
88 | remove_arcs &
89 |
90 | (while true; do sleep 10; done)
91 |
92 |
93 |
--------------------------------------------------------------------------------
/doc/install.rst:
--------------------------------------------------------------------------------
1 | GraphServ: Installation
2 | =======================
3 |
4 | The Graph Processor project aims to develop an infrastructure for rapidly analyzing and evaluating Wikipedia's category structure. The `GraphCore `_ component maintains and processes large directed graphs in memory. `GraphServ `_ handles access to running GraphCore instances.
5 |
6 | This file documents getting, building and running GraphServ.
7 |
8 |
9 | Getting the Code
10 | ----------------
11 |
12 | Prerequisites:
13 | - `git `_
14 |
15 | To clone a read-only copy of the GraphServ repository, use the following command: ::
16 |
17 | $ git clone --recursive git://github.com/jkroll20/graphserv.git
18 |
19 | The `--recursive` switch will automatically clone the required GraphCore repository as a submodule.
20 |
21 |
22 |
23 | Building
24 | --------
25 |
26 | Prerequisites:
27 | - GNU Toolchain (make, g++, libc)
28 | - GNU `Readline `_.
29 |
30 | The build process does not involve the use of any autofrobnication scripts. To compile the code, simply run: ::
31 |
32 | $ make
33 |
34 | This will build debug and release binaries of GraphServ and GraphCore.
35 |
36 | The code should build and run on 32-Bit Linux and 64-Bit Solaris systems. Care was taken to ensure compatibility to other Unix-ish systems. If the code does not build or run on your platform, please let me know.
37 |
38 |
39 | Running GraphServ
40 | -----------------
41 |
42 | By default, GraphServ will look for the GraphCore binary in the subdirectory `graphcore`. Default values for TCP ports and authentication files are also set at compile time. You may want to override these defaults using one of the command line options. ::
43 |
44 | use: graphserv [options]
45 | options:
46 | -h print this text
47 | -t PORT listen on PORT for tcp connections [6666]
48 | -H PORT listen on PORT for http connections [8090]
49 | -p FILENAME set htpassword file name [gspasswd.conf]
50 | -g FILENAME set group file name [gsgroups.conf]
51 | -c FILENAME set path of GraphCore binary [./graphcore/graphcore]
52 | -l FLAGS set logging flags.
53 | e: log error messages (default)
54 | i: log error and informational messages
55 | a: log authentication messages
56 | q: quiet mode, don't log anything
57 | flags can be combined.
58 |
59 | Before spawning a GraphCore instance, the child process will chdir() to the directory where graphcore resides. Currently, any redirected output will be written to that directory. Server log messages are written to stderr.
60 |
61 |
62 | |
63 | |
64 | | `GraphServ, GraphCore (C) 2011 Wikimedia Deutschland, written by Johannes Kroll .`
65 | | `Last update to this text: 2011/06/16`
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/concurrent.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Graph Processor concurrency test script.
3 | # (c) Wikimedia Deutschland, written by Johannes Kroll in 2011
4 |
5 | # this script tests concurrent graph manipulation.
6 | # a number of random arcs are created ("input arcs").
7 | # the input arcs are fed through graphcore, sorting them and removing duplicates ("comparison set").
8 | # the input arcs are then split into several files.
9 | # each file is concurrently fed to a GraphCore instance, using several GraphServ sessions.
10 | # the result set from the core is then compared with the comparison set.
11 | # the test is successful if the result and comparison sets match.
12 |
13 | # the script will run $CONCURRENCY sessions at the same time, adding $ARCSPERPART random arcs each.
14 | CONCURRENCY=8
15 | ARCSPERPART=20000
16 |
17 | # server binary
18 | SERVBIN="../graphserv.dbg"
19 | # core binary. must use the debug version for list-by-* commands.
20 | COREBIN="../graphcore/graphcore.dbg"
21 | # use the example password and group files
22 | PWFILE="../example-gspasswd.conf"
23 | GRPFILE="../example-gsgroups.conf"
24 | # tcp port the server will listen on
25 | TCPPORT=6666
26 |
27 | NUMARCS=$(( $ARCSPERPART * $CONCURRENCY ))
28 |
29 | # build core & server
30 | echo "building..."
31 | (make -C.. Debug && make -C../graphcore Debug) >/dev/null
32 | if ! [[ -x $SERVBIN ]] || ! [[ -x $COREBIN ]] ; then echo 'Build failed.'; exit 1; fi
33 |
34 | # start the server
35 | $SERVBIN -lia -p $TCPPORT -c $COREBIN -p $PWFILE -g $GRPFILE & SERVPID=$!
36 |
37 | # creating random arcs should take long enough for the server to start up, don't sleep.
38 | #sleep 1
39 |
40 | echo "creating $NUMARCS random arcs..."
41 |
42 | # create some random arcs
43 | [ -f tmp-arcs ] && rm tmp-arcs
44 | i=0
45 | until [[ $i == $NUMARCS ]] ; do
46 | # $RANDOM is 0..32767. multiply to generate something between 0..ffffffff (not uniformly distributed)
47 | echo $(( $RANDOM * $RANDOM % ($NUMARCS/10) + 1 ))", "$(( $RANDOM * $RANDOM % ($NUMARCS/10) + 1 )) >> tmp-arcs
48 | let i++
49 | done
50 |
51 | # sort them using graphcore
52 | (echo 'add-arcs < tmp-arcs'; echo 'list-by-tail 0') | $COREBIN | egrep -v '^$' | egrep -v '^OK' > tmp-arcs-sorted || exit 1
53 | # | grep -v "OK." | egrep -v "^$"
54 |
55 | # break them into pieces
56 | i=0
57 | part=0
58 | until [[ $i == $NUMARCS ]] ; do
59 | head -n $(( $i + $ARCSPERPART )) tmp-arcs | tail -n $ARCSPERPART > tmp-arcs-part$part
60 | let i+=$ARCSPERPART
61 | let part++
62 | done
63 |
64 | # check if the server failed to start up.
65 | ps -p $SERVPID >/dev/null || exit 1
66 |
67 | # create test graph
68 | RESULT=$(
69 | ( echo 'authorize password fred:test'
70 | echo 'create-graph test'
71 | sleep 1
72 | ) | nc localhost $TCPPORT )
73 |
74 | if ! [[ $RESULT =~ OK.*OK.* ]] ; then echo "couldn't create graph. output:"; echo "$RESULT"; kill $SERVPID; exit 1; fi
75 |
76 | # fill graph with the generated random data, concurrently, using several sessions
77 | PIDLIST=""
78 | part=0
79 | until [[ $part == $CONCURRENCY ]] ; do
80 | echo "starting part $part."
81 | >f$part
82 | (
83 | (echo 'authorize password fred:test';
84 | echo 'use-graph test';
85 | echo 'add-arcs:'; cat tmp-arcs-part$part; echo "";
86 | # make the process writing to netcat wait for the last "OK." output coming from netcat.
87 | # if we don't do this, netcat will finish early.
88 | while true; do if egrep "^OK\. $" f$part >/dev/null; then exit 0; fi; sleep 0.2; done
89 | sleep 1) \
90 | | nc localhost $TCPPORT | tee f$part
91 | ) & PIDLIST="$PIDLIST $!"
92 |
93 | let part++
94 | done
95 |
96 | # wait for all sessions to finish
97 | wait $PIDLIST
98 |
99 | # remove temporary files
100 | rm f?
101 |
102 | # now, get the result set stitched together from the concurrent sessions
103 | (echo "use-graph test";
104 | echo "list-by-tail 0";
105 | # wait for empty line.
106 | while true; do sleep 0.1; if tail -n 1 result-set | egrep "^$" >/dev/null; then exit 0; fi; done) |
107 | nc localhost $TCPPORT > result-set
108 |
109 | grep -v "OK." result-set | egrep -v '^$' > result-arcs
110 |
111 | echo "comparing result files with diff..."
112 |
113 | # compare result files
114 |
115 | if ! diff tmp-arcs-sorted result-arcs >/dev/null ; then
116 | echo "Test FAILED! Result files don't match."
117 | echo -n "sorted input arcs: "; sort tmp-arcs-sorted | uniq | wc -l
118 | echo -n " output arcs: "; uniq result-arcs | wc -l
119 | exit 1
120 | fi
121 |
122 | echo "Test SUCCEEDED. Result files match."
123 |
124 | rm tmp-arcs* result-set result-arcs*
125 |
126 | kill $SERVPID
127 |
128 | exit 0
129 |
130 |
--------------------------------------------------------------------------------
/messages/graphserv.pot:
--------------------------------------------------------------------------------
1 | # Message template file for the graphserv program.
2 | # Copyright (C) Wikimedia Deutschland, created by Johannes Kroll in 2011
3 | # This file is distributed under the same license as the graphserv package.
4 | # Johannes Kroll , 2011.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: graphserv\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2011-06-08 19:42+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: src/main.cpp:168
21 | msgid " no such server command.\n"
22 | msgstr ""
23 |
24 | #: src/main.cpp:179 src/servapp.h:325
25 | #, c-format
26 | msgid " insufficient access level (command needs %s, you have %s)\n"
27 | msgstr ""
28 |
29 | #: src/main.cpp:211
30 | msgid "create a named graphcore instance."
31 | msgstr ""
32 |
33 | #: src/main.cpp:222
34 | msgid "an instance with this name already exists.\n"
35 | msgstr ""
36 |
37 | #: src/main.cpp:224
38 | msgid "Graphserv::createCoreInstance() failed.\n"
39 | msgstr ""
40 |
41 | #: src/main.cpp:226
42 | #, c-format
43 | msgid "spawned pid %d.\n"
44 | msgstr ""
45 |
46 | #: src/main.cpp:237
47 | msgid "connect to a named graphcore instance."
48 | msgstr ""
49 |
50 | #: src/main.cpp:248
51 | msgid "already connected. switching instances is not currently supported.\n"
52 | msgstr ""
53 |
54 | #: src/main.cpp:250 src/main.cpp:274
55 | msgid "no such instance.\n"
56 | msgstr ""
57 |
58 | #: src/main.cpp:252
59 | #, c-format
60 | msgid "connected to pid %d.\n"
61 | msgstr ""
62 |
63 | #: src/main.cpp:263
64 | msgid "drop a named graphcore instance immediately (terminate the process)."
65 | msgstr ""
66 |
67 | #: src/main.cpp:277
68 | #, c-format
69 | msgid "couldn't kill the process. %s\n"
70 | msgstr ""
71 |
72 | #: src/main.cpp:280
73 | #, c-format
74 | msgid "killed pid %d.\n"
75 | msgstr ""
76 |
77 | #: src/main.cpp:292
78 | msgid "list currently running graphcore instances."
79 | msgstr ""
80 |
81 | #: src/main.cpp:303
82 | msgid "running graphs:\n"
83 | msgstr ""
84 |
85 | #: src/main.cpp:319
86 | msgid "returns information on your current session."
87 | msgstr ""
88 |
89 | #: src/main.cpp:330
90 | msgid "session info:\n"
91 | msgstr ""
92 |
93 | #: src/main.cpp:347
94 | msgid "returns information on the server."
95 | msgstr ""
96 |
97 | #: src/main.cpp:358
98 | msgid "server info:\n"
99 | msgstr ""
100 |
101 | #: src/main.cpp:373
102 | msgid "authorize with the named authority using the given credentials."
103 | msgstr ""
104 |
105 | #: src/main.cpp:388
106 | #, c-format
107 | msgid "no such authority '%s'.\n"
108 | msgstr ""
109 |
110 | #: src/main.cpp:394
111 | msgid "authorization failure.\n"
112 | msgstr ""
113 |
114 | #: src/main.cpp:398
115 | #, c-format
116 | msgid "access level: %s\n"
117 | msgstr ""
118 |
119 | #: src/main.cpp:411
120 | msgid "print info (debugging)"
121 | msgstr ""
122 |
123 | #: src/main.cpp:449 src/main.cpp:477
124 | msgid "get help on commands"
125 | msgstr ""
126 |
127 | #: src/main.cpp:457 src/main.cpp:496
128 | msgid "available commands:\n"
129 | msgstr ""
130 |
131 | #: src/main.cpp:462
132 | msgid ""
133 | "note: 'corehelp' prints help on core commands when connected to a core.\n"
134 | msgstr ""
135 |
136 | #: src/main.cpp:504
137 | msgid "the following are the core commands:\n"
138 | msgstr ""
139 |
140 | #: src/coreinstance.h:107
141 | msgid "core replied: "
142 | msgstr ""
143 |
144 | #: src/coreinstance.h:114
145 | msgid "protocol version mismatch (server: "
146 | msgstr ""
147 |
148 | #: src/coreinstance.h:126
149 | msgid "child process terminated by signal"
150 | msgstr ""
151 |
152 | #: src/coreinstance.h:130
153 | msgid "child process exited: "
154 | msgstr ""
155 |
156 | #: src/servapp.h:320
157 | #, c-format
158 | msgid "%s client has invalid core ID %u\n"
159 | msgstr ""
160 |
161 | #: src/servapp.h:330
162 | #, c-format
163 | msgid "no such core command '%s'."
164 | msgstr ""
165 |
166 | #: src/servapp.h:542
167 | #, c-format
168 | msgid "%s %s accepts no data set.\n"
169 | msgstr ""
170 |
171 | #: src/servapp.h:544
172 | msgid " input/output of server commands can't be redirected.\n"
173 | msgstr ""
174 |
175 | #: src/servapp.h:555 src/servapp.h:557
176 | #, c-format
177 | msgid "no such server command '%s'."
178 | msgstr ""
179 |
180 | #: src/servapp.h:572
181 | #, c-format
182 | msgid "bad HTTP request string, disconnecting.\n"
183 | msgstr ""
184 |
185 | #: src/servapp.h:579
186 | #, c-format
187 | msgid "unknown HTTP version, disconnecting.\n"
188 | msgstr ""
189 |
190 | #: src/servapp.h:599
191 | #, c-format
192 | msgid "i=%d len=%d %s %02X bad hex in request URI, disconnecting\n"
193 | msgstr ""
194 |
195 | #: src/servapp.h:607
196 | msgid " data sets not allowed in HTTP GET requests.\n"
197 | msgstr ""
198 |
199 | #: src/servapp.h:628
200 | msgid "No such instance."
201 | msgstr ""
202 |
--------------------------------------------------------------------------------
/messages/en_US/LC_MESSAGES/graphserv.po:
--------------------------------------------------------------------------------
1 | # Message template file for the graphserv program.
2 | # Copyright (C) Wikimedia Deutschland, created by Johannes Kroll in 2011
3 | # This file is distributed under the same license as the graphserv package.
4 | # Johannes Kroll , 2011.
5 | #
6 | msgid ""
7 | msgstr ""
8 | "Project-Id-Version: graphserv\n"
9 | "Report-Msgid-Bugs-To: \n"
10 | "POT-Creation-Date: 2011-06-08 19:42+0200\n"
11 | "PO-Revision-Date: 2011-05-16 16:43+0100\n"
12 | "Last-Translator: Your name \n"
13 | "Language-Team: LANGUAGE \n"
14 | "Language: \n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 |
19 | #: src/main.cpp:168
20 | msgid " no such server command.\n"
21 | msgstr ""
22 |
23 | #: src/main.cpp:179 src/servapp.h:325
24 | #, c-format
25 | msgid " insufficient access level (command needs %s, you have %s)\n"
26 | msgstr ""
27 |
28 | #: src/main.cpp:211
29 | msgid "create a named graphcore instance."
30 | msgstr ""
31 |
32 | #: src/main.cpp:222
33 | msgid "an instance with this name already exists.\n"
34 | msgstr ""
35 |
36 | #: src/main.cpp:224
37 | msgid "Graphserv::createCoreInstance() failed.\n"
38 | msgstr ""
39 |
40 | #: src/main.cpp:226
41 | #, c-format
42 | msgid "spawned pid %d.\n"
43 | msgstr ""
44 |
45 | #: src/main.cpp:237
46 | msgid "connect to a named graphcore instance."
47 | msgstr ""
48 |
49 | #: src/main.cpp:248
50 | msgid "already connected. switching instances is not currently supported.\n"
51 | msgstr ""
52 |
53 | #: src/main.cpp:250 src/main.cpp:274
54 | msgid "no such instance.\n"
55 | msgstr ""
56 |
57 | #: src/main.cpp:252
58 | #, c-format
59 | msgid "connected to pid %d.\n"
60 | msgstr ""
61 |
62 | #: src/main.cpp:263
63 | msgid "drop a named graphcore instance immediately (terminate the process)."
64 | msgstr ""
65 |
66 | #: src/main.cpp:277
67 | #, c-format
68 | msgid "couldn't kill the process. %s\n"
69 | msgstr ""
70 |
71 | #: src/main.cpp:280
72 | #, c-format
73 | msgid "killed pid %d.\n"
74 | msgstr ""
75 |
76 | #: src/main.cpp:292
77 | msgid "list currently running graphcore instances."
78 | msgstr ""
79 |
80 | #: src/main.cpp:303
81 | msgid "running graphs:\n"
82 | msgstr ""
83 |
84 | #: src/main.cpp:319
85 | msgid "returns information on your current session."
86 | msgstr ""
87 |
88 | #: src/main.cpp:330
89 | msgid "session info:\n"
90 | msgstr ""
91 |
92 | #: src/main.cpp:347
93 | msgid "returns information on the server."
94 | msgstr ""
95 |
96 | #: src/main.cpp:358
97 | msgid "server info:\n"
98 | msgstr ""
99 |
100 | #: src/main.cpp:373
101 | msgid "authorize with the named authority using the given credentials."
102 | msgstr ""
103 |
104 | #: src/main.cpp:388
105 | #, c-format
106 | msgid "no such authority '%s'.\n"
107 | msgstr ""
108 |
109 | #: src/main.cpp:394
110 | msgid "authorization failure.\n"
111 | msgstr ""
112 |
113 | #: src/main.cpp:398
114 | #, c-format
115 | msgid "access level: %s\n"
116 | msgstr ""
117 |
118 | #: src/main.cpp:411
119 | msgid "print info (debugging)"
120 | msgstr ""
121 |
122 | #: src/main.cpp:449 src/main.cpp:477
123 | msgid "get help on commands"
124 | msgstr ""
125 |
126 | #: src/main.cpp:457 src/main.cpp:496
127 | msgid "available commands:\n"
128 | msgstr ""
129 |
130 | #: src/main.cpp:462
131 | msgid ""
132 | "note: 'corehelp' prints help on core commands when connected to a core.\n"
133 | msgstr ""
134 |
135 | #: src/main.cpp:504
136 | msgid "the following are the core commands:\n"
137 | msgstr ""
138 |
139 | #: src/coreinstance.h:107
140 | msgid "core replied: "
141 | msgstr ""
142 |
143 | #: src/coreinstance.h:114
144 | msgid "protocol version mismatch (server: "
145 | msgstr ""
146 |
147 | #: src/coreinstance.h:126
148 | msgid "child process terminated by signal"
149 | msgstr ""
150 |
151 | #: src/coreinstance.h:130
152 | msgid "child process exited: "
153 | msgstr ""
154 |
155 | #: src/servapp.h:320
156 | #, c-format
157 | msgid "%s client has invalid core ID %u\n"
158 | msgstr ""
159 |
160 | #: src/servapp.h:330
161 | #, c-format
162 | msgid "no such core command '%s'."
163 | msgstr ""
164 |
165 | #: src/servapp.h:542
166 | #, c-format
167 | msgid "%s %s accepts no data set.\n"
168 | msgstr ""
169 |
170 | #: src/servapp.h:544
171 | msgid " input/output of server commands can't be redirected.\n"
172 | msgstr ""
173 |
174 | #: src/servapp.h:555 src/servapp.h:557
175 | #, c-format
176 | msgid "no such server command '%s'."
177 | msgstr ""
178 |
179 | #: src/servapp.h:572
180 | #, c-format
181 | msgid "bad HTTP request string, disconnecting.\n"
182 | msgstr ""
183 |
184 | #: src/servapp.h:579
185 | #, c-format
186 | msgid "unknown HTTP version, disconnecting.\n"
187 | msgstr ""
188 |
189 | #: src/servapp.h:599
190 | #, c-format
191 | msgid "i=%d len=%d %s %02X bad hex in request URI, disconnecting\n"
192 | msgstr ""
193 |
194 | #: src/servapp.h:607
195 | msgid " data sets not allowed in HTTP GET requests.\n"
196 | msgstr ""
197 |
198 | #: src/servapp.h:628
199 | msgid "No such instance."
200 | msgstr ""
201 |
--------------------------------------------------------------------------------
/proj/graphserv-codelite/graphcore.project:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | make clean; make Debug
50 | make clean
51 | make Debug
52 |
53 |
54 |
55 | None
56 | /home/johannes/code/graphserv/graphcore
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | make clean; make Release
89 | make clean
90 | make STDERR_DEBUGGING=1 Release
91 |
92 |
93 |
94 | None
95 | ../..
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/proj/graphserv_codelite.project:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | set follow-fork-mode child
47 |
48 |
49 |
50 |
51 | -killall graphserv.dbg
52 |
53 |
54 | make clean; make Debug
55 | make clean
56 | make STDERR_DEBUGGING=1 USE_MMAP_POOL=1 Debug
57 |
58 |
59 |
60 | None
61 | $(ProjectPath)/..
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | set follow-fork-mode child
87 |
88 |
89 |
90 |
91 | -killall graphserv
92 |
93 |
94 | make clean; make
95 | make clean
96 | make STDERR_DEBUGGING=1 USE_MMAP_POOL=1 Release
97 |
98 |
99 |
100 | None
101 | $(ProjectPath)/..
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/src/utils.h:
--------------------------------------------------------------------------------
1 | // Graph Processor server component.
2 | // (c) Wikimedia Deutschland, written by Johannes Kroll in 2011, 2012
3 | // utilities and helper functions.
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | #ifndef UTILS_H
19 | #define UTILS_H
20 |
21 | extern uint32_t logMask;
22 |
23 | void flog(Loglevel level, const char *fmt, ...)
24 | {
25 | if( !(logMask & (1<::iterator it= buffer.begin(); it!=buffer.end(); ++it)
158 | ret+= it->length();
159 | return ret;
160 | }
161 |
162 | // error callback.
163 | virtual void writeFailed(int _errno)= 0;
164 |
165 | private:
166 | int fd;
167 | deque buffer;
168 |
169 | // write a string without buffering. return number of bytes written.
170 | size_t writeString(const string& s)
171 | {
172 | ssize_t sz= ::write(fd, s.data(), s.size());
173 | if(sz<0)
174 | {
175 | if( (errno!=EAGAIN)&&(errno!=EWOULDBLOCK) )
176 | logerror("write"),
177 | writeFailed(errno);
178 | return 0;
179 | }
180 | return sz;
181 | }
182 | };
183 |
184 | #endif // UTILS_H
185 |
--------------------------------------------------------------------------------
/src/session.h:
--------------------------------------------------------------------------------
1 | // Graph Processor server component.
2 | // (c) Wikimedia Deutschland, written by Johannes Kroll in 2011, 2012
3 | // session contexts.
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | #ifndef SESSION_H
19 | #define SESSION_H
20 |
21 | // session context with information about and methods for handling a client connection.
22 | // this base class handles TCP connections.
23 | struct SessionContext: public NonblockWriter
24 | {
25 | uint32_t clientID;
26 | AccessLevel accessLevel;
27 | ConnectionType connectionType;
28 | uint32_t coreID; // non-zero if connected to a core instance
29 | int sockfd;
30 | string linebuf; // text which is read from this client is buffered here.
31 | std::queue lineQueue; // lines which arrive from this client while the session is waiting for core reply are buffered here.
32 | class Graphserv &app;
33 | double chokeTime;
34 | // this is set when a client sends an invalid command with a data set.
35 | // the data set must be read and discarded.
36 | CommandStatus invalidDatasetStatus;
37 | string invalidDatasetMsg; // the status line to send after invalid data set has been read
38 | double shutdownTime; // time when shutdown was called on the socket, or 0 if the connection is running.
39 |
40 | CommandQEntry *curCommand; // if non-NULL, command which is currently being transferred to the server but not yet processed
41 |
42 | event *readEvent, *writeEvent; // libevent read and write events for sockfd
43 | int sockfdRead; // libevent doesn't support mixing edge- and level triggered events on the same fd, so
44 | // we need to dup() the socket fd for the read event...
45 |
46 | // some statistics about this connection. currently mostly used for debugging.
47 | struct Stats
48 | {
49 | double lastTime;
50 | union { struct {
51 | double linesSent, coreCommandsSent, servCommandsSent,
52 | bytesSent, dataRecordsSent, linesQueued;
53 | }; double values[6]; };
54 | Stats()
55 | { reset(); }
56 | void reset(double t= getTime())
57 | {
58 | lastTime= t;
59 | memset(values, 0, sizeof(values));
60 | }
61 | void normalize(double t= getTime())
62 | {
63 | double idt= 1.0/(t-lastTime);
64 | for(unsigned i= 0; i request;
127 | string requestString;
128 | unsigned commandsExecuted;
129 | HttpClientState(): commandsExecuted(0) { }
130 | } http;
131 |
132 | HTTPSessionContext(class Graphserv &app_, uint32_t cID, int sock):
133 | SessionContext(app_, cID, sock, CONN_HTTP),
134 | conversationFinished(false)
135 | {
136 | }
137 |
138 | void httpWriteResponseHeader(int code, const string &title, const string &contentType, const string &optionalField= "")
139 | {
140 | writef("HTTP/1.0 %d %s\r\n", code, title.c_str());
141 | writef("Content-Type: %s\r\n", contentType.c_str());
142 | if(optionalField.length())
143 | {
144 | string field= optionalField;
145 | while(isspace(field[field.size()-1]))
146 | field.resize(field.size()-1);
147 | write(field);
148 | write("\r\n"); // make sure we have consistent newlines in the header.
149 | }
150 | writef("\r\n");
151 | }
152 |
153 | void httpWriteErrorBody(const string& title, const string& description)
154 | {
155 | // writef("%s%s
%s