Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F619701
mongocrypt-cache.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None
mongocrypt-cache.c
View Options
/*
* Copyright 2019-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include
"mongocrypt-cache-private.h"
#include
"mongocrypt-private.h"
/* Did the cache pair expire? Caller must hold lock. */
static
bool
_pair_expired
(
_mongocrypt_cache_t
*
cache
,
_mongocrypt_cache_pair_t
*
pair
)
{
int64_t
current
;
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
pair
);
current
=
bson_get_monotonic_time
()
/
1000
;
BSON_ASSERT
(
current
>=
INT64_MIN
+
pair
->
last_updated
);
BSON_ASSERT
(
cache
->
expiration
<=
INT64_MAX
);
return
cache
->
expiration
>
0
&&
(
current
-
pair
->
last_updated
)
>
(
int64_t
)
cache
->
expiration
;
}
/* Return the pair after the one being destroyed. */
static
_mongocrypt_cache_pair_t
*
_destroy_pair
(
_mongocrypt_cache_t
*
cache
,
_mongocrypt_cache_pair_t
*
prev
,
_mongocrypt_cache_pair_t
*
pair
)
{
_mongocrypt_cache_pair_t
*
tmp
;
BSON_ASSERT_PARAM
(
cache
);
/* prev is checked before being used, so it can be NULL */
BSON_ASSERT_PARAM
(
pair
);
tmp
=
pair
->
next
;
/* Unlink */
if
(
!
prev
)
{
cache
->
pair
=
cache
->
pair
->
next
;
}
else
{
prev
->
next
=
pair
->
next
;
}
/* Destroy pair */
cache
->
destroy_attr
(
pair
->
attr
);
cache
->
destroy_value
(
pair
->
value
);
bson_free
(
pair
);
return
tmp
;
}
/* Caller must hold mutex. */
static
void
_mongocrypt_cache_evict
(
_mongocrypt_cache_t
*
cache
)
{
_mongocrypt_cache_pair_t
*
pair
,
*
prev
;
BSON_ASSERT_PARAM
(
cache
);
prev
=
NULL
;
pair
=
cache
->
pair
;
while
(
pair
)
{
if
(
_pair_expired
(
cache
,
pair
))
{
pair
=
_destroy_pair
(
cache
,
prev
,
pair
);
continue
;
}
prev
=
pair
;
pair
=
pair
->
next
;
}
}
/* Caller must hold mutex. */
static
bool
_mongocrypt_remove_matches
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
)
{
_mongocrypt_cache_pair_t
*
pair
,
*
prev
;
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
prev
=
NULL
;
pair
=
cache
->
pair
;
while
(
pair
)
{
int
res
;
if
(
!
cache
->
cmp_attr
(
pair
->
attr
,
attr
,
&
res
))
{
return
false
;
}
if
(
0
==
res
)
{
pair
=
_destroy_pair
(
cache
,
prev
,
pair
);
continue
;
}
prev
=
pair
;
pair
=
pair
->
next
;
}
return
true
;
}
void
_mongocrypt_cache_set_expiration
(
_mongocrypt_cache_t
*
cache
,
uint64_t
milli
)
{
BSON_ASSERT_PARAM
(
cache
);
cache
->
expiration
=
milli
;
}
/* caller must hold lock. */
static
bool
_find_pair
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
,
_mongocrypt_cache_pair_t
**
out
)
{
_mongocrypt_cache_pair_t
*
pair
;
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
BSON_ASSERT_PARAM
(
out
);
*
out
=
NULL
;
pair
=
cache
->
pair
;
while
(
pair
)
{
int
res
;
/* TODO: this is a naive O(n) lookup. Consider optimizing
with a hash map (possibly vendor one). */
if
(
!
cache
->
cmp_attr
(
pair
->
attr
,
attr
,
&
res
))
{
return
false
;
}
if
(
res
==
0
)
{
*
out
=
pair
;
return
true
;
}
pair
=
pair
->
next
;
}
return
true
;
}
/* Create a new pair on linked list. Caller must hold lock. */
static
_mongocrypt_cache_pair_t
*
_pair_new
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
)
{
_mongocrypt_cache_pair_t
*
pair
;
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
pair
=
bson_malloc0
(
sizeof
(
_mongocrypt_cache_pair_t
));
BSON_ASSERT
(
pair
);
pair
->
attr
=
cache
->
copy_attr
(
attr
);
/* add rest of values. */
pair
->
next
=
cache
->
pair
;
pair
->
last_updated
=
bson_get_monotonic_time
()
/
1000
;
cache
->
pair
=
pair
;
return
pair
;
}
/* Caller must hold lock. */
static
void
_cache_pair_destroy
(
_mongocrypt_cache_t
*
cache
,
_mongocrypt_cache_pair_t
*
pair
)
{
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
pair
);
cache
->
destroy_attr
(
pair
->
attr
);
cache
->
destroy_value
(
pair
->
value
);
bson_free
(
pair
);
}
bool
_mongocrypt_cache_get
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
,
/* attr of cache item */
void
**
value
/* copied to. */
)
{
_mongocrypt_cache_pair_t
*
match
;
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
BSON_ASSERT_PARAM
(
value
);
*
value
=
NULL
;
_mongocrypt_mutex_lock
(
&
cache
->
mutex
);
/* TODO CDRIVER-3120: optimize the eviction algorithm to avoid unnecessary
* O(n) traversal */
_mongocrypt_cache_evict
(
cache
);
if
(
!
_find_pair
(
cache
,
attr
,
&
match
))
{
_mongocrypt_mutex_unlock
(
&
cache
->
mutex
);
return
false
;
}
if
(
match
)
{
*
value
=
cache
->
copy_value
(
match
->
value
);
}
_mongocrypt_mutex_unlock
(
&
cache
->
mutex
);
return
true
;
}
static
bool
_cache_add
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
,
void
*
value
,
mongocrypt_status_t
*
status
,
bool
steal_value
)
{
_mongocrypt_cache_pair_t
*
pair
;
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
BSON_ASSERT_PARAM
(
value
);
_mongocrypt_mutex_lock
(
&
cache
->
mutex
);
_mongocrypt_cache_evict
(
cache
);
if
(
!
_mongocrypt_remove_matches
(
cache
,
attr
))
{
CLIENT_ERR
(
"error removing from cache"
);
_mongocrypt_mutex_unlock
(
&
cache
->
mutex
);
return
false
;
}
pair
=
_pair_new
(
cache
,
attr
);
if
(
steal_value
)
{
pair
->
value
=
value
;
}
else
{
pair
->
value
=
cache
->
copy_value
(
value
);
}
_mongocrypt_mutex_unlock
(
&
cache
->
mutex
);
return
true
;
}
bool
_mongocrypt_cache_add_copy
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
,
void
*
value
,
mongocrypt_status_t
*
status
)
{
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
BSON_ASSERT_PARAM
(
value
);
return
_cache_add
(
cache
,
attr
,
value
,
status
,
false
);
}
bool
_mongocrypt_cache_add_stolen
(
_mongocrypt_cache_t
*
cache
,
void
*
attr
,
void
*
value
,
mongocrypt_status_t
*
status
)
{
BSON_ASSERT_PARAM
(
cache
);
BSON_ASSERT_PARAM
(
attr
);
BSON_ASSERT_PARAM
(
value
);
return
_cache_add
(
cache
,
attr
,
value
,
status
,
true
);
}
void
_mongocrypt_cache_cleanup
(
_mongocrypt_cache_t
*
cache
)
{
_mongocrypt_cache_pair_t
*
pair
,
*
tmp
;
if
(
!
cache
)
{
return
;
}
pair
=
cache
->
pair
;
while
(
pair
)
{
tmp
=
pair
->
next
;
_cache_pair_destroy
(
cache
,
pair
);
pair
=
tmp
;
}
}
uint32_t
_mongocrypt_cache_num_entries
(
_mongocrypt_cache_t
*
cache
)
{
_mongocrypt_cache_pair_t
*
pair
;
uint32_t
count
;
BSON_ASSERT_PARAM
(
cache
);
_mongocrypt_mutex_lock
(
&
cache
->
mutex
);
count
=
0
;
for
(
pair
=
cache
->
pair
;
pair
!=
NULL
;
pair
=
pair
->
next
)
{
count
++
;
}
_mongocrypt_mutex_unlock
(
&
cache
->
mutex
);
return
count
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Nov 14, 5:05 PM (11 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
134849
Default Alt Text
mongocrypt-cache.c (6 KB)
Attached To
Mode
R114 php-mongodb
Attached
Detach File
Event Timeline