Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lab3 #1

Merged
merged 7 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ CMakeFiles
build
examples/tmp
_deps
*svg.bkp
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ https://github.com/deevroman/low-level-programming-labs/blob/master/.github/work

- [Первая лабораторная](reports/lab1.pdf)
- [Вторая лабораторная](reports/lab2.pdf)
- [Третья лабораторная](reports/lab3.pdf)

---

<img src="img/mudroe-tainstvennoe-derevo-mem.jpg" width="50">

Вариант 1. Форма данных: документное дерево
Вариант 7. Язык запросов: MongoShell
Вариант 3. Формат транспортного протокола: Protocol Buffers


<table>
Expand Down
1 change: 1 addition & 0 deletions client/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ColumnLimit: 120
26 changes: 26 additions & 0 deletions client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.21)

project(Client LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)

find_package(Threads)

set(SOURCES
src/main.cpp
)

source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})

add_subdirectory("../proto" "./proto")
add_subdirectory("../parser" "./parser")

add_executable(client ${SOURCES})
target_link_libraries(client
PRIVATE
proto
flex_bison
)

target_include_directories(client PRIVATE "${PARSER_DIR}" "${PARSER_SRC_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/parser/parser" "${PROTOBUF_INCLUDE_DIRS}")

set(EXECUTABLE_OUTPUT_PATH "./bin/${CMAKE_SYSTEM}")
164 changes: 164 additions & 0 deletions client/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
extern "C" {
#include "parser.h"
}

#include <query.grpc.pb.h>
#include <query.pb.h>

#include <grpc/grpc.h>
#include <grpcpp/create_channel.h>

#include "types.h"
#include <iostream>

void set_key_value(proto_query::field_key_value *field, field_key_value cur) {
field->set_key(cur.key);
switch (cur.value.value_type) {
case DB_INT32: {
field->mutable_value()->set_value_type(proto_query::DB_INT32);
field->mutable_value()->set_int_value(cur.value.data.int_value);
break;
}
case DB_DOUBLE: {
field->mutable_value()->set_value_type(proto_query::DB_DOUBLE);
field->mutable_value()->set_double_value(cur.value.data.double_value);
break;
}
case DB_STRING: {
field->mutable_value()->set_value_type(proto_query::DB_STRING);
field->mutable_value()->set_str_value(cur.value.data.str_value);
break;
}
case DB_BOOL: {
field->mutable_value()->set_value_type(proto_query::DB_BOOL);
field->mutable_value()->set_bool_value(cur.value.data.bool_value);
break;
}
}
}

void node_to_proto_filter(filter *cur_node, proto_query::filter *f, proto_query::Query &q) {
if (cur_node->left) {
f->set_left_node(q.cond_size());
auto cond = q.add_cond();
node_to_proto_filter(cur_node->left, cond, q);
}
if (cur_node->right) {
f->set_right_node(q.cond_size());
auto cond = q.add_cond();
node_to_proto_filter(cur_node->right, cond, q);
}
switch (cur_node->op) {
case OP_AND:
f->set_op(proto_query::OP_AND);
break;
case OP_OR:
f->set_op(proto_query::OP_OR);
break;
case OP_KEY_VALUE:
f->set_op(proto_query::OP_KEY_VALUE);
set_key_value(f->mutable_key_value(), cur_node->key_value);
break;
case OP_COMP:
f->set_op(proto_query::OP_COMP);
set_key_value(f->mutable_key_value(), cur_node->key_value);
break;
}
}

