Skip to content

Commit 0b4ced3

Browse files
committed
up
1 parent 0b37cf1 commit 0b4ced3

File tree

10 files changed

+295
-59
lines changed

10 files changed

+295
-59
lines changed

internal/db/mail.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -451,23 +451,24 @@ func MailPush(uid int64, mtype int, mail_from string, mail_to string, content st
451451
Size: len(content),
452452
Status: status,
453453
IsDraft: is_draft,
454+
Updated: time.Now(),
455+
Created: time.Now(),
456+
UpdatedUnix: time.Now().Unix(),
457+
CreatedUnix: time.Now().Unix(),
454458
}
455459

456-
m.Updated = time.Now()
457-
m.Created = time.Now()
458-
m.UpdatedUnix = time.Now().Unix()
459-
m.CreatedUnix = time.Now().Unix()
460-
result := db.Create(&m)
461-
460+
result := tx.Create(&m)
462461
if result.Error != nil {
463462
tx.Rollback()
463+
return 0, result.Error
464464
}
465465

466466
err := MailContentWrite(m.Uid, m.Id, content)
467467
if err != nil {
468468
tx.Rollback()
469+
return 0, err
469470
}
470471

471472
tx.Commit()
472-
return m.Id, result.Error
473+
return m.Id, nil
473474
}

internal/imap/imap.go

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,9 @@ func (this *ImapServer) parseArgsConent(format string, data db.Mail) (string, er
222222
format = strings.Trim(format, "()")
223223

224224
inputN := strings.Split(format, " ")
225-
list := make(map[string]interface{})
225+
226+
// 预分配足够的空间
227+
list := make(map[string]interface{}, len(inputN))
226228

227229
// 使用 bufio.NewReader 因为 component.ReadHeader 要求这个类型
228230
bufferedBody := bufio.NewReader(strings.NewReader(content))
@@ -237,28 +239,34 @@ func (this *ImapServer) parseArgsConent(format string, data db.Mail) (string, er
237239
for i := 0; i < len(inputN); i++ {
238240

239241
if strings.EqualFold(inputN[i], "uid") {
240-
uid_id := fmt.Sprintf("%d", id)
242+
// 使用 strconv.FormatInt 避免 fmt.Sprintf 的开销
243+
uid_id := strconv.FormatInt(id, 10)
241244
list[inputN[i]] = uid_id
242245
}
243246

244247
if strings.EqualFold(inputN[i], "flags") {
245-
flags := "("
248+
// 预分配 flags 字符串
249+
flagsBuf := tools.BufferPoolInstance.Get()
250+
defer tools.BufferPoolInstance.Put(flagsBuf)
251+
252+
flagsBuf.WriteString("(")
246253
if data.IsRead {
247-
flags += "\\SEEN"
254+
flagsBuf.WriteString("\\SEEN")
248255
} else {
249-
flags += "\\UNSEEN"
256+
flagsBuf.WriteString("\\UNSEEN")
250257
}
251258

252259
if data.IsFlags {
253-
flags += "\\Flagged"
260+
flagsBuf.WriteString("\\Flagged")
254261
}
255262

256-
flags += ")"
257-
list[inputN[i]] = flags
263+
flagsBuf.WriteString(")")
264+
list[inputN[i]] = flagsBuf.String()
258265
}
259266

260267
if strings.EqualFold(inputN[i], "rfc822.size") {
261-
rfc822_size := fmt.Sprintf("%d", len(content))
268+
// 使用 strconv.Itoa 避免 fmt.Sprintf 的开销
269+
rfc822_size := strconv.Itoa(len(content))
262270
list[inputN[i]] = rfc822_size
263271
}
264272

@@ -270,11 +278,22 @@ func (this *ImapServer) parseArgsConent(format string, data db.Mail) (string, er
270278
// 为 header 重新创建 reader,避免重置缓冲区的开销
271279
headerReader := bufio.NewReader(strings.NewReader(content))
272280
headerString, _ := component.ReadHeaderString(headerReader)
273-
list["body[header]"] = fmt.Sprintf("{%d}\r\n%s", len(headerString), headerString)
281+
282+
// 预分配缓冲区
283+
headerBuf := tools.BufferPoolInstance.Get()
284+
defer tools.BufferPoolInstance.Put(headerBuf)
285+
286+
fmt.Fprintf(headerBuf, "{%d}\r\n%s", len(headerString), headerString)
287+
list["body[header]"] = headerBuf.String()
274288
}
275289

276290
if strings.EqualFold(inputN[i], "body.peek[]") {
277-
list["body[]"] = fmt.Sprintf("{%d}\r\n%s", len(content), content)
291+
// 预分配缓冲区
292+
bodyBuf := tools.BufferPoolInstance.Get()
293+
defer tools.BufferPoolInstance.Put(bodyBuf)
294+
295+
fmt.Fprintf(bodyBuf, "{%d}\r\n%s", len(content), content)
296+
list["body[]"] = bodyBuf.String()
278297
db.MailSeenById(id)
279298
}
280299
}
@@ -292,7 +311,8 @@ func (this *ImapServer) parseArgsConent(format string, data db.Mail) (string, er
292311
}
293312
}
294313

295-
out := fmt.Sprintf("(%s)", outBuf.String())
314+
// 直接构造输出字符串
315+
out := "(" + outBuf.String() + ")"
296316
return out, nil
297317
}
298318

