Skip to content

Commit

Permalink
Merge pull request #1 from deevroman/lab3
Browse files Browse the repository at this point in the history
  • Loading branch information
deevroman authored Jan 28, 2023
2 parents 28f05ff + 6afbca1 commit c75b4af
Show file tree
Hide file tree
Showing 19 changed files with 590 additions and 29 deletions.
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

0 comments on commit c75b4af

Please sign in to comment.