use

Gena Makhomed gmm at csdoc.com
Sun Jul 24 13:35:55 UTC 2011


On 24.07.2011 5:22, António P. P. Almeida wrote:

[...]

>>> Each redefinition overrides the previous.
>>> It should issue a warning when there's a reload.

in this case it will be many useless warnings during nginx start/reload.
and such warnings never help to find real errors in configuration files.
if 100-200-300 'local' site config files -- we got 100-200-300 warnings.
to solve this problem - I offer 'require' directive, as described above.

>> in C all macros are global - from point of definition
>> to end of file. if we make C-like syntax and C-like directives
>> - behaviour of 'define' directive should be close to C preprocessor
>> '#define' directive.
>>
>> if I define some macro at start of 'local' configuration file -
>> I can be sure what this macro will be same to end of this file.
>>
>> if macro will be redefined multiple times in nested levels -
>> this is will be nightmage of support such nginx config files.
>>
>> to make changes and sure that changes will be applied -
>> you will need to re-read all config file from start to end.
>>
>> ================================================
>>
>> define static_images { code1 }
>>
>> server {
>> define static_images { code2 }
>>
>> location / {
>> define static_images { code3 }
>> use static_images;                   [1]
>> location /nested/ {
>> use static_images;               [2]
>> define static_images { code4 }
>> location /one/more/ {
>> use static_images;           [3]
>
>> ================================================
>>
>> can you easy say which codeX will
>> be used for each case [1], [2], [3] ?
>
> Yes: [1] code 3
>       [2] code 3
>       [3] code 4

this is not easy to read / unrerstand / maintain.
and this is un-necessary level of config complexity.

macro - is "define once, use many to end of file" fragment of code.
if you need other code - just define another macro with other name.

so, - macro redefinitions must be errors
on config parse phase, not just warnings.

this allow system administrators to be sure,
what macro defined on beginning of config file
will stay unchanged from point of definition
to end of scope (usually, to end of this file)

after fast looking to macro definition at start of file -
system administrator can use this macro with confidence.
and in this case - never will be changed silently or unexpectedly.
and such nignx configs will be easy to read / unrerstand / maintain.

>> ...even if such config will contain 100 locations?
>
> It could have as many locations as you want it, the more specific
> level always gets the priority.

you understand which the problem in this case?
for make changes in one location you will need
re-read and re-understand comlpete configuration file,
each line, and each macro defitinoin and re-definition.

also - all such re-definitions will issue useless warnings
in each case of re-defitinion, or - real errors will be silent.

> This is like C, no?
>
> int i = 0;
> {
>    int i = 1;
>    printf("%d", i); // prints 1
> }

no.
we talk about macros, like in C preprocessor #define directive.

#define MACRO 1
#define MACRO 2
main(){}

# gcc test.c
test.c:2:1: warning: "MACRO" redefined
test.c:1:1: warning: this is the location of the previous definition

[...]

>>> That can be solved by having an internal symbol table for
>>> macros. When the configuration is read, a symbol table is built
>>> that maps the user defined identifiers to internal identifiers and
>>> these internal symbols replace the user defined identifiers.
>>
>> semantic of static_images will be unexpetedly
>> changed from macro to built-it nginx directive.
>
> No problem as long as you constrain the user defined macros to be just
> mere syntactic transformations. The builtin directive whose name
> collides with the user defined macro, it's processed in a later
> phase.

this is no problem from computer only.
but this will be real problem for human.

>> and this is will be nightmage of supporting
>> nginx config files with volatile semantics.

> Semantics?

yes. this is volatile semantics for system administrators,
which need to read / understand / maintain such config files.

for example:

- admin1 define macro static_images and use it in config

- admin2 upgrade nginx, new nginx version have such directive.

- now semantics of static_images silently changed
from user-defined macro to build-it nginx directive.
or build-in nginx directive will be silently masked
in sone configuration fragments by user-redined macro.

- curtain, support nightmare show begins.

> The macros are code generation and that's it.
> Like in the case of the C preprocessor.

silent overwriting of directives by macros -
this is the dark side of C preprocessor.

this "feature" of C preprocessor is drawback / defect / flaw.
there is no reasons to import such design bugs to nginx config.

[...]

>> sorry, I can't understand this conglomeration of punctuation
>> symbols:
>>
>> (defmacro my-unless (condition&body body)
>> `(if (funcall ',#'not ,condition)
>> (progn
>> , at body)))
>
> That's OT, but it's terse, which is something to be wished IMHO, and
> has a lot of expressive power. Computer languages are not human
> vernacular languages.

nginx config will read the both - computer and the human.
LISP-way is make such language comfortable for computers.
nginx-way - make nginx config syntax comfortable for humahs.

> Note that the above is much more complex than
> the scheme we're discussing. There's no way to control evaluation on
> Nginx config. All you can do is control the flow (to a certain
> extent), you cannot subvert the evalution of the expressions. Which is
> what you're doing above.

sorry, my english language is not very well,
and complex sentences are hard to understand by me.

maybe I misunderstand you, but you can control anything,
just by writing you own nginx config generator in any
programming language, for example, LISP or Python.
and you can make you own Domain-specific language,
which can be translated to raw nginx config.
in this case DSL will be high level language, like C
and raw nginx config will be low level language,
like assembler.

for example:

DSL config syntax:

short_name  full_url  description of this resource

DSL config example fragment:

=======================================================

h       http://habrahabr.ru$request_uri?      HabraHabr

gt      http://translate.google.com/          Google Translate

tr      http://rutracker.org/                 --- torrents.ru
rt      http://rutracker.org/                 --- torrents.ru

sane    http://www.sane-project.org/          --- sane
wine    http://www.winehq.org/                --- wine

=======================================================

my python script parse this high-level DSL
and generate low level nginx raw config, for example,
this is generated raw nginx config fragment for HabraHabr:

server {
     server_name h;
     server_name h.example.com;
     rewrite  ^  http://habrahabr.ru$request_uri?  redirect;
}

also - generate static html file with descriptions for redirects.
for example, html file fragment for HabraHabr description:

<tr class="ffffff" onMouseOver='this.style.backgroundColor="yellow";' 
onMouseOut='this.style.backgroundColor="#ffffff";' >
<td class="name"><a href="http://h/">h</a></td>
<td class="desc"><a href="http://h/">HabraHabr</a></td>
</tr>

how it works:

if in browser window I just press <h> and <enter>
- browser will open HabraHabr site.

if I press <g><t><enter> - browser will open Google Translate site
and so on...

if press <t><enter> - I can see descriptions of all redirects.
't' means 'teleport service' or 'descrip*t*ions' of redirects.

you also can write you own DSL and nginx config generator.
even using LISP programming language or any other language.

this is no problem.

[...]

>> when I read config - how I cat understand which semanctic have
>>
>> fragment of config
>>
>> static_images /srv/www/img;
>>
>> - this is new nginx directive or macro with different semactics ?

> Yes you're right that would involve semantics to find out what's
> what. I agree that 'use' simplifies things significantly.

we should use 'use' directive to explicitly mark macro usage.

nginx config is specific language - system anmitistrator
write config fragment once and read/re-read this fragment
many times, so nginx config sytnax must be optimized
for 'easy to read / easy to understand' as main goal.

and nginx config MUST NOT be optimized for easy to write goal.
so, 'plain' macros usage witout explicit 'use' directive - is bad idea.

> Perhaps we
> can use a prefix for user defined macros:
>
> define static_images {
>
> }
>
> then we just prepend a ':' or a '+' when referring to the user defined
> macros.
>
>     location ^~ /img/ {
>        :static_images; # or +static_images
>     }

how administrators must read this mixture?

'colon static images' ?
'plus static images' ?

we must read 'colon'/'plus' but we must imply/suppose
such text as 'use macro' / 'macro usage' directive???

this is bad approach.

this is syntax optimization for easy of writing config.
but also this is predicament of reading / understanding of config.

but on the average nginx config have 1% of write access
operations by human and 99% of read access operations by human.

so, nginx confix syntax MUST be optimized for 'easy of reading'
and MUST NOT for just 'easy of writing' nginx configuration files.

[...]

>>>>> The scope could continue to be global and thus it wouldn't touch
>>>>> on the location configuration merge process and preserve all the
>>>>> current capabilities of hooking into the multitude of aspects of
>>>>> nginx processing cycle when writing a module.
>>>>
>>>> this is dangerous.
>>>>
>>>> if in one local site config file you write
>>>>
>>>> define static_images { ... }
>>>>
>>>> and in other local site config file by mistake you write
>>>>
>>>> define static_inages { ... }
>>>>
>>>> - nginx will sliently use static_images from prevous local site
>>>> config file and sliently ignone all your changes in current file.
>>>>
>>>> this is bad approach.

>>> I don't think so. If there's a scope for the define
>>> directive. Meaning that the more specific wins. It's clear.

>> this is break rule "Errors should never pass silently".

> Not silent.

in this case hunam error will be silent during config parse.
compare two above define directives carefully - second with typo.

> Like I said before, namespace collisions will generate a
> warning but it will proceed assuming that DWIM is the way to go.

and if I have 100-200-300 'local' config files in /etc/nginx/virtual
- I must create separate macro names, because all have global scope,
or I must accept 100-200-300 useless warnings on each nginx reload.

any of this two ways is bad way.

solution - is use C preprocessor approach - macros defined
from point of definition to end of currend file.

in this case typo errors from previous example will not be silent.

olny we need 'require' directive for inclusion 'local' site config-files
into 'global' nginx config nginx.conf for preventing pollution of global
name space and preventing of generation 100-200-300 useless nignx
warnings, or - necessity to make different and unique macro names
for each 'local' configuration file. for example:

example.com.conf:
define example_com_static_images { }
use example_com_static_images;

example.net.conf:
define example_net_static_images { }
use example1_net_static_images;

example.org.conf:
define example_org_static_images { }
use example_org_static_images;

and so on...

this is really very uncomfortable for every day usage.

nginx config syntax must me smart and comfortable for users,
not stupid/dumb and verbose/ugly as in above macro examples.

>>> It's your responsibility to be aware of redefinitions and unwanted
>>> side effects due to namespace collisions.
>>
>> do it manually in nginx configurations with 100-200-300 config
>> files?
>
> Isn't that the situation now? You cannot preempt logic errors in a
> language. Why would Nginx config be any different?

I am not talk about logic errors,
I am talk about typo errors in configuration files,
for example - "define static_inages" instead of "define static_images"
- such errors MUST NOT be silent during configuration parsing by nginx.

>> none warnings, none errors.
>>
>> example1.com.conf:
>>
>> define static_images { ... }
>> use static_images;
>>
>> example2.com.conf:
>>
>> define static_inages { ... }
>> use static_images;
>>
>> nginx.conf:
>>
>> include example1.com.conf;
>> include example2.com.conf;
>>
>> ==============================
>>
>> in config file example2.com.conf
>> use static_images; - will use
>> definitions from example1.com.conf
>> and silently ignore definitions
>> from example2.com.conf
>
> Nope because the most recent definition wins. It works at all contexts
> and it's respected even across contexts.

no. please attentive read above detailed explanation.

and compare:

static_i*m*ages
static_i*n*ages

above example with unpremeditated typo error, 'n' instead of 'm'.

> In example2.com.conf will use the "closest" definition, which is
> obviously on that file.

this is "obviously" only for you, not for computer.

because computer will read that you write in config,
and not read that you intend to write in nginx config.

good syntax design must take into account human
usage patterns and human errors during such usage.

look at C language: '=' and '==' - easy to make a mistake.

==================================

a = 1

if( a = 0 ) /* human intend to write '==', but real write '=' */
{
   ...
}

==================================

in early C compilers this not produce any warnings or errors.

-- 
Best regards,
  Gena



More information about the nginx-devel mailing list