Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
picodata
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Container Registry
Model registry
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
picodata
Commits
0a132cbc
Unverified
Commit
0a132cbc
authored
3 years ago
by
Sergey V
Browse files
Options
Downloads
Patches
Plain Diff
refactor: rm Stash
parent
51e20a36
No related branches found
Branches containing commit
No related tags found
Tags containing commit
1 merge request
!64
refactor: rm Stash
Pipeline
#3664
passed
3 years ago
Stage: build
Changes
2
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/main.rs
+20
-61
20 additions, 61 deletions
src/main.rs
src/stash.rs
+0
-114
0 additions, 114 deletions
src/stash.rs
with
20 additions
and
175 deletions
src/main.rs
+
20
−
61
View file @
0a132cbc
...
...
@@ -10,45 +10,29 @@ use ::tarantool::set_error;
use
::
tarantool
::
tlua
;
use
::
tarantool
::
tuple
::{
FunctionArgs
,
FunctionCtx
,
Tuple
};
use
indoc
::
indoc
;
use
message
::
Message
;
use
std
::
convert
::
TryFrom
;
use
std
::
time
::
Duration
;
mod
app
;
mod
args
;
mod
error
;
mod
message
;
pub
mod
stash
;
mod
tarantool
;
mod
tlog
;
mod
traft
;
inventory
::
collect!
(
InnerTest
);
pub
struct
InnerTest
{
pub
name
:
&
'static
str
,
pub
body
:
fn
(),
}
inventory
::
collect!
(
InnerTest
);
use
message
::
Message
;
use
std
::
cell
::
Ref
;
use
std
::
cell
::
RefCell
;
use
std
::
convert
::
TryFrom
;
use
std
::
time
::
Duration
;
static
mut
NODE
:
Option
<&
'static
traft
::
Node
>
=
None
;
#[derive(Default)]
pub
struct
Stash
{
raft_node
:
RefCell
<
Option
<
traft
::
Node
>>
,
}
impl
Stash
{
pub
fn
access
()
->
&
'static
Self
{
stash
::
access
(
"_picolib_stash"
)
}
pub
fn
set_raft_node
(
&
self
,
raft_node
:
traft
::
Node
)
{
*
self
.raft_node
.borrow_mut
()
=
Some
(
raft_node
);
}
pub
fn
raft_node
(
&
self
)
->
Ref
<
Option
<
traft
::
Node
>>
{
self
.raft_node
.borrow
()
}
fn
node
()
->
&
'static
traft
::
Node
{
unsafe
{
NODE
.expect
(
"Picodata not running yet"
)
}
}
fn
picolib_setup
(
args
:
args
::
Run
)
{
...
...
@@ -79,17 +63,17 @@ fn picolib_setup(args: args::Run) {
//
// Export public API
luamod
.set
(
"run"
,
tlua
::
function0
(
move
||
start
(
&
args
)));
luamod
.set
(
"raft_status"
,
tlua
::
function0
(
raft_
status
));
luamod
.set
(
"raft_status"
,
tlua
::
function0
(
||
node
()
.
status
()
));
luamod
.set
(
"raft_tick"
,
tlua
::
function1
(
raft_tick
));
luamod
.set
(
"raft_propose_info"
,
tlua
::
function1
(|
x
:
String
|
raft_
propose
(
Message
::
Info
{
msg
:
x
})),
tlua
::
function1
(|
x
:
String
|
node
()
.
propose
(
&
Message
::
Info
{
msg
:
x
})),
);
luamod
.set
(
"raft_propose_eval"
,
tlua
::
function2
(|
timeout
:
f64
,
x
:
String
|
{
raft_
propose_wait_applied
(
Message
::
EvalLua
{
code
:
x
},
node
()
.
propose_wait_applied
(
&
Message
::
EvalLua
{
code
:
x
},
Duration
::
from_secs_f64
(
timeout
),
)
}),
...
...
@@ -110,8 +94,6 @@ fn picolib_setup(args: args::Run) {
}
fn
start
(
args
:
&
args
::
Run
)
{
let
stash
=
Stash
::
access
();
if
tarantool
::
cfg
()
.is_some
()
{
// Already initialized
return
;
...
...
@@ -175,8 +157,12 @@ fn start(args: &args::Run) {
applied
:
traft
::
Storage
::
applied
()
.unwrap
()
.unwrap_or_default
(),
..
Default
::
default
()
};
let
node
=
traft
::
Node
::
new
(
&
raft_cfg
,
handle_committed_data
)
.unwrap
();
stash
.set_raft_node
(
node
);
unsafe
{
NODE
=
Some
(
Box
::
leak
(
Box
::
new
(
traft
::
Node
::
new
(
&
raft_cfg
,
handle_committed_data
)
.unwrap
(),
)));
};
cfg
.listen
=
Some
(
args
.listen
.clone
());
tarantool
::
set_cfg
(
&
cfg
);
...
...
@@ -191,35 +177,12 @@ fn start(args: &args::Run) {
}
fn
raft_tick
(
n_times
:
u32
)
{
let
stash
=
Stash
::
access
();
let
raft_ref
=
stash
.raft_node
();
let
raft_node
=
raft_ref
.as_ref
()
.expect
(
"Picodata not running yet"
);
let
raft_node
=
node
();
for
_
in
0
..
n_times
{
raft_node
.tick
();
}
}
fn
raft_status
()
->
traft
::
Status
{
let
stash
=
Stash
::
access
();
let
raft_ref
=
stash
.raft_node
();
let
raft_node
=
raft_ref
.as_ref
()
.expect
(
"Picodata not running yet"
);
raft_node
.status
()
}
fn
raft_propose
(
msg
:
Message
)
{
let
stash
=
Stash
::
access
();
let
raft_ref
=
stash
.raft_node
();
let
raft_node
=
raft_ref
.as_ref
()
.expect
(
"Picodata not running yet"
);
raft_node
.propose
(
&
msg
)
}
fn
raft_propose_wait_applied
(
msg
:
Message
,
timeout
:
Duration
)
->
bool
{
let
stash
=
Stash
::
access
();
let
raft_ref
=
stash
.raft_node
();
let
raft_node
=
raft_ref
.as_ref
()
.expect
(
"Picodata not running yet"
);
raft_node
.propose_wait_applied
(
&
msg
,
timeout
)
}
fn
handle_committed_data
(
data
:
&
[
u8
])
{
use
Message
::
*
;
...
...
@@ -246,11 +209,7 @@ fn init_handlers() {
#[no_mangle]
pub
extern
"C"
fn
raft_interact
(
_
:
FunctionCtx
,
args
:
FunctionArgs
)
->
c_int
{
let
stash
=
Stash
::
access
();
let
raft_ref
=
stash
.raft_node
();
let
raft_node
=
raft_ref
.as_ref
()
.expect
(
"picodata should already be running"
);
let
raft_node
=
node
();
// Conversion pipeline:
// FunctionArgs -> Tuple -?-> traft::row::Message -?-> raft::Message;
...
...
This diff is collapsed.
Click to expand it.
src/stash.rs
deleted
100644 → 0
+
0
−
114
View file @
51e20a36
//! Tarantool-flavored singleton pattern implementation.
//!
//! Tarantool has a peculiarity - when calling stored procedures with `{language = "C"}` option, it
//! disregards the shared object (`.so` / `.dylib`) already loaded by Lua and makes the second
//! independent `dlopen`. As a result, Lua and C stored procedures can't share state, because even
//! static variables point to different memory locations.
//!
//! As a workaround, this module provides the API for hiding the state inside `lua_State`. Under the
//! hood, the stash consumes a custom struct and leaks the wrapping box. Inside Lua, it's
//! represented by a userdata, which the `access()` function provides access to.
//!
//! Example:
//!
//! ```
//! use std::cell::Ref;
//! use std::cell::RefCell;
//!
//! /// The particular singleton structure
//! #[derive(Default)]
//! struct Stash {
//! x: RefCell<u32>,
//! }
//!
//! unsafe impl Send for Stash {}
//! unsafe impl Sync for Stash {}
//! impl Stash {
//! pub fn access() -> &'static Self {
//! stash::access("my_stash")
//! }
//! pub fn set_x(&self, x: u32) {
//! *self.x.borrow_mut() = x;
//! }
//! pub fn x(&self) -> Ref<u32> {
//! self.x.borrow()
//! }
//! }
//!
//! #[no_mangle]
//! pub extern "C" fn luaopen_easy(_l: std::ffi::c_void) -> std::os::raw::c_int {
//! // Tarantool calls this function upon require("easy")
//! let stash = Stash::access();
//! stash.set_x(100);
//! assert_eq!(*stash.x(), 100);
//! 0
//! }
//! ```
//!
use
::
tarantool
::
tlua
;
use
std
::
ops
::
Deref
;
#[derive(Default)]
struct
Inner
<
S
>
(
S
);
impl
<
S
>
std
::
ops
::
Deref
for
Inner
<
S
>
{
type
Target
=
S
;
#[inline]
fn
deref
(
&
self
)
->
&
S
{
&
self
.0
}
}
impl
<
L
,
S
>
tlua
::
PushInto
<
L
>
for
Inner
<
S
>
where
L
:
tlua
::
AsLua
,
S
:
'static
,
{
type
Err
=
tlua
::
Void
;
fn
push_into_lua
(
self
,
lua
:
L
)
->
Result
<
tlua
::
PushGuard
<
L
>
,
(
tlua
::
Void
,
L
)
>
{
let
boxed
=
Box
::
new
(
self
);
let
ptr
:
&
'static
Inner
<
S
>
=
Box
::
leak
(
boxed
);
Ok
(
tlua
::
push_userdata
(
ptr
,
lua
,
|
_
|
{}))
}
}
impl
<
L
,
S
>
tlua
::
PushOneInto
<
L
>
for
Inner
<
S
>
where
L
:
tlua
::
AsLua
,
S
:
'static
,
{
}
impl
<
L
,
S
>
tlua
::
LuaRead
<
L
>
for
&
Inner
<
S
>
where
L
:
tlua
::
AsLua
,
{
fn
lua_read_at_position
(
lua
:
L
,
index
:
std
::
num
::
NonZeroI32
)
->
Result
<&
'static
Inner
<
S
>
,
L
>
{
let
val
:
tlua
::
UserdataOnStack
<&
Inner
<
S
>
,
_
>
=
tlua
::
LuaRead
::
lua_read_at_position
(
lua
,
index
)
?
;
Ok
(
val
.deref
())
}
}
/// Returns reference to the particular singleton structure.
///
/// When called for the first time, initializes it with the default values.
pub
fn
access
<
S
>
(
name
:
&
str
)
->
&
'static
S
where
S
:
Default
,
{
// TODO: this place is a potential performance bottleneck.
// Every access to the stash implies a call to `lua_newthread()`
// and further garbage collection.
let
l
=
tarantool
::
lua_state
();
let
get
=
||
l
.get
::
<&
Inner
<
S
>
,
_
>
(
name
);
match
get
()
{
Some
(
Inner
(
v
))
=>
v
,
None
=>
{
l
.set
(
name
,
Inner
::
<
S
>
::
default
());
get
()
.expect
(
"impossible"
)
}
}
}
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