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

concurrent write and foreach not working as expected. #159

Open
girishranganathan opened this issue Jan 3, 2018 · 2 comments
Open

concurrent write and foreach not working as expected. #159

girishranganathan opened this issue Jan 3, 2018 · 2 comments

Comments

@girishranganathan
Copy link

girishranganathan commented Jan 3, 2018

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.

@HouzuoGuo
Copy link
Owner

Thanks for the feedback, there is an oversight in documentation, the input function may not modify data while iteration is taking place. For your use case, please use the iterator function to collect the document IDs to delete, and then delete each of them afterwards.

I shall note this down in the ForEachDoc function.

@girishranganathan
Copy link
Author

Thanks a lot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants