package auth import ( "context" "runtime" "sync/atomic" ) // Pool 是 argon2id 并发池(DEVELOPMENT 第 12 节)。 type Pool struct { sem chan struct{} waiting atomic.Int64 active atomic.Int64 maxSeen atomic.Int64 // 测试用:观察到的最大并发 } // NewPool 创建大小为 CPU 核数的哈希池。 func NewPool() *Pool { return NewPoolSize(runtime.NumCPU()) } // NewPoolSize 创建指定并发上限的哈希池(测试可传入 1)。 func NewPoolSize(n int) *Pool { if n < 1 { n = 1 } return &Pool{sem: make(chan struct{}, n)} } // Hash 在池内计算 PHC 格式哈希。 func (p *Pool) Hash(ctx context.Context, _ PasswordKind, password string) (string, error) { if err := p.acquire(ctx); err != nil { return "", err } defer p.release() return HashPassword(password) } // Verify 在池内校验;常量时间比较。 func (p *Pool) Verify(ctx context.Context, _ PasswordKind, password, phc string) (bool, error) { if err := p.acquire(ctx); err != nil { return false, err } defer p.release() return VerifyPassword(password, phc) } // QueueLen 返回等待获取池槽位的任务数。 func (p *Pool) QueueLen() int { return int(p.waiting.Load()) } // MaxActive 返回曾达到的最大并发哈希数(测试用)。 func (p *Pool) MaxActive() int { return int(p.maxSeen.Load()) } func (p *Pool) acquire(ctx context.Context) error { p.waiting.Add(1) select { case p.sem <- struct{}{}: p.waiting.Add(-1) cur := p.active.Add(1) for { old := p.maxSeen.Load() if cur <= old || p.maxSeen.CompareAndSwap(old, cur) { break } } return nil case <-ctx.Done(): p.waiting.Add(-1) return ctx.Err() } } func (p *Pool) release() { p.active.Add(-1) <-p.sem } var _ HashPool = (*Pool)(nil)