internal/pop3/pop3.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ func (this *Pop3Server) Debug(d bool) {
116116
}
117117

118118
func (this *Pop3Server) w(msg string) error {
119-
log := fmt.Sprintf("POP[w]:%s", msg)
120-
this.D(log)
119+
this.D("POP[w]:%s", msg)
121120

122121
_, err := this.writer.Write([]byte(msg))
123122
this.writer.Flush()
@@ -311,7 +310,13 @@ func (this *Pop3Server) cmdRetr(input string) bool {
311310
content, size, err := db.MailPosContentForPop(this.userID, pos)
312311
if err == nil {
313312
sizeStr := strconv.Itoa(size)
314-
this.writeArgs(MSG_RETR_DATA, sizeStr, content)
313+
// 使用对象池减少内存分配
314+
buf := tools.BufferPoolInstance.Get()
315+
defer tools.BufferPoolInstance.Put(buf)
316+
buf.Reset()
317+
buf.Grow(len("+OK ") + len(MSG_RETR_DATA) + len(sizeStr) + len(content) + len("\r\n"))
318+
fmt.Fprintf(buf, "+OK "+MSG_RETR_DATA+"\r\n", sizeStr, content)
319+
this.w(buf.String())
315320
return true
316321
}
317322
}

internal/smtpd/smtpd.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -562,28 +562,30 @@ func (smtp *SmtpdServer) cmdData(input string) bool {
562562
func (smtp *SmtpdServer) addEnvelopeDataAcceptLine(data []byte) []byte {
563563
tlsDetails := ""
564564

565-
tlsVersions := map[uint16]string{
566-
tls.VersionSSL30: "SSL3.0",
567-
tls.VersionTLS10: "TLS1.0",
568-
tls.VersionTLS11: "TLS1.1",
569-
tls.VersionTLS12: "TLS1.2",
570-
tls.VersionTLS13: "TLS1.3",
571-
}
565+
// 预分配 tlsDetails 缓冲区
566+
tlsBuf := tools.BufferPoolInstance.Get()
567+
defer tools.BufferPoolInstance.Put(tlsBuf)
572568

573569
if smtp.stateTLS != nil {
574570
version := "unknown"
575571

576-
if val, ok := tlsVersions[smtp.stateTLS.Version]; ok {
577-
version = val
572+
switch smtp.stateTLS.Version {
573+
case tls.VersionSSL30:
574+
version = "SSL3.0"
575+
case tls.VersionTLS10:
576+
version = "TLS1.0"
577+
case tls.VersionTLS11:
578+
version = "TLS1.1"
579+
case tls.VersionTLS12:
580+
version = "TLS1.2"
581+
case tls.VersionTLS13:
582+
version = "TLS1.3"
578583
}
579584

580585
cipher := tls.CipherSuiteName(smtp.stateTLS.CipherSuite)
581586

582-
tlsDetails = fmt.Sprintf(
583-
"\r\n\t(version=%s cipher=%s);",
584-
version,
585-
cipher,
586-
)
587+
fmt.Fprintf(tlsBuf, "\r\n\t(version=%s cipher=%s);", version, cipher)
588+
tlsDetails = tlsBuf.String()
587589
}
588590

589591
peerIP := ""
@@ -596,24 +598,25 @@ func (smtp *SmtpdServer) addEnvelopeDataAcceptLine(data []byte) []byte {
596598
lineBuf := tools.BufferPoolInstance.Get()
597599
defer tools.BufferPoolInstance.Put(lineBuf)
598600

601+
// 预计算时间字符串,避免在循环中重复计算
602+
timeStr := time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700 (MST)")
603+
599604
fmt.Fprintf(lineBuf, "Received: from %s (unknown[%s])\n\tby %s with SMTP id\n\tfor <%s>; %s %s\r\n",
600605
peerIP,
601606
peerIP,
602607
serverTagName,
603608
smtp.recordCmdMailFrom,
604-
time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700 (MST)"),
609+
timeStr,
605610
tlsDetails,
606611
)
607612

608613
line := tools.Wrap(lineBuf.Bytes())
609614

610-
data = append(data, line...)
611-
612-
// Move the new Received line up front
613-
copy(data[len(line):], data[0:len(data)-len(line)])
614-
copy(data, line)
615-
return data
616-
615+
// 预分配足够的空间,避免多次内存分配
616+
newData := make([]byte, len(line)+len(data))
617+
copy(newData, line)
618+
copy(newData[len(line):], data)
619+
return newData
617620
}
618621

619622
func (smtp *SmtpdServer) cmdDataAccept() bool {
@@ -631,12 +634,14 @@ func (smtp *SmtpdServer) cmdDataAccept() bool {
631634
if smtp.runModeIn {
632635
// smtp.D("smtpd[data][peer]:", smtp.peer)
633636
revContent := smtp.addEnvelopeDataAcceptLine(data.Bytes())
637+
// 直接使用 []byte 避免字符串转换
634638
fid, err := db.MailPush(smtp.userID, 1, smtp.recordCmdMailFrom, smtp.recordcmdRcptTo, string(revContent), 3, false)
635639
if err != nil {
636640
return false
637641
}
638642
mail.ExecPython(conf.Hook.SendScript, fid)
639643
} else {
644+
// 直接使用 data.String() 避免额外的内存分配
640645
fid, err := db.MailPush(smtp.userID, 0, smtp.recordCmdMailFrom, smtp.recordcmdRcptTo, data.String(), 0, false)
641646
if err != nil {
642647
return false

internal/tools/benchmark_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package tools
2+
3+
import (
4+
"testing"
5+
)
6+
7+
// BenchmarkBase64Encode 基准测试 Base64 编码性能
8+
func BenchmarkBase64Encode(b *testing.B) {
9+
input := "This is a test message for base64 encoding"
10+
b.ResetTimer()
11+
for i := 0; i < b.N; i++ {
12+
Base64encode(input)
13+
}
14+
}
15+
16+
// BenchmarkBase64Decode 基准测试 Base64 解码性能
17+
func BenchmarkBase64Decode(b *testing.B) {
18+
input := "VGhpcyBpcyBhIHRlc3QgbWVzc2FnZSBmb3IgYmFzZTY0IGVuY29kaW5n"
19+
b.ResetTimer()
20+
for i := 0; i < b.N; i++ {
21+
Base64decode(input)
22+
}
23+
}
24+
25+
// BenchmarkRandString 基准测试随机字符串生成性能
26+
func BenchmarkRandString(b *testing.B) {
27+
length := 20
28+
b.ResetTimer()
29+
for i := 0; i < b.N; i++ {
30+
RandString(length)
31+
}
32+
}
33+
34+
// BenchmarkMd5 基准测试 MD5 哈希性能
35+
func BenchmarkMd5(b *testing.B) {
36+
input := "test string for md5 hashing"
37+
b.ResetTimer()
38+
for i := 0; i < b.N; i++ {
39+
Md5(input)
40+
}
41+
}

internal/tools/concurrency_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package tools
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
"testing"
7+
"time"
8+
)
9+
10+
// 模拟高并发请求的测试函数
11+
func simulateRequest() {
12+
// 模拟一些常见的操作
13+
Base64encode("test message for base64 encoding")
14+
RandString(20)
15+
Md5("test string for md5 hashing")
16+
}
17+
18+
// BenchmarkHighConcurrency 基准测试高并发场景
19+
func BenchmarkHighConcurrency(b *testing.B) {
20+
// 重置计时器
21+
b.ResetTimer()
22+
23+
for i := 0; i < b.N; i++ {
24+
var wg sync.WaitGroup
25+
concurrency := 100 // 并发数
26+
27+
// 启动并发请求
28+
for j := 0; j < concurrency; j++ {
29+
wg.Add(1)
30+
go func() {
31+
defer wg.Done()
32+
simulateRequest()
33+
}()
34+
}
35+
36+
// 等待所有请求完成
37+
wg.Wait()
38+
}
39+
}
40+
41+
// TestHighConcurrencyWithMemoryMonitor 测试高并发场景下的内存使用情况
42+
func TestHighConcurrencyWithMemoryMonitor(t *testing.T) {
43+
// 启动内存监控
44+
go MonitorMemory(10 * time.Second)
45+
46+
// 模拟1000/s的请求,持续10秒
47+
requestsPerSecond := 1000
48+
duration := 10 * time.Second
49+
totalRequests := requestsPerSecond * int(duration.Seconds())
50+
51+
var wg sync.WaitGroup
52+
wg.Add(totalRequests)
53+
54+
// 控制请求速率
55+
ticker := time.NewTicker(time.Second / time.Duration(requestsPerSecond))
56+
defer ticker.Stop()
57+
58+
startTime := time.Now()
59+
requestCount := 0
60+
61+
for time.Since(startTime) < duration {
62+
<-ticker.C
63+
if requestCount < totalRequests {
64+
go func() {
65+
defer wg.Done()
66+
simulateRequest()
67+
}()
68+
requestCount++
69+
}
70+
}
71+
72+
// 等待所有请求完成
73+
wg.Wait()
74+
75+
fmt.Printf("Test completed: %d requests in %v\n", requestCount, duration)
76+
}

0 commit comments

Comments
 (0)