![Do you remember?](https://quera.org/qbox/view/YvZopPEFmD/do-you-remember.jpg)
چیزی که از شما در این سوال میخواهیم، یک حافظهی نهان (*Cache*) از نوع کلید و مقداری است. این حافظهی نهان، اطلاعات را داخل دیسک نگهداری نمیکند و از نوع «داخل حافظهای» است.
تا اینجا احتمالاً ذهنتان سمت [*Redis*](https://redis.io/) رفته است، اما این حافظه به شکل خاص برای زبان *Go* طراحی شده و از امکانات این زبان بهره میبرد. به طور خاص برای اتصال از سمت کاربر به حافظهی نهان از چنلها استفاده میشود.
روال کار استفاده از حافظهی نهان را میتوان به این شکل خلاصه کرد:
+ یک کَش جدید ساخته میشود. این کش از کشهای دیگر که تا الان ساخته شدهاند مجزا است.
+ از کش درخواست یک اتصال جدید میشود. در نتیجه یک جفت چنل ارسال و دریافت برمیگردد.
+ با کمک *اتصال* خود میتوانیم به کش دستور دهیم، مثلاً یک کلید و مقدار دهیم تا ذخیره شود.
+ با کمک همین اتصال یا اتصالات دیگر میتوانیم با داشتن کلید خود، مقدار را به دست بیاوریم.
به جز `Get` و `Set` که قابلیتهای اولیهی یک حافظهی نهان هستند، یک عملیات دیگر نیز تعریف میشود به نام `SetWithRTL` که در اینجا *RTL* مخفف *Request to Live* است. این عدد برای هر کلید تعریف میشود و به معنی تعداد درخواستهای خواندن است که پس از ذخیره شدن مقدار آن کلید میتوانیم انجام دهیم تا نهایتاً آن کلید حذف شود. برای نمونه اگر یک *RTL* برابر با ۳ داشته باشیم، چنین اتفاقی میتواند بیفتد: پس از ۳ بار خواندن، آن مقدار از حافظه حذف شده است، بهگونهای که اصلاً وجود نداشته.
```
client: Set my_key my_val 3
client: Get my_key
server: my_val
client: Get my_key
server: my_val
client: Get my_key
server: my_val
client: Get my_key
server:
```
## جزئیات پروژه
پروژهی اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/157643/) دانلود کنید. ساختار فایلهای پروژه به صورت زیر است:
```
cache/
├── go.mod
├── go.sum
├── main.go
├── cache.go
└── main_sample_test.go
```
در فایل `cache.go` چند تابع وجود دارد که در `main.go` استفاده شدهاند و شما باید آنها را کامل کنید.
در فایل `main.go` که نمیتوانید محتوای آن را تغییر دهید، پیادهسازی سمت کاربر این حافظهی نهان آمده است و در فایل تست نمونه، نحوه استفاده از آن آمده است.
در فایل `cache.go` فقط امضای توابع آمدهاند. شما باید مطابق خواستهی صورت سؤال توابع را کامل کرده و در صورت نیاز توابع جدید اضافه کنید.
### فایل `main.go`
```go main.go go
func (conn *CacheClientConnection) Set(key string, val CacheVal) {
}
func (conn *CacheClientConnection) SetWithRTL(key string, val CacheVal, RTL int) {
}
func (conn *CacheClientConnection) Get(key string) CacheVal {
}
```
در این فایل همهی توابع پیادهسازی شدهاند و بر اساس این پیادهسازیها پروتوکل ارتباط بین کلاینت و سرور را مشاهده خواهید کرد. برای مثال، در صورتی که برای کلید مقداری وجود نداشته باشد، رشتهی خالی برمیگردد.
### فایل `cache.go`
```go cache.go go
type Cache struct {
}
type CacheServerConnection struct {
}
func InitCache() *Cache {
// TODO
return nil
}
func (cache *Cache) Connect(name string) *CacheClientConnection {
}
```
### تابع `InitCache`
در این تابع یک کش جدید ساخته شده و مقدار میگیرد و اشارهگر به آن برمیگردد. همچنین در صورت نیاز میتواند عملیات دیگری نیز انجام شود.
### تابع `Connect`
در این قسمت یک کاربر جدید با یک نام جدید (که تضمین میشود یکتاست) میخواهد به این کش متصل شود. برای این منظور یک جفت چنل درست میشود که در قالب یک `CacheClientConnection` به کاربر برمیگردد. همچنین باید این دو چنل برای خود کش نیز نگه داشته شوند تا بتوان به آنها گوش داد.
# آنچه باید آپلود کنید
پس از پیادهسازی توابع خواستهشده، فایل `cache.go` را آپلود کنید.