You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
5.0 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
  1. package cassandra
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "github.com/gocql/gocql"
  7. "github.com/chrislusf/seaweedfs/weed/filer2"
  8. "github.com/chrislusf/seaweedfs/weed/glog"
  9. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  10. "github.com/chrislusf/seaweedfs/weed/util"
  11. )
  12. func init() {
  13. filer2.Stores = append(filer2.Stores, &CassandraStore{})
  14. }
  15. type CassandraStore struct {
  16. cluster *gocql.ClusterConfig
  17. session *gocql.Session
  18. }
  19. func (store *CassandraStore) GetName() string {
  20. return "cassandra"
  21. }
  22. func (store *CassandraStore) Initialize(configuration util.Configuration, prefix string) (err error) {
  23. return store.initialize(
  24. configuration.GetString(prefix+"keyspace"),
  25. configuration.GetStringSlice(prefix+"hosts"),
  26. )
  27. }
  28. func (store *CassandraStore) initialize(keyspace string, hosts []string) (err error) {
  29. store.cluster = gocql.NewCluster(hosts...)
  30. store.cluster.Keyspace = keyspace
  31. store.cluster.Consistency = gocql.LocalQuorum
  32. store.session, err = store.cluster.CreateSession()
  33. if err != nil {
  34. glog.V(0).Infof("Failed to open cassandra store, hosts %v, keyspace %s", hosts, keyspace)
  35. }
  36. return
  37. }
  38. func (store *CassandraStore) BeginTransaction(ctx context.Context) (context.Context, error) {
  39. return ctx, nil
  40. }
  41. func (store *CassandraStore) CommitTransaction(ctx context.Context) error {
  42. return nil
  43. }
  44. func (store *CassandraStore) RollbackTransaction(ctx context.Context) error {
  45. return nil
  46. }
  47. func (store *CassandraStore) InsertEntry(ctx context.Context, entry *filer2.Entry) (err error) {
  48. dir, name := entry.FullPath.DirAndName()
  49. meta, err := entry.EncodeAttributesAndChunks()
  50. if err != nil {
  51. return fmt.Errorf("encode %s: %s", entry.FullPath, err)
  52. }
  53. if err := store.session.Query(
  54. "INSERT INTO filemeta (directory,name,meta) VALUES(?,?,?) USING TTL ? ",
  55. dir, name, meta, entry.TtlSec).Exec(); err != nil {
  56. return fmt.Errorf("insert %s: %s", entry.FullPath, err)
  57. }
  58. return nil
  59. }
  60. func (store *CassandraStore) UpdateEntry(ctx context.Context, entry *filer2.Entry) (err error) {
  61. return store.InsertEntry(ctx, entry)
  62. }
  63. func (store *CassandraStore) FindEntry(ctx context.Context, fullpath util.FullPath) (entry *filer2.Entry, err error) {
  64. dir, name := fullpath.DirAndName()
  65. var data []byte
  66. if err := store.session.Query(
  67. "SELECT meta FROM filemeta WHERE directory=? AND name=?",
  68. dir, name).Consistency(gocql.One).Scan(&data); err != nil {
  69. if err != gocql.ErrNotFound {
  70. return nil, filer_pb.ErrNotFound
  71. }
  72. }
  73. if len(data) == 0 {
  74. return nil, filer_pb.ErrNotFound
  75. }
  76. entry = &filer2.Entry{
  77. FullPath: fullpath,
  78. }
  79. err = entry.DecodeAttributesAndChunks(data)
  80. if err != nil {
  81. return entry, fmt.Errorf("decode %s : %v", entry.FullPath, err)
  82. }
  83. return entry, nil
  84. }
  85. func (store *CassandraStore) DeleteEntry(ctx context.Context, fullpath util.FullPath) error {
  86. dir, name := fullpath.DirAndName()
  87. if err := store.session.Query(
  88. "DELETE FROM filemeta WHERE directory=? AND name=?",
  89. dir, name).Exec(); err != nil {
  90. return fmt.Errorf("delete %s : %v", fullpath, err)
  91. }
  92. return nil
  93. }
  94. func (store *CassandraStore) DeleteFolderChildren(ctx context.Context, fullpath util.FullPath) error {
  95. if err := store.session.Query(
  96. "DELETE FROM filemeta WHERE directory=?",
  97. fullpath).Exec(); err != nil {
  98. return fmt.Errorf("delete %s : %v", fullpath, err)
  99. }
  100. return nil
  101. }
  102. func (store *CassandraStore) ListDirectoryPrefixedEntries(ctx context.Context, fullpath util.FullPath, startFileName string, inclusive bool, limit int, prefix string) (entries []*filer2.Entry, err error) {
  103. count := 0
  104. notPrefixed, err := store.ListDirectoryEntries(ctx, fullpath, startFileName, inclusive, limit)
  105. if err != nil {
  106. return nil, err
  107. }
  108. if prefix == "" {
  109. return notPrefixed, nil
  110. }
  111. for count < limit {
  112. for _, entry := range notPrefixed {
  113. if strings.HasPrefix(entry.Name(), prefix) {
  114. count++
  115. entries = append(entries, entry)
  116. }
  117. }
  118. if count >= limit {
  119. break
  120. }
  121. notPrefixed, err = store.ListDirectoryEntries(ctx, fullpath, startFileName, inclusive, limit)
  122. if err != nil {
  123. return nil, err
  124. }
  125. }
  126. return entries, nil
  127. }
  128. func (store *CassandraStore) ListDirectoryEntries(ctx context.Context, fullpath util.FullPath, startFileName string, inclusive bool,
  129. limit int) (entries []*filer2.Entry, err error) {
  130. cqlStr := "SELECT NAME, meta FROM filemeta WHERE directory=? AND name>? ORDER BY NAME ASC LIMIT ?"
  131. if inclusive {
  132. cqlStr = "SELECT NAME, meta FROM filemeta WHERE directory=? AND name>=? ORDER BY NAME ASC LIMIT ?"
  133. }
  134. var data []byte
  135. var name string
  136. iter := store.session.Query(cqlStr, string(fullpath), startFileName, limit).Iter()
  137. for iter.Scan(&name, &data) {
  138. entry := &filer2.Entry{
  139. FullPath: util.NewFullPath(string(fullpath), name),
  140. }
  141. if decodeErr := entry.DecodeAttributesAndChunks(data); decodeErr != nil {
  142. err = decodeErr
  143. glog.V(0).Infof("list %s : %v", entry.FullPath, err)
  144. break
  145. }
  146. entries = append(entries, entry)
  147. }
  148. if err := iter.Close(); err != nil {
  149. glog.V(0).Infof("list iterator close: %v", err)
  150. }
  151. return entries, err
  152. }
  153. func (store *CassandraStore) Shutdown() {
  154. store.session.Close()
  155. }