Skip to content

Commit

Permalink
testing: store containers in map instead of slice for faster lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
cezarsa committed Apr 26, 2018
1 parent 7ac8442 commit 9e249ff
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 324 deletions.
112 changes: 61 additions & 51 deletions testing/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ var nameRegexp = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`)
//
// For more details on the remote API, check http://goo.gl/G3plxW.
type DockerServer struct {
containers []*docker.Container
containers map[string]*docker.Container
contNameToID map[string]string
uploadedFiles map[string]string
execs []*docker.ExecInspect
execMut sync.RWMutex
Expand Down Expand Up @@ -80,19 +81,25 @@ type volumeCounter struct {
count int
}

func buildDockerServer(listener net.Listener, containerChan chan<- *docker.Container, hook func(*http.Request)) *DockerServer {
server := DockerServer{
listener: listener,
func baseDockerServer() DockerServer {
return DockerServer{
containers: make(map[string]*docker.Container),
contNameToID: make(map[string]string),
imgIDs: make(map[string]string),
images: make(map[string]docker.Image),
hook: hook,
failures: make(map[string]string),
execCallbacks: make(map[string]func()),
statsCallbacks: make(map[string]func(string) docker.Stats),
customHandlers: make(map[string]http.Handler),
uploadedFiles: make(map[string]string),
cChan: containerChan,
}
}

func buildDockerServer(listener net.Listener, containerChan chan<- *docker.Container, hook func(*http.Request)) *DockerServer {
server := baseDockerServer()
server.listener = listener
server.hook = hook
server.cChan = containerChan
server.buildMuxer()
return &server
}
Expand Down Expand Up @@ -301,11 +308,9 @@ func (s *DockerServer) CustomHandler(path string, handler http.Handler) {
func (s *DockerServer) MutateContainer(id string, state docker.State) error {
s.cMut.Lock()
defer s.cMut.Unlock()
for _, container := range s.containers {
if container.ID == id {
container.State = state
return nil
}
if container, ok := s.containers[id]; ok {
container.State = state
return nil
}
return errors.New("container not found")
}
Expand Down Expand Up @@ -534,22 +539,28 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
s.uploadedFiles[container.ID] = val
}
if container.Name != "" {
for _, c := range s.containers {
if c.Name == container.Name {
defer s.cMut.Unlock()
http.Error(w, "there's already a container with this name", http.StatusConflict)
return
}
_, err = s.findContainerWithLock(container.Name, false)
if err == nil {
defer s.cMut.Unlock()
http.Error(w, "there's already a container with this name", http.StatusConflict)
return
}
}
s.containers = append(s.containers, &container)
s.addContainer(&container)
s.cMut.Unlock()
w.WriteHeader(http.StatusCreated)
s.notify(&container)

json.NewEncoder(w).Encode(container)
}

func (s *DockerServer) addContainer(container *docker.Container) {
s.containers[container.ID] = container
if container.Name != "" {
s.contNameToID[container.Name] = container.ID
}
}

func (s *DockerServer) generateID() string {
var buf [16]byte
rand.Read(buf[:])
Expand All @@ -558,24 +569,22 @@ func (s *DockerServer) generateID() string {

func (s *DockerServer) renameContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, index, err := s.findContainer(id)
s.cMut.Lock()
defer s.cMut.Unlock()
container, err := s.findContainerWithLock(id, false)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
s.cMut.Lock()
defer s.cMut.Unlock()
copy := *container
copy.Name = r.URL.Query().Get("name")
if s.containers[index].ID == copy.ID {
s.containers[index] = &copy
}
delete(s.contNameToID, container.Name)
container.Name = r.URL.Query().Get("name")
s.contNameToID[container.Name] = container.ID
w.WriteHeader(http.StatusNoContent)
}

func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -589,7 +598,7 @@ func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request)

func (s *DockerServer) statsContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
_, _, err := s.findContainer(id)
_, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -613,7 +622,7 @@ func (s *DockerServer) statsContainer(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) uploadToContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
_, _, err := s.findContainer(id)
_, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -633,7 +642,7 @@ func (s *DockerServer) uploadToContainer(w http.ResponseWriter, r *http.Request)

func (s *DockerServer) downloadFromContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
_, _, err := s.findContainer(id)
_, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -653,7 +662,7 @@ func (s *DockerServer) downloadFromContainer(w http.ResponseWriter, r *http.Requ

func (s *DockerServer) topContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -678,7 +687,7 @@ func (s *DockerServer) topContainer(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand Down Expand Up @@ -729,7 +738,7 @@ func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -747,7 +756,7 @@ func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) pauseContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -764,7 +773,7 @@ func (s *DockerServer) pauseContainer(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) unpauseContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -781,7 +790,7 @@ func (s *DockerServer) unpauseContainer(w http.ResponseWriter, r *http.Request)

func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand Down Expand Up @@ -833,7 +842,7 @@ func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) waitContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -858,7 +867,7 @@ func (s *DockerServer) removeContainer(w http.ResponseWriter, r *http.Request) {
force := r.URL.Query().Get("force")
s.cMut.Lock()
defer s.cMut.Unlock()
container, index, err := s.findContainerWithLock(id, false)
container, err := s.findContainerWithLock(id, false)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand All @@ -869,13 +878,13 @@ func (s *DockerServer) removeContainer(w http.ResponseWriter, r *http.Request) {
return
}
w.WriteHeader(http.StatusNoContent)
s.containers[index] = s.containers[len(s.containers)-1]
s.containers = s.containers[:len(s.containers)-1]
delete(s.containers, container.ID)
delete(s.contNameToID, container.Name)
}

func (s *DockerServer) commitContainer(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("container")
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand Down Expand Up @@ -917,26 +926,27 @@ func (s *DockerServer) commitContainer(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"ID":%q}`, image.ID)
}

func (s *DockerServer) findContainer(idOrName string) (*docker.Container, int, error) {
func (s *DockerServer) findContainer(idOrName string) (*docker.Container, error) {
return s.findContainerWithLock(idOrName, true)
}

func (s *DockerServer) findContainerWithLock(idOrName string, shouldLock bool) (*docker.Container, int, error) {
func (s *DockerServer) findContainerWithLock(idOrName string, shouldLock bool) (*docker.Container, error) {
if shouldLock {
s.cMut.RLock()
defer s.cMut.RUnlock()
}
for i, container := range s.containers {
if container.ID == idOrName || container.Name == idOrName {
return container, i, nil
}
if contID, ok := s.contNameToID[idOrName]; ok {
idOrName = contID
}
if cont, ok := s.containers[idOrName]; ok {
return cont, nil
}
return nil, -1, errors.New("No such container")
return nil, errors.New("No such container")
}

func (s *DockerServer) logContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand Down Expand Up @@ -1173,7 +1183,7 @@ func (s *DockerServer) getImage(w http.ResponseWriter, r *http.Request) {

func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
container, _, err := s.findContainer(id)
container, err := s.findContainer(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
Expand Down Expand Up @@ -1370,7 +1380,7 @@ func (s *DockerServer) networksConnect(w http.ResponseWriter, r *http.Request) {
}

network, index, _ := s.findNetwork(id)
container, _, _ := s.findContainer(config.Container)
container, _ := s.findContainer(config.Container)
if network == nil || container == nil {
http.Error(w, "network or container not found", http.StatusNotFound)
return
Expand Down
Loading

0 comments on commit 9e249ff

Please sign in to comment.