Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • core/picodata
1 result
Show changes
Commits on Source (29)
Showing
with 323 additions and 246 deletions
......@@ -14,6 +14,7 @@ stages:
- test
- pack
- docker
- build-stress-image
- stress-test
- deploy
......@@ -26,6 +27,7 @@ workflow:
when: never
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "schedule"
variables:
REGISTRY: docker-public.binary.picodata.io
......@@ -70,14 +72,14 @@ variables:
#
.rules:
- &if-build-base-changes-on-master-branch
if: $CI_COMMIT_BRANCH == $MAIN_BRANCH
if: ($CI_COMMIT_BRANCH == $MAIN_BRANCH) && ($CI_PIPELINE_SOURCE != "schedule")
changes:
paths: &build-base-changes-paths
- docker-build-base/**
- .gitlab-ci.yml
- &if-build-base-changes-on-dev-branch
if: $CI_COMMIT_BRANCH != $MAIN_BRANCH
if: ($CI_COMMIT_BRANCH != $MAIN_BRANCH) && ($CI_PIPELINE_SOURCE != "schedule")
changes:
paths:
- docker-build-base/**
......@@ -228,7 +230,6 @@ test-linux:
grep_rust_version Cargo.toml;
grep_toolchain Makefile;
grep_toolchain docker-build-base/Dockerfile;
grep_toolchain helm/picodata.Dockerfile;
} \
| tee /dev/fd/3 \
| cut -d: -f2- | sort | uniq | wc -l
......@@ -246,7 +247,7 @@ test-linux:
- make build-$BUILD_PROFILE CARGO_FLAGS_EXTRA="--timings"
- |
make test \
PYTEST_FLAGS="--junitxml=junit_pytest.xml --with-webui" \
PYTEST_FLAGS="--junitxml=junit_pytest.xml --with-webui -n$KUBERNETES_CPU_REQUEST" \
CARGO_FLAGS_EXTRA="--profile=$BUILD_PROFILE"
artifacts:
......@@ -254,6 +255,8 @@ test-linux:
paths:
- junit_pytest.xml
- ./target/cargo-timings/cargo-timing.html
- core*
- target/$TARGET/picodata
reports:
junit: junit_pytest.xml
......@@ -293,31 +296,8 @@ lint:
.test-patch-rules: &test-patch-rules
rules:
- <<: *if-build-base-changes-on-master-branch
variables:
BASE_IMAGE_TAG: ${BASE_IMAGE_TAG}
# build base didnt chage but we still want the job to run
- if: $CI_COMMIT_BRANCH == $MAIN_BRANCH
variables:
BASE_IMAGE_TAG: ${BASE_IMAGE_TAG}
- <<: *if-build-base-changes-on-dev-branch
when: manual
allow_failure: true
variables:
BASE_IMAGE_TAG: ${CI_COMMIT_SHA}
# build base didnt change but we still want the job to run
# in case certification_patches has changed
- if: $CI_COMMIT_BRANCH != $MAIN_BRANCH
changes:
paths:
- certification_patches/**/*
compare_to: *main-branch
allow_failure: true
variables:
BASE_IMAGE_TAG: ${BASE_IMAGE_LATEST}
# manual in other cases
- if: $CI_COMMIT_BRANCH != $MAIN_BRANCH
when: manual
- if: ($CI_COMMIT_BRANCH == $MAIN_BRANCH) && ($CI_PIPELINE_SOURCE == "schedule")
- when: manual
allow_failure: true
variables:
BASE_IMAGE_TAG: ${BASE_IMAGE_LATEST}
......@@ -388,33 +368,38 @@ test-mac-m1:
# - make lint
# - |
.test-helm:
.helm:
interruptible: true
stage: test
needs: []
rules:
- if: $CI_COMMIT_BRANCH != $MAIN_BRANCH
changes:
compare_to: *main-branch
paths:
- helm/picodata.Dockerfile
- helm/picodata.distroless
- helm/picodata-distroless.Dockerfile
- helm/docker-compose.yml
variables:
PUSH_DOCKER: "--no-push"
- if: $CI_COMMIT_BRANCH == $MAIN_BRANCH
- if: ($CI_COMMIT_BRANCH == $MAIN_BRANCH) && ($CI_PIPELINE_SOURCE == "schedule")
when: on_success
variables:
PUSH_DOCKER: ""
- when: manual
allow_failure: true
test-helm-image:
extends: .test-helm
helm-image:
extends: .helm
variables:
KUBERNETES_CPU_REQUEST: 8
KUBERNETES_MEMORY_REQUEST: "8Gi"
MULTIARCH: "true"
parallel:
matrix:
- DOCKERFILE: helm/picodata.Dockerfile
DESTINATION: ${REGISTRY}/picodata:master
- DOCKERFILE: helm/picodata.distroless
- DOCKERFILE: helm/picodata-distroless.Dockerfile
DESTINATION: ${REGISTRY}/picodata:master-distroless
trigger:
project: picodata/devops/picodata-in-docker
......@@ -517,6 +502,7 @@ pack-on-tag:
stage: docker
variables:
PUSH_DOCKER: ""
MULTIARCH: "true"
rules:
- if: $CI_COMMIT_TAG
variables:
......@@ -528,7 +514,7 @@ deploy-docker:
matrix:
- DOCKERFILE: helm/picodata.Dockerfile
DESTINATION: ${REGISTRY}/picodata:${CI_COMMIT_TAG}
- DOCKERFILE: helm/picodata.distroless
- DOCKERFILE: helm/picodata-distroless.Dockerfile
DESTINATION: ${REGISTRY}/picodata:${CI_COMMIT_TAG}-distroless
- DOCKERFILE: docker-build-base/sbroad.Dockerfile
DESTINATION: ${BASE_IMAGE_NAME}:${CI_COMMIT_TAG}
......@@ -540,26 +526,23 @@ deploy-docker:
docker-compose:
stage: docker
needs: [test-helm-image]
needs: ["helm-image: [helm/picodata.Dockerfile, ${REGISTRY}/picodata:master]"]
tags:
- picodata-shell
rules:
- if: $CI_COMMIT_BRANCH != $MAIN_BRANCH
- if: ($CI_COMMIT_BRANCH != $MAIN_BRANCH) && ($CI_PIPELINE_SOURCE == "schedule")
changes:
compare_to: *main-branch
paths:
- helm/docker-compose.yml
- if: $CI_COMMIT_BRANCH == $MAIN_BRANCH
- if: ($CI_COMMIT_BRANCH == $MAIN_BRANCH) && ($CI_PIPELINE_SOURCE == "schedule")
when: on_success
- when: manual
allow_failure: true
script:
- mkdir --mode=777 pico/
- docker-compose -f helm/docker-compose.yml up -d --wait
- echo "ALTER USER \"admin\" WITH PASSWORD 'T0psecret' using md5" > alter_pass.sql
- docker cp alter_pass.sql picodata-1-1:/pico/
- sleep 30 # the cluster does not manage to assemble quickly enough
- docker exec -t picodata-1-1 sh -c "cat /pico/alter_pass.sql |picodata admin /pico/data/picodata-1-1/admin.sock"
- count=$(psql "user=admin host=127.0.0.1 port=55432 password=T0psecret sslmode=disable" -t -A -c "select count(*) from \"_pico_instance\"") && if [[ $count -eq 4 ]] ; then echo "OK"; else echo count=$count; exit 2; fi
after_script:
- docker-compose -f helm/docker-compose.yml rm -fsv
......@@ -663,6 +646,10 @@ publish-picodata-plugin:
name: docker-public.binary.picodata.io/kaniko-project/executor:v1.23.1-debug
entrypoint: ['']
pull_policy: [if-not-present]
rules:
- if: $CI_PIPELINE_SOURCE != "schedule"
- when: manual
allow_failure: true
tags:
- docker-k8s
before_script:
......@@ -670,7 +657,7 @@ publish-picodata-plugin:
- echo "$DOCKER_AUTH_CONFIG" > /kaniko/.docker/config.json
build-stress-image:
stage: build-base-image
stage: build-stress-image
<<: *kaniko_image
needs: []
variables:
......@@ -689,6 +676,8 @@ build-stress-image:
stage: test
tags:
- docker-k8s
rules:
- if: $CI_PIPELINE_SOURCE != "schedule"
image:
name: $BASE_IMAGE_NAME:$BASE_IMAGE_TAG
pull_policy: [always]
......@@ -733,6 +722,8 @@ stress_tests:
- insert
tags:
- docker-k8s
rules:
- if: $CI_PIPELINE_SOURCE != "schedule"
variables:
TNT_HOST: tarantool
STRESS_TEST: insert
......@@ -760,9 +751,9 @@ stress_tests:
store-stress-results-for-main:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH) && ($CI_PIPELINE_SOURCE != "schedule")
stage: stress-test
image: $BASE_IMAGE_NAME:$BASE_IMAGE_TAG
image: $BASE_IMAGE_NAME:$BASE_IMAGE_TAG
script:
- |
tar -czvf sbroad-main-test-results.tgz -C sbroad/sbroad-cartridge/stress-test/ .
......@@ -776,7 +767,10 @@ store-stress-results-for-main:
diff_stress-results:
image: $BASE_IMAGE_NAME:$BASE_IMAGE_TAG
stage: stress-test
when: manual
rules:
- if: $CI_PIPELINE_SOURCE != "schedule"
when: manual
allow_failure: true
variables:
FARCH: "sbroad-main-test-results.tgz"
script:
......
# Current picodata HTTP API version.
apiVersion = "v1"
# Context to be used if flag --context is not provided.
current-context = "dev-admin"
# List of settings passed as arguments to a specific command
[preferences.list]
format = "json"
describe = true
[preferences.describe]
format = "json"
# List of clusters.
[[cluster]]
name = "development"
# Array of addresses (formatted as [host]:[binary_port]).
# Each element is the peer address of the instance in the cluster
peer = [ "192.168.0.2:3301", "192.168.0.2:3302", "192.168.0.3:3302" ]
# HTTP API address of the cluster.
# At this address, we are accessing the cluster.
http_entrypoint = "192.168.0.2:8081"
[[cluster]]
name = "client.company.com"
peer = [ "192.168.5.2:3301", "192.168.5.2:3302", "192.168.5.3:3302", "192.168.5.2:3303" ]
entrypoint = "192.168.5.2:8081"
# The context is a combination of cluster to work with and
# the user on behalf of which operations would be performed.
[[contexts]]
name = "dev-guest"
[contexts.context]
# Cluster name corresponding to one of the clusters in the cluster block.
cluster = "development"
# The username from which the connection is established.
user = "guest"
# In this example, the same cluster has 2 different contexts
# with different users. This context will run on behalf of the
# user dev-admin.
[[contexts]]
name = "dev-admin"
[contexts.context]
cluster = "development"
user = "admin"
[[contexts]]
name = "prod"
[contexts.context]
cluster = "client.company.com"
user = "petr.ivanov@picodata.io"
......@@ -10,6 +10,10 @@ with the `YY.MINOR.MICRO` scheme.
## [24.7.0] - Unreleased
### Configuration
- New alter system parameters - `vdbe_max_steps` and `vtable_max_rows`.
### CLI
- `picodata expel` takes instance uuid instead of instance name.
......@@ -18,6 +22,11 @@ with the `YY.MINOR.MICRO` scheme.
- `picodata --version` now provides verbose output, including the build type (static or dynamic) and the build configuration (release or debug)
### Configuration
- New parameters for Vinyl configuration: `bloom_fpr`, `max_tuple_size`, `page_size`, `range_size`,
`run_count_per_size`, `run_size_ratio`, `read_threads`, `write_threads` and `timeout`.
### Compatibility
- Added unique index on column `uuid` for `_pico_instance` table. IDs
......@@ -154,6 +163,7 @@ to 2 and 3.
committed across all replicasets or only on the current one
- EXPLAIN estimates query buckets
- SQL supports `COALESCE` function
- `CREATE USER` no need to specify `PASSWORD` for LDAP authentification
### Pgproto
- "vdbe_max_steps" and "vtable_max_rows" options are supported in connection
......
......@@ -19,7 +19,7 @@ fn main() {
let build_root = cargo::get_build_root();
let use_static_build = !cargo::get_feature("dynamic_build");
insert_build_metadata(use_static_build);
insert_build_metadata();
// Build and link all the relevant tarantool libraries.
// For more info, read the comments in tarantool-build.
......@@ -36,24 +36,16 @@ fn main() {
}
}
fn insert_build_metadata(use_static_build: bool) {
rustc::env(
"BUILD_TYPE",
if use_static_build {
"static"
} else {
"dynamic"
},
);
fn insert_build_metadata() {
let build_type: &str = if cfg!(feature = "dynamic_build") {
"dynamic"
} else {
"static"
};
rustc::env("BUILD_TYPE", build_type);
rustc::env(
"BUILD_MODE",
if cfg!(debug_assertions) {
"debug"
} else {
"release"
},
);
let build_profile = std::env::var("PROFILE").expect("always set");
rustc::env("BUILD_PROFILE", build_profile);
let os_version = std::process::Command::new("uname")
.args(["-srmo"])
......
......@@ -5,14 +5,14 @@ RUN set -e; \
sh -s -- -y --profile default --default-toolchain 1.76.0
ENV PATH=/root/.cargo/bin:${PATH}
RUN dnf -y install dnf-plugins-core \
RUN dnf -y install dnf-plugins-core epel-release \
&& dnf config-manager --set-enabled powertools \
&& dnf module -y enable nodejs:20 \
&& curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo -o /etc/yum.repos.d/yarn.repo \
&& rpm --import https://dl.yarnpkg.com/rpm/pubkey.gpg \
&& dnf install -y \
openssl-devel libunwind libunwind-devel \
gcc gcc-c++ make cmake git libstdc++-static libtool \
openssl-devel \
nodejs yarn \
&& dnf clean all
......
......@@ -52,6 +52,8 @@ pub fn proc_service_registrar(_attr: TokenStream, input: TokenStream) -> TokenSt
pub extern "C" fn #ident(registry: &mut picodata_plugin::plugin::interface::ServiceRegistry) {
#[inline(always)]
fn #inner_fn_name (#inputs) {
picodata_plugin::internal::set_panic_hook();
#block
}
......
......@@ -42,6 +42,31 @@ pub fn raft_info() -> types::RaftInfo {
unsafe { pico_ffi_raft_info() }
}
#[inline]
pub fn set_panic_hook() {
// NOTE: this function is called ASAP when starting up the process.
// Even if `say` isn't properly initialized yet, we
// still should be able to print a simplified line to stderr.
std::panic::set_hook(Box::new(|info| {
// Capture a backtrace regardless of RUST_BACKTRACE and such.
let backtrace = std::backtrace::Backtrace::force_capture();
let message = format!("{info}\n\nbacktrace:\n{backtrace}\naborting due to panic");
tarantool::say_crit!("\n\n{message}");
// Dump the backtrace to file for easier debugging experience.
// In particular this is used in the integration tests.
let pid = std::process::id();
let backtrace_filename = format!("picodata-{pid}.backtrace");
_ = std::fs::write(&backtrace_filename, message);
if let Ok(mut dir) = std::env::current_dir() {
dir.push(backtrace_filename);
tarantool::say_info!("dumped panic backtrace to `{}`", dir.display());
}
std::process::abort();
}));
}
#[derive(thiserror::Error, Debug)]
pub enum InternalError {
#[error("timeout")]
......
......@@ -38,7 +38,7 @@ use crate::ir::node::relational::Relational;
use crate::ir::node::{Motion, NodeId};
use crate::ir::transformation::redistribution::MotionPolicy;
use crate::ir::value::Value;
use crate::ir::{Plan, Slices};
use crate::ir::{Options, Plan, Slices};
use crate::utils::MutexLike;
use smol_str::SmolStr;
......@@ -110,7 +110,12 @@ where
/// - Failed to build AST.
/// - Failed to build IR plan.
/// - Failed to apply optimizing transformations to IR plan.
pub fn new(coordinator: &'a C, sql: &str, params: Vec<Value>) -> Result<Self, SbroadError>
pub fn with_options(
coordinator: &'a C,
sql: &str,
params: Vec<Value>,
options: Option<Options>,
) -> Result<Self, SbroadError>
where
C::Cache: Cache<SmolStr, Plan>,
C::ParseTree: Ast,
......@@ -147,6 +152,11 @@ where
cache.put(key, plan.clone())?;
}
}
if let Some(options) = options {
plan.options = options;
}
if plan.is_block()? {
plan.bind_params(params)?;
} else if !plan.is_ddl()? && !plan.is_acl()? && !plan.is_plugin()? {
......@@ -163,6 +173,21 @@ where
Ok(query)
}
/// Create a new query.
///
/// # Errors
/// - Failed to parse SQL.
/// - Failed to build AST.
/// - Failed to build IR plan.
/// - Failed to apply optimizing transformations to IR plan.
pub fn new(coordinator: &'a C, sql: &str, params: Vec<Value>) -> Result<Self, SbroadError>
where
C::Cache: Cache<SmolStr, Plan>,
C::ParseTree: Ast,
{
Self::with_options(coordinator, sql, params, None)
}
fn empty(coordinator: &'a C) -> Self {
Self {
is_explain: false,
......
......@@ -4492,7 +4492,7 @@ impl AbstractSyntaxTree {
}
let name = name.expect("username expected as a child");
let password = password.expect("password expected as a child");
let password = password.unwrap_or_default();
let create_user = CreateUser {
name,
password,
......
......@@ -33,8 +33,8 @@ Plugin = _{ CreatePlugin | DropPlugin | AlterPlugin }
ACL = _{ DropRole | DropUser | CreateRole | CreateUser | AlterUser | GrantPrivilege | RevokePrivilege }
CreateUser = ${
^"create" ~ W ~ ^"user" ~ W ~ (IfNotExists ~ W)? ~ Identifier ~ W ~ (^"with" ~ W)? ~ ^"password" ~ W
~ SingleQuotedString ~ (W ~ AuthMethod)? ~ (W ~ TimeoutOption)?
^"create" ~ W ~ ^"user" ~ W ~ (IfNotExists ~ W)? ~ Identifier ~ (W ~ (^"with" ~ W)? ~ ^"password" ~ W
~ SingleQuotedString)? ~ (W ~ AuthMethod)? ~ (W ~ TimeoutOption)?
}
AlterUser = ${
^"alter" ~ W ~ ^"user" ~ W ~ Identifier ~ W ~ (^"with" ~ W)? ~ AlterOption ~ (W ~ TimeoutOption)?
......
......@@ -12,7 +12,7 @@ use rustyline_derive::{Completer, Helper, Highlighter, Hinter, Validator};
use super::args;
use super::connect::ResultSet;
use super::console::{Command, Console, ReplError, SpecialCommand};
use super::console::{Command, Console, ConsoleLanguage, ReplError, SpecialCommand};
pub struct LuaCompleter {
client: Rc<RefCell<UnixClient>>,
......@@ -53,12 +53,6 @@ pub struct LuaHelper {
completer: LuaCompleter,
}
#[derive(PartialEq)]
enum ConsoleLanguage {
Lua,
Sql,
}
/// Wrapper around unix socket with console-like interface
/// for communicating with tarantool console.
pub struct UnixClient {
......@@ -272,18 +266,11 @@ fn admin_repl(args: args::Admin) -> Result<(), ReplError> {
let mut temp_client = client.borrow_mut();
match command {
Command::Control(command) => match command {
SpecialCommand::SwitchLanguageToLua => {
temp_client.write("\\set language lua")?;
temp_client.read()?;
temp_client.current_language = ConsoleLanguage::Lua;
console.write("Language switched to Lua");
}
SpecialCommand::SwitchLanguageToSql => {
temp_client.write("\\set language sql")?;
SpecialCommand::SwitchLanguage(language) => {
temp_client.write(&format!("\\set language {language}"))?;
temp_client.read()?;
temp_client.current_language = ConsoleLanguage::Sql;
console.write("Language switched to SQL");
temp_client.current_language = language;
console.write(&format!("Language switched to {language}"));
}
SpecialCommand::PrintHelp => {
......
use crate::address::{HttpAddress, IprotoAddress};
use crate::config::{ByteSize, DEFAULT_USERNAME};
use crate::info::FULL_PICODATA_VERSION;
use crate::info::version_for_help;
use crate::util::Uppercase;
use clap::Parser;
use std::borrow::Cow;
......@@ -11,7 +11,7 @@ use tarantool::log::SayLevel;
use tarantool::tlua;
#[derive(Debug, Parser)]
#[clap(name = "picodata", version = FULL_PICODATA_VERSION)]
#[clap(name = "picodata", version = version_for_help())]
pub enum Picodata {
Run(Box<Run>),
#[clap(hide = true)]
......
......@@ -253,7 +253,7 @@ fn sql_repl(args: args::Connect) -> Result<(), ReplError> {
Command::Control(command) => {
match command {
SpecialCommand::PrintHelp => console.write(HELP_MESSAGE),
SpecialCommand::SwitchLanguageToLua | SpecialCommand::SwitchLanguageToSql => {
SpecialCommand::SwitchLanguage(_) => {
// picodata connect doesn't know about language switching
console.write("Unknown special sequence")
}
......
......@@ -37,9 +37,23 @@ pub enum ReplError {
pub type Result<T> = std::result::Result<T, ReplError>;
const DELIMITER: &str = ";";
#[derive(Clone, Copy, PartialEq)]
pub enum ConsoleLanguage {
Lua,
Sql,
}
impl std::fmt::Display for ConsoleLanguage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConsoleLanguage::Lua => write!(f, "lua"),
ConsoleLanguage::Sql => write!(f, "sql"),
}
}
}
pub enum SpecialCommand {
SwitchLanguageToLua,
SwitchLanguageToSql,
SwitchLanguage(ConsoleLanguage),
PrintHelp,
}
......@@ -50,11 +64,6 @@ pub enum Command {
Expression(String),
}
enum ConsoleLanguage {
Lua,
Sql,
}
enum ConsoleCommand {
SetLanguage(ConsoleLanguage),
// None represent default delimiter (pressing enter in console and eof in case of pipe)
......@@ -62,11 +71,19 @@ enum ConsoleCommand {
Invalid,
}
#[derive(PartialEq)]
pub enum Mode {
Admin,
Connection,
}
/// Input/output handler
pub struct Console<H: Helper> {
editor: Editor<H, FileHistory>,
history_file_path: PathBuf,
delimiter: Option<String>,
current_language: ConsoleLanguage,
pub mode: Mode,
// Queue of separated by delimiter statements
separated_statements: VecDeque<String>,
uncompleted_statement: String,
......@@ -75,23 +92,49 @@ pub struct Console<H: Helper> {
impl<T: Helper> Console<T> {
const HISTORY_FILE_NAME: &'static str = ".picodata_history";
const PROMPT: &'static str = "picodata> ";
const INNER_PROMPT: &'static str = " > ";
const INNER_PROMPT_FOR_CONNECT: &'static str = " > ";
const INNER_PROMPT_FOR_ADMIN: &'static str = " > ";
const SPECIAL_COMMAND_PREFIX: &'static str = "\\";
const LUA_PROMPT: &'static str = "lua> ";
const SQL_PROMPT: &'static str = "sql> ";
const ADMIN_MODE: &'static str = "(admin) ";
fn handle_special_command(&mut self, command: &str) -> Result<ControlFlow<Command>> {
match command {
"\\e" | "\\e;" => self.open_external_editor(),
"\\help" | "\\h" | "\\help;" | "\\h;" => Ok(ControlFlow::Break(Command::Control(
SpecialCommand::PrintHelp,
))),
"\\lua" | "\\lua;" => Ok(ControlFlow::Break(Command::Control(
SpecialCommand::SwitchLanguageToLua,
))),
"\\sql" | "\\sql;" => Ok(ControlFlow::Break(Command::Control(
SpecialCommand::SwitchLanguageToSql,
))),
_ => self.handle_parsed_command(command),
use ConsoleLanguage::*;
use SpecialCommand::*;
let parsed_command = match command {
"\\lua" | "\\lua;" => Some(SwitchLanguage(Lua)),
"\\sql" | "\\sql;" => Some(SwitchLanguage(Sql)),
"\\help" | "\\h" | "\\help;" | "\\h;" => Some(PrintHelp),
"\\e" | "\\e;" => return self.open_external_editor(),
_ => match self.parse_special_command(command) {
ConsoleCommand::SetLanguage(language) => Some(SwitchLanguage(language)),
ConsoleCommand::SetDelimiter(delimiter) => {
self.update_delimiter(delimiter);
None
}
ConsoleCommand::Invalid => {
self.write("Unknown special sequence");
None
}
},
};
match parsed_command {
Some(command) => match command {
SwitchLanguage(console_language) => {
if self.mode != Mode::Admin {
self.write("Language cannot be changed in this console");
Ok(ControlFlow::Continue(()))
} else {
self.current_language = console_language;
Ok(ControlFlow::Break(Command::Control(command)))
}
}
PrintHelp => Ok(ControlFlow::Break(Command::Control(command))),
},
None => Ok(ControlFlow::Continue(())),
}
}
......@@ -119,25 +162,6 @@ impl<T: Helper> Console<T> {
Ok(ControlFlow::Break(Command::Expression(line)))
}
fn handle_parsed_command(&mut self, command: &str) -> Result<ControlFlow<Command>> {
match self.parse_special_command(command) {
ConsoleCommand::SetLanguage(ConsoleLanguage::Lua) => Ok(ControlFlow::Break(
Command::Control(SpecialCommand::SwitchLanguageToLua),
)),
ConsoleCommand::SetLanguage(ConsoleLanguage::Sql) => Ok(ControlFlow::Break(
Command::Control(SpecialCommand::SwitchLanguageToSql),
)),
ConsoleCommand::SetDelimiter(delimiter) => {
self.update_delimiter(delimiter);
Ok(ControlFlow::Continue(()))
}
ConsoleCommand::Invalid => {
self.write("Unknown special sequence");
Ok(ControlFlow::Continue(()))
}
}
}
fn update_delimiter(&mut self, delimiter: Option<String>) {
match delimiter {
Some(custom) => {
......@@ -174,7 +198,7 @@ impl<T: Helper> Console<T> {
}
}
fn update_history(&mut self, command: Command) -> Result<Option<Command>> {
fn update_history(&mut self, command: Command) -> Command {
// do not save special commands
if let Command::Expression(expression) = &command {
if let Err(e) = self
......@@ -188,7 +212,7 @@ impl<T: Helper> Console<T> {
}
}
Ok(Some(command))
command
}
fn process_command(&mut self) {
......@@ -226,17 +250,30 @@ impl<T: Helper> Console<T> {
match processed {
ControlFlow::Continue(_) => continue,
ControlFlow::Break(command) => return self.update_history(command),
ControlFlow::Break(command) => return Ok(Some(self.update_history(command))),
}
}
let prompt = if self.uncompleted_statement.is_empty() {
Self::PROMPT
} else {
let prompt = if !self.uncompleted_statement.is_empty() {
self.uncompleted_statement.push(' ');
Self::INNER_PROMPT
match self.mode {
Mode::Admin => Self::INNER_PROMPT_FOR_ADMIN,
Mode::Connection => Self::INNER_PROMPT_FOR_CONNECT,
}
.to_string()
} else {
let admin = match self.mode {
Mode::Admin => Self::ADMIN_MODE,
Mode::Connection => "",
};
let language = match self.current_language {
ConsoleLanguage::Lua => Self::LUA_PROMPT,
ConsoleLanguage::Sql => Self::SQL_PROMPT,
};
format!("{admin}{language}")
};
let readline = self.editor.readline(prompt);
let readline = self.editor.readline(&prompt);
match readline {
Ok(line) => {
......@@ -246,7 +283,9 @@ impl<T: Helper> Console<T> {
match processed {
ControlFlow::Continue(_) => continue,
ControlFlow::Break(command) => return self.update_history(command),
ControlFlow::Break(command) => {
return Ok(Some(self.update_history(command)))
}
}
} else {
self.uncompleted_statement += &line;
......@@ -323,6 +362,8 @@ impl Console<LuaHelper> {
separated_statements: VecDeque::new(),
uncompleted_statement: String::new(),
eof_received: false,
current_language: ConsoleLanguage::Sql,
mode: Mode::Admin,
})
}
}
......@@ -338,6 +379,8 @@ impl Console<()> {
separated_statements: VecDeque::new(),
uncompleted_statement: String::new(),
eof_received: false,
current_language: ConsoleLanguage::Sql,
mode: Mode::Connection,
})
}
}
......@@ -1132,33 +1132,6 @@ impl InstanceConfig {
self.shredding
.expect("is set in PicodataConfig::set_defaults_explicitly")
}
#[inline]
pub fn memtx_memory(&self) -> u64 {
self.memtx
.memory
.as_ref()
.expect("is set in PicodataConfig::set_defaults_explicitly")
.into()
}
#[inline]
pub fn vinyl_memory(&self) -> u64 {
self.vinyl
.memory
.as_ref()
.expect("is set in PicodataConfig::set_defaults_explicitly")
.into()
}
#[inline]
pub fn vinyl_cache(&self) -> u64 {
self.vinyl
.cache
.as_ref()
.expect("is set in PicodataConfig::set_defaults_explicitly")
.into()
}
}
////////////////////////////////////////////////////////////////////////////////
......@@ -1324,6 +1297,60 @@ pub struct VinylSection {
/// Corresponds to `box.cfg.vinyl_cache`
#[introspection(config_default = "128M")]
pub cache: Option<ByteSize>,
/// Bloom filter false positive rate.
///
/// Corresponds to `box.cfg.vinyl_bloom_fpr`
#[introspection(config_default = 0.05)]
pub bloom_fpr: Option<f32>,
/// Size of the largest allocation unit.
///
/// Corresponds to `box.cfg.vinyl_max_tuple_size`
#[introspection(config_default = "1M")]
pub max_tuple_size: Option<ByteSize>,
/// Read and write unit size for disk operations.
///
/// Corresponds to `box.cfg.vinyl_page_size`
#[introspection(config_default = "8K")]
pub page_size: Option<ByteSize>,
/// The default maximum range size for an index.
///
/// Corresponds to `box.cfg.vinyl_range_size`
#[introspection(config_default = "1G")]
pub range_size: Option<ByteSize>,
/// The maximal number of runs per level in LSM tree.
///
/// Corresponds to `box.cfg.vinyl_run_count_per_level`
#[introspection(config_default = 2)]
pub run_count_per_level: Option<i32>,
/// Ratio between the sizes of different levels in the LSM tree.
///
/// Corresponds to `box.cfg.vinyl_run_size_ratio`
#[introspection(config_default = 3.5)]
pub run_size_ratio: Option<f32>,
/// The maximum number of read threads can be used for concurrent operations.
///
/// Corresponds to `box.cfg.vinyl_read_threads`
#[introspection(config_default = 1)]
pub read_threads: Option<i32>,
/// The maximum number of write threads can be used for concurrent operations.
///
/// Corresponds to `box.cfg.vinyl_write_threads`
#[introspection(config_default = 4)]
pub write_threads: Option<i32>,
/// Timeout for queries in the compression scheduler when available memory is low.
///
/// Corresponds to `box.cfg.vinyl_timeout`
#[introspection(config_default = 60.)]
pub timeout: Option<f32>,
}
////////////////////////////////////////////////////////////////////////////////
......@@ -1534,6 +1561,14 @@ pub struct AlterSystemParameters {
#[introspection(sbroad_type = SbroadType::Double)]
#[introspection(config_default = 10.0)]
pub governor_plugin_rpc_timeout: f64,
#[introspection(sbroad_type = SbroadType::Unsigned)]
#[introspection(config_default = 45000)]
pub vdbe_max_steps: u64,
#[introspection(sbroad_type = SbroadType::Unsigned)]
#[introspection(config_default = 5000)]
pub vtable_max_rows: u64,
}
/// A special macro helper for referring to alter system parameters thoroughout
......
......@@ -13,19 +13,33 @@ use std::borrow::Cow;
use tarantool::proc;
use tarantool::tuple::RawByteBuf;
pub const FULL_PICODATA_VERSION: &'static str = concat!(
env!("GIT_DESCRIBE"),
", ",
env!("BUILD_TYPE"),
", ",
env!("BUILD_MODE"),
"\n",
env!("OS_VERSION")
);
pub const PICODATA_VERSION: &'static str = std::env!("GIT_DESCRIBE");
pub const RPC_API_VERSION: &'static str = "1.0.0";
/// Note: this returns a `&'static str` because of clap's requirements.
pub fn version_for_help() -> &'static str {
static VERSION_OUTPUT: std::sync::OnceLock<String> = std::sync::OnceLock::new();
VERSION_OUTPUT.get_or_init(|| {
let mut result = PICODATA_VERSION.to_string();
result.push_str(", ");
result.push_str(env!("BUILD_TYPE"));
result.push_str(", ");
result.push_str(env!("BUILD_PROFILE"));
result.push('\n');
result.push_str("tarantool (fork) version: ");
result.push_str(crate::tarantool::version());
result.push('\n');
result.push_str("target: ");
result.push_str(env!("OS_VERSION"));
result
})
}
////////////////////////////////////////////////////////////////////////////////
// VersionInfo
////////////////////////////////////////////////////////////////////////////////
......@@ -34,6 +48,9 @@ pub const RPC_API_VERSION: &'static str = "1.0.0";
pub struct VersionInfo<'a> {
pub picodata_version: Cow<'a, str>,
pub rpc_api_version: Cow<'a, str>,
pub build_type: Cow<'a, str>,
pub build_profile: Cow<'a, str>,
pub tarantool_version: Cow<'a, str>,
}
impl tarantool::tuple::Encode for VersionInfo<'_> {}
......@@ -51,6 +68,9 @@ impl VersionInfo<'static> {
Self {
picodata_version: PICODATA_VERSION.into(),
rpc_api_version: RPC_API_VERSION.into(),
build_type: env!("BUILD_TYPE").into(),
build_profile: env!("BUILD_PROFILE").into(),
tarantool_version: crate::tarantool::version().into(),
}
}
}
......
......@@ -447,6 +447,12 @@ mod test {
empty: Empty,
}
#[derive(Default, Debug, Introspection, PartialEq)]
struct OptionalS {
#[introspection(config_default = "42.0")]
c: Option<f32>,
}
#[derive(Default, Debug, Introspection, PartialEq)]
struct Empty {}
......@@ -628,10 +634,14 @@ mod test {
},
ignored: serde_yaml::Value::default(),
};
let optional_s = OptionalS { c: None };
//
// Check `get_field_as_rmpv` error cases
//
let e = optional_s.get_field_as_rmpv("c").unwrap();
assert_eq!(e, rmpv::Value::Nil);
let e = s.get_field_as_rmpv("a").unwrap_err();
assert_eq!(
e.to_string(),
......
......@@ -3,17 +3,7 @@ use picodata::cli::{self, args::Picodata};
fn main() -> ! {
// Initialize the panic hook asap.
// Even if `say` isn't properly initialized yet, we
// still should be able to print a simplified line to stderr.
std::panic::set_hook(Box::new(|info| {
// Capture a backtrace regardless of RUST_BACKTRACE and such.
let backtrace = std::backtrace::Backtrace::force_capture();
picodata::tlog!(
Critical,
"\n\n{info}\n\nbacktrace:\n{backtrace}\naborting due to panic"
);
std::process::abort();
}));
picodata_plugin::internal::set_panic_hook();
match Picodata::parse() {
Picodata::Run(args) => cli::run::main(*args),
......
......@@ -532,7 +532,7 @@ fn up_single_file(
tlog!(Debug, "applying `UP` migration query {filename} #{i}/{} `{}`", queries.up.len(), DisplayTruncated(sql));
if let Err(e) = applier.apply(sql, Some(deadline)) {
#[rustfmt::skip]
tlog!(Error, "failed applying `UP` migration query (file: {filename}) `{}`", DisplayTruncated(sql));
tlog!(Error, "failed applying `UP` migration query (file: {filename}) `{}`: {e}", DisplayTruncated(sql));
return Err(Error::Up {
filename: filename.into(),
command: sql.clone(),
......