Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
I
illuna-minetest
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
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
Illuna-Minetest
illuna-minetest
Commits
1fd9a11e
Commit
1fd9a11e
authored
11 years ago
by
Mario Barrera
Committed by
ShadowNinja
11 years ago
Browse files
Options
Downloads
Patches
Plain Diff
SQLite rollback
parent
4f246f0e
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/rollback.cpp
+960
-174
960 additions, 174 deletions
src/rollback.cpp
with
960 additions
and
174 deletions
src/rollback.cpp
+
960
−
174
View file @
1fd9a11e
...
...
@@ -29,11 +29,876 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include
"util/string.h"
#include
"util/numeric.h"
#include
"inventorymanager.h"
// deserializing InventoryLocations
#include
"sqlite3.h"
#include
"filesys.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
#define POINTS_PER_NODE (16.0)
std
::
string
dbp
;
sqlite3
*
dbh
;
sqlite3_stmt
*
dbs_insert
;
sqlite3_stmt
*
dbs_replace
;
sqlite3_stmt
*
dbs_select
;
sqlite3_stmt
*
dbs_select_range
;
sqlite3_stmt
*
dbs_select_withActor
;
sqlite3_stmt
*
dbs_knownActor_select
;
sqlite3_stmt
*
dbs_knownActor_insert
;
sqlite3_stmt
*
dbs_knownNode_select
;
sqlite3_stmt
*
dbs_knownNode_insert
;
struct
Stack
{
int
node
;
int
quantity
;
};
struct
ActionRow
{
int
id
;
int
actor
;
int
timestamp
;
int
type
;
std
::
string
location
,
list
;
int
index
,
add
;
Stack
stack
;
int
nodeMeta
;
int
x
,
y
,
z
;
int
oldNode
;
int
oldParam1
,
oldParam2
;
std
::
string
oldMeta
;
int
newNode
;
int
newParam1
,
newParam2
;
std
::
string
newMeta
;
int
guessed
;
};
struct
Entity
{
int
id
;
std
::
string
name
;
};
typedef
std
::
vector
<
Entity
>
Entities
;
Entities
KnownActors
;
Entities
KnownNodes
;
void
registerNewActor
(
int
id
,
std
::
string
name
)
{
Entity
newActor
;
newActor
.
id
=
id
;
newActor
.
name
=
name
;
KnownActors
.
push_back
(
newActor
);
//std::cout << "New actor registered: " << id << " | " << name << std::endl;
}
void
registerNewNode
(
int
id
,
std
::
string
name
)
{
Entity
newNode
;
newNode
.
id
=
id
;
newNode
.
name
=
name
;
KnownNodes
.
push_back
(
newNode
);
//std::cout << "New node registered: " << id << " | " << name << std::endl;
}
int
getActorId
(
std
::
string
name
)
{
Entities
::
const_iterator
iter
;
for
(
iter
=
KnownActors
.
begin
();
iter
!=
KnownActors
.
end
();
++
iter
)
if
(
iter
->
name
==
name
)
return
iter
->
id
;
sqlite3_reset
(
dbs_knownActor_insert
);
sqlite3_bind_text
(
dbs_knownActor_insert
,
1
,
name
.
c_str
(),
-
1
,
NULL
);
sqlite3_step
(
dbs_knownActor_insert
);
int
id
=
sqlite3_last_insert_rowid
(
dbh
);
//std::cout << "Actor ID insert returns " << insert << std::endl;
registerNewActor
(
id
,
name
);
return
id
;
}
int
getNodeId
(
std
::
string
name
)
{
Entities
::
const_iterator
iter
;
for
(
iter
=
KnownNodes
.
begin
();
iter
!=
KnownNodes
.
end
();
++
iter
)
if
(
iter
->
name
==
name
)
return
iter
->
id
;
sqlite3_reset
(
dbs_knownNode_insert
);
sqlite3_bind_text
(
dbs_knownNode_insert
,
1
,
name
.
c_str
(),
-
1
,
NULL
);
sqlite3_step
(
dbs_knownNode_insert
);
int
id
=
sqlite3_last_insert_rowid
(
dbh
);
registerNewNode
(
id
,
name
);
return
id
;
}
const
char
*
getActorName
(
int
id
)
{
Entities
::
const_iterator
iter
;
//std::cout << "getActorName of id " << id << std::endl;
for
(
iter
=
KnownActors
.
begin
();
iter
!=
KnownActors
.
end
();
++
iter
)
if
(
iter
->
id
==
id
)
return
iter
->
name
.
c_str
();
return
""
;
}
const
char
*
getNodeName
(
int
id
)
{
Entities
::
const_iterator
iter
;
//std::cout << "getNodeName of id " << id << std::endl;
for
(
iter
=
KnownNodes
.
begin
();
iter
!=
KnownNodes
.
end
();
++
iter
)
if
(
iter
->
id
==
id
)
return
iter
->
name
.
c_str
();
return
""
;
}
Stack
getStackFromString
(
std
::
string
text
)
{
Stack
stack
;
size_t
off
=
text
.
find_last_of
(
" "
);
stack
.
node
=
getNodeId
(
text
.
substr
(
0
,
off
));
stack
.
quantity
=
atoi
(
text
.
substr
(
off
+
1
).
c_str
());
return
stack
;
}
std
::
string
getStringFromStack
(
Stack
stack
)
{
std
::
string
text
;
text
.
append
(
getNodeName
(
stack
.
node
));
text
.
append
(
" "
);
text
.
append
(
itos
(
stack
.
quantity
));
return
text
;
}
bool
SQL_createDatabase
(
void
)
{
infostream
<<
"CreateDB:"
<<
dbp
<<
std
::
endl
;
int
dbs
=
sqlite3_exec
(
dbh
,
"CREATE TABLE IF NOT EXISTS `actor` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
"`name` TEXT NOT NULL);"
"CREATE TABLE IF NOT EXISTS `node` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
"`name` TEXT NOT NULL);"
"CREATE TABLE IF NOT EXISTS `action` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT,"
"`actor` INTEGER NOT NULL,"
"`timestamp` INTEGER NOT NULL,"
"`type` INTEGER NOT NULL,"
"`list` TEXT,"
"`index` INTEGER,"
"`add` INTEGER,"
"`stackNode` INTEGER,"
"`stackQuantity` INTEGER,"
"`nodeMeta` INTEGER,"
"`x` INT,"
"`y` INT,"
"`z` INT,"
"`oldNode` INTEGER,"
"`oldParam1` INTEGER,"
"`oldParam2` INTEGER,"
"`oldMeta` TEXT,"
"`newNode` INTEGER,"
"`newParam1` INTEGER,"
"`newParam2` INTEGER,"
"`newMeta` TEXT,"
"`guessedActor` INTEGER,"
"FOREIGN KEY (`actor`) REFERENCES `actor`(`id`),"
"FOREIGN KEY (`oldNode`) REFERENCES `node`(`id`),"
"FOREIGN KEY (`newNode`) REFERENCES `node`(`id`));"
"CREATE INDEX IF NOT EXISTS `actionActor` ON `action`(`actor`);"
"CREATE INDEX IF NOT EXISTS `actionTimestamp` ON `action`(`timestamp`);"
,
NULL
,
NULL
,
NULL
);
if
(
dbs
==
SQLITE_ABORT
)
throw
FileNotGoodException
(
"Could not create sqlite3 database structure"
);
else
if
(
dbs
!=
0
)
throw
FileNotGoodException
(
"SQL Rollback: Exec statement to create table structure returned a non-zero value"
);
else
infostream
<<
"SQL Rollback: SQLite3 database structure was created"
<<
std
::
endl
;
return
true
;
}
void
SQL_databaseCheck
(
void
)
{
if
(
dbh
)
return
;
infostream
<<
"Database connection setup"
<<
std
::
endl
;
bool
needsCreate
=
!
fs
::
PathExists
(
dbp
);
int
dbo
=
sqlite3_open_v2
(
dbp
.
c_str
(),
&
dbh
,
SQLITE_OPEN_READWRITE
|
SQLITE_OPEN_CREATE
,
NULL
);
if
(
dbo
!=
SQLITE_OK
)
{
infostream
<<
"SQLROLLBACK: SQLite3 database failed to open: "
<<
sqlite3_errmsg
(
dbh
)
<<
std
::
endl
;
throw
FileNotGoodException
(
"Cannot open database file"
);
}
if
(
needsCreate
)
SQL_createDatabase
();
int
dbr
;
dbr
=
sqlite3_prepare_v2
(
dbh
,
"INSERT INTO `action`"
" ( `actor`, `timestamp`, `type`,"
" `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,"
" `x`, `y`, `z`,"
" `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
" `newNode`, `newParam1`, `newParam2`, `newMeta`,"
" `guessedActor`"
" )"
"VALUES"
" ( ?, ?, ?,"
" ?, ?, ?, ?, ?, ?,"
" ?, ?, ?,"
" ?, ?, ?, ?,"
" ?, ?, ?, ?,"
" ?"
" );"
,
-
1
,
&
dbs_insert
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
sqlite3_errmsg
(
dbh
));
dbr
=
sqlite3_prepare_v2
(
dbh
,
"REPLACE INTO `action`"
" ( `actor`, `timestamp`, `type`,"
" `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,"
" `x`, `y`, `z`,"
" `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
" `newNode`, `newParam1`, `newParam2`, `newMeta`,"
" `guessedActor`, `id`"
" )"
"VALUES"
" ( ?, ?, ?,"
" ?, ?, ?, ?, ?, ?,"
" ?, ?, ?,"
" ?, ?, ?, ?,"
" ?, ?, ?, ?,"
" ?, ?"
" );"
,
-
1
,
&
dbs_replace
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
sqlite3_errmsg
(
dbh
));
dbr
=
sqlite3_prepare_v2
(
dbh
,
"SELECT "
" `actor`, `timestamp`, `type`"
" , `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`"
" , `x`, `y`, `z`"
" , `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`"
" , `newNode`, `newParam1`, `newParam2`, `newMeta`"
" , `guessedActor`"
" FROM `action`"
" WHERE `timestamp` >= ?"
" ORDER BY `timestamp` DESC, `id` DESC"
,
-
1
,
&
dbs_select
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
dbr
=
sqlite3_prepare_v2
(
dbh
,
"SELECT "
" `actor`, `timestamp`, `type`"
" , `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`"
" , `x`, `y`, `z`"
" , `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`"
" , `newNode`, `newParam1`, `newParam2`, `newMeta`"
" , `guessedActor`"
" FROM `action`"
" WHERE `timestamp` >= ?"
" AND `x` IS NOT NULL"
" AND `y` IS NOT NULL"
" AND `z` IS NOT NULL"
" AND (ABS(`x`) - ABS(?)) <= ?"
" AND (ABS(`y`) - ABS(?)) <= ?"
" AND (ABS(`z`) - ABS(?)) <= ?"
" ORDER BY `timestamp` DESC, `id` DESC"
" LIMIT 0,5"
,
-
1
,
&
dbs_select_range
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
dbr
=
sqlite3_prepare_v2
(
dbh
,
"SELECT "
" `actor`, `timestamp`, `type`"
" , `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`"
" , `x`, `y`, `z`"
" , `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`"
" , `newNode`, `newParam1`, `newParam2`, `newMeta`"
" , `guessedActor`"
" FROM `action`"
" WHERE `timestamp` >= ?"
" AND `actor` = ?"
" ORDER BY `timestamp` DESC, `id` DESC"
,
-
1
,
&
dbs_select_withActor
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
dbr
=
sqlite3_prepare_v2
(
dbh
,
"SELECT `id`, `name` FROM `actor`"
,
-
1
,
&
dbs_knownActor_select
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
dbr
=
sqlite3_prepare_v2
(
dbh
,
"INSERT INTO `actor` (`name`) VALUES (?)"
,
-
1
,
&
dbs_knownActor_insert
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
dbr
=
sqlite3_prepare_v2
(
dbh
,
"SELECT `id`, `name` FROM `node`"
,
-
1
,
&
dbs_knownNode_select
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
dbr
=
sqlite3_prepare_v2
(
dbh
,
"INSERT INTO `node` (`name`) VALUES (?)"
,
-
1
,
&
dbs_knownNode_insert
,
NULL
);
if
(
dbr
!=
SQLITE_OK
)
throw
FileNotGoodException
(
itos
(
dbr
).
c_str
());
infostream
<<
"SQL prepared statements setup correctly"
<<
std
::
endl
;
int
select
;
sqlite3_reset
(
dbs_knownActor_select
);
while
(
SQLITE_ROW
==
(
select
=
sqlite3_step
(
dbs_knownActor_select
)))
registerNewActor
(
sqlite3_column_int
(
dbs_knownActor_select
,
0
),
reinterpret_cast
<
const
char
*>
(
sqlite3_column_text
(
dbs_knownActor_select
,
1
))
);
sqlite3_reset
(
dbs_knownNode_select
);
while
(
SQLITE_ROW
==
(
select
=
sqlite3_step
(
dbs_knownNode_select
)))
registerNewNode
(
sqlite3_column_int
(
dbs_knownNode_select
,
0
),
reinterpret_cast
<
const
char
*>
(
sqlite3_column_text
(
dbs_knownNode_select
,
1
))
);
return
;
}
bool
SQL_registerRow
(
ActionRow
row
)
{
SQL_databaseCheck
();
sqlite3_stmt
*
dbs_do
=
(
row
.
id
)
?
dbs_replace
:
dbs_insert
;
/*
std::cout
<< (row.id? "Replacing": "Inserting")
<< " ActionRow" << std::endl;
*/
sqlite3_reset
(
dbs_do
);
int
bind
[
20
+
(((
bool
)
row
.
id
)
?
1
:
0
)],
ii
=
0
;
bool
nodeMeta
=
false
;
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
1
,
row
.
actor
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
2
,
row
.
timestamp
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
3
,
row
.
type
);
if
(
row
.
type
==
RollbackAction
::
TYPE_MODIFY_INVENTORY_STACK
)
{
std
::
string
loc
=
row
.
location
;
std
::
string
locType
=
loc
.
substr
(
0
,
loc
.
find
(
":"
));
nodeMeta
=
(
locType
==
"nodemeta"
);
bind
[
ii
++
]
=
sqlite3_bind_text
(
dbs_do
,
4
,
row
.
list
.
c_str
(),
row
.
list
.
size
(),
NULL
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
5
,
row
.
index
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
6
,
row
.
add
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
7
,
row
.
stack
.
node
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
8
,
row
.
stack
.
quantity
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
9
,
(
int
)
nodeMeta
);
if
(
nodeMeta
)
{
std
::
string
x
,
y
,
z
;
int
l
,
r
;
l
=
loc
.
find
(
':'
)
+
1
;
r
=
loc
.
find
(
','
);
x
=
loc
.
substr
(
l
,
r
-
l
);
l
=
r
+
1
;
r
=
loc
.
find
(
','
,
l
);
y
=
loc
.
substr
(
l
,
r
-
l
);
z
=
loc
.
substr
(
r
+
1
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
10
,
atoi
(
x
.
c_str
()));
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
11
,
atoi
(
y
.
c_str
()));
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
12
,
atoi
(
z
.
c_str
()));
}
}
else
{
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
4
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
5
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
6
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
7
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
8
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
9
);
}
if
(
row
.
type
==
RollbackAction
::
TYPE_SET_NODE
)
{
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
10
,
row
.
x
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
11
,
row
.
y
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
12
,
row
.
z
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
13
,
row
.
oldNode
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
14
,
row
.
oldParam1
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
15
,
row
.
oldParam2
);
bind
[
ii
++
]
=
sqlite3_bind_text
(
dbs_do
,
16
,
row
.
oldMeta
.
c_str
(),
row
.
oldMeta
.
size
(),
NULL
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
17
,
row
.
newNode
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
18
,
row
.
newParam1
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
19
,
row
.
newParam2
);
bind
[
ii
++
]
=
sqlite3_bind_text
(
dbs_do
,
20
,
row
.
newMeta
.
c_str
(),
row
.
newMeta
.
size
(),
NULL
);
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
21
,
row
.
guessed
?
1
:
0
);
}
else
{
if
(
!
nodeMeta
)
{
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
10
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
11
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
12
);
}
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
13
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
14
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
15
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
16
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
17
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
18
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
19
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
20
);
bind
[
ii
++
]
=
sqlite3_bind_null
(
dbs_do
,
21
);
}
if
(
row
.
id
)
bind
[
ii
++
]
=
sqlite3_bind_int
(
dbs_do
,
22
,
row
.
id
);
for
(
ii
=
0
;
ii
<
20
;
++
ii
)
if
(
bind
[
ii
]
!=
SQLITE_OK
)
infostream
<<
"WARNING: failed to bind param "
<<
ii
+
1
<<
" when inserting an entry in table setnode"
<<
std
::
endl
;
/*
std::cout << "========DB-WRITTEN==========" << std::endl;
std::cout << "id: " << row.id << std::endl;
std::cout << "actor: " << row.actor << std::endl;
std::cout << "time: " << row.timestamp << std::endl;
std::cout << "type: " << row.type << std::endl;
if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
{
std::cout << "Location: " << row.location << std::endl;
std::cout << "List: " << row.list << std::endl;
std::cout << "Index: " << row.index << std::endl;
std::cout << "Add: " << row.add << std::endl;
std::cout << "Stack: " << row.stack << std::endl;
}
if (row.type == RollbackAction::TYPE_SET_NODE)
{
std::cout << "x: " << row.x << std::endl;
std::cout << "y: " << row.y << std::endl;
std::cout << "z: " << row.z << std::endl;
std::cout << "oldNode: " << row.oldNode << std::endl;
std::cout << "oldParam1: " << row.oldParam1 << std::endl;
std::cout << "oldParam2: " << row.oldParam2 << std::endl;
std::cout << "oldMeta: " << row.oldMeta << std::endl;
std::cout << "newNode: " << row.newNode << std::endl;
std::cout << "newParam1: " << row.newParam1 << std::endl;
std::cout << "newParam2: " << row.newParam2 << std::endl;
std::cout << "newMeta: " << row.newMeta << std::endl;
std::cout << "DESERIALIZE" << row.newMeta.c_str() << std::endl;
std::cout << "guessed: " << row.guessed << std::endl;
}
*/
int
written
=
sqlite3_step
(
dbs_do
);
return
written
==
SQLITE_DONE
;
//if (written != SQLITE_DONE)
// std::cout << "WARNING: rollback action not written: " << sqlite3_errmsg(dbh) << std::endl;
//else std::cout << "Action correctly inserted via SQL" << std::endl;
}
std
::
list
<
ActionRow
>
actionRowsFromSelect
(
sqlite3_stmt
*
stmt
)
{
std
::
list
<
ActionRow
>
rows
;
const
unsigned
char
*
text
;
size_t
size
;
while
(
SQLITE_ROW
==
sqlite3_step
(
stmt
))
{
ActionRow
row
;
row
.
actor
=
sqlite3_column_int
(
stmt
,
0
);
row
.
timestamp
=
sqlite3_column_int
(
stmt
,
1
);
row
.
type
=
sqlite3_column_int
(
stmt
,
2
);
if
(
row
.
type
==
RollbackAction
::
TYPE_MODIFY_INVENTORY_STACK
)
{
text
=
sqlite3_column_text
(
stmt
,
3
);
size
=
sqlite3_column_bytes
(
stmt
,
3
);
row
.
list
=
std
::
string
(
reinterpret_cast
<
const
char
*>
(
text
),
size
);
row
.
index
=
sqlite3_column_int
(
stmt
,
4
);
row
.
add
=
sqlite3_column_int
(
stmt
,
5
);
row
.
stack
.
node
=
sqlite3_column_int
(
stmt
,
6
);
row
.
stack
.
quantity
=
sqlite3_column_int
(
stmt
,
7
);
row
.
nodeMeta
=
sqlite3_column_int
(
stmt
,
8
);
}
if
(
row
.
type
==
RollbackAction
::
TYPE_SET_NODE
||
row
.
nodeMeta
)
{
row
.
x
=
sqlite3_column_int
(
stmt
,
9
);
row
.
y
=
sqlite3_column_int
(
stmt
,
10
);
row
.
z
=
sqlite3_column_int
(
stmt
,
11
);
}
if
(
row
.
type
==
RollbackAction
::
TYPE_SET_NODE
)
{
row
.
oldNode
=
sqlite3_column_int
(
stmt
,
12
);
row
.
oldParam1
=
sqlite3_column_int
(
stmt
,
13
);
row
.
oldParam2
=
sqlite3_column_int
(
stmt
,
14
);
text
=
sqlite3_column_text
(
stmt
,
15
);
size
=
sqlite3_column_bytes
(
stmt
,
15
);
row
.
oldMeta
=
std
::
string
(
reinterpret_cast
<
const
char
*>
(
text
),
size
);
row
.
newNode
=
sqlite3_column_int
(
stmt
,
16
);
row
.
newParam1
=
sqlite3_column_int
(
stmt
,
17
);
row
.
newParam2
=
sqlite3_column_int
(
stmt
,
18
);
text
=
sqlite3_column_text
(
stmt
,
19
);
size
=
sqlite3_column_bytes
(
stmt
,
19
);
row
.
newMeta
=
std
::
string
(
reinterpret_cast
<
const
char
*>
(
text
),
size
);
row
.
guessed
=
sqlite3_column_int
(
stmt
,
20
);
}
row
.
location
=
row
.
nodeMeta
?
"nodemeta:"
:
getActorName
(
row
.
actor
);
if
(
row
.
nodeMeta
)
{
row
.
location
.
append
(
itos
(
row
.
x
));
row
.
location
.
append
(
","
);
row
.
location
.
append
(
itos
(
row
.
y
));
row
.
location
.
append
(
","
);
row
.
location
.
append
(
itos
(
row
.
z
));
}
/*
std::cout << "=======SELECTED==========" << "\n";
std::cout << "Actor: " << row.actor << "\n";
std::cout << "Timestamp: " << row.timestamp << "\n";
if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
{
std::cout << "list: " << row.list << "\n";
std::cout << "index: " << row.index << "\n";
std::cout << "add: " << row.add << "\n";
std::cout << "stackNode: " << row.stack.node << "\n";
std::cout << "stackQuantity: " << row.stack.quantity << "\n";
if (row.nodeMeta)
{
std::cout << "X: " << row.x << "\n";
std::cout << "Y: " << row.y << "\n";
std::cout << "Z: " << row.z << "\n";
}
std::cout << "Location: " << row.location << "\n";
}
else
{
std::cout << "X: " << row.x << "\n";
std::cout << "Y: " << row.y << "\n";
std::cout << "Z: " << row.z << "\n";
std::cout << "oldNode: " << row.oldNode << "\n";
std::cout << "oldParam1: " << row.oldParam1 << "\n";
std::cout << "oldParam2: " << row.oldParam2 << "\n";
std::cout << "oldMeta: " << row.oldMeta << "\n";
std::cout << "newNode: " << row.newNode << "\n";
std::cout << "newParam1: " << row.newParam1 << "\n";
std::cout << "newParam2: " << row.newParam2 << "\n";
std::cout << "newMeta: " << row.newMeta << "\n";
std::cout << "guessed: " << row.guessed << "\n";
}
*/
rows
.
push_back
(
row
);
}
return
rows
;
}
ActionRow
actionRowFromRollbackAction
(
RollbackAction
action
)
{
ActionRow
row
;
row
.
id
=
0
;
row
.
actor
=
getActorId
(
action
.
actor
);
row
.
timestamp
=
action
.
unix_time
;
row
.
type
=
action
.
type
;
if
(
row
.
type
==
RollbackAction
::
TYPE_MODIFY_INVENTORY_STACK
)
{
row
.
location
=
action
.
inventory_location
;
row
.
list
=
action
.
inventory_list
;
row
.
index
=
action
.
inventory_index
;
row
.
add
=
action
.
inventory_add
;
row
.
stack
=
getStackFromString
(
action
.
inventory_stack
);
}
else
{
row
.
x
=
action
.
p
.
X
;
row
.
y
=
action
.
p
.
Y
;
row
.
z
=
action
.
p
.
Z
;
row
.
oldNode
=
getNodeId
(
action
.
n_old
.
name
);
row
.
oldParam1
=
action
.
n_old
.
param1
;
row
.
oldParam2
=
action
.
n_old
.
param2
;
row
.
oldMeta
=
action
.
n_old
.
meta
;
row
.
newNode
=
getNodeId
(
action
.
n_new
.
name
);
row
.
newParam1
=
action
.
n_new
.
param1
;
row
.
newParam2
=
action
.
n_new
.
param2
;
row
.
newMeta
=
action
.
n_new
.
meta
;
row
.
guessed
=
action
.
actor_is_guess
;
}
return
row
;
}
std
::
list
<
RollbackAction
>
rollbackActionsFromActionRows
(
std
::
list
<
ActionRow
>
rows
)
{
std
::
list
<
RollbackAction
>
actions
;
std
::
list
<
ActionRow
>::
const_iterator
it
;
for
(
it
=
rows
.
begin
();
it
!=
rows
.
end
();
++
it
)
{
RollbackAction
action
;
action
.
actor
=
(
it
->
actor
)
?
getActorName
(
it
->
actor
)
:
""
;
action
.
unix_time
=
it
->
timestamp
;
action
.
type
=
static_cast
<
RollbackAction
::
Type
>
(
it
->
type
);
switch
(
action
.
type
)
{
case
RollbackAction
::
TYPE_MODIFY_INVENTORY_STACK
:
action
.
inventory_location
=
it
->
location
.
c_str
();
action
.
inventory_list
=
it
->
list
;
action
.
inventory_index
=
it
->
index
;
action
.
inventory_add
=
it
->
add
;
action
.
inventory_stack
=
getStringFromStack
(
it
->
stack
);
break
;
case
RollbackAction
::
TYPE_SET_NODE
:
action
.
p
=
v3s16
(
it
->
x
,
it
->
y
,
it
->
z
);
action
.
n_old
.
name
=
getNodeName
(
it
->
oldNode
);
action
.
n_old
.
param1
=
it
->
oldParam1
;
action
.
n_old
.
param2
=
it
->
oldParam2
;
action
.
n_old
.
meta
=
it
->
oldMeta
;
action
.
n_new
.
name
=
getNodeName
(
it
->
newNode
);
action
.
n_new
.
param1
=
it
->
newParam1
;
action
.
n_new
.
param2
=
it
->
newParam2
;
action
.
n_new
.
meta
=
it
->
newMeta
;
break
;
default:
throw
(
"W.T.F."
);
break
;
}
actions
.
push_back
(
action
);
}
return
actions
;
}
std
::
list
<
ActionRow
>
SQL_getRowsSince
(
int
firstTime
,
std
::
string
actor
=
""
)
{
sqlite3_stmt
*
dbs_stmt
=
(
!
actor
.
length
())
?
dbs_select
:
dbs_select_withActor
;
sqlite3_reset
(
dbs_stmt
);
sqlite3_bind_int
(
dbs_stmt
,
1
,
firstTime
);
if
(
actor
.
length
())
sqlite3_bind_int
(
dbs_stmt
,
2
,
getActorId
(
actor
));
return
actionRowsFromSelect
(
dbs_stmt
);
}
std
::
list
<
ActionRow
>
SQL_getRowsSince_range
(
int
firstTime
,
v3s16
p
,
int
range
)
{
sqlite3_stmt
*
stmt
=
dbs_select_range
;
sqlite3_reset
(
stmt
);
sqlite3_bind_int
(
stmt
,
1
,
firstTime
);
sqlite3_bind_int
(
stmt
,
2
,
(
int
)
p
.
X
);
sqlite3_bind_int
(
stmt
,
3
,
range
);
sqlite3_bind_int
(
stmt
,
4
,
(
int
)
p
.
Y
);
sqlite3_bind_int
(
stmt
,
5
,
range
);
sqlite3_bind_int
(
stmt
,
6
,
(
int
)
p
.
Z
);
sqlite3_bind_int
(
stmt
,
7
,
range
);
return
actionRowsFromSelect
(
stmt
);
}
std
::
list
<
RollbackAction
>
SQL_getActionsSince_range
(
int
firstTime
,
v3s16
p
,
int
range
)
{
std
::
list
<
ActionRow
>
rows
=
SQL_getRowsSince_range
(
firstTime
,
p
,
range
);
return
rollbackActionsFromActionRows
(
rows
);
}
std
::
list
<
RollbackAction
>
SQL_getActionsSince
(
int
firstTime
,
std
::
string
actor
=
""
)
{
std
::
list
<
ActionRow
>
rows
=
SQL_getRowsSince
(
firstTime
,
actor
);
return
rollbackActionsFromActionRows
(
rows
);
}
void
TXT_migrate
(
std
::
string
filepath
)
{
std
::
cout
<<
"Migrating from rollback.txt to rollback.sqlite"
<<
std
::
endl
;
SQL_databaseCheck
();
std
::
ifstream
fh
(
filepath
.
c_str
(),
std
::
ios
::
in
|
std
::
ios
::
ate
);
if
(
!
fh
.
good
())
throw
(
"DIE"
);
int
filesize
=
fh
.
tellg
();
if
(
filesize
>
10
)
{
fh
.
seekg
(
0
);
std
::
string
bit
;
int
i
=
0
;
int
id
=
1
;
int
t
=
0
;
do
{
ActionRow
row
;
row
.
id
=
id
;
// Get the timestamp
std
::
getline
(
fh
,
bit
,
' '
);
bit
=
trim
(
bit
);
if
(
!
atoi
(
trim
(
bit
).
c_str
()))
{
std
::
getline
(
fh
,
bit
);
continue
;
}
row
.
timestamp
=
atoi
(
bit
.
c_str
());
// Get the actor
row
.
actor
=
getActorId
(
trim
(
deSerializeJsonString
(
fh
)));
// Get the action type
std
::
getline
(
fh
,
bit
,
'['
);
std
::
getline
(
fh
,
bit
,
' '
);
if
(
bit
==
"modify_inventory_stack"
)
row
.
type
=
RollbackAction
::
TYPE_MODIFY_INVENTORY_STACK
;
if
(
bit
==
"set_node"
)
row
.
type
=
RollbackAction
::
TYPE_SET_NODE
;
if
(
row
.
type
==
RollbackAction
::
TYPE_MODIFY_INVENTORY_STACK
)
{
row
.
location
=
trim
(
deSerializeJsonString
(
fh
));
std
::
getline
(
fh
,
bit
,
' '
);
row
.
list
=
trim
(
deSerializeJsonString
(
fh
));
std
::
getline
(
fh
,
bit
,
' '
);
std
::
getline
(
fh
,
bit
,
' '
);
row
.
index
=
atoi
(
trim
(
bit
).
c_str
());
std
::
getline
(
fh
,
bit
,
' '
);
row
.
add
=
(
int
)
(
trim
(
bit
)
==
"add"
);
row
.
stack
=
getStackFromString
(
trim
(
deSerializeJsonString
(
fh
)));
std
::
getline
(
fh
,
bit
);
}
else
if
(
row
.
type
==
RollbackAction
::
TYPE_SET_NODE
)
{
std
::
getline
(
fh
,
bit
,
'('
);
std
::
getline
(
fh
,
bit
,
','
);
row
.
x
=
atoi
(
trim
(
bit
).
c_str
());
std
::
getline
(
fh
,
bit
,
','
);
row
.
y
=
atoi
(
trim
(
bit
).
c_str
());
std
::
getline
(
fh
,
bit
,
')'
);
row
.
z
=
atoi
(
trim
(
bit
).
c_str
());
std
::
getline
(
fh
,
bit
,
' '
);
row
.
oldNode
=
getNodeId
(
trim
(
deSerializeJsonString
(
fh
)));
std
::
getline
(
fh
,
bit
,
' '
);
std
::
getline
(
fh
,
bit
,
' '
);
row
.
oldParam1
=
atoi
(
trim
(
bit
).
c_str
());
std
::
getline
(
fh
,
bit
,
' '
);
row
.
oldParam2
=
atoi
(
trim
(
bit
).
c_str
());
row
.
oldMeta
=
trim
(
deSerializeJsonString
(
fh
));
std
::
getline
(
fh
,
bit
,
' '
);
row
.
newNode
=
getNodeId
(
trim
(
deSerializeJsonString
(
fh
)));
std
::
getline
(
fh
,
bit
,
' '
);
std
::
getline
(
fh
,
bit
,
' '
);
row
.
newParam1
=
atoi
(
trim
(
bit
).
c_str
());
std
::
getline
(
fh
,
bit
,
' '
);
row
.
newParam2
=
atoi
(
trim
(
bit
).
c_str
());
row
.
newMeta
=
trim
(
deSerializeJsonString
(
fh
));
std
::
getline
(
fh
,
bit
,
' '
);
std
::
getline
(
fh
,
bit
,
' '
);
std
::
getline
(
fh
,
bit
);
row
.
guessed
=
(
int
)
(
trim
(
bit
)
==
"actor_is_guess"
);
}
/*
std::cout << "==========READ===========" << std::endl;
std::cout << "time: " << row.timestamp << std::endl;
std::cout << "actor: " << row.actor << std::endl;
std::cout << "type: " << row.type << std::endl;
if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
{
std::cout << "Location: " << row.location << std::endl;
std::cout << "List: " << row.list << std::endl;
std::cout << "Index: " << row.index << std::endl;
std::cout << "Add: " << row.add << std::endl;
std::cout << "Stack: " << row.stack << std::endl;
}
if (row.type == RollbackAction::TYPE_SET_NODE)
{
std::cout << "x: " << row.x << std::endl;
std::cout << "y: " << row.y << std::endl;
std::cout << "z: " << row.z << std::endl;
std::cout << "oldNode: " << row.oldNode << std::endl;
std::cout << "oldParam1: " << row.oldParam1 << std::endl;
std::cout << "oldParam2: " << row.oldParam2 << std::endl;
std::cout << "oldMeta: " << row.oldMeta << std::endl;
std::cout << "newNode: " << row.newNode << std::endl;
std::cout << "newParam1: " << row.newParam1 << std::endl;
std::cout << "newParam2: " << row.newParam2 << std::endl;
std::cout << "newMeta: " << row.newMeta << std::endl;
std::cout << "guessed: " << row.guessed << std::endl;
}
*/
if
(
i
==
0
)
{
t
=
time
(
0
);
sqlite3_exec
(
dbh
,
"BEGIN"
,
NULL
,
NULL
,
NULL
);
}
SQL_registerRow
(
row
);
++
i
;
if
(
time
(
0
)
-
t
)
{
sqlite3_exec
(
dbh
,
"COMMIT"
,
NULL
,
NULL
,
NULL
);
t
=
time
(
0
)
-
t
;
std
::
cout
<<
" Done: "
<<
(
int
)(((
float
)
fh
.
tellg
()
/
(
float
)
filesize
)
*
100
)
<<
"%"
<<
"
\t
Speed: "
<<
i
/
t
<<
" actions inserted per second "
<<
"
\r
"
;
std
::
cout
.
flush
();
i
=
0
;
}
++
id
;
}
while
(
!
fh
.
eof
()
&&
fh
.
good
());
}
std
::
cout
<<
" Done: 100%"
<<
std
::
endl
<<
" Now you can delete the old rollback.txt file."
<<
std
::
endl
;
}
// Get nearness factor for subject's action for this action
// Return value: 0 = impossible, >0 = factor
static
float
getSuspectNearness
(
bool
is_guess
,
v3s16
suspect_p
,
int
suspect_t
,
...
...
@@ -56,38 +921,43 @@ static float getSuspectNearness(bool is_guess, v3s16 suspect_p, int suspect_t,
f
=
0
;
return
f
;
}
class
RollbackManager
:
public
IRollbackManager
{
public:
// IRollbackManager interface
void
reportAction
(
const
RollbackAction
&
action_
)
{
// Ignore if not important
if
(
!
action_
.
isImportant
(
m_gamedef
))
if
(
!
action_
.
isImportant
(
m_gamedef
))
return
;
RollbackAction
action
=
action_
;
action
.
unix_time
=
time
(
0
);
// Figure out actor
action
.
actor
=
m_current_actor
;
action
.
actor_is_guess
=
m_current_actor_is_guess
;
// If actor is not known, find out suspect or cancel
if
(
action
.
actor
.
empty
()){
if
(
action
.
actor
.
empty
())
// If actor is not known, find out suspect or cancel
{
v3s16
p
;
if
(
!
action
.
getPosition
(
&
p
))
if
(
!
action
.
getPosition
(
&
p
))
return
;
action
.
actor
=
getSuspect
(
p
,
83
,
1
);
if
(
action
.
actor
.
empty
())
if
(
action
.
actor
.
empty
())
return
;
action
.
actor_is_guess
=
true
;
}
infostream
<<
"RollbackManager::reportAction():"
<<
" time="
<<
action
.
unix_time
<<
" actor=
\"
"
<<
action
.
actor
<<
"
\"
"
<<
(
action
.
actor_is_guess
?
" (guess)"
:
""
)
<<
" action="
<<
action
.
toString
()
<<
std
::
endl
;
infostream
<<
"RollbackManager::reportAction():"
<<
" time="
<<
action
.
unix_time
<<
" actor=
\"
"
<<
action
.
actor
<<
"
\"
"
<<
(
action
.
actor_is_guess
?
" (guess)"
:
""
)
<<
" action="
<<
action
.
toString
()
<<
std
::
endl
;
addAction
(
action
);
}
std
::
string
getActor
()
...
...
@@ -140,213 +1010,131 @@ class RollbackManager: public IRollbackManager
}
void
flush
()
{
infostream
<<
"RollbackManager::flush()"
<<
std
::
endl
;
std
::
ofstream
of
(
m_filepath
.
c_str
(),
std
::
ios
::
app
);
if
(
!
of
.
good
()){
errorstream
<<
"RollbackManager::flush(): Could not open file "
<<
"for appending:
\"
"
<<
m_filepath
<<
"
\"
"
<<
std
::
endl
;
return
;
}
for
(
std
::
list
<
RollbackAction
>::
const_iterator
i
=
m_action_todisk_buffer
.
begin
();
i
!=
m_action_todisk_buffer
.
end
();
i
++
)
infostream
<<
"RollbackManager::flush()"
<<
std
::
endl
;
sqlite3_exec
(
dbh
,
"BEGIN"
,
NULL
,
NULL
,
NULL
);
std
::
list
<
RollbackAction
>::
const_iterator
iter
;
for
(
iter
=
m_action_todisk_buffer
.
begin
();
iter
!=
m_action_todisk_buffer
.
end
();
iter
++
)
{
// Do not save stuff that does not have an actor
if
(
i
->
actor
==
""
)
if
(
iter
->
actor
==
""
)
continue
;
of
<<
i
->
unix_time
;
of
<<
" "
;
of
<<
serializeJsonString
(
i
->
actor
);
of
<<
" "
;
of
<<
i
->
toString
();
if
(
i
->
actor_is_guess
){
of
<<
" "
;
of
<<
"actor_is_guess"
;
}
of
<<
std
::
endl
;
SQL_registerRow
(
actionRowFromRollbackAction
(
*
iter
));
}
sqlite3_exec
(
dbh
,
"COMMIT"
,
NULL
,
NULL
,
NULL
);
m_action_todisk_buffer
.
clear
();
}
// Other
RollbackManager
(
const
std
::
string
&
filepath
,
IGameDef
*
gamedef
)
:
m_filepath
(
filepath
),
m_gamedef
(
gamedef
),
m_current_actor_is_guess
(
false
)
{
infostream
<<
"RollbackManager::RollbackManager("
<<
filepath
<<
")"
<<
std
::
endl
;
infostream
<<
"RollbackManager::RollbackManager("
<<
filepath
<<
")"
<<
std
::
endl
;
// Operate correctly in case of still being given rollback.txt as filepath
std
::
string
directory
=
filepath
.
substr
(
0
,
filepath
.
rfind
(
DIR_DELIM
)
+
1
);
std
::
string
filenameOld
=
filepath
.
substr
(
1
+
filepath
.
rfind
(
DIR_DELIM
));
std
::
string
filenameNew
=
(
filenameOld
==
"rollback.txt"
)
?
"rollback.sqlite"
:
filenameOld
;
std
::
string
filenameTXT
=
directory
+
"rollback.txt"
;
std
::
string
migratingFlag
=
filepath
;
migratingFlag
.
append
(
".migrating"
);
infostream
<<
"Directory: "
<<
directory
<<
std
::
endl
;
infostream
<<
"CheckFor: "
<<
filenameTXT
<<
std
::
endl
;
infostream
<<
"FileOld: "
<<
filenameOld
<<
std
::
endl
;
infostream
<<
"FileNew: "
<<
filenameNew
<<
std
::
endl
;
dbp
=
directory
+
filenameNew
;
if
((
fs
::
PathExists
(
filenameTXT
)
&&
fs
::
PathExists
(
migratingFlag
))
||
(
fs
::
PathExists
(
filenameTXT
)
&&
!
fs
::
PathExists
(
dbp
)))
{
std
::
ofstream
of
(
migratingFlag
.
c_str
());
TXT_migrate
(
filenameTXT
);
fs
::
DeleteSingleFileOrEmptyDirectory
(
migratingFlag
);
}
SQL_databaseCheck
();
}
~
RollbackManager
()
{
infostream
<<
"RollbackManager::~RollbackManager()"
<<
std
::
endl
;
infostream
<<
"RollbackManager::~RollbackManager()"
<<
std
::
endl
;
flush
();
}
void
addAction
(
const
RollbackAction
&
action
)
{
m_action_todisk_buffer
.
push_back
(
action
);
m_action_latest_buffer
.
push_back
(
action
);
// Flush to disk sometimes
if
(
m_action_todisk_buffer
.
size
()
>=
1
00
)
if
(
m_action_todisk_buffer
.
size
()
>=
5
00
)
flush
();
}
bool
readFile
(
std
::
list
<
RollbackAction
>
&
dst
)
{
// Load whole file to memory
std
::
ifstream
f
(
m_filepath
.
c_str
(),
std
::
ios
::
in
);
if
(
!
f
.
good
()){
errorstream
<<
"RollbackManager::readFile(): Could not open "
<<
"file for reading:
\"
"
<<
m_filepath
<<
"
\"
"
<<
std
::
endl
;
return
false
;
}
for
(;;){
if
(
f
.
eof
()
||
!
f
.
good
())
break
;
std
::
string
line
;
std
::
getline
(
f
,
line
);
line
=
trim
(
line
);
if
(
line
==
""
)
continue
;
std
::
istringstream
is
(
line
);
try
{
std
::
string
action_time_raw
;
std
::
getline
(
is
,
action_time_raw
,
' '
);
std
::
string
action_actor
;
try
{
action_actor
=
deSerializeJsonString
(
is
);
}
catch
(
SerializationError
&
e
){
errorstream
<<
"RollbackManager: Error deserializing actor: "
<<
e
.
what
()
<<
std
::
endl
;
throw
e
;
}
RollbackAction
action
;
action
.
unix_time
=
stoi
(
action_time_raw
);
action
.
actor
=
action_actor
;
int
c
=
is
.
get
();
if
(
c
!=
' '
){
is
.
putback
(
c
);
throw
SerializationError
(
"readFile(): second ' ' not found"
);
}
action
.
fromStream
(
is
);
/*infostream<<"RollbackManager::readFile(): Action from disk: "
<<action.toString()<<std::endl;*/
dst
.
push_back
(
action
);
}
catch
(
SerializationError
&
e
){
errorstream
<<
"RollbackManager: Error on line: "
<<
line
<<
std
::
endl
;
errorstream
<<
"RollbackManager: ^ error: "
<<
e
.
what
()
<<
std
::
endl
;
}
}
return
true
;
}
std
::
list
<
RollbackAction
>
getEntriesSince
(
int
first_time
)
{
infostream
<<
"RollbackManager::getEntriesSince("
<<
first_time
<<
")"
<<
std
::
endl
;
// Collect enough data to this buffer
std
::
list
<
RollbackAction
>
action_buffer
;
// Use the latest buffer if it is long enough
if
(
!
m_action_latest_buffer
.
empty
()
&&
m_action_latest_buffer
.
begin
()
->
unix_time
<=
first_time
){
action_buffer
=
m_action_latest_buffer
;
}
else
{
// Save all remaining stuff
flush
();
// Load whole file to memory
bool
good
=
readFile
(
action_buffer
);
if
(
!
good
){
errorstream
<<
"RollbackManager::getEntriesSince(): Failed to"
<<
" open file; using data in memory."
<<
std
::
endl
;
action_buffer
=
m_action_latest_buffer
;
}
}
return
action_buffer
;
infostream
<<
"RollbackManager::getEntriesSince("
<<
first_time
<<
")"
<<
std
::
endl
;
flush
();
std
::
list
<
RollbackAction
>
result
=
SQL_getActionsSince
(
first_time
);
return
result
;
}
std
::
string
getLastNodeActor
(
v3s16
p
,
int
range
,
int
seconds
,
v3s16
*
act_p
,
int
*
act_seconds
)
std
::
string
getLastNodeActor
(
v3s16
p
,
int
range
,
int
seconds
,
v3s16
*
act_p
,
int
*
act_seconds
)
{
infostream
<<
"RollbackManager::getLastNodeActor("
<<
PP
(
p
)
<<
", "
<<
seconds
<<
")"
<<
std
::
endl
;
// Figure out time
int
cur_time
=
time
(
0
);
int
first_time
=
cur_time
-
seconds
;
std
::
list
<
RollbackAction
>
action_buffer
=
getEntriesSince
(
first_time
);
std
::
list
<
RollbackAction
>
result
;
std
::
list
<
RollbackAction
>
action_buffer
=
SQL_getActionsSince_range
(
first_time
,
p
,
range
);
std
::
list
<
RollbackAction
>::
const_reverse_iterator
iter
;
for
(
std
::
list
<
RollbackAction
>::
const_reverse_iterator
i
=
action_buffer
.
r
begin
();
i
!=
action_buffer
.
rend
();
i
++
)
for
(
iter
=
action_buffer
.
rbegin
();
iter
!
=
action_buffer
.
r
end
();
iter
++
)
{
if
(
i
->
unix_time
<
first_time
)
break
;
// Find position of action or continue
v3s16
action_p
;
if
(
!
i
->
getPosition
(
&
action_p
))
continue
;
if
(
range
==
0
){
if
(
action_p
!=
p
)
continue
;
}
else
{
if
(
abs
(
action_p
.
X
-
p
.
X
)
>
range
||
abs
(
action_p
.
Y
-
p
.
Y
)
>
range
||
abs
(
action_p
.
Z
-
p
.
Z
)
>
range
)
continue
;
}
action_p
.
X
=
iter
->
p
.
X
;
action_p
.
Y
=
iter
->
p
.
Y
;
action_p
.
Z
=
iter
->
p
.
Z
;
if
(
act_p
)
if
(
act_p
)
*
act_p
=
action_p
;
if
(
act_seconds
)
*
act_seconds
=
cur_time
-
i
->
unix_time
;
return
i
->
actor
;
if
(
act_seconds
)
*
act_seconds
=
cur_time
-
iter
->
unix_time
;
return
iter
->
actor
;
}
return
""
;
}
std
::
list
<
RollbackAction
>
getRevertActions
(
const
std
::
string
&
actor_filter
,
int
seconds
)
std
::
list
<
RollbackAction
>
getRevertActions
(
const
std
::
string
&
actor_filter
,
int
seconds
)
{
infostream
<<
"RollbackManager::getRevertActions("
<<
actor_filter
<<
", "
<<
seconds
<<
")"
<<
std
::
endl
;
infostream
<<
"RollbackManager::getRevertActions("
<<
actor_filter
<<
", "
<<
seconds
<<
")"
<<
std
::
endl
;
// Figure out time
int
cur_time
=
time
(
0
);
int
first_time
=
cur_time
-
seconds
;
std
::
list
<
RollbackAction
>
action_buffer
=
getEntriesSince
(
first_time
);
flush
(
);
std
::
list
<
RollbackAction
>
result
;
for
(
std
::
list
<
RollbackAction
>::
const_reverse_iterator
i
=
action_buffer
.
rbegin
();
i
!=
action_buffer
.
rend
();
i
++
)
{
if
(
i
->
unix_time
<
first_time
)
break
;
if
(
i
->
actor
!=
actor_filter
)
continue
;
const
RollbackAction
&
action
=
*
i
;
/*infostream<<"RollbackManager::revertAction(): Should revert"
<<" time="<<action.unix_time
<<" actor=\""<<action.actor<<"\""
<<" action="<<action.toString()
<<std::endl;*/
result
.
push_back
(
action
);
}
std
::
list
<
RollbackAction
>
result
=
SQL_getActionsSince
(
first_time
,
actor_filter
);
return
result
;
}
private
:
std
::
string
m_filepath
;
IGameDef
*
m_gamedef
;
...
...
@@ -360,5 +1148,3 @@ IRollbackManager *createRollbackManager(const std::string &filepath, IGameDef *g
{
return
new
RollbackManager
(
filepath
,
gamedef
);
}
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