Diff for /parser3/src/classes/op.C between versions 1.62.2.1.2.2 and 1.71

version 1.62.2.1.2.2, 2001/12/06 21:34:50 version 1.71, 2002/02/08 08:30:10
Line 1 Line 1
 /** @file  /** @file
         Parser: parser @b operators.          Parser: parser @b operators.
   
         Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexander Petrosyan <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         $Id$          $Id$
 */  */
   
 #include "classes.h"  #include "classes.h"
 #include "pa_config_includes.h"  
 #include "pa_common.h"  #include "pa_common.h"
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_vint.h"  #include "pa_vint.h"
Line 125  static void _process(Request& r, const S Line 124  static void _process(Request& r, const S
   
                 // process source code, append processed methods to 'self' class                  // process source code, append processed methods to 'self' class
                 // maybe-define new @main                  // maybe-define new @main
                 r.use_buf(source.cstr(String::UL_UNSPECIFIED, r.connection), place, &self_class);                  r.use_buf(
                           source.cstr(String::UL_UNSPECIFIED, r.connection(0)), 
                           place, 
                           &self_class);
                                   
                 // maybe-execute @main[]                  // maybe-execute @main[]
                 if(const Method *method=self_class.get_method(*main_method_name)) {                  if(const Method *method=self_class.get_method(*main_method_name)) {
Line 246  struct timeval mt[2]; Line 248  struct timeval mt[2];
 gettimeofday(&mt[0],NULL);  gettimeofday(&mt[0],NULL);
 #endif  #endif
         // connect          // connect
         SQL_Connection& connection=SQL_driver_manager->get_connection(          SQL_Connection_ptr connection=SQL_driver_manager->get_connection(
                 url.as_string(), method_name, protocol2driver_and_client);                  url.as_string(), method_name, protocol2driver_and_client);
   
 #ifdef RESOURCES_DEBUG  #ifdef RESOURCES_DEBUG
Line 259  for(int i=0;i<2;i++) Line 261  for(int i=0;i<2;i++)
   
 r.sql_connect_time+=t[1]-t[0];  r.sql_connect_time+=t[1]-t[0];
 #endif  #endif
         // remember/set current connection          Temp_connection temp_connection(r, connection.get());
         SQL_Connection *saved_connection=r.connection;  
         r.connection=&connection;  
         // execute body          // execute body
         try {          try {
                 try {                  r.write_assign_lang(r.process(body_code));
                         r.write_assign_lang(r.process(body_code));                  
                                   } catch(...) { // process/commit problem
                         connection.commit();                  connection->mark_to_rollback();
                 } catch(...) { // process/commit problem                  /*re*/throw; 
                         connection.rollback();  
                           
                         /*re*/throw;   
                 }  
   
         } catch(...) {  
                 // close connection [cache it]  
                 connection.close();  
                 // recall current connection from remembered  
                 r.connection=saved_connection;  
   
                 /*re*/throw;  
         }          }
   
         // and anyway  
         // close connection [cache it]  
         connection.close();  
         // recall current connection from remembered  
         r.connection=saved_connection;  
 }  }
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
Line 356  struct Data_string_serialized_prolog { Line 338  struct Data_string_serialized_prolog {
 };  };
 #endif  #endif
   
 void cache_delete(Pool& pool, const String& file_spec) {  void cache_delete(const String& file_spec) {
         file_delete(pool, file_spec, false/*fail_on_read_problem*/);          file_delete(file_spec, false/*fail_on_read_problem*/);
 }  }
 void cache_put(Pool& pool, const String& file_spec, const String& data_string) {  
   #ifndef DOXYGEN
   struct Locked_process_and_cache_put_action_info {
           Request *r;
           Value *body;
   };
   #endif
   static void locked_process_and_cache_put_action(int f, void *context) {
           Locked_process_and_cache_put_action_info& info=
                   *static_cast<Locked_process_and_cache_put_action_info *>(context);
           
           // body->process 
           info.body=&info.r->process(*info.body);
   
           // result->string
           const String& data_string=info.body->as_string();
   
           // string -serialize> buffer
         void *data; size_t data_size;          void *data; size_t data_size;
         data_string.serialize(          data_string.serialize(
                 sizeof(Data_string_serialized_prolog),                   sizeof(Data_string_serialized_prolog), 
                 data, data_size);                  data, data_size);
         Data_string_serialized_prolog& prolog=          Data_string_serialized_prolog& prolog=
                 *static_cast<Data_string_serialized_prolog *>(data);                  *static_cast<Data_string_serialized_prolog *>(data);
   
         prolog.version=DATA_STRING_SERIALIZED_VERSION;          prolog.version=DATA_STRING_SERIALIZED_VERSION;
           
         file_write(pool,           // buffer -write> file
                                 file_spec,           write(f, data, data_size);
                                 data, data_size,   }
                                 false/*as_text*/);  Value *locked_process_and_cache_put(Request& r, 
                                                                           Value& body_code,
                                                                           const String& file_spec) {
           Locked_process_and_cache_put_action_info info={
                   &r,
                   &body_code,
           };
   
           return file_write_action_under_lock(
                   file_spec, 
                   "cache_put", locked_process_and_cache_put_action, &info,
                   false/*as_text*/,
                   false/*do_append*/,
                   false/*block*/) ? info.body : 0;
 }  }
 String *cache_get(Pool& pool, const String& file_spec) {  String *cache_get(Pool& pool, const String& file_spec) {
         void* data; size_t data_size;          void* data; size_t data_size;
         if(!file_read(pool, file_spec,           if(!file_read(pool, file_spec, 
                            data, data_size,                              data, data_size, 
                            false/*as_text*/,                              false/*as_text*/, 
                            false/*fail_on_read_problem*/))                             false/*fail_on_read_problem*/)
               || !data_size/* ignore reads which are empty due to 
                           non-unary open+lockEX conflict with lockSH */)
                 return 0;                  return 0;
                   
         Data_string_serialized_prolog& prolog=          Data_string_serialized_prolog& prolog=
Line 388  String *cache_get(Pool& pool, const Stri Line 401  String *cache_get(Pool& pool, const Stri
         if(data_size<sizeof(Data_string_serialized_prolog))          if(data_size<sizeof(Data_string_serialized_prolog))
                 throw Exception(0, 0,                  throw Exception(0, 0,
                         &file_spec,                          &file_spec,
                         "bad cached file, too short");                          "bad cached file (size=%d), too short (minsize=%d)", 
                               data_size, sizeof(Data_string_serialized_prolog));
   
         if(prolog.version!=DATA_STRING_SERIALIZED_VERSION)          if(prolog.version!=DATA_STRING_SERIALIZED_VERSION)
                 throw Exception(0, 0,                  throw Exception(0, 0,
Line 397  String *cache_get(Pool& pool, const Stri Line 411  String *cache_get(Pool& pool, const Stri
                                 prolog.version, DATA_STRING_SERIALIZED_VERSION);                                  prolog.version, DATA_STRING_SERIALIZED_VERSION);
   
         String& result=*new(pool) String(pool);          String& result=*new(pool) String(pool);
         if(data_size) {          result.deserialize(
                 result.deserialize(                  sizeof(Data_string_serialized_prolog), 
                         sizeof(Data_string_serialized_prolog),                   data, data_size, file_spec.cstr());
                         data, data_size, file_spec.cstr());  
         }  
           
         return &result;          return &result;
 }  }
 static void _cache(Request& r, const String& method_name, MethodParams *params) {  static void _cache(Request& r, const String& method_name, MethodParams *params) {
         // ^cache[file_spec](lifespan){code} time=0 no cache  
         Pool& pool=r.pool();          Pool& pool=r.pool();
                   
         // file_spec, expires, body code          // file_spec, expires, body code
         const String &file_spec=params->as_string(0, "key must be string");          const String &file_spec=r.absolute(params->as_string(0, "filespec must be string"));
           if(params->size()==1) { // delete
                   cache_delete(file_spec);
                   return;
           }
   
         time_t lifespan=(time_t)params->as_double(1, "lifespan must be number", r);          time_t lifespan=(time_t)params->as_double(1, "lifespan must be number", r);
         Value& body_code=params->as_junction(2, "body must be code");          Value& body_code=params->as_junction(2, "body must be code");
   
         if(lifespan) { // 'lifespan' specified? try cached copy...          if(lifespan) { // 'lifespan' specified? try cached copy...
                 size_t size;                  size_t size;
                 time_t atime, mtime, ctime;                  time_t atime, mtime, ctime;
   
                   // 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; ...
   
                 // {file_spec} modification time                  // {file_spec} modification time
                 if(!file_stat(file_spec, size, atime, mtime, ctime, false/*no exception on error*/)                   for(int retry=0; retry<2; retry++) {
                         || (time(0)-mtime) > lifespan) // cached file expired                          if(file_stat(file_spec, size, atime, mtime, ctime, false/*no exception on error*/)) // exists?
                         cache_delete(pool, file_spec);                                  if(time(0)-mtime > lifespan) // expired
                 else                                          cache_delete(file_spec);
                         if(String *cached_body=cache_get(pool, file_spec)) { // have cached copy?                                  else // not expired
                                           if(String *cached_body=cache_get(pool, file_spec)) { // have cached copy?
                                                   // write it out 
                                                   r.write_assign_lang(*cached_body);
                                                   // happy with it
                                                   return;
                                           }
   
                           // non-blocked lock; process; cache it
                           if(Value *processed_body=locked_process_and_cache_put(r, body_code, file_spec)) {
                                 // write it out                                   // write it out 
                                 r.write_assign_lang(*cached_body);                                  r.write_assign_lang(*processed_body);
                                 // happy with it                                  // happy with it
                                 return;                                  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
                         }                          }
         } else // 'lifespan'=0, forget cached copy                  }
                 cache_delete(pool, file_spec);                  throw Exception(0, 0,
                                   &file_spec,
         // process                          "locking problem");
         Value& processed_body=r.process(body_code);          } else { 
                           // 'lifespan'=0, forget cached copy
         // put it to cache if 'lifespan' specified                  cache_delete(file_spec);
         if(lifespan)                  // process
                 cache_put(pool, file_spec, processed_body.as_string());                  Value& processed_body=r.process(body_code);
                   // write it out 
         // write it out                   r.write_assign_lang(processed_body);
         r.write_assign_lang(processed_body);                  // happy with it
                   return;
           }
           // never reached
 }  }
   
 // constructor  // constructor
Line 487  MOP::MOP(Pool& apool) : Methoded(apool), Line 534  MOP::MOP(Pool& apool) : Methoded(apool),
         add_native_method("connect", Method::CT_ANY, _connect, 2, 2);          add_native_method("connect", Method::CT_ANY, _connect, 2, 2);
   
   
           // ^cache[file_spec] delete cache
         // ^cache[file_spec](time){code} time=0 no cache          // ^cache[file_spec](time){code} time=0 no cache
         add_native_method("cache", Method::CT_ANY, _cache, 3, 3);          add_native_method("cache", Method::CT_ANY, _cache, 1, 3);
                   
         // switch          // switch
   

Removed from v.1.62.2.1.2.2  
changed lines
  Added in v.1.71


E-mail: