Решение на Concurrent Tasks от Юлия Недялкова

Обратно към всички решения

Към профила на Юлия Недялкова

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 8 успешни тест(а)
  • 2 неуспешни тест(а)

Код

package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"sync"
)
const (
_ = iota
TakeBook
ReturnBook
GetAvailability
)
type Author struct {
FirstName string `json:"first_name" xml:"first_name"`
SecondName string `json:"last_name" xml:"last_name"`
}
type Book struct {
Isbn string `json:"isbn" xml:"isbn,attr"`
Title string `json:"title" xml:"title"`
Author Author `json:"author" xml:"author"`
Ratings []int `json:"ratings" xml:"ratings>rating"`
}
func (b *Book) String() string {
return fmt.Sprintf("[%s] %s от %s %s", b.Isbn, b.Title, b.Author.FirstName, b.Author.SecondName)
}
type Library interface {
AddBookJSON(data []byte) (int, error)
AddBookXML(data []byte) (int, error)
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type Librarians struct {
count int
mutex *sync.Mutex
condition *sync.Cond
}
type MyLibrary struct {
syncLibrary *SyncLibrary
librarians *Librarians
}
type SyncLibrary struct {
books map[string]*LibraryBook
mutex *sync.Mutex
}
func (b *MyLibrary) AddBook(data []byte, format string) (int, error) {
var book Book
var err error
library := b.syncLibrary.books
libraryMutex := b.syncLibrary.mutex
if format == "json" {
err = json.Unmarshal(data, &book)
} else {
err = xml.Unmarshal(data, &book)
}
if err != nil {
return 0, err
}
libraryMutex.Lock()
value, ok := library[book.Isbn]
libraryMutex.Unlock()
if !ok {
libraryMutex.Lock()
library[book.Isbn] = &LibraryBook{book, 1, 0}
libraryMutex.Unlock()
return 1, nil
} else {
if value.registered == 4 {
return 0, fmt.Errorf("Има 4 копия на книга %s", book.Isbn)
}
count := library[book.Isbn].add("registered")
return count, nil
}
}
func (b *MyLibrary) AddBookJSON(data []byte) (int, error) {
return b.AddBook(data, "json")
}
func (b *MyLibrary) AddBookXML(data []byte) (int, error) {
return b.AddBook(data, "xml")
}
func (l *MyLibrary) TakeLibrarian() {
librarians := l.librarians
librarians.mutex.Lock()
defer librarians.mutex.Unlock()
librarians.condition.L.Lock()
for librarians.count == 0 {
librarians.condition.Wait()
}
librarians.count -= 1
librarians.condition.L.Unlock()
}
func (l *MyLibrary) ReturnLibrarian() {
librarians := l.librarians
librarians.mutex.Lock()
defer librarians.mutex.Unlock()
librarians.count += 1
if librarians.count == 1 {
librarians.condition.Broadcast()
}
}
func (b *MyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
b.TakeLibrarian()
requestChannel := make(chan LibraryRequest, 10000)
responseChannel := make(chan LibraryResponse, 10000)
go serveRequests(b, requestChannel, responseChannel)
return requestChannel, responseChannel
}
func serveRequests(library *MyLibrary, requests chan LibraryRequest, responses chan LibraryResponse) {
for request := range requests {
switch request.GetType() {
case TakeBook:
takeBook(library, request, responses)
case ReturnBook:
returnBook(library, request, responses)
case GetAvailability:
getAvailability(library, request, responses)
}
}
library.ReturnLibrarian()
}
func takeBook(lib *MyLibrary, request LibraryRequest, responses chan LibraryResponse) {
library := lib.syncLibrary.books
libraryMutex := lib.syncLibrary.mutex
libraryMutex.Lock()
bookInfo, ok := library[request.GetISBN()]
if !ok {
response := &LibraryResponseInfo{nil, 0, 0, fmt.Errorf("Непозната книга %s", request.GetISBN())}
libraryMutex.Unlock()
responses <- response
return
}
if bookInfo.get("available") == 0 {
response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), fmt.Errorf("Няма наличност на книга %s", request.GetISBN())}
libraryMutex.Unlock()
responses <- response
return
}
bookInfo.add("borrowed")
response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), nil}
libraryMutex.Unlock()
responses <- response
}
func returnBook(lib *MyLibrary, request LibraryRequest, responses chan LibraryResponse) {
library := lib.syncLibrary.books
libraryMutex := lib.syncLibrary.mutex
libraryMutex.Lock()
bookInfo, ok := library[request.GetISBN()]
if !ok {
response := &LibraryResponseInfo{nil, 0, 0, fmt.Errorf("Непозната книга %s", request.GetISBN())}
libraryMutex.Unlock()
responses <- response
return
} else if bookInfo.get("borrowed") == bookInfo.get("registered") {
response := &LibraryResponseInfo{nil, bookInfo.get("available"), bookInfo.get("registered"), fmt.Errorf("Всички копия са налични %s", request.GetISBN())}
libraryMutex.Unlock()
responses <- response
return
}
bookInfo.returnBorrowed()
response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), nil}
libraryMutex.Unlock()
responses <- response
}
func getAvailability(lib *MyLibrary, request LibraryRequest, responses chan LibraryResponse) {
library := lib.syncLibrary.books
libraryMutex := lib.syncLibrary.mutex
libraryMutex.Lock()
bookInfo, ok := library[request.GetISBN()]
if !ok {
response := &LibraryResponseInfo{nil, 0, 0, fmt.Errorf("Непозната книга %s", request.GetISBN())}
libraryMutex.Unlock()
responses <- response
return
} else {
response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), nil}
libraryMutex.Unlock()
responses <- response
}
}
type LibraryBook struct {
book Book
registered int
borrowed int
}
func (lb *LibraryBook) add(field string) int {
switch field {
case "registered":
lb.registered++
return lb.registered
case "borrowed":
lb.borrowed++
return lb.borrowed
}
return -1
}
func (lb *LibraryBook) returnBorrowed() int {
lb.borrowed--
return lb.borrowed
}
func (lb *LibraryBook) get(field string) int {
switch field {
case "borrowed":
return lb.borrowed
case "registered":
return lb.registered
case "available":
return lb.registered - lb.borrowed
}
return -1
}
func NewLibrary(librariansNum int) Library {
lib := make(map[string]*LibraryBook)
locker := new(sync.Mutex)
librarians := &Librarians{librariansNum, new(sync.Mutex), sync.NewCond(locker)}
syncLibrary := &SyncLibrary{lib, new(sync.Mutex)}
library := &MyLibrary{syncLibrary, librarians}
return library
}
type LibraryRequest interface {
GetType() int
GetISBN() string
}
type LibraryRequestInfo struct {
requestType int
bookRequestedISBN string
}
func (r *LibraryRequestInfo) GetType() int {
return r.requestType
}
func (r *LibraryRequestInfo) GetISBN() string {
return r.bookRequestedISBN
}
type LibraryResponse interface {
GetBook() (fmt.Stringer, error)
GetAvailability() (available int, registered int)
}
type LibraryResponseInfo struct {
book *Book
availableLeft int
registered int
error error
}
func (l *LibraryResponseInfo) GetBook() (fmt.Stringer, error) {
if l.book == nil {
return nil, l.error
}
return l.book, nil
}
func (l *LibraryResponseInfo) GetAvailability() (available int, registered int) {
return l.availableLeft, l.registered
}

