Skip to content

Commit 818e24c

Browse files
committed
implement truncate for spaces
This patch implements "crud.truncate" call. It's needed for spaces truncation. Closes #91
1 parent 186259d commit 818e24c

File tree

5 files changed

+229
-0
lines changed

5 files changed

+229
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1414
selecting by equality of partially specified multipart primary index
1515
value was misinterpreted as a selecting by fully specified key value.
1616

17+
### Added
18+
19+
* `truncate` operation
20+
1721
## [0.3.0] - 2020-10-26
1822

1923
### Fixed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,38 @@ for _, object in crud.pairs('customers', {{'<=', 'age', 35}}, {use_tomap = true}
335335
end
336336
```
337337

338+
### Truncate
339+
340+
```lua
341+
-- Truncate space
342+
local result, err = crud.truncate(space_name, opts)
343+
```
344+
345+
where:
346+
347+
* `space_name` (`string`) - name of the space
348+
* `opts`:
349+
* `timeout` (`?number`) - `vshard.call` timeout (in seconds)
350+
351+
Returns true or nil with error.
352+
353+
**Example:**
354+
355+
```lua
356+
#crud.select('customers', {{'<=', 'age', 35}})
357+
---
358+
- 1
359+
...
360+
crud.truncate('customers', {timeout = 2})
361+
---
362+
- true
363+
...
364+
#crud.select('customers', {{'<=', 'age', 35}})
365+
---
366+
- 0
367+
...
368+
```
369+
338370
## Cartridge roles
339371

340372
`cartridge.roles.crud-storage` is a Tarantool Cartridge role that depends on the

crud.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ local update = require('crud.update')
99
local upsert = require('crud.upsert')
1010
local delete = require('crud.delete')
1111
local select = require('crud.select')
12+
local truncate = require('crud.truncate')
1213
local utils = require('crud.common.utils')
1314

1415
local crud = {}
@@ -64,6 +65,10 @@ crud.pairs = select.pairs
6465
-- @function unflatten_rows
6566
crud.unflatten_rows = utils.unflatten_rows
6667

68+
-- @refer truncate.call
69+
-- @function truncate
70+
crud.truncate = truncate.call
71+
6772
--- Initializes crud on node
6873
--
6974
-- Exports all functions that are used for calls
@@ -83,6 +88,7 @@ function crud.init_storage()
8388
upsert.init()
8489
delete.init()
8590
select.init()
91+
truncate.init()
8692
end
8793

8894
function crud.init_router()

crud/truncate.lua

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
local checks = require('checks')
2+
local errors = require('errors')
3+
local vshard = require('vshard')
4+
5+
local dev_checks = require('crud.common.dev_checks')
6+
local call = require('crud.common.call')
7+
8+
local TruncateError = errors.new_class('Truncate', {capture_stack = false})
9+
10+
local truncate = {}
11+
12+
local TRUNCATE_FUNC_NAME = '_crud.truncate_on_storage'
13+
14+
local function truncate_on_storage(space_name)
15+
dev_checks('string')
16+
17+
local space = box.space[space_name]
18+
if space == nil then
19+
return nil, TruncateError:new("Space %q doesn't exist", space_name)
20+
end
21+
22+
return space:truncate()
23+
end
24+
25+
function truncate.init()
26+
_G._crud.truncate_on_storage = truncate_on_storage
27+
end
28+
29+
--- Truncates specified space
30+
--
31+
-- @function call
32+
--
33+
-- @param string space_name
34+
-- A space name
35+
--
36+
-- @tparam ?number opts.timeout
37+
-- Function call timeout
38+
--
39+
-- @return[1] boolean true
40+
-- @treturn[2] nil
41+
-- @treturn[2] table Error description
42+
--
43+
function truncate.call(space_name, opts)
44+
checks('string', {
45+
timeout = '?number',
46+
})
47+
48+
opts = opts or {}
49+
50+
local replicasets = vshard.router.routeall()
51+
local _, err = call.rw(TRUNCATE_FUNC_NAME, {space_name}, {
52+
replicasets = replicasets,
53+
timeout = opts.timeout,
54+
})
55+
56+
if err ~= nil then
57+
return nil, TruncateError:new("Failed to truncate: %s", err)
58+
end
59+
60+
return true
61+
end
62+
63+
return truncate

test/integration/truncate_test.lua

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
local fio = require('fio')
2+
3+
local t = require('luatest')
4+
local g_memtx = t.group('truncate_memtx')
5+
local g_vinyl = t.group('truncate_vinyl')
6+
7+
local helpers = require('test.helper')
8+
9+
math.randomseed(os.time())
10+
11+
local function before_all(g, engine)
12+
g.cluster = helpers.Cluster:new({
13+
datadir = fio.tempdir(),
14+
server_command = helpers.entrypoint('srv_select'),
15+
use_vshard = true,
16+
replicasets = {
17+
{
18+
uuid = helpers.uuid('a'),
19+
alias = 'router',
20+
roles = { 'customers-router' },
21+
servers = {
22+
{ instance_uuid = helpers.uuid('a', 1), alias = 'router' },
23+
},
24+
},
25+
{
26+
uuid = helpers.uuid('b'),
27+
alias = 's-1',
28+
roles = { 'customers-storage' },
29+
servers = {
30+
{ instance_uuid = helpers.uuid('b', 1), alias = 's1-master' },
31+
{ instance_uuid = helpers.uuid('b', 2), alias = 's1-replica' },
32+
},
33+
},
34+
{
35+
uuid = helpers.uuid('c'),
36+
alias = 's-2',
37+
roles = { 'customers-storage' },
38+
servers = {
39+
{ instance_uuid = helpers.uuid('c', 1), alias = 's2-master' },
40+
{ instance_uuid = helpers.uuid('c', 2), alias = 's2-replica' },
41+
},
42+
}
43+
},
44+
env = {
45+
['ENGINE'] = engine,
46+
},
47+
})
48+
g.engine = engine
49+
g.cluster:start()
50+
51+
g.space_format = g.cluster.servers[2].net_box.space.customers:format()
52+
end
53+
54+
g_memtx.before_all = function() before_all(g_memtx, 'memtx') end
55+
g_vinyl.before_all = function() before_all(g_vinyl, 'vinyl') end
56+
57+
local function after_all(g)
58+
g.cluster:stop()
59+
fio.rmtree(g.cluster.datadir)
60+
end
61+
62+
g_memtx.after_all = function() after_all(g_memtx) end
63+
g_vinyl.after_all = function() after_all(g_vinyl) end
64+
65+
local function before_each(g)
66+
for _, server in ipairs(g.cluster.servers) do
67+
server.net_box:eval([[
68+
local space = box.space.customers
69+
if space ~= nil and not box.cfg.read_only then
70+
space:truncate()
71+
end
72+
]])
73+
end
74+
end
75+
76+
g_memtx.before_each(function() before_each(g_memtx) end)
77+
g_vinyl.before_each(function() before_each(g_vinyl) end)
78+
79+
local function add(name, fn)
80+
g_memtx[name] = fn
81+
g_vinyl[name] = fn
82+
end
83+
84+
add('test_non_existent_space', function(g)
85+
-- insert
86+
local obj, err = g.cluster.main_server.net_box:call(
87+
'crud.truncate', {'non_existent_space'}
88+
)
89+
90+
t.assert_equals(obj, nil)
91+
t.assert_str_contains(err.err, "Space \"non_existent_space\" doesn't exist")
92+
end)
93+
94+
add('test_truncate', function(g)
95+
local customers = helpers.insert_objects(g, 'customers', {
96+
{
97+
id = 1, name = "Elizabeth", last_name = "Jackson",
98+
age = 12, city = "New York",
99+
}, {
100+
id = 2, name = "Mary", last_name = "Brown",
101+
age = 46, city = "Los Angeles",
102+
}, {
103+
id = 3, name = "David", last_name = "Smith",
104+
age = 33, city = "Los Angeles",
105+
}, {
106+
id = 4, name = "William", last_name = "White",
107+
age = 81, city = "Chicago",
108+
},
109+
})
110+
111+
table.sort(customers, function(obj1, obj2) return obj1.id < obj2.id end)
112+
113+
local result, err = g.cluster.main_server.net_box:call('crud.select', {'customers', nil})
114+
t.assert_equals(err, nil)
115+
t.assert(#result.rows > 0)
116+
117+
local result, err = g.cluster.main_server.net_box:call('crud.truncate', {'customers'})
118+
t.assert_equals(err, nil)
119+
t.assert_equals(result, true)
120+
121+
local result, err = g.cluster.main_server.net_box:call('crud.select', {'customers', nil})
122+
t.assert_equals(err, nil)
123+
t.assert(#result.rows == 0)
124+
end)

0 commit comments

Comments
 (0)