obi458 commented on issue #1182: fixed race is_idle
URL: https://github.com/apache/couchdb/pull/1182#issuecomment-369345885
 
 
   I don't give up :-)
   
   ```
   incref(#db{fd = Fd} = Db) ->
       incref(Db,couch_file:lock(Fd)).
   
   incref(#db{fd = Fd} = Db, true = _Locked) ->
       % first monitor
       Ref = erlang:monitor(process, Fd),
       % than release the lock
       couch_file:unlock(Fd),
       {ok, Db#db{fd_monitor = Ref}};
   % we are not able to write the lock,
   % either the file will be closed or another process want to monitor
   % we will try it again
   incref(#db{fd = _Fd} = _Db, false = _Locked) ->
       retry.
   ```
   
   couch_file:
   
   ```
   % System dbs aren't monitored by couch_stats_process_tracker
   is_idle(#file{is_sys=true}) ->
       case process_info(self(), monitored_by) of
           {monitored_by, []} -> lock(self());
           _ -> false
       end;
   is_idle(#file{is_sys=false}) ->
       Tracker = whereis(couch_stats_process_tracker),
       case process_info(self(), monitored_by) of
           {monitored_by, []} -> lock(self());
           {monitored_by, [Tracker]} -> lock(self());
           {monitored_by, [_]} -> exit(tracker_monitoring_failed);
           _ -> false
       end.
   
   lock(Fd) -> try
                   ets:new(list_to_atom(pid_to_list(Fd)), [named_table]), true
               catch
                   _:_ -> false
               end.
   unlock(Fd) -> ets:delete(list_to_atom(pid_to_list(Fd))).
   ```
   
   couchd_db_updater:
   
   ```
   handle_info(timeout, #db{fd=Fd, name=DbName} = Db) ->
       IdleLimitMSec = update_idle_limit_from_config(),
       case couch_db:is_idle(Db) of
           true ->
               % we have to unlock Fd, cause close_db_if_idle will check 
is_idle again
               couch_file:unlock(Fd),
               MSecSinceLastRead = couch_file:msec_since_last_read(Fd),
               case MSecSinceLastRead > IdleLimitMSec of
                   true ->
                       ok = couch_server:close_db_if_idle(DbName);
                   false ->
                       ok
               end;
           false ->
               ok
       end,
       % Send a message to wake up and then hibernate. Hibernation here is done 
to
       % force a thorough garbage collection.
       gen_server:cast(self(), wakeup),
       {noreply, Db, hibernate}.
   ```
   
   couchd_db:
   
   ```
   is_idle(#db{compactor_pid=nil, waiting_delayed_commit=nil} = Db) ->
       monitored_by(Db) == [] andalso couch_file:lock(Db#db.fd);
   is_idle(_Db) ->
       false.
   ```
   
   Process died -> ets died and lock will released!
   
   `timer:tc(fun() -> [begin couch_file:lock(self()), couch_file:unlock() end 
|| _ <- lists:seq(1,1000000)] end).`
   
   {2191728,ok} on iMac Pro

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to