Лог от изпълнението

PASS
ok  	_/tmp/d20151207-5667-upmt93	0.004s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.004s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.004s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.005s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.003s
--- FAIL: TestTakeBookRequest (0.00s)
	solution_test.go:255: Expected error but got nil
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-upmt93	0.004s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.004s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.004s
--- FAIL: TestReturnSomeBooks (0.00s)
	solution_test.go:351: Expected error got nil
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-upmt93	0.006s
PASS
ok  	_/tmp/d20151207-5667-upmt93	0.004s

История (1 версия и 0 коментара)

Юлия обнови решението на 06.12.2015 17:33 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "sync"
+)
+
+const (
+ _ = iota
+ TakeBook
+ ReturnBook
+ GetAvailability
+)
+
+type Author struct {
+ FirstName string `json:"first_name" xml:"first_name"`
+ SecondName string `json:"last_name" xml:"last_name"`
+}
+
+type Book struct {
+ Isbn string `json:"isbn" xml:"isbn,attr"`
+ Title string `json:"title" xml:"title"`
+ Author Author `json:"author" xml:"author"`
+ Ratings []int `json:"ratings" xml:"ratings>rating"`
+}
+
+func (b *Book) String() string {
+ return fmt.Sprintf("[%s] %s от %s %s", b.Isbn, b.Title, b.Author.FirstName, b.Author.SecondName)
+}
+
+type Library interface {
+ AddBookJSON(data []byte) (int, error)
+ AddBookXML(data []byte) (int, error)
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+type Librarians struct {
+ count int
+ mutex *sync.Mutex
+ condition *sync.Cond
+}
+
+type MyLibrary struct {
+ syncLibrary *SyncLibrary
+ librarians *Librarians
+}
+
+type SyncLibrary struct {
+ books map[string]*LibraryBook
+ mutex *sync.Mutex
+}
+
+func (b *MyLibrary) AddBook(data []byte, format string) (int, error) {
+ var book Book
+ var err error
+ library := b.syncLibrary.books
+ libraryMutex := b.syncLibrary.mutex
+
+ if format == "json" {
+ err = json.Unmarshal(data, &book)
+ } else {
+ err = xml.Unmarshal(data, &book)
+ }
+ if err != nil {
+ return 0, err
+ }
+ libraryMutex.Lock()
+ value, ok := library[book.Isbn]
+ libraryMutex.Unlock()
+
+ if !ok {
+ libraryMutex.Lock()
+ library[book.Isbn] = &LibraryBook{book, 1, 0}
+ libraryMutex.Unlock()
+ return 1, nil
+ } else {
+ if value.registered == 4 {
+ return 0, fmt.Errorf("Има 4 копия на книга %s", book.Isbn)
+ }
+ count := library[book.Isbn].add("registered")
+ return count, nil
+ }
+}
+func (b *MyLibrary) AddBookJSON(data []byte) (int, error) {
+ return b.AddBook(data, "json")
+}
+
+func (b *MyLibrary) AddBookXML(data []byte) (int, error) {
+ return b.AddBook(data, "xml")
+}
+
+func (l *MyLibrary) TakeLibrarian() {
+ librarians := l.librarians
+ librarians.mutex.Lock()
+ defer librarians.mutex.Unlock()
+ librarians.condition.L.Lock()
+ for librarians.count == 0 {
+ librarians.condition.Wait()
+ }
+ librarians.count -= 1
+ librarians.condition.L.Unlock()
+}
+
+func (l *MyLibrary) ReturnLibrarian() {
+ librarians := l.librarians
+ librarians.mutex.Lock()
+ defer librarians.mutex.Unlock()
+ librarians.count += 1
+ if librarians.count == 1 {
+ librarians.condition.Broadcast()
+ }
+}
+
+func (b *MyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ b.TakeLibrarian()
+ requestChannel := make(chan LibraryRequest, 10000)
+ responseChannel := make(chan LibraryResponse, 10000)
+ go serveRequests(b, requestChannel, responseChannel)
+ return requestChannel, responseChannel
+}
+
+func serveRequests(library *MyLibrary, requests chan LibraryRequest, responses chan LibraryResponse) {
+ for request := range requests {
+ switch request.GetType() {
+ case TakeBook:
+ takeBook(library, request, responses)
+ case ReturnBook:
+ returnBook(library, request, responses)
+ case GetAvailability:
+ getAvailability(library, request, responses)
+ }
+ }
+ library.ReturnLibrarian()
+}
+
+func takeBook(lib *MyLibrary, request LibraryRequest, responses chan LibraryResponse) {
+ library := lib.syncLibrary.books
+ libraryMutex := lib.syncLibrary.mutex
+ libraryMutex.Lock()
+ bookInfo, ok := library[request.GetISBN()]
+ if !ok {
+ response := &LibraryResponseInfo{nil, 0, 0, fmt.Errorf("Непозната книга %s", request.GetISBN())}
+ libraryMutex.Unlock()
+ responses <- response
+ return
+ }
+ if bookInfo.get("available") == 0 {
+ response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), fmt.Errorf("Няма наличност на книга %s", request.GetISBN())}
+ libraryMutex.Unlock()
+ responses <- response
+ return
+ }
+ bookInfo.add("borrowed")
+ response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), nil}
+ libraryMutex.Unlock()
+ responses <- response
+}
+
+func returnBook(lib *MyLibrary, request LibraryRequest, responses chan LibraryResponse) {
+ library := lib.syncLibrary.books
+ libraryMutex := lib.syncLibrary.mutex
+ libraryMutex.Lock()
+ bookInfo, ok := library[request.GetISBN()]
+ if !ok {
+ response := &LibraryResponseInfo{nil, 0, 0, fmt.Errorf("Непозната книга %s", request.GetISBN())}
+ libraryMutex.Unlock()
+ responses <- response
+ return
+ } else if bookInfo.get("borrowed") == bookInfo.get("registered") {
+ response := &LibraryResponseInfo{nil, bookInfo.get("available"), bookInfo.get("registered"), fmt.Errorf("Всички копия са налични %s", request.GetISBN())}
+ libraryMutex.Unlock()
+ responses <- response
+ return
+ }
+ bookInfo.returnBorrowed()
+ response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), nil}
+ libraryMutex.Unlock()
+ responses <- response
+}
+
+func getAvailability(lib *MyLibrary, request LibraryRequest, responses chan LibraryResponse) {
+ library := lib.syncLibrary.books
+ libraryMutex := lib.syncLibrary.mutex
+ libraryMutex.Lock()
+ bookInfo, ok := library[request.GetISBN()]
+ if !ok {
+ response := &LibraryResponseInfo{nil, 0, 0, fmt.Errorf("Непозната книга %s", request.GetISBN())}
+ libraryMutex.Unlock()
+ responses <- response
+ return
+ } else {
+ response := &LibraryResponseInfo{&bookInfo.book, bookInfo.get("available"), bookInfo.get("registered"), nil}
+ libraryMutex.Unlock()
+ responses <- response
+ }
+}
+
+type LibraryBook struct {
+ book Book
+ registered int
+ borrowed int
+}
+
+func (lb *LibraryBook) add(field string) int {
+ switch field {
+ case "registered":
+ lb.registered++
+ return lb.registered
+ case "borrowed":
+ lb.borrowed++
+ return lb.borrowed
+ }
+ return -1
+}
+
+func (lb *LibraryBook) returnBorrowed() int {
+ lb.borrowed--
+ return lb.borrowed
+}
+
+func (lb *LibraryBook) get(field string) int {
+ switch field {
+ case "borrowed":
+ return lb.borrowed
+ case "registered":
+ return lb.registered
+ case "available":
+ return lb.registered - lb.borrowed
+ }
+ return -1
+}
+
+func NewLibrary(librariansNum int) Library {
+ lib := make(map[string]*LibraryBook)
+ locker := new(sync.Mutex)
+ librarians := &Librarians{librariansNum, new(sync.Mutex), sync.NewCond(locker)}
+ syncLibrary := &SyncLibrary{lib, new(sync.Mutex)}
+ library := &MyLibrary{syncLibrary, librarians}
+ return library
+}
+
+type LibraryRequest interface {
+ GetType() int
+ GetISBN() string
+}
+
+type LibraryRequestInfo struct {
+ requestType int
+ bookRequestedISBN string
+}
+
+func (r *LibraryRequestInfo) GetType() int {
+ return r.requestType
+}
+
+func (r *LibraryRequestInfo) GetISBN() string {
+ return r.bookRequestedISBN
+}
+
+type LibraryResponse interface {
+ GetBook() (fmt.Stringer, error)
+ GetAvailability() (available int, registered int)
+}
+
+type LibraryResponseInfo struct {
+ book *Book
+ availableLeft int
+ registered int
+ error error
+}
+
+func (l *LibraryResponseInfo) GetBook() (fmt.Stringer, error) {
+ if l.book == nil {
+ return nil, l.error
+ }
+ return l.book, nil
+}
+
+func (l *LibraryResponseInfo) GetAvailability() (available int, registered int) {
+ return l.availableLeft, l.registered
+}