--- parser3/src/classes/op.C 2007/04/20 10:16:54 1.165 +++ parser3/src/classes/op.C 2007/06/09 16:22:08 1.170 @@ -5,7 +5,7 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_OP_C="$Date: 2007/04/20 10:16:54 $"; +static const char * const IDENT_OP_C="$Date: 2007/06/09 16:22:08 $"; #include "classes.h" #include "pa_vmethod_frame.h" @@ -163,7 +163,7 @@ static void _process(Request& r, MethodP { VStateless_class *target_class=target_self->get_last_derived_class(); if(!target_class) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "no target class"); @@ -180,7 +180,7 @@ static void _process(Request& r, MethodP Value& voptions=params.as_no_junction(options_index, "options must not be code"); options=voptions.get_hash(); if(!options) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "options must be hash"); } @@ -204,7 +204,7 @@ static void _process(Request& r, MethodP } if(valid_options!=options->count()) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "called with invalid option"); } @@ -243,7 +243,8 @@ static void _while(Request& r, MethodPar Temp_hash_value cycle_data_setter(r.classes_conf, cycle_data_name, /*any not null flag*/&r); - Value& vcondition=params.as_junction(0, "condition must be expression"); + Value& vcondition=params.as_expression(0, "condition must be number, bool or expression"); + Value& body_code=params.as_junction(1, "body must be code"); Value* delim_maybe_code=params.count()>2?¶ms[2]:0; @@ -252,7 +253,7 @@ static void _while(Request& r, MethodPar bool need_delim=false; while(true) { if(++endless_loop_count>=MAX_LOOPS) // endless loop? - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "endless loop detected"); @@ -284,7 +285,7 @@ static void _use(Request& r, MethodParam static void set_skip(Request& r, Request::Skip askip) { void* data=r.classes_conf.get(cycle_data_name); if(!data) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "without cycle"); @@ -310,7 +311,7 @@ static void _for(Request& r, MethodParam Value* delim_maybe_code=params.count()>4?¶ms[4]:0; if(to-from>=MAX_LOOPS) // too long loop? - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "endless loop detected"); @@ -423,7 +424,7 @@ static void _switch(Request& r, MethodPa static void _case(Request& r, MethodParams& params) { Switch_data* data=static_cast(r.classes_conf.get(switch_data_name)); if(!data) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "without switch"); @@ -448,7 +449,7 @@ static void _case(Request& r, MethodPara if(matches) { if(data->found) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "duplicate found"); @@ -535,7 +536,7 @@ struct Data_string_serialized_prolog { #endif void cache_delete(const String& file_spec) { - file_delete(file_spec, false/*fail_on_read_problem*/); + file_delete(file_spec, false/*fail_on_problem*/); } #ifndef DOXYGEN @@ -547,7 +548,8 @@ public: struct Locked_process_and_cache_put_action_info { Request *r; Cache_scope *scope; - Value* body_code; Value* catch_code; + Value* body_code; + Value* catch_code; const String* processed_code; }; #endif @@ -566,7 +568,6 @@ static void locked_process_and_cache_put Locked_process_and_cache_put_action_info& info= *static_cast(context); - const String* body_from_disk=info.scope->body_from_disk; // body->process Try_catch_result result=try_catch(*info.r, @@ -578,7 +579,7 @@ static void locked_process_and_cache_put assert(body_from_disk); info.processed_code=body_from_disk; } else - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, result.exception_should_be_handled, "$"EXCEPTION_VAR_NAME"."EXCEPTION_HANDLED_PART_NAME" value must be " "either boolean or string '"CACHE_EXCEPTION_HANDLED_CACHE_NAME"'"); @@ -610,11 +611,13 @@ const String* locked_process_and_cache_p const String* result=file_write_action_under_lock( file_spec, - "cache_put", locked_process_and_cache_put_action, &info, + "cache_put", + locked_process_and_cache_put_action, + &info, false/*as_text*/, false/*do_append*/, - false/*block*/, - false/*fail on lock problem*/) ? info.processed_code: 0; + false/*block == don't wait till other thread release lock*/) ? info.processed_code: 0; + time_t now=time(0); if(scope.expires<=now) cache_delete(file_spec); @@ -671,7 +674,7 @@ static void _cache(Request& r, MethodPar // return current expiration time Cache_scope* scope=static_cast(r.classes_conf.get(cache_data_name)); if(!scope) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "expire-time get without cache"); r.write_no_lang(*new VDate(scope->expires)); @@ -690,7 +693,7 @@ static void _cache(Request& r, MethodPar // secods|expires date Cache_scope* scope=static_cast(r.classes_conf.get(cache_data_name)); if(!scope) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "expire-time reducing instruction without cache"); @@ -700,7 +703,7 @@ static void _cache(Request& r, MethodPar return; } else if(params.count()<3) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "invalid number of parameters"); @@ -716,63 +719,41 @@ static void _cache(Request& r, MethodPar if(params.count()>3) catch_code=¶ms.as_junction(3, "catch_code must be code"); - if(scope.expires>now) { // valid 'expires' specified? try cached copy... - // hence we don't hope to have unary create/lockEX - // we need some plan to live in a life like that, so... - // worst races plan: - // A B - // open - // |open - // lockSH - // |nonblocking-lockEX fails - // unlockSH - // close, cache_get returns 0 - // open - // nonblocking-lockEX succeeds; process, write, close - // |retry1: open - // ... - // |lockSH succeeds; ... - - for(int retry=0; retry<2; retry++) { - Cache_get_result cached=cache_get(r.charsets, file_spec, now); - if(cached.body) { // have cached copy - if(cached.expired) - scope.body_from_disk=cached.body; // storing for user to retrive it with ^cache[] - else // and it's not expired yet - { - // write it out - r.write_assign_lang(*cached.body); - // happy with it - return; - } - } + if(scope.expires>now) { + Cache_get_result cached=cache_get(r.charsets, file_spec, now); - // non-blocked lock; process; cache it - if(const String* processed_body= - locked_process_and_cache_put(r, body_code, catch_code, scope, file_spec)) { - // write it out - r.write_assign_lang(*processed_body); - // happy with it - return; - } else { // somebody writing result right now - pa_sleep(0, 500000); // waiting half a second - retry=0; // prolonging our wait, than could cache_get it, without processing body_code - } - } - throw Exception(0, - &file_spec, - "locking problem"); + if(cached.body) { // have cached copy + if(cached.expired) { + scope.body_from_disk=cached.body; // storing for user to retrive it with ^cache[] + } else { + // and it's not expired yet write it out + r.write_assign_lang(*cached.body); + // happy with it + return; + } + } + + // no cached info or it's already expired + try { + // try to process and store in file + const String* processed_body=locked_process_and_cache_put(r, body_code, catch_code, scope, file_spec); + // write it out + r.write_assign_lang(*processed_body); + // happy with it + return; + } catch(...) { + // we fail during get exclusive lock + // nvm we just process it a bit later + } } else { // instructed not to cache; forget cached copy cache_delete(file_spec); - // process - const String& processed_body=r.process_to_string(body_code); - // write it out - r.write_assign_lang(processed_body); - // happy with it - return; } - // never reached + + // process without cacheing + const String& processed_body=r.process_to_string(body_code); + // write it out + r.write_assign_lang(processed_body); } static StringOrValue process_try_body_code(Request& r, Value* body_code) { @@ -787,7 +768,7 @@ static void _try_operator(Request& r, Me &catch_code); if(result.exception_should_be_handled) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, result.exception_should_be_handled, "catch block must set $exception.handled to some boolean value, not string"); @@ -812,7 +793,7 @@ static void _throw_operator(Request&, Me source?source:0, "%s", comment?comment:""); } else - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "one-param version has hash param"); } else {