Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
T
tarantool
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
core
tarantool
Commits
e4150145
Commit
e4150145
authored
10 years ago
by
Alexandr
Browse files
Options
Downloads
Patches
Plain Diff
added forgotten files to quota patch
parent
8abc6295
Loading
Loading
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/lib/small/quota.h
+183
-0
183 additions, 0 deletions
src/lib/small/quota.h
test/unit/quota.cc
+95
-0
95 additions, 0 deletions
test/unit/quota.cc
test/unit/quota.result
+6
-0
6 additions, 0 deletions
test/unit/quota.result
with
284 additions
and
0 deletions
src/lib/small/quota.h
0 → 100644
+
183
−
0
View file @
e4150145
#ifndef INCLUDES_TARANTOOL_SMALL_QUOTA_H
#define INCLUDES_TARANTOOL_SMALL_QUOTA_H
/*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include
<stddef.h>
#include
<stdlib.h>
#include
<stdint.h>
#include
<assert.h>
#if defined(__cplusplus)
extern
"C"
{
#endif
/* defined(__cplusplus) */
enum
{
QUOTA_MAX_ALLOC
=
0xFFFFFFFFull
*
1024u
,
QUOTA_GRANULARITY
=
1024
};
/** A basic limit on memory usage */
struct
quota
{
/* high order dword is total available memory and low order dword
* - currently used memory both in QUOTA_GRANULARITY units
*/
uint64_t
value
;
};
/**
* Initialize quota with gived memory limit
*/
static
inline
void
quota_init
(
struct
quota
*
quota
,
size_t
total
)
{
uint64_t
new_total_in_granul
=
(
total
+
(
QUOTA_GRANULARITY
-
1
))
/
QUOTA_GRANULARITY
;
quota
->
value
=
new_total_in_granul
<<
32
;
}
/**
* Provide wrappers around gcc built-ins for now.
* These built-ins work with all numeric types - may not
* be the case when another implementation is used.
* Private use only.
*/
#define atomic_cas(a, b, c) __sync_val_compare_and_swap(a, b, c)
/**
* Get current quota limit
*/
static
inline
size_t
quota_get_total
(
const
struct
quota
*
quota
)
{
return
(
quota
->
value
>>
32
)
*
QUOTA_GRANULARITY
;
}
/**
* Get current quota usage
*/
static
inline
size_t
quota_get_used
(
const
struct
quota
*
quota
)
{
return
(
quota
->
value
&
0xFFFFFFFFu
)
*
QUOTA_GRANULARITY
;
}
static
inline
void
quota_get_total_and_used
(
struct
quota
*
quota
,
size_t
*
total
,
size_t
*
used
)
{
uint64_t
value
=
quota
->
value
;
*
total
=
(
value
>>
32
)
*
QUOTA_GRANULARITY
;
*
used
=
(
value
&
0xFFFFFFFFu
)
*
QUOTA_GRANULARITY
;
}
/**
* Set quota memory limit.
* returns 0 on success
* returns -1 on error - if it's not possible to decrease limit
* due to greater current usage
*/
static
inline
int
quota_set
(
struct
quota
*
quota
,
size_t
new_total
)
{
uint32_t
new_total_in_granul
=
(
new_total
+
(
QUOTA_GRANULARITY
-
1
))
/
QUOTA_GRANULARITY
;
while
(
1
)
{
uint64_t
old_value
=
quota
->
value
;
/* uint32_t cur_total = old_value >> 32; */
uint32_t
cur_used
=
old_value
&
0xFFFFFFFFu
;
if
(
new_total_in_granul
<
cur_used
)
return
-
1
;
uint64_t
new_value
=
(((
uint64_t
)
new_total_in_granul
)
<<
32
)
|
cur_used
;
if
(
atomic_cas
(
&
quota
->
value
,
old_value
,
new_value
)
==
old_value
)
break
;
}
return
0
;
}
/**
* Use up a quota
* returns 0 on success
* returns -1 on error - if quota limit reached
*/
static
inline
int
quota_use
(
struct
quota
*
quota
,
size_t
size
)
{
uint32_t
size_in_granul
=
(
size
+
(
QUOTA_GRANULARITY
-
1
))
/
QUOTA_GRANULARITY
;
assert
(
size_in_granul
);
while
(
1
)
{
uint64_t
old_value
=
quota
->
value
;
uint32_t
cur_total
=
old_value
>>
32
;
uint32_t
old_used
=
old_value
&
0xFFFFFFFFu
;
uint32_t
new_used
=
old_used
+
size_in_granul
;
assert
(
new_used
>
old_used
);
if
(
new_used
>
cur_total
)
return
-
1
;
uint64_t
new_value
=
(((
uint64_t
)
cur_total
)
<<
32
)
|
new_used
;
if
(
atomic_cas
(
&
quota
->
value
,
old_value
,
new_value
)
==
old_value
)
break
;
}
return
0
;
}
/** Release used memory */
static
inline
void
quota_release
(
struct
quota
*
quota
,
size_t
size
)
{
uint32_t
size_in_granul
=
(
size
+
(
QUOTA_GRANULARITY
-
1
))
/
QUOTA_GRANULARITY
;
assert
(
size_in_granul
);
while
(
1
)
{
uint64_t
old_value
=
quota
->
value
;
uint32_t
cur_total
=
old_value
>>
32
;
uint32_t
old_used
=
old_value
&
0xFFFFFFFFu
;
assert
(
size_in_granul
<=
old_used
);
uint32_t
new_used
=
old_used
-
size_in_granul
;
uint64_t
new_value
=
(((
uint64_t
)
cur_total
)
<<
32
)
|
new_used
;
if
(
atomic_cas
(
&
quota
->
value
,
old_value
,
new_value
)
==
old_value
)
break
;
}
}
#undef atomic_cas
#if defined(__cplusplus)
}
/* extern "C" { */
#endif
/* defined(__cplusplus) */
#endif
/* INCLUDES_TARANTOOL_SMALL_QUOTA_H */
This diff is collapsed.
Click to expand it.
test/unit/quota.cc
0 → 100644
+
95
−
0
View file @
e4150145
#include
"small/quota.h"
#include
<pthread.h>
#include
"test.h"
struct
quota
quota
;
const
size_t
THREAD_CNT
=
10
;
const
size_t
RUN_CNT
=
128
*
1024
;
struct
thread_data
{
long
use_change
;
long
last_lim_set
;
long
use_change_success
;
long
lim_change_success
;
};
pthread_t
threads
[
THREAD_CNT
];
thread_data
datum
[
THREAD_CNT
];
void
*
thread_routine
(
void
*
vparam
)
{
struct
thread_data
*
data
=
(
struct
thread_data
*
)
vparam
;
size_t
check_fail_count
=
0
;
bool
allocated
=
false
;
size_t
allocated_size
=
0
;
for
(
size_t
i
=
0
;
i
<
RUN_CNT
;
i
++
)
{
{
size_t
total
,
used
;
quota_get_total_and_used
(
&
quota
,
&
total
,
&
used
);
if
(
used
>
total
)
check_fail_count
++
;
}
long
rnd
=
((
rand
()
&
0xFFFFFFF
)
+
1
)
*
QUOTA_GRANULARITY
;
int
succ
=
quota_set
(
&
quota
,
(
size_t
)
rnd
);
if
(
succ
==
0
)
{
data
->
last_lim_set
=
rnd
;
data
->
lim_change_success
++
;
}
if
(
allocated
)
{
quota_release
(
&
quota
,
allocated_size
);
allocated
=
false
;
data
->
use_change
=
0
;
data
->
use_change_success
++
;
}
else
{
allocated_size
=
(((
long
)
rand
())
&
0xFFFFFFl
)
+
1
;
if
(
quota_use
(
&
quota
,
allocated_size
)
==
0
)
{
allocated
=
true
;
data
->
use_change
=
allocated_size
;
data
->
use_change_success
++
;
}
}
}
return
(
void
*
)
check_fail_count
;
}
int
main
(
int
n
,
char
**
a
)
{
(
void
)
n
;
(
void
)
a
;
quota_init
(
&
quota
,
0
);
plan
(
5
);
for
(
size_t
i
=
0
;
i
<
THREAD_CNT
;
i
++
)
{
pthread_create
(
threads
+
i
,
0
,
thread_routine
,
(
void
*
)(
datum
+
i
));
}
size_t
check_fail_count
=
0
;
for
(
size_t
i
=
0
;
i
<
THREAD_CNT
;
i
++
)
{
void
*
ret
;
check_fail_count
+=
(
size_t
)
pthread_join
(
threads
[
i
],
&
ret
);
}
bool
one_set_successed
=
false
;
size_t
total_alloc
=
0
;
long
set_success_count
=
0
;
long
use_success_count
=
0
;
for
(
size_t
i
=
0
;
i
<
THREAD_CNT
;
i
++
)
{
if
(
datum
[
i
].
last_lim_set
==
quota_get_total
(
&
quota
))
one_set_successed
=
true
;
total_alloc
+=
((
datum
[
i
].
use_change
+
QUOTA_GRANULARITY
-
1
)
/
QUOTA_GRANULARITY
)
*
QUOTA_GRANULARITY
;
use_success_count
+=
datum
[
i
].
use_change_success
;
set_success_count
+=
datum
[
i
].
lim_change_success
;
}
ok
(
check_fail_count
==
0
,
"no fails detected"
);
ok
(
one_set_successed
,
"one of thread limit set is final"
);
ok
(
total_alloc
==
quota_get_used
(
&
quota
),
"total alloc match"
);
ok
(
use_success_count
>
THREAD_CNT
*
RUN_CNT
*
.9
,
"uses are mosly successful"
);
ok
(
set_success_count
>
THREAD_CNT
*
RUN_CNT
*
.9
,
"sets are mosly successful"
);
return
check_plan
();
}
This diff is collapsed.
Click to expand it.
test/unit/quota.result
0 → 100644
+
6
−
0
View file @
e4150145
1..5
ok 1 - no fails detected
ok 2 - one of thread limit set is final
ok 3 - total alloc match
ok 4 - uses are mosly successful
ok 5 - sets are mosly successful
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment