Ver Fonte

Adding remaining test cases for Prolog/SWI-Prolog (#6666)

* Adding remaining test cases

* increasing timeout
vka há 4 anos atrás
pai
commit
9c47a4e895

+ 0 - 3
frameworks/Prolog/SWI-Prolog/README

@@ -3,6 +3,3 @@ Prolog is a logic programming language associated with artificial intelligence a
 SWI-Prolog is a free implementation of the programming language Prolog, commonly used for teaching and semantic web applications
 
 This implementation uses the [HTTP Server libraries](https://www.swi-prolog.org/pldoc/man?section=httpserver) available with SWI-Prolog
-
-Currently only the /json and /plaintext endpoints have been implemented
-

+ 62 - 0
frameworks/Prolog/SWI-Prolog/app/database.pl

@@ -0,0 +1,62 @@
+:- module(database, [find_random_numbers/4,
+                     update_random_numbers/3,
+                     find_fortunes/2]).
+
+:- use_module(library(odbc)).
+:- use_module(library(random)).
+
+:- dynamic cache/2.
+
+top_id(10001).
+
+find_random_numbers(_Connection, 0, [], _Cached).
+find_random_numbers(Connection, N, Rows, Cached) :-
+    world_by_id_statement(Connection, Statement),
+    find_random_numbers_(Statement, N, Rows, Cached).
+
+find_random_numbers_(_Statement, 0, [], _Cached).
+find_random_numbers_(Statement, N, [Row|Rows], Cached) :-
+    N > 0,
+    top_id(Top),
+    random(1, Top, Id),
+    odbc_execute_cached(Statement, [Id], Row, Cached),
+    N1 is N - 1,
+    find_random_numbers_(Statement, N1, Rows, Cached).
+
+find_fortunes(Connection, Rows) :-
+    fortune_statement(Connection, Statement),
+    findall(Row, odbc_execute(Statement, [], Row), Rows).
+
+update_random_numbers(_Connection, [], []).
+update_random_numbers(Connection, Rows0, Rows) :-
+    update_world_statement(Connection, Statement),
+    update_random_numbers_(Statement, Rows0, Rows).
+
+update_random_numbers_(_Statement, [], []).
+update_random_numbers_(Statement, [row(Id0,_)|Rows0], [Row|Rows]) :-
+    top_id(Top),
+    random(1, Top, RandomNumber),
+    Row = row(Id0, RandomNumber),
+    odbc_execute(Statement, [RandomNumber, Id0]),
+    update_random_numbers_(Statement, Rows0, Rows).
+
+% ------------------------------------------------------------------------------------
+
+world_by_id_statement(Connection, Statement) :-
+    odbc_prepare(Connection, 'SELECT id, randomNumber FROM World WHERE id = ?', [integer], Statement).
+
+fortune_statement(Connection, Statement) :-
+    odbc_prepare(Connection, 'SELECT id, message FROM Fortune', [], Statement).
+
+update_world_statement(Connection, Statement) :-
+    odbc_prepare(Connection, 'UPDATE World SET randomNumber = ? WHERE id = ?', [integer, integer], Statement).
+
+% ------------------------------------------------------------------------------------
+
+odbc_execute_cached(Statement, Params, Row, true) :-
+    ( cache(Params, Row)
+    ; odbc_execute(Statement, Params, Row),
+      assertz(cache(Params, Row))
+    ).
+odbc_execute_cached(Statement, Params, Row, false) :-
+    odbc_execute(Statement, Params, Row).

+ 18 - 0
frameworks/Prolog/SWI-Prolog/app/fortunes.html

@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+    <tr>
+        <th>id</th>
+        <th>message</th>
+    </tr>
+    {{ each items, item }}
+        <tr>
+            <td>{{= item.id }}</td>
+            <td>{{= item.message }}</td>
+        </tr>
+    {{ end }}
+</table>
+</body>
+</html>

+ 103 - 0
frameworks/Prolog/SWI-Prolog/app/server.pl

@@ -0,0 +1,103 @@
+:- module(server, [server/1]).
+
+:- use_module(service).
+
+:- use_module(library(http/http_dispatch)).
+:- use_module(library(http/http_dyn_workers)).
+:- use_module(library(http/http_json)).
+:- use_module(library(http/http_parameters)).
+:- use_module(library(http/http_unix_daemon)).
+:- use_module(library(st/st_render)).
+:- use_module(library(http/thread_httpd)).
+
+
+server(Port) :-
+    odbc_set_option(connection_pooling(true)),
+    current_prolog_flag(cpu_count, Cores),
+    Workers is Cores * 2,
+    server(Port, [workers(Workers)]).
+
+server(Port, Options) :-
+    http_server(http_dispatch, [port(Port),timeout(120)|Options]).
+
+
+:- http_handler('/plaintext',     plaintext_handler,     [chunked]).
+:- http_handler('/json',          json_handler,          [chunked]).
+:- http_handler('/db',            db_handler,            [chunked]).
+:- http_handler('/queries',       queries_handler,       [chunked]).
+:- http_handler('/fortunes',      fortunes_handler,      [chunked]).
+:- http_handler('/updates',       updates_handler,       [chunked]).
+:- http_handler('/cached-worlds', cached_worlds_handler, [chunked]).
+
+
+plaintext_handler(_Request) :-
+    format('Server: SWI-Prolog~n'),
+    format('Content-Type: text/plain~n~n'),
+    format('Hello, World!').
+
+json_handler(_Request) :-
+    format('Server: SWI-Prolog~n'),
+    reply_json_dict(_{message: 'Hello, World!'}).
+
+db_handler(_Request) :-
+    service:random_number(Row),
+    world_json(Row, Json),
+    format('Server: SWI-Prolog~n'),
+    reply_json_dict(Json).
+
+queries_handler(Request) :-
+    queries(Request, N),
+    service:random_numbers(N, Rows),
+    maplist(world_json, Rows, Json),
+    format('Server: SWI-Prolog~n'),
+    reply_json_dict(Json).
+
+fortunes_handler(_Request) :-
+    service:fortunes(Rows),
+    maplist(fortune_json, Rows, Items),
+    render_template(fortunes, _{ items: Items }, Payload, Len),
+    format('Server: SWI-Prolog~n'),
+    format('Content-Type: text/html; charset=utf-8~n'),
+    format('Content-Length: ~d~n~n', [Len]),
+    format(Payload).
+
+updates_handler(Request) :-
+    queries(Request, N),
+    service:update(N, Rows),
+    maplist(world_json, Rows, Json),
+    format('Server: SWI-Prolog~n'),
+    reply_json_dict(Json).
+
+cached_worlds_handler(Request) :-
+    queries(Request, N),
+    service:random_numbers_cached(N, Rows),
+    maplist(world_json, Rows, Json),
+    format('Server: SWI-Prolog~n'),
+    reply_json_dict(Json).
+
+% -----------------------------------------------------------------------
+
+queries(Request, Queries) :-
+    catch(
+        ( http_parameters(Request, [queries(Value, [integer, optional(true), default(1)])])
+        , cut_off(Value, 1, 500, Queries)
+        ),
+        Caught,
+        Queries = 1
+    ).
+
+cut_off(V, L, _, L) :- V < L.
+cut_off(V, _, U, U) :- V > U.
+cut_off(V, _, _, V).
+
+world_json(row(Id, RandomNumber), _{ id: Id, randomNumber: RandomNumber }).
+
+fortune_json(row(Id, Message), _{ id: Id, message: Message }).
+
+render_template(Template, Data, Result, Len) :-
+    with_output_to(codes(Codes), (
+        current_output(Out),
+        st_render_file(Template, Data, Out, _{ cache: true })
+    )),
+    length(Codes, Len),
+    string_codes(Result, Codes).

+ 58 - 0
frameworks/Prolog/SWI-Prolog/app/service.pl

@@ -0,0 +1,58 @@
+:- module(service, [random_number/1, 
+                    random_numbers/2,
+                    random_numbers_cached/2,
+                    fortunes/1]).
+
+:- use_module(database).
+
+:- use_module(library(odbc)).
+:- use_module(library(solution_sequences)).
+
+
+random_number(Row) :-
+    setup_call_cleanup(
+        odbc_connect('benchmark', Connection, []),
+        database:find_random_numbers(Connection, 1, [Row], false),
+        odbc_disconnect(Connection)
+    ).
+
+random_numbers(0, []).
+random_numbers(N, Rows) :-
+    setup_call_cleanup(
+        odbc_connect('benchmark', Connection, []),
+        database:find_random_numbers(Connection, N, Rows, false),
+        odbc_disconnect(Connection)
+    ).
+
+random_numbers_cached(0, []).
+random_numbers_cached(N, Rows) :-
+    setup_call_cleanup(
+        odbc_connect('benchmark', Connection, []),
+        database:find_random_numbers(Connection, N, Rows, true),
+        odbc_disconnect(Connection)
+    ).
+
+fortunes(Rows) :-
+    setup_call_cleanup(
+        odbc_connect('benchmark', Connection, []),
+        database:find_fortunes(Connection, Rows0),
+        odbc_disconnect(Connection)
+    ),
+    Rows1 = [row(0, 'Additional fortune added at request time.')|Rows0],
+    maplist(fortune_to_pair, Rows1, Pairs),
+    keysort(Pairs, SortedPairs),
+    pairs_values(SortedPairs, Rows).
+
+update(0, []).
+update(N, Rows) :-
+    setup_call_cleanup(
+        odbc_connect('benchmark', Connection, []),
+        ( database:find_random_numbers(Connection, N, Rows0, false)
+        , database:update_random_numbers(Connection, Rows0, Rows)
+        ),
+        odbc_disconnect(Connection)
+    ).
+
+% -----------------------------------------------------------
+
+fortune_to_pair(row(Id, Message), Message-row(Id, Message)).

+ 7 - 3
frameworks/Prolog/SWI-Prolog/benchmark_config.json

@@ -4,13 +4,18 @@
 		"default": {
 			"json_url": "/json",
 			"plaintext_url": "/plaintext",
+			"db_url": "/db",
+			"query_url": "/queries?queries=",
+      		"fortune_url": "/fortunes",
+      		"update_url": "/updates?queries=",
+			"cached_query_url": "/cached-worlds?queries=",
 			"port": 8080,
 			"approach": "Realistic",
 			"classification": "None",
-			"database": "None",
+			"database": "Postgres",
 			"framework": "SWI-Prolog",
 			"language": "Prolog",
-			"orm": "None",
+			"orm": "Raw",
 			"platform": "None",
 			"webserver": "SWI-Prolog",
 			"os": "Linux",
@@ -22,4 +27,3 @@
 		}
 	}]
 }