int main(int argc, char *argv[]) {
if (argc <= 1) {
std::cout << "Usage: ./client host:port";
return 0;
}

auto channel = grpc::CreateChannel(argv[1], grpc::InsecureChannelCredentials());
std::unique_ptr<proto_query::QueryService::Stub> stub = proto_query::QueryService::NewStub(channel);

while (true) {
grpc::ClientContext context;
std::cout << ">";
if (yyparse() || q.command == CMD_NONE) {
free_all();
std::cout << std::endl;
continue;
}
proto_query::Query _query;
_query.set_schema(q.schema);

switch (q.command) {
case CMD_INSERT: {
_query.set_command(proto_query::CommandType::CMD_INSERT);
_query.set_parent(q.parent);
auto cur = q.new_fields;
while (cur) {
auto field = _query.add_new_fields();
set_key_value(field, cur->field);
cur = cur->next;
}
break;
}
case CMD_FIND: {
_query.set_command(proto_query::CommandType::CMD_FIND);
auto cond = _query.add_cond();
node_to_proto_filter(q.cond, cond, _query);
break;
}
case CMD_UPDATE: {
_query.set_command(proto_query::CommandType::CMD_UPDATE);

auto cond = _query.add_cond();
node_to_proto_filter(q.cond, cond, _query);

auto cur = q.new_fields;
while (cur) {
auto field = _query.add_new_fields();
set_key_value(field, cur->field);
cur = cur->next;
}
break;
}
case CMD_DELETE: {
_query.set_command(proto_query::CommandType::CMD_DELETE);
auto cond = _query.add_cond();
node_to_proto_filter(q.cond, cond, _query);
break;
}
default:
break;
}

free_all();
proto_query::QueryResponse result;
grpc::Status status = stub->GetQuery(&context, _query, &result);

std::cout << "Ok: " << (result.ok() ? "True" : "False") << std::endl;
if (!result.ok()) {
std::cout << "Error: " << result.error_message() << std::endl;
} else if (_query.command() == proto_query::CMD_INSERT){
std::cout << "Inserted id: " << result.inserted_id() << std::endl;
}
else if (_query.command() == proto_query::CMD_FIND) {
std::cout << "Count elements: " << result.elements_size() << std::endl;
for (const auto &now : result.elements()) {
std::cout << "id: " << now.id() << "\n";
std::cout << "schema: " << now.schema() << "\n";
for (const auto& now2 : now.key_values()) {
std::cout << now2.key() << ": ";
if (now2.value().value_type() == proto_query::DB_STRING) {
std::cout << now2.value().str_value();
} else if (now2.value().value_type() == proto_query::DB_INT32) {
std::cout << now2.value().int_value();
} else if (now2.value().value_type() == proto_query::DB_DOUBLE) {
std::cout << now2.value().double_value();
} else if (now2.value().value_type() == proto_query::DB_BOOL) {
std::cout << (now2.value().bool_value() ? "True" : "False");
}
std::cout << "\n";
}
std::cout << "\n";
}
}
}
return 0;
}
18 changes: 15 additions & 3 deletions llp/include/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ Database::SchemasListIterator::SchemasListIterator(Database *db, FileChunkedList
Database::ElementsTreeIterator::ElementsTreeIterator(Database *db, FileChunkedList<kNodesPageMarker> head) {
db_ = db;
current_ptr_ = head.first_element;
Down();
if (current_ptr_) {
Down();
}
}

void Database::ElementsTreeIterator::Down() {
Expand Down Expand Up @@ -423,7 +425,7 @@ void Database::FreeBytesBatch(DbPtr target_batch, FileChunkedList<PageMarker> &e
UpdateMasterHeader();
}

void Database::RewriteBytesBatch(Byte *target_batch, DbSize size, DbPtr start) const {
void Database::RewriteBytesBatch(Byte *target_batch, DbSize size, DbPtr start) const {
debug_assert(start);
debug_assert(size != 0);

Expand Down Expand Up @@ -535,6 +537,9 @@ Result Database::GetElements(const select_query &args) {
return {false, "Schema for element not created"};
}
for (const auto &cond : args.conditionals) {
if (cond.op == OP_AND || cond.op == OP_OR) {
continue;
}
if (schema.fields_.find(cond.field_name) == schema.fields_.end() ||
schema.fields_[cond.field_name] != cond.value.index()) {
debug("Conditions of field'" + cond.field_name + "' not match with schema");
Expand All @@ -560,6 +565,9 @@ Result Database::UpdateElements(update_query args) {
return {false, "Schema for element not created"};
}
for (const auto &cond : args.selector.conditionals) {
if (cond.op == OP_AND || cond.op == OP_OR) {
continue;
}
if (schema.fields_.find(cond.field_name) == schema.fields_.end() ||
schema.fields_[cond.field_name] != cond.value.index()) {
debug("Conditions of field'" + cond.field_name + "' not match with schema");
Expand Down Expand Up @@ -756,6 +764,9 @@ Result Database::DeleteElements(const select_query &args) {
return {false, "Schema for element not created"};
}
for (const auto &cond : args.conditionals) {
if (cond.op == OP_AND || cond.op == OP_OR) {
continue;
}
if (schema.fields_.find(cond.field_name) == schema.fields_.end() ||
schema.fields_[cond.field_name] != cond.value.index()) {
debug("Conditions of field'" + cond.field_name + "' not match with schema");
Expand Down Expand Up @@ -845,7 +856,8 @@ bool Database::ValidateElementByPtr(DbPtr ptr) const {
}
auto chunk = PageChunk();
file_->Read(&chunk, sizeof(PageChunk), ptr);
return chunk.nxt_chunk >= 0;
return chunk.nxt_chunk >= 0; // TODO придумал случай когда можно сломать. Когда указатель дан на единственный
// свободный чанк, то проверка даже в учётом размера схемы обходится :(
}

#endif // LLP_INCLUDE_DATABASE_H_
4 changes: 3 additions & 1 deletion llp/include/Element.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

typedef std::variant<int32_t, double, std::string, bool> DataItem;

enum Operator { OP_EQUAL, OP_NOT_EQUAL, OP_GREATER, OP_LESS };
enum Operator { OP_EQUAL, OP_NOT_EQUAL, OP_GREATER, OP_LESS, OP_AND, OP_OR };

template <typename T>
bool EvalOperator(Operator op, T a, T b) {
Expand All @@ -33,6 +33,8 @@ struct fields_conditional {
std::string field_name;
Operator op;
DataItem value;
int64_t left_op;
int64_t right_op;
};

class Element {
Expand Down
18 changes: 16 additions & 2 deletions llp/include/Query.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,22 @@ struct insert_query {
struct select_query {
std::string schema_name;
std::vector<fields_conditional> conditionals;
[[nodiscard]] bool CheckConditionals(const Element &e) const {
return all_of(conditionals.begin(), conditionals.end(), [&e](auto x) { return e.CheckConditional(x); });
[[nodiscard]] bool CheckConditionals(const Element &e, int now_ind = 0) const {
if (conditionals[now_ind].left_op == 0 and conditionals[now_ind].right_op == 0) {
return e.CheckConditional(conditionals[now_ind]);
} else if (conditionals[now_ind].right_op != 0) {
if (conditionals[now_ind].op == OP_AND) {
return CheckConditionals(e, conditionals[now_ind].left_op) &&
CheckConditionals(e, conditionals[now_ind].right_op);
} else if (conditionals[now_ind].op == OP_OR) {
return CheckConditionals(e, conditionals[now_ind].left_op) ||
CheckConditionals(e, conditionals[now_ind].right_op);
} else {
error("Invalid binary operator");
}
} else {
return CheckConditionals(e, conditionals[now_ind].left_op);
}
}
};

Expand Down
18 changes: 11 additions & 7 deletions parser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
cmake_minimum_required(VERSION 3.21)

project(Parser LANGUAGES C)
set(CMAKE_CXX_STANDARD 20)

set(SRC_DIR "src")
set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}")
set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}/parser")
file(MAKE_DIRECTORY ${PARSER_DIR})

find_package(FLEX 2.6 REQUIRED)
find_package(BISON 3.0 REQUIRED)

set(LEXER_OUT "${PARSER_DIR}/lexer.c")
set(PARSER_OUT "${PARSER_DIR}/parser.c")

include_directories(SRC_DIR)
include_directories(CMAKE_CURRENT_BINARY_DIR)
configure_file("${SRC_DIR}/types.h" "${PARSER_DIR}/types.h" COPYONLY)

flex_target(LEXER "${SRC_DIR}/lexer.l" "${LEXER_OUT}" DEFINES_FILE "${PARSER_DIR}/lexer.h")
bison_target(PARSER "${SRC_DIR}/parser.y" "${PARSER_OUT}" DEFINES_FILE "${PARSER_DIR}/parser.h")
add_flex_bison_dependency(LEXER PARSER)

add_executable(parser "${SRC_DIR}/main.c" "${LEXER_OUT}" "${PARSER_OUT}")
target_include_directories(parser PRIVATE "${PARSER_DIR}" "${SRC_DIR}")
add_library(flex_bison STATIC "${LEXER_OUT}" "${PARSER_OUT}" "${SRC_DIR}/types.h")
set_target_properties(flex_bison PROPERTIES LINKER_LANGUAGE C)
target_include_directories(flex_bison PRIVATE "${SRC_DIR}")

set(EXECUTABLE_OUTPUT_PATH "./bin/${CMAKE_SYSTEM}")
add_executable(parser "${SRC_DIR}/main.c" "${LEXER_OUT}" "${PARSER_OUT}" "${PROTO_SRC}" "${SRC_DIR}/types.h")
target_include_directories(parser PRIVATE "${PARSER_DIR}" "${SRC_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" "${PROTOBUF_INCLUDE_DIRS}")
target_link_libraries(parser PRIVATE flex_bison)

set(EXECUTABLE_OUTPUT_PATH "./bin/${CMAKE_SYSTEM}")
2 changes: 1 addition & 1 deletion parser/src/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"lt" return LT;
"lte" return LTE;
"gt" return GT;
"gte" return GTE;
"gte" return GTE ;
"ne" return NE;
"regex" return REGEX;
\( return OPBRACE;
Expand Down
10 changes: 5 additions & 5 deletions parser/src/main.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include <stdio.h>

#include "lexer.h"
#include "parser.h"

int main (void) {
return yyparse();
int main() {
int status = yyparse();
print_query(q);
print_allocations_size();
return status;
}
Loading