mirror of
https://shylinux.com/x/ContextOS
synced 2025-04-25 16:58:06 +08:00
add ssh.multi
This commit is contained in:
parent
a968cc6096
commit
ed027c8c9d
@ -2,4 +2,6 @@
|
||||
config save tmp/flash.json flash
|
||||
~aaa
|
||||
config save tmp/auth.json auth
|
||||
~cli
|
||||
config save tmp/runtime.json runtime
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
~cli
|
||||
config load tmp/runtime.json runtime
|
||||
~aaa
|
||||
config load tmp/auth.json auth
|
||||
~code
|
||||
|
@ -485,7 +485,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
return
|
||||
}
|
||||
|
||||
now := int64(m.Sess("cli").Cmd("time").Appendi("timestamp"))
|
||||
now := m.Sess("cli").Cmd("time").Appendi("timestamp")
|
||||
begin := now
|
||||
if len(arg) > 0 && arg[0] == "begin" {
|
||||
begin, arg = int64(m.Sess("cli").Cmd("time", arg[1]).Appendi("timestamp")), arg[2:]
|
||||
@ -524,7 +524,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
m.GoLoop(m, func(m *ctx.Message) {
|
||||
select {
|
||||
case <-cli.Timer.C:
|
||||
m.Log("info", "timer %s", m.Conf("timer_next"))
|
||||
if m.Conf("timer_next") == "" {
|
||||
break
|
||||
}
|
||||
@ -675,10 +674,11 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
}},
|
||||
"quit": &ctx.Command{Name: "quit code", Help: "停止服务", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Cmd("cli.source", m.Conf("system", "script.exit"))
|
||||
go func() {
|
||||
|
||||
m.GoFunc(m, func(m *ctx.Message) {
|
||||
time.Sleep(time.Second * 3)
|
||||
os.Exit(kit.Int(arg[0]))
|
||||
}()
|
||||
})
|
||||
return
|
||||
}},
|
||||
|
||||
@ -761,7 +761,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
|
||||
// 解析路由
|
||||
if msg == m {
|
||||
if routes := strings.Split(detail[0], "."); len(routes) > 1 {
|
||||
if routes := strings.Split(detail[0], "."); len(routes) > 1 && !strings.Contains(detail[0], ":") {
|
||||
route := strings.Join(routes[:len(routes)-1], ".")
|
||||
if msg = m.Find(route, false); msg == nil {
|
||||
msg = m.Find(route, true)
|
||||
|
@ -335,9 +335,14 @@ var Index = &Context{Name: "ctx", Help: "模块中心", Server: &CTX{},
|
||||
}
|
||||
|
||||
msg := m.message
|
||||
keys := map[string]bool{}
|
||||
for msg = msg; msg != nil; msg = msg.message {
|
||||
for _, k := range msg.Meta["option"] {
|
||||
if len(arg) == 0 {
|
||||
if keys[k] {
|
||||
continue
|
||||
}
|
||||
keys[k] = true
|
||||
m.Add("append", "key", k)
|
||||
m.Add("append", "len", len(msg.Meta[k]))
|
||||
m.Add("append", "value", fmt.Sprintf("%v", msg.Meta[k]))
|
||||
@ -601,9 +606,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心", Server: &CTX{},
|
||||
switch action {
|
||||
case "cmd":
|
||||
componet := "source"
|
||||
if m.Options("bench") && m.Options("username") &&
|
||||
!m.Cmds("aaa.work", m.Option("bench"), "right", m.Option("username"), componet, arg[0]) {
|
||||
m.Log("info", "check %v: %v failure", componet, arg[0])
|
||||
if m.Options("bench") && m.Options("username") && !m.Cmds("aaa.work", "right", componet, arg[0]) {
|
||||
m.Log("info", "%s no right [%v: %v]", m.Option("username"), componet, arg[0])
|
||||
m.Echo("error: ").Echo("no right [%s: %s]", componet, arg[0])
|
||||
break
|
||||
}
|
||||
@ -1407,6 +1411,7 @@ func Start(args ...string) bool {
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
Pulse.Option("routine", 0)
|
||||
if Index.Begin(Pulse, args...); Index.Start(Pulse, args...) {
|
||||
return Index.Close(Pulse, args...)
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package ctx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"errors"
|
||||
@ -409,7 +411,7 @@ func (m *Message) Format(arg ...interface{}) string {
|
||||
case "code":
|
||||
meta = append(meta, kit.Format(m.code))
|
||||
case "ship":
|
||||
meta = append(meta, fmt.Sprintf("%d(%s->%s)", m.code, m.source.Name, m.target.Name))
|
||||
meta = append(meta, fmt.Sprintf("%s:%d(%s->%s)", m.Option("routine"), m.code, m.source.Name, m.target.Name))
|
||||
case "source":
|
||||
target := m.target
|
||||
m.target = m.source
|
||||
@ -903,9 +905,9 @@ func (m *Message) Append(key string, arg ...interface{}) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (m *Message) Appendi(key string, arg ...interface{}) int {
|
||||
return kit.Int(m.Append(key, arg...))
|
||||
|
||||
func (m *Message) Appendi(key string, arg ...interface{}) int64 {
|
||||
i, _ := strconv.ParseInt(m.Append(key, arg...), 10, 64)
|
||||
return i
|
||||
}
|
||||
func (m *Message) Appends(key string, arg ...interface{}) bool {
|
||||
return kit.Right(m.Append(key, arg...))
|
||||
@ -1123,11 +1125,11 @@ func (m *Message) Parse(arg interface{}) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (m *Message) ToHTML() string {
|
||||
func (m *Message) ToHTML(style string) string {
|
||||
cmd := strings.Join(m.Meta["detail"], " ")
|
||||
result := []string{}
|
||||
if len(m.Meta["append"]) > 0 {
|
||||
result = append(result, "<table>")
|
||||
result = append(result, fmt.Sprintf("<table class='%s'>", style))
|
||||
result = append(result, "<caption>", cmd, "</caption>")
|
||||
m.Table(func(maps map[string]string, list []string, line int) bool {
|
||||
if line == -1 {
|
||||
@ -1212,8 +1214,7 @@ func (m *Message) Assert(e interface{}, msg ...string) bool {
|
||||
}
|
||||
func (m *Message) TryCatch(msg *Message, safe bool, hand ...func(msg *Message)) *Message {
|
||||
defer func() {
|
||||
e := recover()
|
||||
switch e {
|
||||
switch e := recover(); e {
|
||||
case io.EOF:
|
||||
case nil:
|
||||
default:
|
||||
@ -1221,9 +1222,7 @@ func (m *Message) TryCatch(msg *Message, safe bool, hand ...func(msg *Message))
|
||||
m.Log("bench", "catch: %s", e)
|
||||
m.Log("bench", "stack: %s", msg.Format("stack"))
|
||||
|
||||
m.Log("error", "catch: %s", e)
|
||||
|
||||
if len(hand) > 1 {
|
||||
if m.Log("error", "catch: %s", e); len(hand) > 1 {
|
||||
m.TryCatch(msg, safe, hand[1:]...)
|
||||
} else if !safe {
|
||||
msg.Assert(e)
|
||||
@ -1234,23 +1233,25 @@ func (m *Message) TryCatch(msg *Message, safe bool, hand ...func(msg *Message))
|
||||
if len(hand) > 0 {
|
||||
hand[0](msg)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
func (m *Message) GoFunc(msg *Message, hand ...func(msg *Message)) *Message {
|
||||
go func() {
|
||||
ngo := msg.Option("routine", m.Capi("ngo", 1))
|
||||
msg.Log("info", "%v safe go begin", ngo)
|
||||
kit.Log("error", "%s ngo %s start", msg.Format(), ngo)
|
||||
m.TryCatch(msg, true, hand...)
|
||||
kit.Log("error", "%s ngo %s end", msg.Format(), ngo)
|
||||
msg.Log("info", "%v safe go end", ngo)
|
||||
}()
|
||||
return m
|
||||
}
|
||||
func (m *Message) GoLoop(msg *Message, hand ...func(msg *Message)) *Message {
|
||||
go func() {
|
||||
m.Log("info", "%v safe go begin", m.Capi("ngo", 1))
|
||||
m.GoFunc(msg, func(msg *Message) {
|
||||
for {
|
||||
m.TryCatch(msg, true, hand...)
|
||||
hand[0](msg)
|
||||
}
|
||||
m.Log("info", "%v safe go end", m.Capi("ngo", -1)+1)
|
||||
}()
|
||||
})
|
||||
return m
|
||||
}
|
||||
func (m *Message) Start(name string, help string, arg ...string) bool {
|
||||
@ -1464,14 +1465,14 @@ func (m *Message) CallBack(sync bool, cb func(msg *Message) (sub *Message), arg
|
||||
}
|
||||
|
||||
wait := make(chan *Message, 10)
|
||||
m.GoFunc(m, func(m *Message) {
|
||||
m.Call(func(sub *Message) *Message {
|
||||
msg := cb(sub)
|
||||
m.Log("sync", m.Format("done", "result", "append"))
|
||||
wait <- m
|
||||
return msg
|
||||
}, arg...)
|
||||
})
|
||||
// m.GoFunc(m, func(m *Message) {
|
||||
m.Call(func(sub *Message) *Message {
|
||||
msg := cb(sub)
|
||||
m.Log("sync", m.Format("done", "result", "append"))
|
||||
wait <- m
|
||||
return msg
|
||||
}, arg...)
|
||||
// })
|
||||
|
||||
m.Log("sync", m.Format("wait", "result", "append"))
|
||||
select {
|
||||
@ -1538,20 +1539,27 @@ func (m *Message) Cmd(args ...interface{}) *Message {
|
||||
}
|
||||
key, arg := m.Meta["detail"][0], m.Meta["detail"][1:]
|
||||
|
||||
if strings.Contains(key, ".") {
|
||||
msg := m
|
||||
if strings.Contains(key, ":") {
|
||||
ps := strings.Split(key, ":")
|
||||
msg, key, arg = msg.Sess("ssh"), "sh", append([]string{"node", ps[0], "sync", ps[1]}, arg...)
|
||||
defer func() { m.Copy(msg, "append").Copy(msg, "result") }()
|
||||
m.Hand = true
|
||||
|
||||
} else if strings.Contains(key, ".") {
|
||||
arg := strings.Split(key, ".")
|
||||
m, key = m.Sess(arg[0]), arg[1]
|
||||
m.Option("remote_code", "")
|
||||
msg, key = msg.Sess(arg[0]), arg[1]
|
||||
msg.Option("remote_code", "")
|
||||
}
|
||||
if m == nil {
|
||||
return m
|
||||
if msg == nil {
|
||||
return msg
|
||||
}
|
||||
|
||||
m = m.Match(key, true, func(m *Message, s *Context, c *Context, key string) bool {
|
||||
m.Hand = false
|
||||
msg = msg.Match(key, true, func(msg *Message, s *Context, c *Context, key string) bool {
|
||||
msg.Hand = false
|
||||
if x, ok := c.Commands[key]; ok && x.Hand != nil {
|
||||
m.TryCatch(m, true, func(m *Message) {
|
||||
m.Log("cmd", "%s %s %v %v", c.Name, key, arg, m.Meta["option"])
|
||||
msg.TryCatch(msg, true, func(msg *Message) {
|
||||
msg.Log("cmd", "%s %s %v %v", c.Name, key, arg, msg.Meta["option"])
|
||||
|
||||
if args := []string{}; x.Form != nil {
|
||||
for i := 0; i < len(arg); i++ {
|
||||
@ -1565,9 +1573,9 @@ func (m *Message) Cmd(args ...interface{}) *Message {
|
||||
}
|
||||
}
|
||||
if i+1+n > len(arg) {
|
||||
m.Add("option", arg[i], arg[i+1:])
|
||||
msg.Add("option", arg[i], arg[i+1:])
|
||||
} else {
|
||||
m.Add("option", arg[i], arg[i+1:i+1+n])
|
||||
msg.Add("option", arg[i], arg[i+1:i+1+n])
|
||||
}
|
||||
i += n
|
||||
} else {
|
||||
@ -1577,37 +1585,38 @@ func (m *Message) Cmd(args ...interface{}) *Message {
|
||||
arg = args
|
||||
}
|
||||
|
||||
target := m.target
|
||||
m.target = s
|
||||
target := msg.target
|
||||
msg.target = s
|
||||
|
||||
m.Hand = true
|
||||
switch v := m.Gdb("command", key, arg).(type) {
|
||||
msg.Hand = true
|
||||
switch v := msg.Gdb("command", key, arg).(type) {
|
||||
case string:
|
||||
m.Echo(v)
|
||||
msg.Echo(v)
|
||||
case nil:
|
||||
if m.Options("auto_cmd") {
|
||||
if msg.Options("auto_cmd") {
|
||||
if x.Auto != nil {
|
||||
x.Auto(m, c, key, arg...)
|
||||
x.Auto(msg, c, key, arg...)
|
||||
}
|
||||
} else {
|
||||
x.Hand(m, c, key, arg...)
|
||||
x.Hand(msg, c, key, arg...)
|
||||
}
|
||||
}
|
||||
if m.target == s {
|
||||
m.target = target
|
||||
if msg.target == s {
|
||||
msg.target = target
|
||||
}
|
||||
})
|
||||
}
|
||||
return m.Hand
|
||||
return msg.Hand
|
||||
})
|
||||
|
||||
if !m.Hand {
|
||||
m.Log("error", "cmd run error %s", m.Format())
|
||||
if !msg.Hand {
|
||||
msg.Log("error", "cmd run error %s", msg.Format())
|
||||
}
|
||||
return m
|
||||
return msg
|
||||
}
|
||||
|
||||
func (m *Message) Confm(key string, args ...interface{}) map[string]interface{} {
|
||||
random := ""
|
||||
var chain interface{}
|
||||
if len(args) > 0 {
|
||||
switch arg := args[0].(type) {
|
||||
@ -1616,7 +1625,12 @@ func (m *Message) Confm(key string, args ...interface{}) map[string]interface{}
|
||||
case []string:
|
||||
chain, args = arg, args[1:]
|
||||
case string:
|
||||
chain, args = arg, args[1:]
|
||||
switch arg {
|
||||
case "%", "*":
|
||||
random, args = arg, args[1:]
|
||||
default:
|
||||
chain, args = arg, args[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1660,9 +1674,23 @@ func (m *Message) Confm(key string, args ...interface{}) map[string]interface{}
|
||||
}
|
||||
fun(value)
|
||||
case func(string, map[string]interface{}):
|
||||
for k, v := range value {
|
||||
if val, ok := v.(map[string]interface{}); ok {
|
||||
fun(k, val)
|
||||
switch random {
|
||||
case "%":
|
||||
n, i := rand.Intn(len(value)), 0
|
||||
for k, v := range value {
|
||||
if val, ok := v.(map[string]interface{}); i == n && ok {
|
||||
fun(k, val)
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
case "*":
|
||||
fallthrough
|
||||
default:
|
||||
for k, v := range value {
|
||||
if val, ok := v.(map[string]interface{}); ok {
|
||||
fun(k, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
case func(string, map[string]interface{}) bool:
|
||||
|
@ -923,7 +923,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
nfs.printf(msg.Meta["result"])
|
||||
|
||||
if msg.Appends("file_pos0") {
|
||||
i = msg.Appendi("file_pos0") - 1
|
||||
i = int(msg.Appendi("file_pos0")) - 1
|
||||
msg.Append("file_pos0", "")
|
||||
}
|
||||
}
|
||||
@ -984,16 +984,15 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
if head == "detail" { // 接收请求
|
||||
msg.Detail(-1, "remote")
|
||||
msg.Option("remote_code", code)
|
||||
go msg.Call(func(msg *ctx.Message) *ctx.Message {
|
||||
nfs.echo <- msg
|
||||
return nil
|
||||
m.GoFunc(msg, func(msg *ctx.Message) {
|
||||
msg.Call(func(msg *ctx.Message) *ctx.Message {
|
||||
nfs.echo <- msg
|
||||
return nil
|
||||
})
|
||||
})
|
||||
} else { // 接收响应
|
||||
h := nfs.hand[kit.Int(code)]
|
||||
h.Copy(msg, "result").Copy(msg, "append")
|
||||
go func() {
|
||||
h.Back(h)
|
||||
}()
|
||||
h.Copy(msg, "result").Copy(msg, "append").Back(h)
|
||||
}
|
||||
msg, code, head, body = nil, "0", "result", "append"
|
||||
|
||||
|
@ -37,11 +37,10 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
"nnode": &ctx.Cache{Name: "nnode", Value: "0", Help: "节点数量"},
|
||||
},
|
||||
Configs: map[string]*ctx.Config{
|
||||
"node": &ctx.Config{Name: "node", Value: map[string]interface{}{}, Help: "主机信息"},
|
||||
"trust": &ctx.Config{Name: "trust", Value: map[string]interface{}{}, Help: "主机信息"},
|
||||
"current": &ctx.Config{Name: "current", Value: "", Help: "当前主机"},
|
||||
"timer": &ctx.Config{Name: "timer", Value: "", Help: "断线重连"},
|
||||
"timer_interval": &ctx.Config{Name: "timer_interval", Value: "10s", Help: "断线重连"},
|
||||
"current": &ctx.Config{Name: "current", Value: "", Help: "当前主机"},
|
||||
"trust": &ctx.Config{Name: "trust", Value: map[string]interface{}{}, Help: "可信主机"},
|
||||
"node": &ctx.Config{Name: "node", Value: map[string]interface{}{}, Help: "主机信息"},
|
||||
"timer": &ctx.Config{Name: "timer", Value: map[string]interface{}{"interval": "10s", "timer": ""}, Help: "断线重连"},
|
||||
},
|
||||
Commands: map[string]*ctx.Command{
|
||||
"init": &ctx.Command{Name: "init", Help: "启动", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
@ -94,8 +93,8 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
case "dial": // 连接主机
|
||||
m.Call(func(nfs *ctx.Message) *ctx.Message {
|
||||
// 断线重连
|
||||
if m.Confs("timer") {
|
||||
m.Conf("timer", m.Cmdx("cli.timer", "delete", m.Conf("timer")))
|
||||
if m.Confs("timer", "timer") {
|
||||
m.Conf("timer", "timer", m.Cmdx("cli.timer", "delete", m.Conf("timer", "timer")))
|
||||
}
|
||||
|
||||
m.Spawn(nfs.Target()).Call(func(node *ctx.Message) *ctx.Message {
|
||||
@ -126,7 +125,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
|
||||
// 清理主机
|
||||
nfs.Free(func(nfs *ctx.Message) bool {
|
||||
m.Conf("timer", m.Cmdx("cli.timer", "repeat", m.Conf("timer_interval"), "context", "ssh", "remote", "redial", arg[1:]))
|
||||
m.Conf("timer", "timer", m.Cmdx("cli.timer", "repeat", m.Conf("timer", "interval"), "context", "ssh", "remote", "redial", arg[1:]))
|
||||
m.Cmd("aaa.auth", m.Cmdx("aaa.auth", "nodes", node.Append("node.name")), "delete", "node")
|
||||
m.Log("info", "delete node %s", node.Append("node.name"))
|
||||
delete(m.Confm("node"), node.Append("node.name"))
|
||||
@ -213,11 +212,11 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
}
|
||||
}
|
||||
|
||||
if names[0] == "*" { // 广播命令
|
||||
m.Confm("node", func(name string, node map[string]interface{}) {
|
||||
if names[0] == "%" || names[0] == "*" { // 广播命令
|
||||
m.Confm("node", names[0], func(name string, node map[string]interface{}) {
|
||||
m.Find(kit.Format(node["module"]), true).Copy(m, "option").CallBack(sync, func(sub *ctx.Message) *ctx.Message {
|
||||
return m.Copy(sub, "append").Copy(sub, "result")
|
||||
}, "send", "", arg)
|
||||
return m.CopyFuck(sub, "append").CopyFuck(sub, "result").Echo("\n\n")
|
||||
}, "send", rest, arg)
|
||||
})
|
||||
|
||||
} else if m.Confm("node", names[0], func(node map[string]interface{}) { // 单播命令
|
||||
@ -344,7 +343,6 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
m.Cmd("aaa.auth", sess, "proxy", m.Option("node.route"))
|
||||
m.Echo(sess)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
if m.Options("remote_code") {
|
||||
|
@ -25,7 +25,7 @@ func (tcp *TCP) Fuck(address []string, action func(address string) (net.Conn, er
|
||||
for _, p := range address {
|
||||
m.Cap("address", p)
|
||||
for i := 0; i < m.Confi("retry", "counts"); i++ {
|
||||
go func() {
|
||||
m.GoFunc(m, func(m *ctx.Message) {
|
||||
p := m.Cap("address")
|
||||
if c, e := action(p); e == nil {
|
||||
tcp.Conn = c
|
||||
@ -34,7 +34,7 @@ func (tcp *TCP) Fuck(address []string, action func(address string) (net.Conn, er
|
||||
m.Log("info", "dial %s:%s %s", m.Cap("protocol"), p, e)
|
||||
fuck <- false
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
select {
|
||||
case ok := <-fuck:
|
||||
@ -176,6 +176,8 @@ func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool {
|
||||
ports = append(ports, fmt.Sprintf("%s:%s", "127.0.0.1", addr[len(addr)-1]))
|
||||
}
|
||||
m.Back(m.Spawn(m.Source()).Put("option", "node.port", ports))
|
||||
default:
|
||||
return true
|
||||
}
|
||||
|
||||
for {
|
||||
|
@ -310,7 +310,7 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
map[string]interface{}{"page": "stm", "hash": "expr", "word": []interface{}{"expr", "rep{", "exp", "}"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "return", "word": []interface{}{"return", "rep{", "exp", "}"}},
|
||||
|
||||
map[string]interface{}{"page": "word", "hash": "word", "word": []interface{}{"mul{", "~", "!", "=", "\\?\\?", "\\?", "<", ">$", ">@", ">", "\\|", "%", "exe", "str", "[a-zA-Z0-9_/\\-.:]+", "}"}},
|
||||
map[string]interface{}{"page": "word", "hash": "word", "word": []interface{}{"mul{", "~", "!", "=", "\\?\\?", "\\?", "<", ">$", ">@", ">", "\\|", "%", "exe", "str", "[a-zA-Z0-9_/\\-.:*%]+", "}"}},
|
||||
map[string]interface{}{"page": "cmd", "hash": "cmd", "word": []interface{}{"rep{", "word", "}"}},
|
||||
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"$", "(", "cmd", ")"}},
|
||||
|
||||
|
@ -116,7 +116,7 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心",
|
||||
if kit.Int(access["expire"]) < now {
|
||||
msg := m.Cmd("web.get", "wexin", access["url"], "appid", m.Conf("chat", "appid"), "secret", m.Conf("chat", "appmm"), "temp", "data")
|
||||
access["token"] = msg.Append("access_token")
|
||||
access["expire"] = msg.Appendi("expires_in") + now
|
||||
access["expire"] = int(msg.Appendi("expires_in")) + now
|
||||
}
|
||||
m.Echo("%v", access["token"])
|
||||
return
|
||||
@ -129,7 +129,7 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心",
|
||||
if kit.Int(ticket["expire"]) < now {
|
||||
msg := m.Cmd("web.get", "wexin", ticket["url"], "access_token", m.Cmdx(".access"), "temp", "data")
|
||||
ticket["value"] = msg.Append("ticket")
|
||||
ticket["expire"] = msg.Appendi("expires_in") + now
|
||||
ticket["expire"] = int(msg.Appendi("expires_in")) + now
|
||||
}
|
||||
m.Echo("%v", ticket["value"])
|
||||
return
|
||||
|
@ -88,7 +88,7 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心",
|
||||
"componet_view": "ScheduleList", "componet_init": "initScheduleList",
|
||||
"componet_ctx": "web.code", "componet_cmd": "schedule",
|
||||
"inputs": []interface{}{
|
||||
map[string]interface{}{"type": "choice", "name": "view", "value": "summary", "label": "显示字段", "choice": []interface{}{
|
||||
map[string]interface{}{"type": "choice", "name": "view", "value": "order", "label": "显示字段", "choice": []interface{}{
|
||||
map[string]interface{}{"name": "默认", "value": "default"},
|
||||
map[string]interface{}{"name": "行程", "value": "order"},
|
||||
map[string]interface{}{"name": "总结", "value": "summary"},
|
||||
@ -106,6 +106,9 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心",
|
||||
map[string]interface{}{"componet_name": "code", "componet_tmpl": "head", "metas": []interface{}{
|
||||
map[string]interface{}{"name": "viewport", "content": "width=device-width, initial-scale=0.7, user-scalable=no"},
|
||||
}, "favicon": "favicon.ico", "styles": []interface{}{"example.css", "code.css"}},
|
||||
map[string]interface{}{"componet_name": "banner", "componet_help": "banner", "componet_tmpl": "banner",
|
||||
"componet_view": "Banner", "componet_init": "initBanner",
|
||||
},
|
||||
|
||||
map[string]interface{}{"componet_name": "toolkit", "componet_help": "Ctrl+B", "componet_tmpl": "toolkit",
|
||||
"componet_view": "KitList", "componet_init": "initKitList",
|
||||
|
@ -62,7 +62,7 @@ var Index = &ctx.Context{Name: "wiki", Help: "文档中心",
|
||||
},
|
||||
Commands: map[string]*ctx.Command{
|
||||
"wiki_tree": &ctx.Command{Name: "wiki_tree", Help: "wiki_tree", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Cmdy("nfs.dir", path.Join(m.Confx("wiki_level"), kit.Select(m.Option("wiki_class"), arg, 0)), "dir_sort", "time_r")
|
||||
m.Cmdy("nfs.dir", path.Join(m.Confx("wiki_level"), kit.Select(m.Option("wiki_class"), arg, 0)), "dir_sort", "time", "time_r")
|
||||
return
|
||||
}},
|
||||
"wiki_text": &ctx.Command{Name: "wiki_text", Help: "wiki_text", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
@ -80,8 +80,12 @@ var Index = &ctx.Context{Name: "wiki", Help: "文档中心",
|
||||
ls = markdown.ToHTML(ls, nil, nil)
|
||||
m.Echo(string(ls))
|
||||
} else {
|
||||
m.Echo(m.Cmd("nfs.dir", path.Join(m.Confx("wiki_level"), m.Option("wiki_class")),
|
||||
"dir_deep", "dir_type", "dir", "time", "path").ToHTML())
|
||||
msg := m.Cmd("nfs.dir", path.Join(m.Confx("wiki_level"), m.Option("wiki_class")),
|
||||
"dir_deep", "dir_type", "dir", "time", "path")
|
||||
msg.Table(func(index int, value map[string]string) {
|
||||
msg.Meta["path"][index] = strings.TrimPrefix(value["path"], path.Join("usr", m.Confx("wiki_level")))
|
||||
})
|
||||
m.Echo(msg.ToHTML("wiki_list"))
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
@ -70,6 +70,9 @@ ctx = context = {
|
||||
var searchs = search[1].split("&");
|
||||
for (var i = 0; i < searchs.length; i++) {
|
||||
var keys = searchs[i].split("=");
|
||||
if (keys[1]=="") {
|
||||
continue
|
||||
}
|
||||
args[keys[0]] = decodeURIComponent(keys[1]);
|
||||
}
|
||||
}
|
||||
@ -93,6 +96,7 @@ ctx = context = {
|
||||
arg.push(k+"="+encodeURIComponent(args[k]));
|
||||
}
|
||||
location.search = arg.join("&");
|
||||
return value
|
||||
},
|
||||
Cookie: function(key, value) {
|
||||
if (key == undefined) {
|
||||
|
@ -50,3 +50,16 @@ fieldset pre code, fieldset code pre {
|
||||
border-left:solid 4px green;
|
||||
display:block;
|
||||
}
|
||||
|
||||
fieldset.Banner>ul {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
fieldset.Banner>ul>li {
|
||||
display:inline;
|
||||
padding:5px;
|
||||
margin:0;
|
||||
}
|
||||
fieldset.Banner>ul>li:hover {
|
||||
background-color:red;
|
||||
}
|
||||
|
@ -9,13 +9,21 @@ exp = example = {
|
||||
}
|
||||
return this
|
||||
},
|
||||
initHeader: function(field, option, output) {
|
||||
initHeader: function(page, field, option, output) {
|
||||
return [{"text": ["shylinux", "div", "title"]}]
|
||||
},
|
||||
initBanner: function(field, option, output) {
|
||||
initBanner: function(page, field, option, output) {
|
||||
field.querySelectorAll("li").forEach(function(item) {
|
||||
item.onclick = function(event) {
|
||||
ctx.Search("componet_group", item.innerText)
|
||||
if (item.innerText == "login") {
|
||||
ctx.Cookie("sessid", "")
|
||||
}
|
||||
}
|
||||
})
|
||||
return [{"text": ["shylinux", "div", "title"]}]
|
||||
},
|
||||
initFooter: function(field, option) {
|
||||
initFooter: function(page, field, option) {
|
||||
return [{"text": ["shycontext", "div", "title"]}]
|
||||
},
|
||||
onscroll: function(event, target, action) {
|
||||
|
@ -313,10 +313,16 @@ kit = toolkit = {
|
||||
input.onclick = input.onclick || function(event) {
|
||||
if (index == array.length-1) {
|
||||
if (input.value == "login") {
|
||||
option.ondaemon = function(msg) {
|
||||
page.reload()
|
||||
}
|
||||
page.Runs(page, option, function(msg) {
|
||||
if (document.referrer) {
|
||||
location.href = document.referrer
|
||||
} else {
|
||||
m.Search("componet_group", "")
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
page.Runs(page, option)
|
||||
return
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ var page = Page({
|
||||
ctx.Runs(page, option, function(msg) {
|
||||
output.innerHTML = ""
|
||||
var back = [{"button": ["知识", function(event) {
|
||||
ctx.Search({"wiki_class": "", "wiki_favor": ""})
|
||||
ctx.Search({"wiki_level": "", "wiki_class": "", "wiki_favor": ""})
|
||||
}]}]
|
||||
ctx.Search("wiki_class").split("/").forEach(function(value, index, array) {
|
||||
if (value) {
|
||||
@ -29,7 +29,7 @@ var page = Page({
|
||||
})}]},
|
||||
{"view": ["list"], "list": [{"tree": ctx.Table(msg, function(value, index) {
|
||||
if (!value.filename.endsWith("/")) {
|
||||
return {"leaf": [value.filename, function(event, target) {
|
||||
return {"leaf": [value.time.substr(5, 5)+" "+value.filename, function(event, target) {
|
||||
ctx.Search("wiki_favor", value.filename)
|
||||
}]}
|
||||
}
|
||||
@ -61,7 +61,13 @@ var page = Page({
|
||||
])
|
||||
|
||||
ui.text.querySelectorAll("table").forEach(function(value, index, array) {
|
||||
kit.OrderTable(value, field)
|
||||
kit.OrderTable(value)
|
||||
})
|
||||
ui.text.querySelectorAll("table.wiki_list").forEach(function(value, index, array) {
|
||||
kit.OrderTable(value, "path", function(event) {
|
||||
var text = event.target.innerText
|
||||
ctx.Search({"wiki_class": text})
|
||||
})
|
||||
})
|
||||
|
||||
ui.text.querySelectorAll("a").forEach(function(value, index, array) {
|
||||
@ -96,7 +102,7 @@ var page = Page({
|
||||
location.hash = id
|
||||
}]})
|
||||
} else if (value.tagName == "H4") {
|
||||
id = i+"."+(++j)+"."+(++k)
|
||||
id = i+"."+j+"."+(++k)
|
||||
text = id+" "+text
|
||||
h3.push({"leaf": [text+" ("+ratio+"%)", function(event) {
|
||||
console.log(text)
|
||||
@ -120,6 +126,7 @@ var page = Page({
|
||||
},
|
||||
init: function(exp) {
|
||||
var page = this
|
||||
|
||||
document.querySelectorAll("body>fieldset").forEach(function(field) {
|
||||
var option = field.querySelector("form.option")
|
||||
var output = field.querySelector("div.output")
|
||||
|
@ -20,6 +20,11 @@
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{define "banner"}}
|
||||
<fieldset class="{{options . "componet_view"}}" data-init="{{options . "componet_init"}}">
|
||||
<ul>{{range $key, $item := conf . "componet"}}<li>{{$key}}</li>{{end}}</ul>
|
||||
</fieldset>
|
||||
{{end}}
|
||||
{{define "fieldset"}}
|
||||
<fieldset class="{{options . "componet_view"}}" data-init="{{options . "componet_init"}}">
|
||||
<form class="option {{options . "componet_name"}}"
|
||||
|
@ -1,12 +1,84 @@
|
||||
## 《后端技术栈》简介
|
||||
## 后端技术栈
|
||||
后端技术栈,是对后端服务器开发中所用到的技术进行组合,不断的优化框架结构与服务水平。
|
||||
|
||||
- Linux
|
||||
- Nginx
|
||||
- Python 是一种脚本语言,
|
||||
- MySQL
|
||||
## 单机架构
|
||||
### LAMP
|
||||
#### Linux
|
||||
#### Apache
|
||||
#### Mysql
|
||||
#### PHP
|
||||
### OpenResty
|
||||
#### Nginx
|
||||
#### Sqlite3
|
||||
#### Lua
|
||||
### Flask
|
||||
#### Python
|
||||
### NodeJS+MongoDB
|
||||
#### NodeJS
|
||||
#### MongoDB
|
||||
## 集群架构
|
||||
### 平台
|
||||
#### 应用接口
|
||||
- REST API
|
||||
|
||||
#### 反向代理
|
||||
- nginx
|
||||
|
||||
#### 服务发现
|
||||
- consul
|
||||
|
||||
#### 服务治理
|
||||
|
||||
#### 代码仓库
|
||||
- gitlab
|
||||
|
||||
#### 虚拟容器
|
||||
- docker
|
||||
- linux
|
||||
- K8S
|
||||
|
||||
#### 配置中心
|
||||
- ETCD
|
||||
|
||||
#### 日志监控
|
||||
|
||||
#### 同步通信
|
||||
- Thrift
|
||||
- gRPC
|
||||
|
||||
#### 异步通信
|
||||
- Kafka
|
||||
|
||||
#### 缓冲存储
|
||||
- Redis
|
||||
|
||||
#### 事务存储
|
||||
- MySQL
|
||||
|
||||
#### 搜索引擎
|
||||
- es
|
||||
|
||||
#### 推荐引擎
|
||||
|
||||
### 设计
|
||||
#### DDD
|
||||
#### 事务性
|
||||
#### 分布式
|
||||
#### 高并发
|
||||
#### 高可用
|
||||
|
||||
### 开发
|
||||
#### 逻辑性
|
||||
#### 可读性
|
||||
### 测试
|
||||
#### 单元测试
|
||||
#### 集成测试
|
||||
### 部署
|
||||
#### 持续集成
|
||||
#### 持续部署
|
||||
### 运维
|
||||
#### DevOps
|
||||
|
||||
## 基础入门
|
||||
### Linux
|
||||
Linux系统的应用十分广泛,有很多流行的桌面操作系统与移动操作系统,尤其是在云计算的服务器领域和物联网的嵌入式设备中,
|
||||
|
@ -0,0 +1,8 @@
|
||||
## 简介
|
||||
|
||||
Kafka
|
||||
|
||||
- 官网: <https://kafka.apache.org/>
|
||||
- 文档: <https://kafka.apache.org/documentation/>
|
||||
- 源码: <https://archive.apache.org/dist/kafka/0.11.0.3/kafka-0.11.0.3-src.tgz>
|
||||
- 开源: <https://github.com/apache/kafka/tree/0.11.0>
|
@ -3,9 +3,9 @@
|
||||
MySQL 是一个开源的关系型数据库管理系统。
|
||||
|
||||
- 官网: <https://www.mysql.com/>
|
||||
- 源码: <https://dev.mysql.com/downloads/file/?id=482483>
|
||||
- 文档: <https://dev.mysql.com/doc/refman/5.6/en>
|
||||
- 开源: <https://github.com/mysql/mysql-server>
|
||||
- 源码: <https://dev.mysql.com/downloads/file/?id=480541>
|
||||
- 文档: <https://dev.mysql.com/doc/refman/5.5/en>
|
||||
- 开源: <https://github.com/mysql/mysql-server/tree/5.5>
|
||||
|
||||
## 下载安装
|
||||
### Ubuntu安装MySQL
|
||||
@ -44,6 +44,9 @@ mysql> help
|
||||
- connect 重新连接服务器
|
||||
- use 切换数据库
|
||||
|
||||
### 配置操作
|
||||
mysql启动时会从/etc/mysql/my.cnf加载配置,show variables;可以查看当前配置
|
||||
|
||||
### 数据库操作
|
||||
|
||||
- 查看 show databases
|
||||
@ -70,8 +73,10 @@ mysql> drop database demo;
|
||||
|
||||
### 关系表操作
|
||||
|
||||
- 查看 show tables
|
||||
- 创建 create table demo(a int)
|
||||
- 修改 alter table add column b int
|
||||
- 查看 desc demo
|
||||
- 删除 drop table demo
|
||||
|
||||
### 数据操作
|
||||
@ -82,31 +87,181 @@ mysql> drop database demo;
|
||||
- 删除 delete from demo where a=1
|
||||
|
||||
## 存储引擎
|
||||
|
||||
- 源码:<https://github.com/mysql/mysql-server/tree/5.5/storage>
|
||||
- 文档:<https://dev.mysql.com/doc/refman/5.5/en/storage-engines.html>
|
||||
|
||||
```
|
||||
mysql> show engines;
|
||||
```
|
||||
|
||||
|engine|comment|
|
||||
|------|-------|
|
||||
|InnoDB| supports transactions, row-level locking, and foreign keys|
|
||||
|MyISAM| |
|
||||
|MEMORY|hash based, stored in memory, useful for temporary tables|
|
||||
|BLACKHOLE| |
|
||||
|ARCHIVE| |
|
||||
|CSV| |
|
||||
|MRG_MYISAM| |
|
||||
|PERFORMANCE_SCHEMA| |
|
||||
|FEDERATED| |
|
||||
|
||||
### InnoDB
|
||||
|
||||
InnoDB是一种支持ACID事务的存储引擎
|
||||
|
||||
- 源码:<https://github.com/mysql/mysql-server/tree/5.5/storage/innobase>
|
||||
- 文档:<https://dev.mysql.com/doc/refman/5.5/en/innodb-storage-engine.html>
|
||||
|
||||
InnoDB是多线程的,通过命令可以看各线程的状态
|
||||
```
|
||||
mysql> show engine innodb status\G
|
||||
```
|
||||
|meta|task|
|
||||
|------|----|
|
||||
|BACKGROUND| 主线程 |
|
||||
|FILE I/O| IO线程 |
|
||||
|INSERT BUFFER AND HASH INDEX| 插入缓存与哈希索引 |
|
||||
|SEMAPHORES| |
|
||||
|TRANSACTIONS| |
|
||||
|BUFFER POOL AND MEMORY| |
|
||||
|ROW OPERATIONS| |
|
||||
|LOG| |
|
||||
|
||||
#### 线程与缓存
|
||||
MySQL的存储引擎是模块化,所以需要注册模块信息
|
||||
```
|
||||
// 注册模块 struct st_mysql_plugin {} // mysql-5.5.62/include/mysql/plugin.h:423
|
||||
mysql_declare_plugin(innobase) { // mysql-5.5.62/storage/innobase/handler/ha_innodb.cc:11925
|
||||
MYSQL_STORAGE_ENGINE_PLUGIN,
|
||||
&innobase_storage_engine,
|
||||
innobase_hton_name,
|
||||
plugin_author,
|
||||
"Supports transactions, row-level locking, and foreign keys",
|
||||
PLUGIN_LICENSE_GPL,
|
||||
innobase_init, /* Plugin Init */
|
||||
NULL, /* Plugin Deinit */
|
||||
INNODB_VERSION_SHORT,
|
||||
innodb_status_variables_export,/* status variables */
|
||||
innobase_system_variables, /* system variables */
|
||||
NULL, /* reserved */
|
||||
0, /* flags */
|
||||
}
|
||||
...
|
||||
mysql_declare_plugin_end;
|
||||
```
|
||||
|
||||
InnoDB在初始化函数中,会注册各种回调函数,并启动各种工作线程
|
||||
```
|
||||
innobase_init() // mysql-5.5.62/storage/innobase/handler/ha_innodb.cc:2218
|
||||
// 注册各种回调函数 struct handlerton {} // mysql-5.5.62/sql/handler.h:705
|
||||
innobase_hton->state = SHOW_OPTION_YES;
|
||||
innobase_hton->db_type= DB_TYPE_INNODB;
|
||||
innobase_hton->savepoint_offset=sizeof(trx_named_savept_t);
|
||||
innobase_hton->close_connection=innobase_close_connection;
|
||||
innobase_hton->savepoint_set=innobase_savepoint;
|
||||
innobase_hton->savepoint_rollback=innobase_rollback_to_savepoint;
|
||||
innobase_hton->savepoint_release=innobase_release_savepoint;
|
||||
innobase_hton->commit=innobase_commit;
|
||||
innobase_hton->rollback=innobase_rollback;
|
||||
innobase_hton->prepare=innobase_xa_prepare;
|
||||
innobase_hton->recover=innobase_xa_recover;
|
||||
innobase_hton->commit_by_xid=innobase_commit_by_xid;
|
||||
innobase_hton->rollback_by_xid=innobase_rollback_by_xid;
|
||||
innobase_hton->create_cursor_read_view=innobase_create_cursor_view;
|
||||
innobase_hton->set_cursor_read_view=innobase_set_cursor_view;
|
||||
innobase_hton->close_cursor_read_view=innobase_close_cursor_view;
|
||||
innobase_hton->create=innobase_create_handler;
|
||||
innobase_hton->drop_database=innobase_drop_database;
|
||||
innobase_hton->panic=innobase_end;
|
||||
innobase_hton->start_consistent_snapshot=innobase_start_trx_and_assign_read_view;
|
||||
innobase_hton->flush_logs=innobase_flush_logs;
|
||||
innobase_hton->show_status=innobase_show_status;
|
||||
innobase_hton->flags=HTON_SUPPORTS_FOREIGN_KEYS;
|
||||
innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
|
||||
|
||||
// 启动各种工作线程
|
||||
innobase_start_or_create_for_mysql() // srv/srv0start.c:1028
|
||||
os_thread_create(io_handler_thread, NULL, NULL);
|
||||
os_thread_create(&srv_lock_time_thread, NULL, NULL);
|
||||
os_thread_create(&srv_error_monitor_thread, NULL, NULL);
|
||||
os_thread_create(&srv_monitor_thread, NULL, NULL);
|
||||
os_thread_create(&srv_master_thread, NULL, NULL);
|
||||
os_thread_create(&srv_purge_thread, NULL, NULL);
|
||||
```
|
||||
|
||||
主线程
|
||||
```
|
||||
srv_master_thread() // mysql-5.5.62/storage/innobase/srv/srv0srv.c:2748
|
||||
loop:
|
||||
srv_main_1_second_loops++;
|
||||
|
||||
// 同步日志缓存
|
||||
srv_sync_log_buffer_in_background(); // srv/srv0srv.c:2702
|
||||
log_buffer_sync_in_background(TRUE); // log/log0log.c:1689
|
||||
log_write_up_to(lsn, LOG_NO_WAIT, flush);
|
||||
mutex_enter(&(log_sys->mutex));
|
||||
log_sys->write_lsn = log_sys->lsn;
|
||||
fil_flush(group->space_id); // fil/fil0fil.c:4755
|
||||
mutex_enter(&fil_system->mutex);
|
||||
os_file_flush(file); // os/os0file.c:2119
|
||||
os_file_fsync(file);
|
||||
fsync(file);
|
||||
|
||||
// 合并插入缓存
|
||||
ibuf_contract_for_n_pages(FALSE, PCT_IO(5));
|
||||
|
||||
// 刷新数据缓存
|
||||
buf_flush_list(PCT_IO(100), IB_ULONGLONG_MAX); // buf/buf0flu.c:1928
|
||||
buf_flush_batch(buf_pool, BUF_FLUSH_LRU, min_n, 0);
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
buf_flush_LRU_list_batch(buf_pool, min_n);
|
||||
buf_flush_flush_list_batch(buf_pool, min_n, lsn_limit);
|
||||
buf_flush_buffered_writes();
|
||||
mutex_enter(&(trx_doublewrite->mutex));
|
||||
buf_flush_sync_datafiles();
|
||||
|
||||
// 执行清理任务
|
||||
srv_master_do_purge();
|
||||
trx_purge(srv_purge_batch_size); // trx/trx0purge.c:1139
|
||||
rw_lock_x_lock(&purge_sys->latch);
|
||||
thr = que_fork_start_command(purge_sys->query);
|
||||
que_run_threads(thr);
|
||||
|
||||
background_loop:
|
||||
srv_main_background_loops++;
|
||||
row_drop_tables_for_mysql_in_background(); // row/row0mysql.c:2253
|
||||
mem_free(drop->table_name);
|
||||
|
||||
flush_loop:
|
||||
srv_main_flush_loops++;
|
||||
log_checkpoint(TRUE, FALSE); // log/log0log.c:2077
|
||||
log_groups_write_checkpoint_info();
|
||||
log_group_checkpoint(group);
|
||||
|
||||
suspend_thread:
|
||||
srv_suspend_thread(slot);
|
||||
|
||||
```
|
||||
|
||||
- 插入缓存与两次写
|
||||
- 自适应哈希索引
|
||||
- 启动、恢复、关闭
|
||||
- 引擎插件升级
|
||||
|
||||
#### 各种文件
|
||||
|
||||
配置文件,MySQL在启动时会加载配置文件,这些配置在运行时也可以随时读写
|
||||
|
||||
- show variables;
|
||||
- show variables like 'timeout';
|
||||
- set [global|session] var=val
|
||||
|
||||
日志文件
|
||||
数据文件
|
||||
|
||||
### MyISAM
|
||||
|
||||
- 下载: <https://dev.mysql.com/downloads/mysql/5.6.html#downloads>
|
||||
|
||||
- 博客: <http://blog.codinglabs.org/articles/theory-of-mysql-index.html>
|
||||
|
||||
变量的定义与引用: <https://www.cnblogs.com/EasonJim/p/7966918.html>
|
||||
|
||||
show engines
|
||||
show engine innodb status
|
||||
show variables
|
||||
|
||||
show databases
|
||||
create database demo
|
||||
drop database demo
|
||||
use demo
|
||||
|
||||
show tables
|
||||
create table t(a int unsigned not null, b char(10), primary key(a))
|
||||
drop table t
|
||||
|
||||
select * from t;
|
||||
insert into t values()
|
||||
update t set b='1234'
|
||||
delete from t
|
||||
|
||||
- 源码:<https://github.com/mysql/mysql-server/tree/5.5/storage/myisam>
|
||||
- 文档:<https://dev.mysql.com/doc/refman/5.5/en/myisam-storage-engine.html>
|
||||
|
@ -1,16 +1,16 @@
|
||||
## 简介
|
||||
Nginx 是一个异步框架的Web服务器,也可以用作反向代理,负载均衡和HTTP缓存。
|
||||
|
||||
- 维基百科: [https://zh.wikipedia.org/wiki/Nginx](https://zh.wikipedia.org/wiki/Nginx)
|
||||
- 官网: [https://www.nginx.org/](https://www.nginx.org/)
|
||||
- 官网: <https://www.nginx.org/>
|
||||
- 文档: <https://nginx.org/en/docs/>
|
||||
- 源码: <https://nginx.org/download/nginx-1.0.15.tar.gz>
|
||||
- 开源: <https://github.com/nginx/nginx/tree/branches/stable-1.0>
|
||||
|
||||
## 源码安装
|
||||
```
|
||||
$ wget http://nginx.org/download/nginx-1.15.2.tar.gz
|
||||
$ tar xzf nginx-1.15.2.tar.gz
|
||||
$ cd nginx-1.15.2
|
||||
$ ./configure
|
||||
$ make
|
||||
$ wget http://nginx.org/download/nginx-1.0.15.tar.gz
|
||||
$ tar xzf nginx-1.0.15.tar.gz && cd nginx-1.0.15
|
||||
$ ./configure && make
|
||||
$ sudo make install
|
||||
$ sudo nginx
|
||||
$ curl localhost
|
||||
|
@ -6,13 +6,12 @@ Redis是最流行的键值对存储数据库。
|
||||
- 官网: <https://redis.io>
|
||||
- 源码: <http://download.redis.io/releases/redis-4.0.9.tar.gz>
|
||||
- 文档: <https://redis.io/documentation>
|
||||
- 开源: <https://github.com/antirez/redis/tree/4.0>
|
||||
|
||||
## 源码安装
|
||||
```
|
||||
$ wget http://download.redis.io/releases/redis-4.0.11.tar.gz
|
||||
$ tar xzf redis-4.0.11.tar.gz
|
||||
$ cd redis-4.0.11
|
||||
$ make
|
||||
$ tar xzf redis-4.0.11.tar.gz && cd redis-4.0.11 && make
|
||||
```
|
||||
#### 启动服务端
|
||||
```
|
||||
@ -32,6 +31,186 @@ OK
|
||||
127.0.0.1:6379> get employee_name
|
||||
"shy"
|
||||
```
|
||||
## 源码解析
|
||||
### 数据结构
|
||||
#### sds
|
||||
#### dict
|
||||
#### intset
|
||||
#### adlist
|
||||
#### ziplist
|
||||
#### geohash
|
||||
#### geo
|
||||
|
||||
### 数据类型
|
||||
#### string
|
||||
#### list
|
||||
#### hash
|
||||
#### set
|
||||
#### zset
|
||||
|
||||
### 数据存储
|
||||
#### db
|
||||
#### expire
|
||||
#### notify
|
||||
#### script
|
||||
#### multi
|
||||
#### sort
|
||||
|
||||
### 服务框架
|
||||
#### server
|
||||
#### config
|
||||
#### module
|
||||
#### ae
|
||||
#### aof
|
||||
#### rdb
|
||||
|
||||
### 服务集群
|
||||
#### replication
|
||||
#### sentinel
|
||||
#### cluster
|
||||
#### pubsub
|
||||
|
||||
### 应用场景
|
||||
#### 数据缓存
|
||||
#### 分布式锁
|
||||
#### 计数统计
|
||||
#### 消息队列
|
||||
|
||||
基本类型
|
||||
```
|
||||
typedef struct redisObject { // server.h:585
|
||||
unsigned type:4;
|
||||
unsigned encoding:4;
|
||||
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
|
||||
* LFU data (least significant 8 bits frequency
|
||||
* and most significant 16 bits access time). */
|
||||
int refcount;
|
||||
void *ptr;
|
||||
} robj;
|
||||
```
|
||||
```
|
||||
typedef struct redisDb { // server.h:611
|
||||
dict *dict; /* The keyspace for this DB */
|
||||
dict *expires; /* Timeout of keys with a timeout set */
|
||||
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
|
||||
dict *ready_keys; /* Blocked keys that received a PUSH */
|
||||
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
|
||||
int id; /* Database ID */
|
||||
long long avg_ttl; /* Average TTL, just for stats */
|
||||
} redisDb;
|
||||
|
||||
struct redisServer { // server.h:874
|
||||
...
|
||||
redisDb *db;
|
||||
...
|
||||
int dbnum; /* Total number of configured DBs */
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 基本类型
|
||||
### 字符串sds
|
||||
```
|
||||
struct __attribute__ ((__packed__)) sdshdr64 { // sds.h:68
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
```
|
||||
|
||||
### 双链表adlist
|
||||
```
|
||||
typedef struct listNode { // adlist.h
|
||||
struct listNode *prev;
|
||||
struct listNode *next;
|
||||
void *value;
|
||||
} listNode;
|
||||
|
||||
typedef struct list {
|
||||
listNode *head;
|
||||
listNode *tail;
|
||||
void *(*dup)(void *ptr);
|
||||
void (*free)(void *ptr);
|
||||
int (*match)(void *ptr, void *key);
|
||||
unsigned long len;
|
||||
} list;
|
||||
```
|
||||
|
||||
```
|
||||
struct redisCommand redisCommandTable[] = {
|
||||
}
|
||||
```
|
||||
|
||||
### 哈希表dict
|
||||
```
|
||||
typedef struct dictEntry { // dict.h
|
||||
void *key;
|
||||
union {
|
||||
void *val;
|
||||
uint64_t u64;
|
||||
int64_t s64;
|
||||
double d;
|
||||
} v;
|
||||
struct dictEntry *next;
|
||||
} dictEntry;
|
||||
|
||||
typedef struct dictType {
|
||||
uint64_t (*hashFunction)(const void *key);
|
||||
void *(*keyDup)(void *privdata, const void *key);
|
||||
void *(*valDup)(void *privdata, const void *obj);
|
||||
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
|
||||
void (*keyDestructor)(void *privdata, void *key);
|
||||
void (*valDestructor)(void *privdata, void *obj);
|
||||
} dictType;
|
||||
|
||||
/* This is our hash table structure. Every dictionary has two of this as we
|
||||
* implement incremental rehashing, for the old to the new table. */
|
||||
typedef struct dictht {
|
||||
dictEntry **table;
|
||||
unsigned long size;
|
||||
unsigned long sizemask;
|
||||
unsigned long used;
|
||||
} dictht;
|
||||
|
||||
typedef struct dict {
|
||||
dictType *type;
|
||||
void *privdata;
|
||||
dictht ht[2];
|
||||
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
|
||||
unsigned long iterators; /* number of iterators currently running */
|
||||
} dict;
|
||||
```
|
||||
|
||||
### 跳跃表zskiplist
|
||||
```
|
||||
zskiplistNode { // server.h
|
||||
sds ele;
|
||||
double score;
|
||||
struct zskiplistNode *backward;
|
||||
struct zskiplistLevel {
|
||||
struct zskiplistNode *forward;
|
||||
unsigned int span;
|
||||
} level[];
|
||||
} zskiplistNode;
|
||||
|
||||
typedef struct zskiplist {
|
||||
struct zskiplistNode *header, *tail;
|
||||
unsigned long length;
|
||||
int level;
|
||||
} zskiplist;
|
||||
```
|
||||
|
||||
### 整数集合intset
|
||||
```
|
||||
typedef struct intset { // intset.h
|
||||
uint32_t encoding;
|
||||
uint32_t length;
|
||||
int8_t contents[];
|
||||
} intset;
|
||||
```
|
||||
|
||||
## 源码解析
|
||||
### 目录解析
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user