-

+ 7 - 2
frameworks/Prolog/SWI-Prolog/config.toml

@@ -4,12 +4,17 @@ name = "swi-prolog"
 [main]
 urls.plaintext = "/plaintext"
 urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.fortune = "/fortunes"
+urls.update = "/updates?queries="
+urls.cached_query = "/cached-worlds?queries="
 approach = "Realistic"
 classification = "None"
-database = "None"
+database = "Postgres"
 database_os = "Linux"
 os = "Linux"
-orm = "None"
+orm = "Raw"
 platform = "None"
 webserver = "SWI-Prolog"
 versus = ""

+ 19 - 0
frameworks/Prolog/SWI-Prolog/config/odbc.ini

@@ -0,0 +1,19 @@
+[benchmark]
+Description         = Benchmark Database
+Driver              = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so
+Trace               = Yes
+TraceFile           = sql.log
+Servername          = tfb-database
+Database            = hello_world
+UserName            = benchmarkdbuser
+Password            = benchmarkdbpass
+Port                = 5432
+Protocol            = 13.3
+ReadOnly            = No
+RowVersioning       = No
+ShowSystemTables    = No
+ShowOidColumn       = No
+FakeOidIndex        = No
+ConnSettings        =
+MaxVarcharSize      = 4096
+Pooling             = Yes

