Skip to content

concurrent write and foreach not working as expected. #159

@girishranganathan

Description

@girishranganathan

Hello,
I was playing with Tiedot and came across an interesting scenario. I took the example code and modified it to simulate some concurrency.

Here is my code:

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/HouzuoGuo/tiedot/db"
	"github.com/HouzuoGuo/tiedot/dberr"
)

func main() {
	myDBDir := "MyDatabase"
	os.RemoveAll(myDBDir)
	defer os.RemoveAll(myDBDir)

	// (Create if not exist) open a database
	myDB, err := db.OpenDB(myDBDir)
	if err != nil {
		panic(err)
	}

	// Create  collections: Feeds
	if err := myDB.Create("Feeds"); err != nil {
		panic(err)
	}

	// ****************** Document Management ******************

	// Start using a collection (the reference is valid until DB schema changes or Scrub is carried out)
	feeds := myDB.Use("Feeds")

	go func() {
		// myDB, err := db.OpenDB(myDBDir)
		// if err != nil {
		// 	panic(err)
		// }
		// feeds := myDB.Use("Feeds")
		for {
			// Insert document (afterwards the docID uniquely identifies the document and will never change)
			docID, err := feeds.Insert(map[string]interface{}{
				"doc": fmt.Sprintf("Go 1.2 is released %d", time.Now().UnixNano())})
			if err != nil {
				panic(err)
			}

			// Read document
			readBack, err := feeds.Read(docID)
			if err != nil {
				panic(err)
			}
			fmt.Println("Inserting - Document", docID, "is", readBack)
			// if err := myDB.Scrub("Feeds"); err != nil {
			// 	panic(err)
			// }
			time.Sleep(time.Millisecond)
		}
	}()
	time.Sleep(time.Second)
	go func() {
		// myDB, err := db.OpenDB(myDBDir)
		// if err != nil {
		// 	panic(err)
		// }
		// feeds := myDB.Use("Feeds")
		for {
			fmt.Println("Read - looping")
			// Process all documents (note that document order is undetermined)
			feeds.ForEachDoc(func(id int, _ []byte) (willMoveOn bool) {
				fmt.Println("Read - Document id:", id)
				data, err := feeds.Read(id)
				if err != nil {
					panic(err)
				}
				fmt.Println("Read - Document read:", data)

				err = feeds.Delete(id)
				if dberr.Type(err) == dberr.ErrorNoDoc {
					fmt.Println("Read - The document was already deleted")
				} else {
					panic(err)
				}
				return true // move on to the next document
			})
			time.Sleep(time.Millisecond)
		}
	}()
	fmt.Println("Out of the loops. . . ")
	var str string
	fmt.Scanln(&str)
	// Gracefully close database
	if err := myDB.Close(); err != nil {
		panic(err)
	}
}

I tried this on a mac and a linux box and the behavior was exactly the same. Looks like foreach locks up after the first read.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions