Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial module with codes and documentation #1

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
coverage:
status:
project:
default:
target: 0
threshold: null
base: auto
patch:
default:
target: 0
threshold: null
base: auto
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @yuseferi
13 changes: 13 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

# Configure version updates for both dependencies defined in manifests and vendored dependencies

version: 2
updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: "weekly"
24 changes: 24 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Build
on:
workflow_run:
workflows: [Quality check]
types: [completed]

push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
- name: Build
run: go mod download; go build -v ./...
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Quality check
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
lint:
name: Linter
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Linter
uses: golangci/golangci-lint-action@v3
with:
version: v1.53.2
fail_ci_if_error: true
tests:
name: Tests
needs: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
- name: Run tests
run: go mod download; go test -cover -coverprofile=./unit-cover.txt -race ./...
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
files: ./unit-cover.txt
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true
verbose: true
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@

# Go workspace file
go.work
.vs/
.idea/
47 changes: 47 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
run:
deadline: 5m
issues-exit-code: 1
skip-dirs:
- docs
- mocks
- scripts

output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true

linters-settings:
dupl:
threshold: 250
lll:
line-length: 160
goconst:
min-len: 2
min-occurrences: 3
errcheck:
exclude-functions:
- (io.Closer).Close
cyclop:
max-complexity: 10
funlen:
lines: 50

linters:
disable-all: true
enable:
- dupl
- errcheck
- goconst
- gosec
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused
- funlen
- cyclop
- lll
- forbidigo

39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# gocache (zap with context)
[![codecov](https://codecov.io/github/yuseferi/gocache/branch/codecov-integration/graph/badge.svg?token=64IHXT3ROF)](https://codecov.io/github/yuseferi/gocache)
[![CodeQL](https://github.com/yuseferi/gocache/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/yuseferi/gocache/actions/workflows/github-code-scanning/codeql)
[![Check & Build](https://github.com/yuseferi/gocache/actions/workflows/ci.yml/badge.svg)](https://github.com/yuseferi/gocache/actions/workflows/ci.yml)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/yuseferi/gocache)

gocache provides a data race-free cache implementation in Go.


### Installation

```shell
go get -u github.com/yuseferi/gocache
```

### Usage:



```Go
cache := gocache.NewCache(time.Minute * 2) // with 2 minutes interval cleaning expired items
cache.Set("key", "value", time.Minute) // set cache
value, found := cache.Get("key") // retrive cache data
cache.Delete("key") // delete specific key manually
cache.Clear() // clear all cache items ( purge)
size := cache.Size() // get cache size
```


### Contributing
We strongly believe in open-source ❤️😊. Please feel free to contribute by raising issues and submitting pull requests to make gocache even better!


Released under the [GNU GENERAL PUBLIC LICENSE](LICENSE).




11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/yuseferi/gocache

go 1.20

require github.com/stretchr/testify v1.8.4

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
114 changes: 114 additions & 0 deletions gocache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Package gocache provides a data race-free cache implementation in Go.
//
// Usage:
//
// cache := gocache.NewCache(time.Minute * 2) // with 2 minutes interval cleaning
// cache.Set("key", "value", time.Minute)
// value, found := cache.Get("key")
// cache.Delete("key")
// cache.Clear()
// size := cache.Size()
package gocache

import (
"sync"
"time"
)

// Cache represents a data race-free cache.
type Cache struct {
items map[string]cacheItem
mutex sync.RWMutex
cleanupExpiredPeriod time.Duration
}

type cacheItem struct {
value interface{}
expiration time.Time
}

// NewCache creates a new Cache instance.
func NewCache(cleanupExpiredPeriod time.Duration) *Cache {
cache := &Cache{
items: make(map[string]cacheItem),
}
cache.cleanupExpiredPeriod = cleanupExpiredPeriod
// Start a goroutine to periodically check for expired items and remove them
go cache.deleteExpiredItems()

return cache
}

// Get retrieves the value associated with the specified key from the cache.
// It returns the value and a boolean indicating whether the key was found or not.
// If the key is found but the associated item has expired, the value will be nil
// and the boolean will be false.
func (c *Cache) Get(key string) (interface{}, bool) {
c.mutex.RLock()
defer c.mutex.RUnlock()

item, found := c.items[key]
if !found {
return nil, false
}

if item.expiration.Before(time.Now()) {
return nil, false
}

return item.value, true
}

// Set adds or updates a key-value pair in the cache with the specified expiration duration.
// If the key already exists, its value and expiration are updated.
func (c *Cache) Set(key string, value interface{}, expiration time.Duration) {
c.mutex.Lock()
defer c.mutex.Unlock()

expirationTime := time.Now().Add(expiration)
c.items[key] = cacheItem{
value: value,
expiration: expirationTime,
}
}

// Delete removes the specified key and its associated value from the cache.
// If the key does not exist in the cache, the function does nothing.
func (c *Cache) Delete(key string) {
c.mutex.Lock()
defer c.mutex.Unlock()

delete(c.items, key)
}

// Clear removes all items from the cache, making it empty.
func (c *Cache) Clear() {
c.mutex.Lock()
defer c.mutex.Unlock()

c.items = make(map[string]cacheItem)
}

// Size returns the number of items currently stored in the cache.
func (c *Cache) Size() int {
c.mutex.RLock()
defer c.mutex.RUnlock()

return len(c.items)
}

// deleteExpiredItems is a background goroutine that periodically checks for expired items in the cache
// and removes them. It runs indefinitely after the Cache is created.
func (c *Cache) deleteExpiredItems() {
for {
<-time.After(c.cleanupExpiredPeriod) // Adjust the time interval for checking expired items

c.mutex.Lock()
for key, item := range c.items {
if item.expiration.Before(time.Now()) {
delete(c.items, key)
}
}
c.mutex.Unlock()
}
}
Loading