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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
7d1f0333
Commit
7d1f0333
authored
Jun 16, 2004
by
pekka@mysql.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tux optim 2 - use physical TUP address for index nodes
parent
547608f2
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
403 additions
and
336 deletions
+403
-336
ndb/include/kernel/signaldata/TupAccess.hpp
ndb/include/kernel/signaldata/TupAccess.hpp
+4
-2
ndb/src/kernel/blocks/dbtux/Dbtux.hpp
ndb/src/kernel/blocks/dbtux/Dbtux.hpp
+222
-176
ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
+28
-13
ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
+7
-10
ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
+3
-2
ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
+13
-13
ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
+28
-28
ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
+89
-90
ndb/src/kernel/blocks/dbtux/Times.txt
ndb/src/kernel/blocks/dbtux/Times.txt
+9
-2
No files found.
ndb/include/kernel/signaldata/TupAccess.hpp
View file @
7d1f0333
...
@@ -129,6 +129,8 @@ private:
...
@@ -129,6 +129,8 @@ private:
/*
/*
* Operate on entire tuple. Used by TUX where the table has a single
* Operate on entire tuple. Used by TUX where the table has a single
* Uint32 array attribute representing an index tree node.
* Uint32 array attribute representing an index tree node.
*
* XXX this signal will be replaced by method in TUP
*/
*/
class
TupStoreTh
{
class
TupStoreTh
{
friend
class
Dbtup
;
friend
class
Dbtup
;
...
@@ -153,8 +155,8 @@ private:
...
@@ -153,8 +155,8 @@ private:
Uint32
tableId
;
Uint32
tableId
;
Uint32
fragId
;
Uint32
fragId
;
Uint32
fragPtrI
;
Uint32
fragPtrI
;
Uint32
tupAddr
;
Uint32
tupAddr
;
// no longer used
Uint32
tupVersion
;
Uint32
tupVersion
;
// no longer used
Uint32
pageId
;
Uint32
pageId
;
Uint32
pageOffset
;
Uint32
pageOffset
;
Uint32
bufferId
;
Uint32
bufferId
;
...
...
ndb/src/kernel/blocks/dbtux/Dbtux.hpp
View file @
7d1f0333
This diff is collapsed.
Click to expand it.
ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
View file @
7d1f0333
...
@@ -97,7 +97,7 @@ Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out)
...
@@ -97,7 +97,7 @@ Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out)
PrintPar
par
;
PrintPar
par
;
strcpy
(
par
.
m_path
,
"."
);
strcpy
(
par
.
m_path
,
"."
);
par
.
m_side
=
2
;
par
.
m_side
=
2
;
par
.
m_parent
=
NullTup
Addr
;
par
.
m_parent
=
NullTup
Loc
;
printNode
(
signal
,
frag
,
out
,
tree
.
m_root
,
par
);
printNode
(
signal
,
frag
,
out
,
tree
.
m_root
,
par
);
out
.
m_out
->
flush
();
out
.
m_out
->
flush
();
if
(
!
par
.
m_ok
)
{
if
(
!
par
.
m_ok
)
{
...
@@ -116,15 +116,15 @@ Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out)
...
@@ -116,15 +116,15 @@ Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out)
}
}
void
void
Dbtux
::
printNode
(
Signal
*
signal
,
Frag
&
frag
,
NdbOut
&
out
,
Tup
Addr
addr
,
PrintPar
&
par
)
Dbtux
::
printNode
(
Signal
*
signal
,
Frag
&
frag
,
NdbOut
&
out
,
Tup
Loc
loc
,
PrintPar
&
par
)
{
{
if
(
addr
==
NullTupAddr
)
{
if
(
loc
==
NullTupLoc
)
{
par
.
m_depth
=
0
;
par
.
m_depth
=
0
;
return
;
return
;
}
}
TreeHead
&
tree
=
frag
.
m_tree
;
TreeHead
&
tree
=
frag
.
m_tree
;
NodeHandlePtr
nodePtr
;
NodeHandlePtr
nodePtr
;
selectNode
(
signal
,
frag
,
nodePtr
,
addr
,
AccFull
);
selectNode
(
signal
,
frag
,
nodePtr
,
loc
,
AccFull
);
out
<<
par
.
m_path
<<
" "
<<
*
nodePtr
.
p
<<
endl
;
out
<<
par
.
m_path
<<
" "
<<
*
nodePtr
.
p
<<
endl
;
// check children
// check children
PrintPar
cpar
[
2
];
PrintPar
cpar
[
2
];
...
@@ -133,7 +133,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
...
@@ -133,7 +133,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
sprintf
(
cpar
[
i
].
m_path
,
"%s%c"
,
par
.
m_path
,
"LR"
[
i
]);
sprintf
(
cpar
[
i
].
m_path
,
"%s%c"
,
par
.
m_path
,
"LR"
[
i
]);
cpar
[
i
].
m_side
=
i
;
cpar
[
i
].
m_side
=
i
;
cpar
[
i
].
m_depth
=
0
;
cpar
[
i
].
m_depth
=
0
;
cpar
[
i
].
m_parent
=
addr
;
cpar
[
i
].
m_parent
=
loc
;
printNode
(
signal
,
frag
,
out
,
nodePtr
.
p
->
getLink
(
i
),
cpar
[
i
]);
printNode
(
signal
,
frag
,
out
,
nodePtr
.
p
->
getLink
(
i
),
cpar
[
i
]);
if
(
!
cpar
[
i
].
m_ok
)
{
if
(
!
cpar
[
i
].
m_ok
)
{
par
.
m_ok
=
false
;
par
.
m_ok
=
false
;
...
@@ -143,7 +143,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
...
@@ -143,7 +143,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
if
(
nodePtr
.
p
->
getLink
(
2
)
!=
par
.
m_parent
)
{
if
(
nodePtr
.
p
->
getLink
(
2
)
!=
par
.
m_parent
)
{
par
.
m_ok
=
false
;
par
.
m_ok
=
false
;
out
<<
par
.
m_path
<<
" *** "
;
out
<<
par
.
m_path
<<
" *** "
;
out
<<
"parent
addr
"
<<
hex
<<
nodePtr
.
p
->
getLink
(
2
);
out
<<
"parent
loc
"
<<
hex
<<
nodePtr
.
p
->
getLink
(
2
);
out
<<
" should be "
<<
hex
<<
par
.
m_parent
<<
endl
;
out
<<
" should be "
<<
hex
<<
par
.
m_parent
<<
endl
;
}
}
if
(
nodePtr
.
p
->
getSide
()
!=
par
.
m_side
)
{
if
(
nodePtr
.
p
->
getSide
()
!=
par
.
m_side
)
{
...
@@ -181,8 +181,8 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
...
@@ -181,8 +181,8 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
}
}
// check missed half-leaf/leaf merge
// check missed half-leaf/leaf merge
for
(
unsigned
i
=
0
;
i
<=
1
;
i
++
)
{
for
(
unsigned
i
=
0
;
i
<=
1
;
i
++
)
{
if
(
nodePtr
.
p
->
getLink
(
i
)
!=
NullTup
Addr
&&
if
(
nodePtr
.
p
->
getLink
(
i
)
!=
NullTup
Loc
&&
nodePtr
.
p
->
getLink
(
1
-
i
)
==
NullTup
Addr
&&
nodePtr
.
p
->
getLink
(
1
-
i
)
==
NullTup
Loc
&&
nodePtr
.
p
->
getOccup
()
+
cpar
[
i
].
m_occup
<=
tree
.
m_maxOccup
)
{
nodePtr
.
p
->
getOccup
()
+
cpar
[
i
].
m_occup
<=
tree
.
m_maxOccup
)
{
par
.
m_ok
=
false
;
par
.
m_ok
=
false
;
out
<<
par
.
m_path
<<
" *** "
;
out
<<
par
.
m_path
<<
" *** "
;
...
@@ -194,6 +194,18 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
...
@@ -194,6 +194,18 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupAddr addr, PrintPar
par
.
m_occup
=
nodePtr
.
p
->
getOccup
();
par
.
m_occup
=
nodePtr
.
p
->
getOccup
();
}
}
NdbOut
&
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TupLoc
&
loc
)
{
if
(
loc
==
Dbtux
::
NullTupLoc
)
{
out
<<
"null"
;
}
else
{
out
<<
hex
<<
loc
.
m_pageId
;
out
<<
"."
<<
dec
<<
loc
.
m_pageOffset
;
}
return
out
;
}
NdbOut
&
NdbOut
&
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TreeEnt
&
ent
)
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TreeEnt
&
ent
)
{
{
...
@@ -206,10 +218,13 @@ operator<<(NdbOut& out, const Dbtux::TreeEnt& ent)
...
@@ -206,10 +218,13 @@ operator<<(NdbOut& out, const Dbtux::TreeEnt& ent)
NdbOut
&
NdbOut
&
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TreeNode
&
node
)
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TreeNode
&
node
)
{
{
Dbtux
::
TupLoc
link0
(
node
.
m_linkPI
[
0
],
node
.
m_linkPO
[
0
]);
Dbtux
::
TupLoc
link1
(
node
.
m_linkPI
[
1
],
node
.
m_linkPO
[
1
]);
Dbtux
::
TupLoc
link2
(
node
.
m_linkPI
[
2
],
node
.
m_linkPO
[
2
]);
out
<<
"[TreeNode "
<<
hex
<<
&
node
;
out
<<
"[TreeNode "
<<
hex
<<
&
node
;
out
<<
" [left "
<<
hex
<<
node
.
m_link
[
0
]
<<
"]"
;
out
<<
" [left "
<<
link0
<<
"]"
;
out
<<
" [right "
<<
hex
<<
node
.
m_link
[
1
]
<<
"]"
;
out
<<
" [right "
<<
link1
<<
"]"
;
out
<<
" [up "
<<
hex
<<
node
.
m_link
[
2
]
<<
"]"
;
out
<<
" [up "
<<
link2
<<
"]"
;
out
<<
" [side "
<<
dec
<<
node
.
m_side
<<
"]"
;
out
<<
" [side "
<<
dec
<<
node
.
m_side
<<
"]"
;
out
<<
" [occup "
<<
dec
<<
node
.
m_occup
<<
"]"
;
out
<<
" [occup "
<<
dec
<<
node
.
m_occup
<<
"]"
;
out
<<
" [balance "
<<
dec
<<
(
int
)
node
.
m_balance
<<
"]"
;
out
<<
" [balance "
<<
dec
<<
(
int
)
node
.
m_balance
<<
"]"
;
...
@@ -238,7 +253,7 @@ NdbOut&
...
@@ -238,7 +253,7 @@ NdbOut&
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TreePos
&
pos
)
operator
<<
(
NdbOut
&
out
,
const
Dbtux
::
TreePos
&
pos
)
{
{
out
<<
"[TreePos "
<<
hex
<<
&
pos
;
out
<<
"[TreePos "
<<
hex
<<
&
pos
;
out
<<
" [
addr "
<<
hex
<<
pos
.
m_addr
<<
"]"
;
out
<<
" [
loc "
<<
pos
.
m_loc
<<
"]"
;
out
<<
" [pos "
<<
dec
<<
pos
.
m_pos
<<
"]"
;
out
<<
" [pos "
<<
dec
<<
pos
.
m_pos
<<
"]"
;
out
<<
" [match "
<<
dec
<<
pos
.
m_match
<<
"]"
;
out
<<
" [match "
<<
dec
<<
pos
.
m_match
<<
"]"
;
out
<<
" [dir "
<<
dec
<<
pos
.
m_dir
<<
"]"
;
out
<<
" [dir "
<<
dec
<<
pos
.
m_dir
<<
"]"
;
...
@@ -338,7 +353,7 @@ operator<<(NdbOut& out, const Dbtux::NodeHandle& node)
...
@@ -338,7 +353,7 @@ operator<<(NdbOut& out, const Dbtux::NodeHandle& node)
const
Dbtux
::
Frag
&
frag
=
node
.
m_frag
;
const
Dbtux
::
Frag
&
frag
=
node
.
m_frag
;
const
Dbtux
::
TreeHead
&
tree
=
frag
.
m_tree
;
const
Dbtux
::
TreeHead
&
tree
=
frag
.
m_tree
;
out
<<
"[NodeHandle "
<<
hex
<<
&
node
;
out
<<
"[NodeHandle "
<<
hex
<<
&
node
;
out
<<
" [
addr "
<<
hex
<<
node
.
m_addr
<<
"]"
;
out
<<
" [
loc "
<<
node
.
m_loc
<<
"]"
;
out
<<
" [acc "
<<
dec
<<
node
.
m_acc
<<
"]"
;
out
<<
" [acc "
<<
dec
<<
node
.
m_acc
<<
"]"
;
out
<<
" [flags "
<<
hex
<<
node
.
m_flags
<<
"]"
;
out
<<
" [flags "
<<
hex
<<
node
.
m_flags
<<
"]"
;
out
<<
" [node "
<<
*
node
.
m_node
<<
"]"
;
out
<<
" [node "
<<
*
node
.
m_node
<<
"]"
;
...
...
ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
View file @
7d1f0333
...
@@ -285,8 +285,8 @@ Dbtux::tupStoreTh(Signal* signal, const Frag& frag, NodeHandlePtr nodePtr, Store
...
@@ -285,8 +285,8 @@ Dbtux::tupStoreTh(Signal* signal, const Frag& frag, NodeHandlePtr nodePtr, Store
req
->
tableId
=
frag
.
m_indexId
;
req
->
tableId
=
frag
.
m_indexId
;
req
->
fragId
=
frag
.
m_fragId
;
req
->
fragId
=
frag
.
m_fragId
;
req
->
fragPtrI
=
frag
.
m_tupIndexFragPtrI
;
req
->
fragPtrI
=
frag
.
m_tupIndexFragPtrI
;
req
->
tupAddr
=
nodePtr
.
p
->
m_addr
;
req
->
tupAddr
=
RNIL
;
// no longer used
req
->
tupVersion
=
0
;
req
->
tupVersion
=
0
;
// no longer used
req
->
pageId
=
nodePtr
.
p
->
m_loc
.
m_pageId
;
req
->
pageId
=
nodePtr
.
p
->
m_loc
.
m_pageId
;
req
->
pageOffset
=
nodePtr
.
p
->
m_loc
.
m_pageOffset
;
req
->
pageOffset
=
nodePtr
.
p
->
m_loc
.
m_pageOffset
;
req
->
bufferId
=
0
;
req
->
bufferId
=
0
;
...
@@ -346,21 +346,18 @@ Dbtux::tupStoreTh(Signal* signal, const Frag& frag, NodeHandlePtr nodePtr, Store
...
@@ -346,21 +346,18 @@ Dbtux::tupStoreTh(Signal* signal, const Frag& frag, NodeHandlePtr nodePtr, Store
const
Uint32
*
src
=
(
const
Uint32
*
)
buffer
+
storePar
.
m_offset
;
const
Uint32
*
src
=
(
const
Uint32
*
)
buffer
+
storePar
.
m_offset
;
memcpy
(
dst
,
src
,
storePar
.
m_size
<<
2
);
memcpy
(
dst
,
src
,
storePar
.
m_size
<<
2
);
}
}
// fallthru
break
;
case
TupStoreTh
:
:
OpInsert
:
case
TupStoreTh
:
:
OpInsert
:
jam
();
jam
();
// fallthru
case
TupStoreTh
:
:
OpUpdate
:
jam
();
nodePtr
.
p
->
m_addr
=
req
->
tupAddr
;
nodePtr
.
p
->
m_loc
.
m_pageId
=
req
->
pageId
;
nodePtr
.
p
->
m_loc
.
m_pageId
=
req
->
pageId
;
nodePtr
.
p
->
m_loc
.
m_pageOffset
=
req
->
pageOffset
;
nodePtr
.
p
->
m_loc
.
m_pageOffset
=
req
->
pageOffset
;
break
;
break
;
case
TupStoreTh
:
:
OpUpdate
:
jam
();
break
;
case
TupStoreTh
:
:
OpDelete
:
case
TupStoreTh
:
:
OpDelete
:
jam
();
jam
();
nodePtr
.
p
->
m_addr
=
NullTupAddr
;
nodePtr
.
p
->
m_loc
=
NullTupLoc
;
nodePtr
.
p
->
m_loc
.
m_pageId
=
RNIL
;
nodePtr
.
p
->
m_loc
.
m_pageOffset
=
0
;
break
;
break
;
default:
default:
ndbrequire
(
false
);
ndbrequire
(
false
);
...
...
ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
View file @
7d1f0333
...
@@ -202,6 +202,7 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
...
@@ -202,6 +202,7 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
jam
();
jam
();
// initialize tree header
// initialize tree header
TreeHead
&
tree
=
fragPtr
.
p
->
m_tree
;
TreeHead
&
tree
=
fragPtr
.
p
->
m_tree
;
new
(
&
tree
)
TreeHead
();
// make these configurable later
// make these configurable later
tree
.
m_nodeSize
=
MAX_TTREE_NODE_SIZE
;
tree
.
m_nodeSize
=
MAX_TTREE_NODE_SIZE
;
tree
.
m_prefSize
=
MAX_TTREE_PREF_SIZE
;
tree
.
m_prefSize
=
MAX_TTREE_PREF_SIZE
;
...
@@ -227,8 +228,8 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
...
@@ -227,8 +228,8 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
break
;
break
;
}
}
tree
.
m_minOccup
=
tree
.
m_maxOccup
-
maxSlack
;
tree
.
m_minOccup
=
tree
.
m_maxOccup
-
maxSlack
;
// root node does not exist
// root node does not exist
(also set by ctor)
tree
.
m_root
=
NullTup
Addr
;
tree
.
m_root
=
NullTup
Loc
;
// fragment is defined
// fragment is defined
c_fragOpPool
.
release
(
fragOpPtr
);
c_fragOpPool
.
release
(
fragOpPtr
);
}
}
...
...
ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
View file @
7d1f0333
...
@@ -80,14 +80,14 @@ Dbtux::preallocNode(Signal* signal, Frag& frag, Uint32& errorCode)
...
@@ -80,14 +80,14 @@ Dbtux::preallocNode(Signal* signal, Frag& frag, Uint32& errorCode)
* Find node in the cache. XXX too slow, use direct links instead
* Find node in the cache. XXX too slow, use direct links instead
*/
*/
void
void
Dbtux
::
findNode
(
Signal
*
signal
,
Frag
&
frag
,
NodeHandlePtr
&
nodePtr
,
Tup
Addr
addr
)
Dbtux
::
findNode
(
Signal
*
signal
,
Frag
&
frag
,
NodeHandlePtr
&
nodePtr
,
Tup
Loc
loc
)
{
{
NodeHandlePtr
tmpPtr
;
NodeHandlePtr
tmpPtr
;
tmpPtr
.
i
=
frag
.
m_nodeList
;
tmpPtr
.
i
=
frag
.
m_nodeList
;
while
(
tmpPtr
.
i
!=
RNIL
)
{
while
(
tmpPtr
.
i
!=
RNIL
)
{
jam
();
jam
();
c_nodeHandlePool
.
getPtr
(
tmpPtr
);
c_nodeHandlePool
.
getPtr
(
tmpPtr
);
if
(
tmpPtr
.
p
->
m_
addr
==
addr
)
{
if
(
tmpPtr
.
p
->
m_
loc
==
loc
)
{
jam
();
jam
();
nodePtr
=
tmpPtr
;
nodePtr
=
tmpPtr
;
return
;
return
;
...
@@ -102,18 +102,18 @@ Dbtux::findNode(Signal* signal, Frag& frag, NodeHandlePtr& nodePtr, TupAddr addr
...
@@ -102,18 +102,18 @@ Dbtux::findNode(Signal* signal, Frag& frag, NodeHandlePtr& nodePtr, TupAddr addr
* Get handle for existing node.
* Get handle for existing node.
*/
*/
void
void
Dbtux
::
selectNode
(
Signal
*
signal
,
Frag
&
frag
,
NodeHandlePtr
&
nodePtr
,
Tup
Addr
addr
,
AccSize
acc
)
Dbtux
::
selectNode
(
Signal
*
signal
,
Frag
&
frag
,
NodeHandlePtr
&
nodePtr
,
Tup
Loc
loc
,
AccSize
acc
)
{
{
ndbrequire
(
addr
!=
NullTupAddr
&&
acc
>
AccNone
);
ndbrequire
(
loc
!=
NullTupLoc
&&
acc
>
AccNone
);
NodeHandlePtr
tmpPtr
;
NodeHandlePtr
tmpPtr
;
// search in cache
// search in cache
findNode
(
signal
,
frag
,
tmpPtr
,
addr
);
findNode
(
signal
,
frag
,
tmpPtr
,
loc
);
if
(
tmpPtr
.
i
==
RNIL
)
{
if
(
tmpPtr
.
i
==
RNIL
)
{
jam
();
jam
();
// add new node
// add new node
seizeNode
(
signal
,
frag
,
tmpPtr
);
seizeNode
(
signal
,
frag
,
tmpPtr
);
ndbrequire
(
tmpPtr
.
i
!=
RNIL
);
ndbrequire
(
tmpPtr
.
i
!=
RNIL
);
tmpPtr
.
p
->
m_
addr
=
addr
;
tmpPtr
.
p
->
m_
loc
=
loc
;
}
}
if
(
tmpPtr
.
p
->
m_acc
<
acc
)
{
if
(
tmpPtr
.
p
->
m_acc
<
acc
)
{
jam
();
jam
();
...
@@ -276,7 +276,7 @@ Dbtux::NodeHandle::pushUp(Signal* signal, unsigned pos, const TreeEnt& ent)
...
@@ -276,7 +276,7 @@ Dbtux::NodeHandle::pushUp(Signal* signal, unsigned pos, const TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
if
(
scanPos
.
m_pos
>=
pos
)
{
if
(
scanPos
.
m_pos
>=
pos
)
{
jam
();
jam
();
#ifdef VM_TRACE
#ifdef VM_TRACE
...
@@ -329,7 +329,7 @@ Dbtux::NodeHandle::popDown(Signal* signal, unsigned pos, TreeEnt& ent)
...
@@ -329,7 +329,7 @@ Dbtux::NodeHandle::popDown(Signal* signal, unsigned pos, TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
const
Uint32
nextPtrI
=
scanPtr
.
p
->
m_nodeScan
;
const
Uint32
nextPtrI
=
scanPtr
.
p
->
m_nodeScan
;
if
(
scanPos
.
m_pos
==
pos
)
{
if
(
scanPos
.
m_pos
==
pos
)
{
jam
();
jam
();
...
@@ -349,7 +349,7 @@ Dbtux::NodeHandle::popDown(Signal* signal, unsigned pos, TreeEnt& ent)
...
@@ -349,7 +349,7 @@ Dbtux::NodeHandle::popDown(Signal* signal, unsigned pos, TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_pos
!=
pos
);
ndbrequire
(
scanPos
.
m_pos
!=
pos
);
if
(
scanPos
.
m_pos
>
pos
)
{
if
(
scanPos
.
m_pos
>
pos
)
{
jam
();
jam
();
...
@@ -403,7 +403,7 @@ Dbtux::NodeHandle::pushDown(Signal* signal, unsigned pos, TreeEnt& ent)
...
@@ -403,7 +403,7 @@ Dbtux::NodeHandle::pushDown(Signal* signal, unsigned pos, TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
const
Uint32
nextPtrI
=
scanPtr
.
p
->
m_nodeScan
;
const
Uint32
nextPtrI
=
scanPtr
.
p
->
m_nodeScan
;
if
(
scanPos
.
m_pos
==
0
)
{
if
(
scanPos
.
m_pos
==
0
)
{
jam
();
jam
();
...
@@ -424,7 +424,7 @@ Dbtux::NodeHandle::pushDown(Signal* signal, unsigned pos, TreeEnt& ent)
...
@@ -424,7 +424,7 @@ Dbtux::NodeHandle::pushDown(Signal* signal, unsigned pos, TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_pos
!=
0
);
ndbrequire
(
scanPos
.
m_pos
!=
0
);
if
(
scanPos
.
m_pos
<=
pos
)
{
if
(
scanPos
.
m_pos
<=
pos
)
{
jam
();
jam
();
...
@@ -480,7 +480,7 @@ Dbtux::NodeHandle::popUp(Signal* signal, unsigned pos, TreeEnt& ent)
...
@@ -480,7 +480,7 @@ Dbtux::NodeHandle::popUp(Signal* signal, unsigned pos, TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
const
Uint32
nextPtrI
=
scanPtr
.
p
->
m_nodeScan
;
const
Uint32
nextPtrI
=
scanPtr
.
p
->
m_nodeScan
;
if
(
scanPos
.
m_pos
==
pos
)
{
if
(
scanPos
.
m_pos
==
pos
)
{
jam
();
jam
();
...
@@ -501,7 +501,7 @@ Dbtux::NodeHandle::popUp(Signal* signal, unsigned pos, TreeEnt& ent)
...
@@ -501,7 +501,7 @@ Dbtux::NodeHandle::popUp(Signal* signal, unsigned pos, TreeEnt& ent)
jam
();
jam
();
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
m_tux
.
c_scanOpPool
.
getPtr
(
scanPtr
);
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
TreePos
&
scanPos
=
scanPtr
.
p
->
m_scanPos
;
ndbrequire
(
scanPos
.
m_
addr
==
m_addr
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_
loc
==
m_loc
&&
scanPos
.
m_pos
<
occup
);
ndbrequire
(
scanPos
.
m_pos
!=
pos
);
ndbrequire
(
scanPos
.
m_pos
!=
pos
);
if
(
scanPos
.
m_pos
<
pos
)
{
if
(
scanPos
.
m_pos
<
pos
)
{
jam
();
jam
();
...
...
ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
View file @
7d1f0333
...
@@ -47,7 +47,7 @@ Dbtux::execACC_SCANREQ(Signal* signal)
...
@@ -47,7 +47,7 @@ Dbtux::execACC_SCANREQ(Signal* signal)
ndbrequire
(
frag
.
m_fragId
<
(
1
<<
frag
.
m_fragOff
));
ndbrequire
(
frag
.
m_fragId
<
(
1
<<
frag
.
m_fragOff
));
TreeHead
&
tree
=
frag
.
m_tree
;
TreeHead
&
tree
=
frag
.
m_tree
;
// check for empty fragment
// check for empty fragment
if
(
tree
.
m_root
==
NullTup
Addr
)
{
if
(
tree
.
m_root
==
NullTup
Loc
)
{
jam
();
jam
();
AccScanConf
*
const
conf
=
(
AccScanConf
*
)
signal
->
getDataPtrSend
();
AccScanConf
*
const
conf
=
(
AccScanConf
*
)
signal
->
getDataPtrSend
();
conf
->
scanPtr
=
req
->
senderData
;
conf
->
scanPtr
=
req
->
senderData
;
...
@@ -275,13 +275,13 @@ Dbtux::execNEXT_SCANREQ(Signal* signal)
...
@@ -275,13 +275,13 @@ Dbtux::execNEXT_SCANREQ(Signal* signal)
case
NextScanReq
:
:
ZSCAN_CLOSE
:
case
NextScanReq
:
:
ZSCAN_CLOSE
:
jam
();
jam
();
// unlink from tree node first to avoid state changes
// unlink from tree node first to avoid state changes
if
(
scan
.
m_scanPos
.
m_
addr
!=
NullTupAddr
)
{
if
(
scan
.
m_scanPos
.
m_
loc
!=
NullTupLoc
)
{
jam
();
jam
();
const
Tup
Addr
addr
=
scan
.
m_scanPos
.
m_addr
;
const
Tup
Loc
loc
=
scan
.
m_scanPos
.
m_loc
;
NodeHandlePtr
nodePtr
;
NodeHandlePtr
nodePtr
;
selectNode
(
signal
,
frag
,
nodePtr
,
addr
,
AccHead
);
selectNode
(
signal
,
frag
,
nodePtr
,
loc
,
AccHead
);
nodePtr
.
p
->
unlinkScan
(
scanPtr
);
nodePtr
.
p
->
unlinkScan
(
scanPtr
);
scan
.
m_scanPos
.
m_
addr
=
NullTupAddr
;
scan
.
m_scanPos
.
m_
loc
=
NullTupLoc
;
}
}
if
(
scan
.
m_lockwait
)
{
if
(
scan
.
m_lockwait
)
{
jam
();
jam
();
...
@@ -699,14 +699,14 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr)
...
@@ -699,14 +699,14 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr)
ScanOp
&
scan
=
*
scanPtr
.
p
;
ScanOp
&
scan
=
*
scanPtr
.
p
;
Frag
&
frag
=
*
c_fragPool
.
getPtr
(
scan
.
m_fragPtrI
);
Frag
&
frag
=
*
c_fragPool
.
getPtr
(
scan
.
m_fragPtrI
);
TreeHead
&
tree
=
frag
.
m_tree
;
TreeHead
&
tree
=
frag
.
m_tree
;
if
(
tree
.
m_root
==
NullTup
Addr
)
{
if
(
tree
.
m_root
==
NullTup
Loc
)
{
// tree may have become empty
// tree may have become empty
jam
();
jam
();
scan
.
m_state
=
ScanOp
::
Last
;
scan
.
m_state
=
ScanOp
::
Last
;
return
;
return
;
}
}
TreePos
pos
;
TreePos
pos
;
pos
.
m_
addr
=
tree
.
m_root
;
pos
.
m_
loc
=
tree
.
m_root
;
NodeHandlePtr
nodePtr
;
NodeHandlePtr
nodePtr
;
// unpack lower bound
// unpack lower bound
const
ScanBound
&
bound
=
*
scan
.
m_bound
[
0
];
const
ScanBound
&
bound
=
*
scan
.
m_bound
[
0
];
...
@@ -724,7 +724,7 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr)
...
@@ -724,7 +724,7 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr)
boundPar
.
m_dir
=
0
;
boundPar
.
m_dir
=
0
;
loop:
{
loop:
{
jam
();
jam
();
selectNode
(
signal
,
frag
,
nodePtr
,
pos
.
m_
addr
,
AccPref
);
selectNode
(
signal
,
frag
,
nodePtr
,
pos
.
m_
loc
,
AccPref
);
const
unsigned
occup
=
nodePtr
.
p
->
getOccup
();
const
unsigned
occup
=
nodePtr
.
p
->
getOccup
();
ndbrequire
(
occup
!=
0
);
ndbrequire
(
occup
!=
0
);
for
(
unsigned
i
=
0
;
i
<=
1
;
i
++
)
{
for
(
unsigned
i
=
0
;
i
<=
1
;
i
++
)
{
...
@@ -750,11 +750,11 @@ loop: {
...
@@ -750,11 +750,11 @@ loop: {
}
}
if
(
i
==
0
&&
ret
<
0
)
{
if
(
i
==
0
&&
ret
<
0
)
{
jam
();
jam
();
const
Tup
Addr
tupAddr
=
nodePtr
.
p
->
getLink
(
i
);
const
Tup
Loc
loc
=
nodePtr
.
p
->
getLink
(
i
);
if
(
tupAddr
!=
NullTupAddr
)
{
if
(
loc
!=
NullTupLoc
)
{
jam
();
jam
();
// continue to left subtree
// continue to left subtree
pos
.
m_
addr
=
tupAddr
;
pos
.
m_
loc
=
loc
;
goto
loop
;
goto
loop
;
}
}
// start scanning this node
// start scanning this node
...
@@ -768,11 +768,11 @@ loop: {
...
@@ -768,11 +768,11 @@ loop: {
}
}
if
(
i
==
1
&&
ret
>
0
)
{
if
(
i
==
1
&&
ret
>
0
)
{
jam
();
jam
();
const
Tup
Addr
tupAddr
=
nodePtr
.
p
->
getLink
(
i
);
const
Tup
Loc
loc
=
nodePtr
.
p
->
getLink
(
i
);
if
(
tupAddr
!=
NullTupAddr
)
{
if
(
loc
!=
NullTupLoc
)
{
jam
();
jam
();
// continue to right subtree
// continue to right subtree
pos
.
m_
addr
=
tupAddr
;
pos
.
m_
loc
=
loc
;
goto
loop
;
goto
loop
;
}
}
// start scanning upwards
// start scanning upwards
...
@@ -869,7 +869,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -869,7 +869,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
TreePos
pos
=
scan
.
m_scanPos
;
TreePos
pos
=
scan
.
m_scanPos
;
// get and remember original node
// get and remember original node
NodeHandlePtr
origNodePtr
;
NodeHandlePtr
origNodePtr
;
selectNode
(
signal
,
frag
,
origNodePtr
,
pos
.
m_
addr
,
AccHead
);
selectNode
(
signal
,
frag
,
origNodePtr
,
pos
.
m_
loc
,
AccHead
);
ndbrequire
(
origNodePtr
.
p
->
islinkScan
(
scanPtr
));
ndbrequire
(
origNodePtr
.
p
->
islinkScan
(
scanPtr
));
// current node in loop
// current node in loop
NodeHandlePtr
nodePtr
=
origNodePtr
;
NodeHandlePtr
nodePtr
=
origNodePtr
;
...
@@ -878,21 +878,21 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -878,21 +878,21 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
if
(
pos
.
m_dir
==
2
)
{
if
(
pos
.
m_dir
==
2
)
{
// coming up from root ends the scan
// coming up from root ends the scan
jam
();
jam
();
pos
.
m_
addr
=
NullTupAddr
;
pos
.
m_
loc
=
NullTupLoc
;
scan
.
m_state
=
ScanOp
::
Last
;
scan
.
m_state
=
ScanOp
::
Last
;
break
;
break
;
}
}
if
(
nodePtr
.
p
->
m_
addr
!=
pos
.
m_addr
)
{
if
(
nodePtr
.
p
->
m_
loc
!=
pos
.
m_loc
)
{
jam
();
jam
();
selectNode
(
signal
,
frag
,
nodePtr
,
pos
.
m_
addr
,
AccHead
);
selectNode
(
signal
,
frag
,
nodePtr
,
pos
.
m_
loc
,
AccHead
);
}
}
if
(
pos
.
m_dir
==
4
)
{
if
(
pos
.
m_dir
==
4
)
{
// coming down from parent proceed to left child
// coming down from parent proceed to left child
jam
();
jam
();
Tup
Addr
addr
=
nodePtr
.
p
->
getLink
(
0
);
Tup
Loc
loc
=
nodePtr
.
p
->
getLink
(
0
);
if
(
addr
!=
NullTupAddr
)
{
if
(
loc
!=
NullTupLoc
)
{
jam
();
jam
();
pos
.
m_
addr
=
addr
;
pos
.
m_
loc
=
loc
;
pos
.
m_dir
=
4
;
// unchanged
pos
.
m_dir
=
4
;
// unchanged
continue
;
continue
;
}
}
...
@@ -937,7 +937,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -937,7 +937,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
jam
();
jam
();
// hit upper bound of single range scan
// hit upper bound of single range scan
pos
.
m_
addr
=
NullTupAddr
;
pos
.
m_
loc
=
NullTupLoc
;
scan
.
m_state
=
ScanOp
::
Last
;
scan
.
m_state
=
ScanOp
::
Last
;
break
;
break
;
}
}
...
@@ -951,10 +951,10 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -951,10 +951,10 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
break
;
break
;
}
}
// after node proceed to right child
// after node proceed to right child
Tup
Addr
addr
=
nodePtr
.
p
->
getLink
(
1
);
Tup
Loc
loc
=
nodePtr
.
p
->
getLink
(
1
);
if
(
addr
!=
NullTupAddr
)
{
if
(
loc
!=
NullTupLoc
)
{
jam
();
jam
();
pos
.
m_
addr
=
addr
;
pos
.
m_
loc
=
loc
;
pos
.
m_dir
=
4
;
pos
.
m_dir
=
4
;
continue
;
continue
;
}
}
...
@@ -964,7 +964,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -964,7 +964,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
if
(
pos
.
m_dir
==
1
)
{
if
(
pos
.
m_dir
==
1
)
{
// coming from right child proceed to parent
// coming from right child proceed to parent
jam
();
jam
();
pos
.
m_
addr
=
nodePtr
.
p
->
getLink
(
2
);
pos
.
m_
loc
=
nodePtr
.
p
->
getLink
(
2
);
pos
.
m_dir
=
nodePtr
.
p
->
getSide
();
pos
.
m_dir
=
nodePtr
.
p
->
getSide
();
continue
;
continue
;
}
}
...
@@ -974,7 +974,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -974,7 +974,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
scan
.
m_scanPos
=
pos
;
scan
.
m_scanPos
=
pos
;
// relink
// relink
if
(
scan
.
m_state
==
ScanOp
::
Current
)
{
if
(
scan
.
m_state
==
ScanOp
::
Current
)
{
ndbrequire
(
pos
.
m_
addr
==
nodePtr
.
p
->
m_addr
);
ndbrequire
(
pos
.
m_
loc
==
nodePtr
.
p
->
m_loc
);
if
(
origNodePtr
.
i
!=
nodePtr
.
i
)
{
if
(
origNodePtr
.
i
!=
nodePtr
.
i
)
{
jam
();
jam
();
origNodePtr
.
p
->
unlinkScan
(
scanPtr
);
origNodePtr
.
p
->
unlinkScan
(
scanPtr
);
...
@@ -982,7 +982,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
...
@@ -982,7 +982,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
}
}
}
else
if
(
scan
.
m_state
==
ScanOp
::
Last
)
{
}
else
if
(
scan
.
m_state
==
ScanOp
::
Last
)
{
jam
();
jam
();
ndbrequire
(
pos
.
m_
addr
==
NullTupAddr
);
ndbrequire
(
pos
.
m_
loc
==
NullTupLoc
);
origNodePtr
.
p
->
unlinkScan
(
scanPtr
);
origNodePtr
.
p
->
unlinkScan
(
scanPtr
);
}
else
{
}
else
{
ndbrequire
(
false
);
ndbrequire
(
false
);
...
...
ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
View file @
7d1f0333
This diff is collapsed.
Click to expand it.
ndb/src/kernel/blocks/dbtux/Times.txt
View file @
7d1f0333
index maintenance overhead
==========================
"mc02" 2x1700 MHz linux-2.4.9 gcc-2.96 -O3 one db-node
"mc02" 2x1700 MHz linux-2.4.9 gcc-2.96 -O3 one db-node
case a: index on Unsigned
case a: index on Unsigned
...
@@ -6,8 +9,8 @@ testOIBasic -case u -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -
...
@@ -6,8 +9,8 @@ testOIBasic -case u -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -
case b: index on Varchar(5) + Varchar(5) + Varchar(20) + Unsigned
case b: index on Varchar(5) + Varchar(5) + Varchar(20) + Unsigned
testOIBasic -case u -table 2 -index 4 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
testOIBasic -case u -table 2 -index 4 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
update without index,
update with index
1 million rows, pk update without index, pk
update with index
shows ms / 1000 for each and pct overhead
shows ms / 1000
rows
for each and pct overhead
040616 mc02/a 40 ms 87 ms 114 pct
040616 mc02/a 40 ms 87 ms 114 pct
mc02/b 51 ms 128 ms 148 pct
mc02/b 51 ms 128 ms 148 pct
...
@@ -15,4 +18,8 @@ shows ms / 1000 for each and pct overhead
...
@@ -15,4 +18,8 @@ shows ms / 1000 for each and pct overhead
optim 1 mc02/a 38 ms 85 ms 124 pct
optim 1 mc02/a 38 ms 85 ms 124 pct
mc02/b 51 ms 123 ms 140 pct
mc02/b 51 ms 123 ms 140 pct
optim 2 mc02/a 41 ms 80 ms 96 pct
mc02/b 51 ms 117 ms 128 pct
vim: set et:
vim: set et:
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