11% %%------------------------------------------------------------------------------
2- % %% @copyright (c) 2013-2014 , DuoMark International, Inc.
2+ % %% @copyright (c) 2013-2015 , DuoMark International, Inc.
33% %% @author Jay Nelson <jay@duomark.com>
4- % %% @reference 2013-2014 Development sponsored by TigerText, Inc. [http://tigertext.com/]
4+ % %% @reference 2013-2015 Development sponsored by TigerText, Inc. [http://tigertext.com/]
55% %% @reference The license is based on the template for Modified BSD from
66% %% <a href="http://opensource.org/licenses/BSD-3-Clause">OSI</a>
77% %% @doc
6767-type cached_key () :: term ().
6868-type cached_value () :: term ().
6969-type cached_value_vsn () :: term ().
70- -callback create_key_value (cached_key ()) -> {cached_value_vsn (), cached_value ()}.
70+ -callback create_key_value (cached_key ()) -> {cached_value_vsn (), cached_value ()} | no_value_available .
7171
7272% % Return 'true' if Vsn2 later than Vsn1, otherwise 'false'.
7373% % -optional_callback is_later_version(Vsn1::cached_value_vsn(), Vsn2::cached_value_vsn()) -> boolean().
@@ -308,13 +308,12 @@ replace_check_generation_fun(Cache_Name, Fun)
308308% %%------------------------------------------------------------------------------
309309
310310-spec delete_item (cache_name (), cached_key ()) -> true .
311- -spec fetch_item (cache_name (), cached_key ()) -> cached_value () | {error , tuple ()}.
312- -spec refresh_item (cache_name (), cached_key ()) -> cached_value () | {error , tuple ()}.
311+ -spec fetch_item (cache_name (), cached_key ()) -> cached_value () | no_value_available | {error , tuple ()}.
312+ -spec refresh_item (cache_name (), cached_key ()) -> cached_value () | no_value_available | {error , tuple ()}.
313313-spec refresh_item (cache_name (), cached_key (), {cached_value_vsn (), cached_value ()})
314- -> cached_value () | {error , tuple ()}.
315- -spec fetch_item_version (cache_name (), cached_key ()) -> cached_value_vsn () | {} | {error , tuple ()}.
316- -spec get_and_clear_counts (cache_name ())
317- -> {cache_name (), proplists :proplist ()}.
314+ -> cached_value () | no_value_available | {error , tuple ()}.
315+ -spec fetch_item_version (cache_name (), cached_key ()) -> cached_value_vsn () | no_value_available | {error , tuple ()}.
316+ -spec get_and_clear_counts (cache_name ()) -> {cache_name (), proplists :proplist ()}.
318317
319318-define (WHEN_GEN_EXISTS (__Gen_Id , __Code ), ets :info (__Gen_Id , type ) =:= set andalso __Code ).
320319
@@ -357,7 +356,7 @@ fetch_item(Cache_Name, Key) ->
357356 Not_Found_Fn = fun (Fn_Cache_Name , Fn_New_Gen_Id , Fn_Old_Gen_Id , Fn_Mod , Fn_Key , _Object ) ->
358357 copy_old_value_if_found (Fn_Cache_Name , Fn_New_Gen_Id , Fn_Old_Gen_Id , Fn_Mod ,Fn_Key )
359358 end ,
360- access_item (Cache_Name , Key , Found_Fn , Not_Found_Fn , {} ).
359+ access_item (Cache_Name , Key , Found_Fn , Not_Found_Fn , no_value_available ).
361360
362361% % Fetch from Generation 1 or 2, after updating with a newer key version or leaving existing newest key version.
363362refresh_item (Cache_Name , Key ) ->
@@ -370,7 +369,7 @@ refresh_item(Cache_Name, Key) ->
370369 Fn_Mod ,Fn_Key ,Fn_Obj ),
371370 return_cache_miss (Fn_Cache_Name , Fn_New_Cached_Value )
372371 end ,
373- access_item (Cache_Name , Key , Found_Fn , Not_Found_Fn , {} ).
372+ access_item (Cache_Name , Key , Found_Fn , Not_Found_Fn , no_value_available ).
374373
375374% % Fetch from Generation 1 or 2, after updating with a newer obj version or leaving existing newest obj version.
376375refresh_item (Cache_Name , Key , {Possibly_New_Vsn , Possibly_New_Value } = Possibly_New_Object ) ->
@@ -393,7 +392,7 @@ fetch_item_version(Cache_Name, Key) ->
393392 Not_Found_Fn = fun (Fn_Cache_Name , _New_Gen_Id , Fn_Old_Gen_Id , _Mod , Fn_Key , _Obj ) ->
394393 fetch_gen2_version (Fn_Cache_Name , Fn_Old_Gen_Id , Fn_Key )
395394 end ,
396- access_item (Cache_Name , Key , Found_Fn , Not_Found_Fn , {} ).
395+ access_item (Cache_Name , Key , Found_Fn , Not_Found_Fn , no_value_available ).
397396
398397% % Old generation function for getting just the version of a cached value entry.
399398fetch_gen2_version (Cache_Name , Old_Gen_Id , Key ) ->
@@ -403,12 +402,13 @@ fetch_gen2_version(Cache_Name, Old_Gen_Id, Key) ->
403402 [# cxy_cache_value {key = Key , version = Version }] ->
404403 Version ;
405404 [] ->
406- {}
405+ no_value_available
407406 end .
408407
409408% % Migrate an old value forward to the new generation and then clobber
410409% % if the key generates a newer version. Otherwise leave the existing
411- % % version in place.
410+ % % version in place, unless there is now no_value_available, in which
411+ % % case the entry is deleted from the cache.
412412refresh_item (Type , Cache_Name , New_Gen_Id , Old_Gen_Id , Mod , Key , Object ) ->
413413 try ets :lookup (Old_Gen_Id , Key ) of
414414
@@ -419,7 +419,22 @@ refresh_item(Type, Cache_Name, New_Gen_Id, Old_Gen_Id, Mod, Key, Object) ->
419419 [# cxy_cache_value {key = Key } = Old_Obj ] ->
420420 insert_to_new_gen (Cache_Name , New_Gen_Id , Mod , Old_Obj ),
421421 % % Then try to clobber it with a newly created value.
422- refresh_now (Type , Cache_Name , New_Gen_Id , Mod , Key , Object )
422+ Cached_Value = case {Type , Object } of
423+ {key , _ } ->
424+ create_new_value (Cache_Name , New_Gen_Id , Mod , Key );
425+ {obj , no_value_available } ->
426+ no_value_available ;
427+ {obj , _ } ->
428+ {Possibly_New_Vsn , Possibly_New_Value } = Object ,
429+ insert_value_if_newer (Cache_Name , New_Gen_Id , Mod ,
430+ Key , Possibly_New_Vsn , Possibly_New_Value )
431+ end ,
432+ case Cached_Value of
433+ no_value_available -> ? WHEN_GEN_EXISTS (New_Gen_Id , ets :delete (New_Gen_Id , Key )),
434+ ? WHEN_GEN_EXISTS (Old_Gen_Id , ets :delete (Old_Gen_Id , Key )),
435+ return_cache_miss (Cache_Name , no_value_available );
436+ {_Version , _Value } -> return_cache_refresh (Cache_Name , Cached_Value )
437+ end
423438 catch
424439 % % Old generation was likely eliminated by another request, try creating a new value.
425440 % % The value will get inserted into 'old_gen' because New_Gen_Id must've been demoted.
@@ -456,7 +471,8 @@ copy_old_value_if_found(Cache_Name, New_Gen_Id, Old_Gen_Id, Mod, Key) ->
456471
457472cache_miss (Cache_Name , New_Gen_Id , Mod , Key ) ->
458473 case create_new_value (Cache_Name , New_Gen_Id , Mod , Key ) of
459- {error , _ } = Error -> Error ;
474+ {error , _ } = Error -> return_cache_miss (Cache_Name , Error );
475+ no_value_available -> return_cache_miss (Cache_Name , no_value_available );
460476 Cached_Value -> return_cache_miss (Cache_Name , Cached_Value )
461477 end .
462478
@@ -501,8 +517,8 @@ get_and_clear_counts(Cache_Name) ->
501517% % Create a new value from the cache Mod:create_key_value(Key) but watch for errors in generating it.
502518create_new_value (Cache_Name , New_Gen_Id , Mod , Key ) ->
503519 try Mod :create_key_value (Key ) of
504- { Version , Value } ->
505- insert_value_if_newer (Cache_Name , New_Gen_Id , Mod , Key , Version , Value )
520+ no_value_available -> no_value_available ;
521+ { Version , Value } -> insert_value_if_newer (Cache_Name , New_Gen_Id , Mod , Key , Version , Value )
506522 catch Type :Class ->
507523 Error = {error , {Type ,Class , {creating_new_value_with , Mod , Key }}},
508524 return_cache_error (Cache_Name , Error )
0 commit comments