+ 0 - 38
frameworks/Prolog/SWI-Prolog/server.pl

@@ -1,38 +0,0 @@
-:- module(server,
-      [ server/1            % ?Port
-      ]).
-
-:- use_module(library(http/thread_httpd)).
-:- use_module(library(http/http_dispatch)).
-:- use_module(library(http/http_unix_daemon)).
-:- use_module(library(http/http_dyn_workers)).
-
-%!  server(+Port) is det.
-%
-%   Start the server at Port.
-
-server(Port) :-
-    server(Port,
-           [ workers(10)
-           ]).
-
-server(Port, Options) :-
-    http_server(http_dispatch,
-                [ port(Port),
-                  timeout(20)
-                | Options
-                ]).
-
-:- http_handler('/plaintext', plaintext, [chunked]).
-:- http_handler('/json', json, [chunked]).
-
-plaintext(_Request) :-
-    format('Server: SWI-Prolog~n'),
-    format('Content-type: text/plain~n~n'),
-    format('Hello, World!').
-
-json(_Request) :-
-    format('Server: SWI-Prolog~n'),
-    format('Content-type: application/json~n~n'),
-    format('{"message":"Hello, World!"}').
-

+ 7 - 7
frameworks/Prolog/SWI-Prolog/swi-prolog.dockerfile

@@ -1,18 +1,18 @@
 FROM ubuntu:20.04
 
-ENV IROOT=/installs
-
 ENV DEBIAN_FRONTEND noninteractive
 RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
 
 RUN apt update -yqq && apt-get install -y software-properties-common
 RUN apt-add-repository ppa:swi-prolog/stable -y
-RUN apt-get update -y && apt-get install -y --no-install-recommends swi-prolog
-
-COPY server.pl ${IROOT}/
-WORKDIR ${IROOT}
+RUN apt-get update -y && apt-get install -y --no-install-recommends swi-prolog swi-prolog-odbc odbc-postgresql
+RUN swipl -g 'pack_install(simple_template, [interactive(false), silent(true)]).'
 
 EXPOSE 8080
 
-CMD swipl server.pl --user=daemon --fork=false --port=8080
+WORKDIR /app
+
+CMD [ "swipl", "server.pl", "--user=daemon", "--fork=false", "--port=8080" ]
 
+COPY ./config/odbc.ini /etc/odbc.ini
+COPY app .