15-440 Project 2 FAQ

The following web page is supplement to the main project document, available as a PDF .

How do I turn in Part 3?

Just like part 2, except the root directory of your solution has to be named P2-3 instead of P2-2.

Is is normal to get "0.0/100.0" after I upload my solution?

Yes (if your solution builds and the log ends with OK).

Why do I get a "tar: This does not look like a tar archive" error when I submit my solution on Autolab?

Because of Autolab limitations, your tar archive has to be smaller than 2 MB. Make sure you clean your directory ("gb -c" and delete any hidden files -- anything that starts with a ".", e.g., .__afs6763). Also, make sure you have no symbolic links.

How do I turn in Part 2?

We will use Autolab:

Unfortunately we have not been able to finalize the automated tests for part 2, so for now, you will not see test results in the upload log.

How do I initialize the RPCs for Storage Servers?

Most of the initialization code is already provided to you (server/server.go). You have to implement the rest (client-side RPC initialization via rpc.DialHTTP) as part of the Storage Server initialization.

How do I turn in my code for Part 1?

Copy the directory containing your solution to /afs/cs.cmu.edu/academic/class/15440-f11/P2/P2-1/<your_andrew_id>. It is sufficient if only one of the partners turns in the code, but make sure to specify in the README who the other person was. Make sure your code builds by running "gb" in the root directory of your solution. Also, make sure you run "gb -c" before copying your solution to AFS.

What characters are allowed in usernames?

Colons are not allowed. Past that, it's up to you. Because we didn't specify this, we won't test with anything other than a-z, A-Z, and 0-9.

When I run gb -t to test, I get the error "can't find import: tribproto"

You must run gb -t from the root source directory, NOT from the server directory.

Should I write the tribbles to disk?

No. The back-end store is simply an in-memory hashtable (a Go map).

What should be the signatures for Get, Put, AddToList and RemoveFromList?

You have to define these signatures yourself, but it is sufficient to make them take only a key and a value as arguments.

If I implement AddToList and RemoveFromList, why do I need Get and Put?

Remember, it is not a good design to store a user's tribbles in a list. Instead, the list should contain only tribble ids (that you have to define). Tribbles should be stored as separate objects in the hashtable, with the tribble id as the key. Get and Put should therefore be used for tribbles, and AddToList and RemoveFromList for manipulating lists (i.e., lists of tribble ids, and lists of "followees").

Does GetTribblesBySubscription retrieve 100 tribbles for each followed user, or 100 tribbles in total?

100 in total.

Can I delete tribbles that are older than the most recent 100?

No. The back-end has to store all the tribbles ever posted.

Should both the keys and the values be JSON-encoded?

It is sufficient to encode only the values (before adding them to the hashtable).

How will points be allocated for the project?

Coming soon

How should my partner and I work on the project together?

We strongly recommend that you use git to do so. See the 15-410 Git Quickstart for help. More information coming on this soon.

How do I JSON-encode something in Go?

Use the package json. Documentation on specific usage is available at: http://golang.org/pkg/json/ and more information on JSON in general is available at http://www.json.org/.

What are some ways to serialize access to a map object?

As the saying goes, there is more than one way to skin this cat.

How do I create a map in Go?

The map data structure in Go allows you to associate values of any type (that are able to be compared with the == operator), with any other type.
Initialize a map as a type with:

type SomeMap map[int]string
myMap := make(SomeMap)
Add a value to the map with:
myMap[1] = "Some String"
You can retrieve this value, along with a boolean telling you if the key is present in the map, with:
value, present := myMap[1]

How do I serialize aceess to a map with a mutex lock in Go?

Utilize the "sync" package to apply a mutex lock to the data structure.
One way this can be implemented is to declare the map type as a struct with two fields - one for the map itself, and one for the lock.

import "sync"

type SomeMap struct {
     theData map[int]string
     theLock sync.RWMutex
However, because of the lack of constructors in Go, you now need a better way to initialize the map. The convention for addressing this is to create a function with the prefix "New" to initialize and return an instance of the type.
func NewSomeMap() *SomeMap {
     return &SomeMap {
     	    theData: make(map[int]string)

An important feature of the mutext lock in Go's sync package is that it has two locks: a read lock and a write lock. Multiple readers can obtain the read lock in parallel, but only one write lock can be obtained at a time (and that lock also excludes readers while active).

This implies that interactions with the map now need to occur through intermediary functions - such as GET and PUT.
For examples, the GET function might look something like this:
func (s *SomeMap) GET(key int) string {
     defer s.theLock.RUnlock()
     return s.theData[key]
And the PUT function might look something like this:
func (s *SomeMap) PUT(key, inputData string) bool {
     defer s.theLock.Unlock()
     //Perhaps add some failure condition here that returns false - for example if the key already exists.
     s.theData[key] = inputData
     return true

Last updated: Mon Dec 12 16:10:50 -0500 2011 [validate xhtml]