Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
c83ffcfc
Commit
c83ffcfc
authored
Aug 24, 2007
by
Rich Prohaska
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
get tree cursor set last working
git-svn-id:
file:///svn/tokudb@186
c7de825b-a66e-492c-adef-691d508d4ae1
parent
7e429177
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
229 additions
and
55 deletions
+229
-55
newbrt/brt-test.c
newbrt/brt-test.c
+142
-7
newbrt/brt.c
newbrt/brt.c
+87
-48
No files found.
newbrt/brt-test.c
View file @
c83ffcfc
...
...
@@ -809,7 +809,7 @@ static void test_wrongendian_compare (int wrong_p, unsigned int N) {
memory_check_all_free
();
}
void
assert_tree_first
(
BRT
brt
,
long
long
firstv
__attribute__
((
unused
)),
long
long
lastv
__attribute__
((
unused
))
)
{
void
assert_tree_first
(
BRT
brt
,
long
long
firstv
)
{
BRT_CURSOR
cursor
;
int
r
;
DBT
kbt
,
vbt
;
...
...
@@ -817,7 +817,7 @@ void assert_tree_first(BRT brt, long long firstv __attribute__((unused)), long l
r
=
brt_cursor
(
brt
,
&
cursor
);
assert
(
r
==
0
);
#if 1
printf
(
"first key: "
);
init_dbt
(
&
kbt
);
kbt
.
flags
=
DB_DBT_MALLOC
;
init_dbt
(
&
vbt
);
vbt
.
flags
=
DB_DBT_MALLOC
;
...
...
@@ -830,8 +830,20 @@ void assert_tree_first(BRT brt, long long firstv __attribute__((unused)), long l
toku_free
(
kbt
.
data
);
toku_free
(
vbt
.
data
);
printf
(
"
\n
"
);
#endif
#if 0
r
=
brt_cursor_close
(
cursor
);
assert
(
r
==
0
);
}
void
assert_tree_last
(
BRT
brt
,
long
long
lastv
)
{
BRT_CURSOR
cursor
;
int
r
;
DBT
kbt
,
vbt
;
long
long
v
;
r
=
brt_cursor
(
brt
,
&
cursor
);
assert
(
r
==
0
);
printf
(
"last key:"
);
init_dbt
(
&
kbt
);
kbt
.
flags
=
DB_DBT_MALLOC
;
init_dbt
(
&
vbt
);
vbt
.
flags
=
DB_DBT_MALLOC
;
...
...
@@ -844,7 +856,46 @@ void assert_tree_first(BRT brt, long long firstv __attribute__((unused)), long l
toku_free
(
kbt
.
data
);
toku_free
(
vbt
.
data
);
printf
(
"
\n
"
);
#endif
r
=
brt_cursor_close
(
cursor
);
assert
(
r
==
0
);
}
void
assert_tree_first_last
(
BRT
brt
,
long
long
firstv
,
long
long
lastv
)
{
BRT_CURSOR
cursor
;
int
r
;
DBT
kbt
,
vbt
;
long
long
v
;
r
=
brt_cursor
(
brt
,
&
cursor
);
assert
(
r
==
0
);
printf
(
"first key: "
);
init_dbt
(
&
kbt
);
kbt
.
flags
=
DB_DBT_MALLOC
;
init_dbt
(
&
vbt
);
vbt
.
flags
=
DB_DBT_MALLOC
;
r
=
brt_c_get
(
cursor
,
&
kbt
,
&
vbt
,
DB_FIRST
);
assert
(
r
==
0
);
printf
(
"%s "
,
(
char
*
)
kbt
.
data
);
assert
(
vbt
.
size
==
sizeof
v
);
memcpy
(
&
v
,
vbt
.
data
,
vbt
.
size
);
assert
(
v
==
firstv
);
toku_free
(
kbt
.
data
);
toku_free
(
vbt
.
data
);
printf
(
"
\n
"
);
printf
(
"last key:"
);
init_dbt
(
&
kbt
);
kbt
.
flags
=
DB_DBT_MALLOC
;
init_dbt
(
&
vbt
);
vbt
.
flags
=
DB_DBT_MALLOC
;
r
=
brt_c_get
(
cursor
,
&
kbt
,
&
vbt
,
DB_LAST
);
assert
(
r
==
0
);
printf
(
"%s "
,
(
char
*
)
kbt
.
data
);
assert
(
vbt
.
size
==
sizeof
v
);
memcpy
(
&
v
,
vbt
.
data
,
vbt
.
size
);
assert
(
v
==
lastv
);
toku_free
(
kbt
.
data
);
toku_free
(
vbt
.
data
);
printf
(
"
\n
"
);
r
=
brt_cursor_close
(
cursor
);
assert
(
r
==
0
);
}
...
...
@@ -879,7 +930,85 @@ void test_brt_cursor_first(int n) {
assert
(
r
==
0
);
}
assert_tree_first
(
brt
,
0
,
n
-
1
);
assert_tree_first
(
brt
,
0
);
r
=
close_brt
(
brt
);
assert
(
r
==
0
);
r
=
cachetable_close
(
&
ct
);
assert
(
r
==
0
);
}
void
test_brt_cursor_last
(
int
n
)
{
const
char
*
fname
=
"testbrt.brt"
;
CACHETABLE
ct
;
BRT
brt
;
int
r
;
int
i
;
printf
(
"test_brt_cursor_last:%d
\n
"
,
n
);
unlink
(
fname
);
r
=
brt_create_cachetable
(
&
ct
,
0
);
assert
(
r
==
0
);
r
=
open_brt
(
fname
,
0
,
1
,
&
brt
,
1
<<
12
,
ct
,
default_compare_fun
);
assert
(
r
==
0
);
/* insert a bunch of kv pairs */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
char
key
[
8
];
long
long
v
;
DBT
kbt
,
vbt
;
snprintf
(
key
,
sizeof
key
,
"%4.4d"
,
i
);
fill_dbt
(
&
kbt
,
key
,
strlen
(
key
)
+
1
);
v
=
i
;
fill_dbt
(
&
vbt
,
&
v
,
sizeof
v
);
r
=
brt_insert
(
brt
,
&
kbt
,
&
vbt
,
0
);
assert
(
r
==
0
);
}
assert_tree_last
(
brt
,
n
-
1
);
r
=
close_brt
(
brt
);
assert
(
r
==
0
);
r
=
cachetable_close
(
&
ct
);
assert
(
r
==
0
);
}
void
test_brt_cursor_first_last
(
int
n
)
{
const
char
*
fname
=
"testbrt.brt"
;
CACHETABLE
ct
;
BRT
brt
;
int
r
;
int
i
;
printf
(
"test_brt_cursor_first_last:%d
\n
"
,
n
);
unlink
(
fname
);
r
=
brt_create_cachetable
(
&
ct
,
0
);
assert
(
r
==
0
);
r
=
open_brt
(
fname
,
0
,
1
,
&
brt
,
1
<<
12
,
ct
,
default_compare_fun
);
assert
(
r
==
0
);
/* insert a bunch of kv pairs */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
char
key
[
8
];
long
long
v
;
DBT
kbt
,
vbt
;
snprintf
(
key
,
sizeof
key
,
"%4.4d"
,
i
);
fill_dbt
(
&
kbt
,
key
,
strlen
(
key
)
+
1
);
v
=
i
;
fill_dbt
(
&
vbt
,
&
v
,
sizeof
v
);
r
=
brt_insert
(
brt
,
&
kbt
,
&
vbt
,
0
);
assert
(
r
==
0
);
}
assert_tree_first_last
(
brt
,
0
,
n
-
1
);
r
=
close_brt
(
brt
);
assert
(
r
==
0
);
...
...
@@ -918,7 +1047,7 @@ void test_brt_cursor_rfirst(int n) {
assert
(
r
==
0
);
}
assert_tree_first
(
brt
,
0
,
n
-
1
);
assert_tree_first
(
brt
,
0
);
r
=
close_brt
(
brt
);
assert
(
r
==
0
);
...
...
@@ -1170,12 +1299,18 @@ void test_brt_cursor_split(int n) {
void
test_brt_cursor
()
{
int
n
;
if
(
1
)
for
(
n
=
100
;
n
<
10000
;
n
+=
100
)
{
test_brt_cursor_last
(
n
);
memory_check_all_free
();
}
if
(
1
)
for
(
n
=
100
;
n
<
10000
;
n
+=
100
)
{
test_brt_cursor_first
(
n
);
memory_check_all_free
();
}
if
(
1
)
for
(
n
=
100
;
n
<
10000
;
n
+=
100
)
{
test_brt_cursor_rfirst
(
n
);
memory_check_all_free
();
}
if
(
1
)
for
(
n
=
100
;
n
<
10000
;
n
+=
100
)
{
test_brt_cursor_first_last
(
n
);
memory_check_all_free
();
}
if
(
1
)
for
(
n
=
100
;
n
<
10000
;
n
+=
100
)
{
test_brt_cursor_walk
(
n
);
memory_check_all_free
();
}
...
...
newbrt/brt.c
View file @
c83ffcfc
...
...
@@ -1530,11 +1530,13 @@ int brtnode_flush_child (BRT brt, BRTNODE node, int cnum) {
abort
();
/* Algorithm: For each key in the cnum'th mdict, insert it to the childnode. It may cause a split. */
}
int
brt_flush_debug
=
0
;
/*
* Flush the buffer for a child of a node.
Handle child splits by extending the
*
current node and splitting when full. Follow the cursor path up the tree
*
until the root has been reached or the current node has not split. If the
*
root is reached, then create a new root for the tree.
* Flush the buffer for a child of a node.
*
If the node split when pushing kvpairs to a child of the node
*
then reflect the node split up the cursor path towards the tree root.
*
If the root is reached then create a new root
*/
void
brt_flush_child
(
BRT
t
,
BRTNODE
node
,
int
childnum
,
BRT_CURSOR
cursor
)
{
int
r
;
...
...
@@ -1542,18 +1544,19 @@ void brt_flush_child(BRT t, BRTNODE node, int childnum, BRT_CURSOR cursor) {
BRTNODE
childa
,
childb
;
DBT
child_splitk
;
#if 0
if
(
brt_flush_debug
)
{
printf
(
"brt_flush_child %lld %d
\n
"
,
node
->
thisnodename
,
childnum
);
brt_cursor_print
(
cursor
);
#endif
}
init_dbt
(
&
child_splitk
);
r
=
push_some_kvpairs_down
(
t
,
node
,
childnum
,
&
child_did_split
,
&
childa
,
&
childb
,
&
child_splitk
,
0
,
0
,
0
);
&
child_did_split
,
&
childa
,
&
childb
,
&
child_splitk
,
brt_flush_debug
,
0
,
0
);
assert
(
r
==
0
);
#if 0
if
(
brt_flush_debug
)
{
printf
(
"brt_flush_child done %lld %d
\n
"
,
node
->
thisnodename
,
childnum
);
brt_cursor_print
(
cursor
);
#endif
}
if
(
child_did_split
)
{
int
i
;
...
...
@@ -1564,9 +1567,8 @@ void brt_flush_child(BRT t, BRTNODE node, int childnum, BRT_CURSOR cursor) {
assert
(
i
==
cursor
->
path_len
-
1
);
while
(
child_did_split
)
{
child_did_split
=
0
;
#if 0
printf("child_did_split %lld %lld\n", childa->thisnodename, childb->thisnodename);
#endif
if
(
0
)
printf
(
"child_did_split %lld %lld
\n
"
,
childa
->
thisnodename
,
childb
->
thisnodename
);
if
(
i
==
0
)
{
CACHEKEY
*
rootp
=
calculate_root_offset_pointer
(
t
);
r
=
brt_init_new_root
(
t
,
childa
,
childb
,
child_splitk
,
rootp
);
...
...
@@ -1597,12 +1599,6 @@ void brt_node_add_cursor(BRTNODE node, int childnum, BRT_CURSOR cursor) {
if
(
node
->
height
>
0
)
{
if
(
0
)
printf
(
"brt_node_add_cursor %lld %d %p
\n
"
,
node
->
thisnodename
,
childnum
,
cursor
);
node
->
u
.
n
.
n_cursors
[
childnum
]
+=
1
;
#if 0
if (node->u.n.n_bytes_in_hashtable[childnum] > 0) {
if (0) printf("hashtable not empty %d\n", node->u.n.n_bytes_in_hashtable[childnum]);
brt_node_flush_child(cursor->brt, node, childnum, cursor);
}
#endif
}
}
...
...
@@ -1617,10 +1613,12 @@ void brt_node_remove_cursor(BRTNODE node, int childnum, BRT_CURSOR cursor __attr
}
}
int
brt_update_debug
=
0
;
void
brt_update_cursors_new_root
(
BRT
t
,
BRTNODE
newroot
,
BRTNODE
left
,
BRTNODE
right
)
{
BRT_CURSOR
cursor
;
if
(
0
)
printf
(
"brt_update_cursors_new_root %lld %lld %lld
\n
"
,
newroot
->
thisnodename
,
if
(
brt_update_debug
)
printf
(
"brt_update_cursors_new_root %lld %lld %lld
\n
"
,
newroot
->
thisnodename
,
left
->
thisnodename
,
right
->
thisnodename
);
for
(
cursor
=
t
->
cursors_head
;
cursor
;
cursor
=
cursor
->
next
)
{
if
(
brt_cursor_active
(
cursor
))
{
...
...
@@ -1632,7 +1630,7 @@ void brt_update_cursors_new_root(BRT t, BRTNODE newroot, BRTNODE left, BRTNODE r
void
brt_update_cursors_leaf_split
(
BRT
t
,
BRTNODE
oldnode
,
BRTNODE
left
,
BRTNODE
right
)
{
BRT_CURSOR
cursor
;
if
(
0
)
printf
(
"brt_update_cursors_leaf_split %lld %lld %lld
\n
"
,
oldnode
->
thisnodename
,
if
(
brt_update_debug
)
printf
(
"brt_update_cursors_leaf_split %lld %lld %lld
\n
"
,
oldnode
->
thisnodename
,
left
->
thisnodename
,
right
->
thisnodename
);
for
(
cursor
=
t
->
cursors_head
;
cursor
;
cursor
=
cursor
->
next
)
{
if
(
brt_cursor_active
(
cursor
))
{
...
...
@@ -1644,7 +1642,7 @@ void brt_update_cursors_leaf_split(BRT t, BRTNODE oldnode, BRTNODE left, BRTNODE
void
brt_update_cursors_nonleaf_expand
(
BRT
t
,
BRTNODE
node
,
int
childnum
,
BRTNODE
left
,
BRTNODE
right
)
{
BRT_CURSOR
cursor
;
if
(
0
)
printf
(
"brt_update_cursors_nonleaf_expand %lld h=%d c=%d nc=%d %lld %lld
\n
"
,
node
->
thisnodename
,
node
->
height
,
childnum
,
if
(
brt_update_debug
)
printf
(
"brt_update_cursors_nonleaf_expand %lld h=%d c=%d nc=%d %lld %lld
\n
"
,
node
->
thisnodename
,
node
->
height
,
childnum
,
node
->
u
.
n
.
n_children
,
left
->
thisnodename
,
right
->
thisnodename
);
for
(
cursor
=
t
->
cursors_head
;
cursor
;
cursor
=
cursor
->
next
)
{
if
(
brt_cursor_active
(
cursor
))
{
...
...
@@ -1656,7 +1654,7 @@ void brt_update_cursors_nonleaf_expand(BRT t, BRTNODE node, int childnum, BRTNOD
void
brt_update_cursors_nonleaf_split
(
BRT
t
,
BRTNODE
oldnode
,
BRTNODE
left
,
BRTNODE
right
)
{
BRT_CURSOR
cursor
;
if
(
0
)
printf
(
"brt_update_cursors_nonleaf_split %lld %lld %lld
\n
"
,
oldnode
->
thisnodename
,
if
(
brt_update_debug
)
printf
(
"brt_update_cursors_nonleaf_split %lld %lld %lld
\n
"
,
oldnode
->
thisnodename
,
left
->
thisnodename
,
right
->
thisnodename
);
for
(
cursor
=
t
->
cursors_head
;
cursor
;
cursor
=
cursor
->
next
)
{
if
(
brt_cursor_active
(
cursor
))
{
...
...
@@ -1856,7 +1854,7 @@ void brt_cursor_print(BRT_CURSOR cursor) {
for
(
i
=
0
;
i
<
cursor
->
path_len
;
i
++
)
{
printf
(
"%lld"
,
cursor
->
path
[
i
]
->
thisnodename
);
if
(
cursor
->
path
[
i
]
->
height
>
0
)
printf
(
",%d
"
,
cursor
->
pathcnum
[
i
]
);
printf
(
",%d
:%d "
,
cursor
->
pathcnum
[
i
],
cursor
->
path
[
i
]
->
u
.
n
.
n_children
);
else
printf
(
" "
);
}
...
...
@@ -1866,7 +1864,6 @@ void brt_cursor_print(BRT_CURSOR cursor) {
int
brtcurs_set_position_last
(
BRT_CURSOR
cursor
,
diskoff
off
)
{
BRT
brt
=
cursor
->
brt
;
void
*
node_v
;
int
more
;
int
r
=
cachetable_get_and_pin
(
brt
->
cf
,
off
,
&
node_v
,
brtnode_flush_callback
,
brtnode_fetch_callback
,
(
void
*
)(
long
)
brt
->
h
->
nodesize
);
...
...
@@ -1878,17 +1875,25 @@ int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off) {
assert
(
cursor
->
path_len
<
CURSOR_PATHLEN_LIMIT
);
cursor
->
path
[
cursor
->
path_len
++
]
=
node
;
if
(
node
->
height
>
0
)
{
int
childnum
=
node
->
u
.
n
.
n_children
-
1
;
int
childnum
;
try_last_child:
childnum
=
node
->
u
.
n
.
n_children
-
1
;
try_prev_child:
cursor
->
pathcnum
[
cursor
->
path_len
-
1
]
=
childnum
;
brt_node_add_cursor
(
node
,
childnum
,
cursor
);
for
(;;)
{
more
=
node
->
u
.
n
.
n_bytes_in_hashtable
[
childnum
];
if
(
more
==
0
)
break
;
if
(
node
->
u
.
n
.
n_bytes_in_hashtable
[
childnum
]
>
0
)
{
brt_flush_child
(
cursor
->
brt
,
node
,
childnum
,
cursor
);
/*
* the flush may have been partially successfull. it may have also
* changed the tree such that the current node have expanded or been
* replaced. lets start over.
*/
node
=
cursor
->
path
[
cursor
->
path_len
-
1
];
childnum
=
cursor
->
pathcnum
[
cursor
->
path_len
-
1
];
brt_node_remove_cursor
(
node
,
childnum
,
cursor
);
goto
try_last_child
;
}
r
=
brtcurs_set_position_last
(
cursor
,
node
->
u
.
n
.
children
[
childnum
]);
if
(
r
==
0
)
...
...
@@ -1920,7 +1925,6 @@ int brtcurs_set_position_last (BRT_CURSOR cursor, diskoff off) {
int
brtcurs_set_position_first
(
BRT_CURSOR
cursor
,
diskoff
off
)
{
BRT
brt
=
cursor
->
brt
;
void
*
node_v
;
int
more
;
int
r
=
cachetable_get_and_pin
(
brt
->
cf
,
off
,
&
node_v
,
brtnode_flush_callback
,
brtnode_fetch_callback
,
(
void
*
)(
long
)
brt
->
h
->
nodesize
);
...
...
@@ -1932,17 +1936,25 @@ int brtcurs_set_position_first (BRT_CURSOR cursor, diskoff off) {
assert
(
cursor
->
path_len
<
CURSOR_PATHLEN_LIMIT
);
cursor
->
path
[
cursor
->
path_len
++
]
=
node
;
if
(
node
->
height
>
0
)
{
int
childnum
=
0
;
int
childnum
;
try_first_child:
childnum
=
0
;
try_next_child:
cursor
->
pathcnum
[
cursor
->
path_len
-
1
]
=
childnum
;
brt_node_add_cursor
(
node
,
childnum
,
cursor
);
for
(;;)
{
more
=
node
->
u
.
n
.
n_bytes_in_hashtable
[
childnum
];
if
(
more
==
0
)
break
;
if
(
node
->
u
.
n
.
n_bytes_in_hashtable
[
childnum
]
>
0
)
{
brt_flush_child
(
cursor
->
brt
,
node
,
childnum
,
cursor
);
/*
* the flush may have been partially successfull. it may have also
* changed the tree such that the current node have expanded or been
* replaced. lets start over.
*/
node
=
cursor
->
path
[
cursor
->
path_len
-
1
];
childnum
=
cursor
->
pathcnum
[
cursor
->
path_len
-
1
];
brt_node_remove_cursor
(
node
,
childnum
,
cursor
);
goto
try_first_child
;
}
r
=
brtcurs_set_position_first
(
cursor
,
node
->
u
.
n
.
children
[
childnum
]);
if
(
r
==
0
)
...
...
@@ -2042,10 +2054,32 @@ static int unpin_cursor (BRT_CURSOR cursor) {
int
r2
=
cachetable_unpin
(
brt
->
cf
,
cursor
->
path
[
i
]
->
thisnodename
,
0
);
if
(
r
==
0
)
r
=
r2
;
}
if
(
cursor
->
pmacurs
)
{
r
=
pma_cursor_free
(
&
cursor
->
pmacurs
);
assert
(
r
==
0
);
}
cursor
->
path_len
=
0
;
return
r
;
}
static
void
assert_cursor_path
(
BRT_CURSOR
cursor
)
{
int
i
;
BRTNODE
node
;
int
child
;
if
(
cursor
->
path_len
<=
0
)
return
;
for
(
i
=
0
;
i
<
cursor
->
path_len
-
1
;
i
++
)
{
node
=
cursor
->
path
[
i
];
child
=
cursor
->
pathcnum
[
i
];
assert
(
node
->
height
>
0
);
assert
(
node
->
u
.
n
.
n_bytes_in_hashtable
[
child
]
==
0
);
assert
(
node
->
u
.
n
.
n_cursors
[
child
]
>
0
);
}
node
=
cursor
->
path
[
i
];
assert
(
node
->
height
==
0
);
}
int
brt_c_get
(
BRT_CURSOR
cursor
,
DBT
*
kbt
,
DBT
*
vbt
,
int
flags
)
{
int
do_rmw
=
0
;
int
r
;
...
...
@@ -2065,15 +2099,20 @@ int brt_c_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int flags) {
switch
(
flags
)
{
case
DB_LAST
:
r
=
unpin_cursor
(
cursor
);
if
(
r
!=
0
)
goto
died0
;
assert
(
cursor
->
pmacurs
==
0
);
r
=
brtcurs_set_position_last
(
cursor
,
*
rootp
);
if
(
r
!=
0
)
goto
died0
;
if
(
0
)
brt_cursor_print
(
cursor
);
r
=
pma_cget_current
(
cursor
->
pmacurs
,
kbt
,
vbt
);
if
(
r
==
0
)
assert_cursor_path
(
cursor
);
break
;
case
DB_FIRST
:
do_db_first:
r
=
unpin_cursor
(
cursor
);
if
(
r
!=
0
)
goto
died0
;
assert
(
cursor
->
pmacurs
==
0
);
r
=
brtcurs_set_position_first
(
cursor
,
*
rootp
);
if
(
r
!=
0
)
goto
died0
;
//
brt_cursor_print(cursor);
if
(
0
)
brt_cursor_print
(
cursor
);
r
=
pma_cget_current
(
cursor
->
pmacurs
,
kbt
,
vbt
);
if
(
r
==
0
)
assert_cursor_path
(
cursor
);
break
;
case
DB_NEXT
:
if
(
cursor
->
path_len
<=
0
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment